implement patching BookingItem.resources

This commit is contained in:
Michael Hoennig 2024-04-14 11:58:57 +02:00
parent 9d0dc358f0
commit 89ef2d9126
10 changed files with 65 additions and 52 deletions

View File

@ -26,7 +26,7 @@ import java.util.UUID;
import java.util.function.BinaryOperator;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.joining;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.lowerInclusiveFromPostgresDateRange;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.upperInclusiveFromPostgresDateRange;
@ -51,9 +51,18 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject {
.withProp(e -> e.getDebitor().toShortString())
.withProp(e -> e.getValidity().asString())
.withProp(HsBookingItemEntity::getCaption)
.withProp(HsBookingItemEntity::getResources)
.withProp(HsBookingItemEntity::getResourcesAsString)
.quotedValues(false);
private String getResourcesAsString() {
return "{ " +
(
resources.keySet().stream().sorted()
.map(k -> k + ": " + resources.get(k)))
.collect(joining(", ")
) + " }";
}
@Id
@GeneratedValue
private UUID uuid;
@ -78,11 +87,6 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject {
@Column(columnDefinition = "resources")
private Map<String, Object> resources = new TreeMap<>();
public Map<String, Object> getResources() {
return resources.entrySet().stream()
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, HsBookingItemEntity::thereIsOnlyOneValuePerKey, TreeMap::new));
}
public void setValidFrom(final LocalDate validFrom) {
setValidity(toPostgresDateRange(validFrom, getValidTo()));
}

View File

