introduce-booking-module #41

Merged
hsh-michaelhoennig merged 21 commits from introduce-booking-module into master 2024-04-16 11:21:35 +02:00
10 changed files with 65 additions and 52 deletions
Showing only changes of commit 89ef2d9126 - Show all commits

View File

@ -26,7 +26,7 @@ import java.util.UUID;
import java.util.function.BinaryOperator; import java.util.function.BinaryOperator;
import static java.util.Optional.ofNullable; 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.lowerInclusiveFromPostgresDateRange;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange; import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.upperInclusiveFromPostgresDateRange; 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.getDebitor().toShortString())
.withProp(e -> e.getValidity().asString()) .withProp(e -> e.getValidity().asString())
.withProp(HsBookingItemEntity::getCaption) .withProp(HsBookingItemEntity::getCaption)
.withProp(HsBookingItemEntity::getResources) .withProp(HsBookingItemEntity::getResourcesAsString)
.quotedValues(false); .quotedValues(false);
private String getResourcesAsString() {
return "{ " +
(
resources.keySet().stream().sorted()
.map(k -> k + ": " + resources.get(k)))
.collect(joining(", ")
) + " }";
}
@Id @Id
@GeneratedValue @GeneratedValue
private UUID uuid; private UUID uuid;
@ -78,11 +87,6 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject {
@Column(columnDefinition = "resources") @Column(columnDefinition = "resources")
private Map<String, Object> resources = new TreeMap<>(); 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) { public void setValidFrom(final LocalDate validFrom) {
setValidity(toPostgresDateRange(validFrom, getValidTo())); 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.hs.booking.generated.api.v1.model.HsBookingItemPatchResource;
import net.hostsharing.hsadminng.mapper.EntityPatcher; import net.hostsharing.hsadminng.mapper.EntityPatcher;
import net.hostsharing.hsadminng.mapper.OptionalFromJson; import net.hostsharing.hsadminng.mapper.OptionalFromJson;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
@ -38,16 +39,24 @@ public class HsBookingItemEntityPatcher implements EntityPatcher<HsBookingItemPa
} }
static Map<String, Object> objectToMap(final Object obj) { static Map<String, Object> objectToMap(final Object obj) {
final var map = stream(obj.getClass().getDeclaredFields()) return stream(obj.getClass().getDeclaredFields())
.map(field -> { .map(field -> {
try { try {
field.setAccessible(true); field.setAccessible(true);
return Map.entry(field.getName(), field.get(obj)); return new ImmutablePair<>(field.getName(), field.get(obj));
} catch (final IllegalAccessException exc) { } catch (final IllegalAccessException exc) {
throw new RuntimeException(exc); throw new RuntimeException(exc);
} }
}) })
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .reduce(
return map; 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.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;

View File

@ -2,9 +2,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
import net.hostsharing.hsadminng.context.Context; 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.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.HsOfficeCoopSharesTransactionInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionResource;
import net.hostsharing.hsadminng.mapper.Mapper; import net.hostsharing.hsadminng.mapper.Mapper;

View File

@ -6,7 +6,6 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import net.hostsharing.hsadminng.errors.DisplayName; 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.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;

View File

@ -148,6 +148,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenBookingItemUuid = bookingItemRepo.findAll().stream() final var givenBookingItemUuid = bookingItemRepo.findAll().stream()
.filter(bi -> bi.getDebitor().getDebitorNumber() == 1000111) .filter(bi -> bi.getDebitor().getDebitorNumber() == 1000111)
.filter(item -> item.getCaption().equals("some CloudServer"))
.findAny().orElseThrow().getUuid(); .findAny().orElseThrow().getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
@ -192,8 +193,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenBookingItemUuid = bookingItemRepo.findAll().stream() final var givenBookingItemUuid = bookingItemRepo.findAll().stream()
.filter(bi -> bi.getDebitor().getDebitorNumber() == 1000313) .filter(bi -> bi.getDebitor().getDebitorNumber() == 1000313)
.filter(item -> item.getCaption().equals("some CloudServer"))
.findAny().orElseThrow().getUuid(); .findAny().orElseThrow().getUuid();
generateRbacDiagramForObjectPermission(givenBookingItemUuid, "SELECT", "booking-item-of-debitor-1000313");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .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_FROM = LocalDate.parse("2022-10-30");
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31"); private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
private static final ArbitraryBookingResourcesJsonResource PATCHED_RESOURCES = new ArbitraryBookingResourcesJsonResource() { private static final ArbitraryBookingResourcesJsonResource INITIAL_RESOURCES = new ArbitraryBookingResourcesJsonResource() {
int cpus = 2; Integer cpus = 1;
int sddStorage = 256; Integer hddStorage = 1024;
int hddStorage = 2048;
}; };
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 @Mock
private EntityManager em; private EntityManager em;
@ -58,8 +63,8 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase<
final var entity = new HsBookingItemEntity(); final var entity = new HsBookingItemEntity();
entity.setUuid(INITIAL_BOOKING_ITEM_UUID); entity.setUuid(INITIAL_BOOKING_ITEM_UUID);
entity.setDebitor(TEST_DEBITOR); entity.setDebitor(TEST_DEBITOR);
entity.setResources(objectToMap(PATCHED_RESOURCES)); entity.setResources(objectToMap(INITIAL_RESOURCES));
entity.setCaption(PATCHED_CAPTION); entity.setCaption(INITIAL_CAPTION);
entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM)); entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM));
return entity; return entity;
} }
@ -82,13 +87,13 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase<
HsBookingItemPatchResource::setCaption, HsBookingItemPatchResource::setCaption,
PATCHED_CAPTION, PATCHED_CAPTION,
HsBookingItemEntity::setCaption), HsBookingItemEntity::setCaption),
// FIXME new SimpleProperty<>(
// new JsonNullableProperty<>( "resources",
// "resources", HsBookingItemPatchResource::setResources,
// HsBookingItemPatchResource::setResources, PATCHED_RESOURCES,
// PATCHED_RESOURCES, HsBookingItemEntity::setResources,
// HsBookingItemEntity::setResources, objectToMap(PATCHED_RESOURCES))
// objectToMap(PATCHED_RESOURCES)), .notNullable(),
new JsonNullableProperty<>( new JsonNullableProperty<>(
"validfrom", "validfrom",
HsBookingItemPatchResource::setValidFrom, HsBookingItemPatchResource::setValidFrom,

View File

@ -28,7 +28,7 @@ class HsBookingItemEntityUnitTest {
void toStringContainsAllPropertiesAndResourcesSortedByKey() { void toStringContainsAllPropertiesAndResourcesSortedByKey() {
final var result = givenBookingItem.toString(); 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 @Test

View File

@ -109,16 +109,16 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
final var all = rawRoleRepo.findAll(); final var all = rawRoleRepo.findAll();
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from( assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
initialRoleNames, initialRoleNames,
"hs_booking_item#somenewbookingitem:ADMIN", "hs_booking_item#D-1000111:some new booking item:ADMIN",
"hs_booking_item#somenewbookingitem:OWNER", "hs_booking_item#D-1000111:some new booking item:OWNER",
"hs_booking_item#somenewbookingitem:TENANT")); "hs_booking_item#D-1000111:some new booking item:TENANT"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())) assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(fromFormatted( .containsExactlyInAnyOrder(fromFormatted(
initialGrantNames, initialGrantNames,
// insert+delete // 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 // owner
@ -126,12 +126,12 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// tenant // tenant
"{ grant perm:hs_booking_item#somenewbookingitem:SELECT 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#somenewbookingitem:UPDATE to role:hs_booking_item#somenewbookingitem:OWNER 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#somenewbookingitem:ADMIN to role:hs_booking_item#somenewbookingitem: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#somenewbookingitem:OWNER to role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:AGENT 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#somenewbookingitem:TENANT to role:hs_booking_item#somenewbookingitem:ADMIN 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#somenewbookingitem:TENANT 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)); null));
} }
@ -148,7 +148,8 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
public void globalAdmin_withoutAssumedRole_canViewAllBookingItemsOfArbitraryDebitor() { public void globalAdmin_withoutAssumedRole_canViewAllBookingItemsOfArbitraryDebitor() {
// given // given
context("superuser-alex@hostsharing.net"); 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 // when
final var result = bookingItemRepo.findAllByDebitorUuid(debitorUuid); final var result = bookingItemRepo.findAllByDebitorUuid(debitorUuid);
@ -156,9 +157,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// then // then
allTheseBookingItemsAreReturned( allTheseBookingItemsAreReturned(
result, 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, [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})"); "HsBookingItemEntity(D-1000212, [2024-04-01,), some Whatever, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })");
} }
@Test @Test
@ -173,9 +174,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
// then: // then:
exactlyTheseBookingItemsAreReturned( exactlyTheseBookingItemsAreReturned(
result, 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, [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})"); "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; 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 org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import static net.hostsharing.hsadminng.hs.office.membership.TestHsMembership.TEST_MEMBERSHIP; import static net.hostsharing.hsadminng.hs.office.membership.TestHsMembership.TEST_MEMBERSHIP;