@ -4,10 +4,11 @@ import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.ArbitraryBook
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemPatchResource;
import net.hostsharing.hsadminng.mapper.EntityPatcher;
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import static java.util.Arrays.stream;
@ -38,16 +39,24 @@ public class HsBookingItemEntityPatcher implements EntityPatcher<HsBookingItemPa
}
static Map<String, Object> objectToMap(final Object obj) {
final var map = stream(obj.getClass().getDeclaredFields())
return stream(obj.getClass().getDeclaredFields())
.map(field -> {
try {
field.setAccessible(true);
return Map.entry(field.getName(), field.get(obj));
return new ImmutablePair<>(field.getName(), field.get(obj));
} catch (final IllegalAccessException exc) {
throw new RuntimeException(exc);
}
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return map;
.reduce(
new HashMap<>(),
(map, pair) -> {
map.put(pair.getKey(), pair.getValue());
return map;
},
(map1, map2) -> {
map1.putAll(map2);
return map1;
});
}
}

View File

@ -18,7 +18,6 @@ import jakarta.persistence.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Optional;
import java.util.UUID;
import static java.util.Optional.ofNullable;

View File

@ -2,9 +2,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
import jakarta.persistence.EntityNotFoundException;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionResource;
import net.hostsharing.hsadminng.mapper.Mapper;

View File

@ -6,7 +6,6 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionEntity;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;

View File

@ -148,6 +148,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
context.define("superuser-alex@hostsharing.net");
final var givenBookingItemUuid = bookingItemRepo.findAll().stream()
.filter(bi -> bi.getDebitor().getDebitorNumber() == 1000111)
.filter(item -> item.getCaption().equals("some CloudServer"))
.findAny().orElseThrow().getUuid();
RestAssured // @formatter:off
@ -192,8 +193,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
context.define("superuser-alex@hostsharing.net");
final var givenBookingItemUuid = bookingItemRepo.findAll().stream()
.filter(bi -> bi.getDebitor().getDebitorNumber() == 1000313)
.filter(item -> item.getCaption().equals("some CloudServer"))
.findAny().orElseThrow().getUuid();
generateRbacDiagramForObjectPermission(givenBookingItemUuid, "SELECT", "booking-item-of-debitor-1000313");
RestAssured // @formatter:off
.given()

View File

@ -35,12 +35,17 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase<
private static final LocalDate PATCHED_VALID_FROM = LocalDate.parse("2022-10-30");
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
private static final ArbitraryBookingResourcesJsonResource PATCHED_RESOURCES = new ArbitraryBookingResourcesJsonResource() {
int cpus = 2;
int sddStorage = 256;
int hddStorage = 2048;
private static final ArbitraryBookingResourcesJsonResource INITIAL_RESOURCES = new ArbitraryBookingResourcesJsonResource() {
Integer cpus = 1;
Integer hddStorage = 1024;
};
private static final String PATCHED_CAPTION = "caption-patched";
private static final ArbitraryBookingResourcesJsonResource PATCHED_RESOURCES = new ArbitraryBookingResourcesJsonResource() {
Integer cpus = 2;
Integer sddStorage = 256;
Integer hddStorage = null;
};
private static final String INITIAL_CAPTION = "initial caption";
private static final String PATCHED_CAPTION = "patched caption";
@Mock
private EntityManager em;
@ -58,8 +63,8 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase<
final var entity = new HsBookingItemEntity();
entity.setUuid(INITIAL_BOOKING_ITEM_UUID);
entity.setDebitor(TEST_DEBITOR);
entity.setResources(objectToMap(PATCHED_RESOURCES));
entity.setCaption(PATCHED_CAPTION);
entity.setResources(objectToMap(INITIAL_RESOURCES));
entity.setCaption(INITIAL_CAPTION);
entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM));
return entity;
}
@ -82,13 +87,13 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase<
HsBookingItemPatchResource::setCaption,
PATCHED_CAPTION,
HsBookingItemEntity::setCaption),
// FIXME
// new JsonNullableProperty<>(
// "resources",
// HsBookingItemPatchResource::setResources,
// PATCHED_RESOURCES,
// HsBookingItemEntity::setResources,
// objectToMap(PATCHED_RESOURCES)),
new SimpleProperty<>(
"resources",
HsBookingItemPatchResource::setResources,
PATCHED_RESOURCES,
HsBookingItemEntity::setResources,
objectToMap(PATCHED_RESOURCES))
.notNullable(),
new JsonNullableProperty<>(
"validfrom",
HsBookingItemPatchResource::setValidFrom,

View File

@ -28,7 +28,7 @@ class HsBookingItemEntityUnitTest {
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
final var result = givenBookingItem.toString();
assertThat(result).isEqualTo("HsBookingItemEntity(D-1000100, [2020-01-01,2031-01-01), some caption, {CPUs=2, HDD-storage=2048, SSD-storage=512})");
assertThat(result).isEqualTo("HsBookingItemEntity(D-1000100, [2020-01-01,2031-01-01), some caption, { CPUs: 2, HDD-storage: 2048, SSD-storage: 512 })");
}
@Test

View File

@ -109,16 +109,16 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
final var all = rawRoleRepo.findAll();
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
initialRoleNames,
"hs_booking_item#somenewbookingitem:ADMIN",
"hs_booking_item#somenewbookingitem:OWNER",
"hs_booking_item#somenewbookingitem:TENANT"));
"hs_booking_item#D-1000111:some new booking item:ADMIN",
"hs_booking_item#D-1000111:some new booking item:OWNER",
"hs_booking_item#D-1000111:some new booking item:TENANT"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(fromFormatted(
initialGrantNames,
// insert+delete
"{ grant perm:hs_booking_item#somenewbookingitem:DELETE to role:global#global:ADMIN by system and assume }",
"{ grant perm:hs_booking_item#D-1000111:some new booking item:DELETE to role:global#global:ADMIN by system and assume }",
// owner
@ -126,12 +126,12 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// tenant
"{ grant perm:hs_booking_item#somenewbookingitem:SELECT to role:hs_booking_item#somenewbookingitem:TENANT by system and assume }",
"{ grant perm:hs_booking_item#somenewbookingitem:UPDATE to role:hs_booking_item#somenewbookingitem:OWNER by system and assume }",
"{ grant role:hs_booking_item#somenewbookingitem:ADMIN to role:hs_booking_item#somenewbookingitem:OWNER by system and assume }",
"{ grant role:hs_booking_item#somenewbookingitem:OWNER to role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:AGENT by system and assume }",
"{ grant role:hs_booking_item#somenewbookingitem:TENANT to role:hs_booking_item#somenewbookingitem:ADMIN by system and assume }",
"{ grant role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:TENANT to role:hs_booking_item#somenewbookingitem:TENANT by system and assume }",
"{ grant perm:hs_booking_item#D-1000111:some new booking item:SELECT to role:hs_booking_item#D-1000111:some new booking item:TENANT by system and assume }",
"{ grant perm:hs_booking_item#D-1000111:some new booking item:UPDATE to role:hs_booking_item#D-1000111:some new booking item:OWNER by system and assume }",
"{ grant role:hs_booking_item#D-1000111:some new booking item:ADMIN to role:hs_booking_item#D-1000111:some new booking item:OWNER by system and assume }",
"{ grant role:hs_booking_item#D-1000111:some new booking item:OWNER to role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:AGENT by system and assume }",
"{ grant role:hs_booking_item#D-1000111:some new booking item:TENANT to role:hs_booking_item#D-1000111:some new booking item:ADMIN by system and assume }",
"{ grant role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:TENANT to role:hs_booking_item#D-1000111:some new booking item:TENANT by system and assume }",
null));
}
@ -148,7 +148,8 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
public void globalAdmin_withoutAssumedRole_canViewAllBookingItemsOfArbitraryDebitor() {
// given
context("superuser-alex@hostsharing.net");
final var debitorUuid = debitorRepo.findDebitorByDebitorNumber(1000212).stream().findAny().orElseThrow().getUuid();
final var debitorUuid = debitorRepo.findDebitorByDebitorNumber(1000212).stream()
.findAny().orElseThrow().getUuid();
// when
final var result = bookingItemRepo.findAllByDebitorUuid(debitorUuid);
@ -156,9 +157,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// then
allTheseBookingItemsAreReturned(
result,
"HsBookingItemEntity(D-1000212, [2023-01-15,2024-04-15), some CloudServer, {CPUs=2, HDD-storage=1024})",
"HsBookingItemEntity(D-1000212, [2022-10-01,), some ManagedServer, {CPUs=2, SDD-storage=512})",
"HsBookingItemEntity(D-1000212, [2024-04-01,), some Whatever, {CPUs=1, HDD-storage=2048, SDD-storage=512})");
"HsBookingItemEntity(D-1000212, [2022-10-01,), some ManagedServer, { CPUs: 2, SDD-storage: 512 })",
"HsBookingItemEntity(D-1000212, [2023-01-15,2024-04-15), some CloudServer, { CPUs: 2, HDD-storage: 1024 })",
"HsBookingItemEntity(D-1000212, [2024-04-01,), some Whatever, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })");
}
@Test
@ -173,9 +174,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// then:
exactlyTheseBookingItemsAreReturned(
result,
"HsBookingItemEntity(D-1000111, [2023-01-15,2024-04-15), some CloudServer, {CPUs=2, HDD-storage=1024})",
"HsBookingItemEntity(D-1000111, [2022-10-01,), some ManagedServer, {CPUs=2, SDD-storage=512})",
"HsBookingItemEntity(D-1000111, [2024-04-01,), some Whatever, {CPUs=1, HDD-storage=2048, SDD-storage=512})");
"HsBookingItemEntity(D-1000111, [2022-10-01,), some ManagedServer, { CPUs: 2, SDD-storage: 512 })",
"HsBookingItemEntity(D-1000111, [2023-01-15,2024-04-15), some CloudServer, { CPUs: 2, HDD-storage: 1024 })",
"HsBookingItemEntity(D-1000111, [2024-04-01,), some Whatever, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })");
}
}

View File

@ -1,10 +1,7 @@
package net.hostsharing.hsadminng.hs.office.coopshares;
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionEntity;
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.time.LocalDate;
import static net.hostsharing.hsadminng.hs.office.membership.TestHsMembership.TEST_MEMBERSHIP;