From fbd17a21e25eb244e6f9d928a52da0f83157a8fe Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 4 Sep 2024 11:15:37 +0200 Subject: [PATCH] ceate bookingitems for domain-setup hostingassets (#95) Co-authored-by: Michael Hoennig Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/95 Reviewed-by: Marc Sandlus --- doc/hs-hosting-asset-type-structure.md | 5 ++ .../hs/booking/item/HsBookingItemType.java | 3 +- .../HsBookingItemEntityValidatorRegistry.java | 2 + .../HsDomainSetupBookingItemValidator.java | 10 +++ .../hs/hosting/asset/HsHostingAssetType.java | 14 +++- .../HostingAssetEntityValidator.java | 28 ++++--- .../630-booking-item/6200-hs-booking-item.sql | 3 +- .../HsBookingItemEntityValidatorUnitTest.java | 3 +- ...sHostingAssetControllerAcceptanceTest.java | 19 ++++- .../asset/HsHostingAssetTypeUnitTest.java | 77 ++++++++++--------- ...ainSetupHostingAssetValidatorUnitTest.java | 22 +++++- .../hs/migration/ImportHostingAssets.java | 36 ++++++--- 12 files changed, 159 insertions(+), 63 deletions(-) create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java diff --git a/doc/hs-hosting-asset-type-structure.md b/doc/hs-hosting-asset-type-structure.md index 5fec7cff..7f9a9ae9 100644 --- a/doc/hs-hosting-asset-type-structure.md +++ b/doc/hs-hosting-asset-type-structure.md @@ -12,6 +12,7 @@ package Booking #feb28c { entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } package Hosting #feb28c{ @@ -67,6 +68,7 @@ package Booking #feb28c { entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } package Hosting #feb28c{ @@ -94,6 +96,7 @@ BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE +HA_DOMAIN_SETUP *==> BI_DOMAIN_SETUP HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP o--> HA_MANAGED_WEBSPACE @@ -125,6 +128,7 @@ package Booking #feb28c { entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } package Hosting #feb28c{ @@ -173,6 +177,7 @@ package Booking #feb28c { entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } package Hosting #feb28c{ diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemType.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemType.java index eee5c1eb..55ff8ede 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemType.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemType.java @@ -9,7 +9,8 @@ public enum HsBookingItemType implements Node { PRIVATE_CLOUD, CLOUD_SERVER(PRIVATE_CLOUD), MANAGED_SERVER(PRIVATE_CLOUD), - MANAGED_WEBSPACE(MANAGED_SERVER); + MANAGED_WEBSPACE(MANAGED_SERVER), + DOMAIN_SETUP; private final HsBookingItemType parentItemType; diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorRegistry.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorRegistry.java index 9387973a..8bfe12fd 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorRegistry.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorRegistry.java @@ -13,6 +13,7 @@ import java.util.Set; import static java.util.Arrays.stream; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER; +import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.DOMAIN_SETUP; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVATE_CLOUD; @@ -25,6 +26,7 @@ public class HsBookingItemEntityValidatorRegistry { register(CLOUD_SERVER, new HsCloudServerBookingItemValidator()); register(MANAGED_SERVER, new HsManagedServerBookingItemValidator()); register(MANAGED_WEBSPACE, new HsManagedWebspaceBookingItemValidator()); + register(DOMAIN_SETUP, new HsDomainSetupBookingItemValidator()); } private static void register(final Enum type, final HsEntityValidator validator) { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java new file mode 100644 index 00000000..a48ed4a5 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java @@ -0,0 +1,10 @@ +package net.hostsharing.hsadminng.hs.booking.item.validators; + +class HsDomainSetupBookingItemValidator extends HsBookingItemEntityValidator { + + HsDomainSetupBookingItemValidator() { + super( + // no properties yet. maybe later, the setup code goes here? + ); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetType.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetType.java index 51b6de46..82076fc0 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetType.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetType.java @@ -24,8 +24,10 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.opti import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.optionallyAssignedTo; import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.requiredParent; import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.requires; +import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.terminatory; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.OPTIONAL; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.REQUIRED; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.TERMINATORY; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.ASSIGNED_TO_ASSET; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.BOOKING_ITEM; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.PARENT_ASSET; @@ -57,6 +59,7 @@ public enum HsHostingAssetType implements Node { DOMAIN_SETUP( // named e.g. example.org inGroup("Domain"), + terminatory(HsBookingItemType.DOMAIN_SETUP), optionalParent(SAME_TYPE) ), @@ -339,7 +342,7 @@ public enum HsHostingAssetType implements Node { } public enum RelationPolicy { - FORBIDDEN, OPTIONAL, REQUIRED + FORBIDDEN, OPTIONAL, TERMINATORY, REQUIRED } public enum RelationType { @@ -376,6 +379,15 @@ class EntityTypeRelation { return (Set) result; } + static EntityTypeRelation terminatory(final HsBookingItemType bookingItemType) { + return new EntityTypeRelation<>( + TERMINATORY, + BOOKING_ITEM, + HsHostingAssetRbacEntity::getBookingItem, + bookingItemType, + " *..> "); + } + static EntityTypeRelation requires(final HsBookingItemType bookingItemType) { return new EntityTypeRelation<>( REQUIRED, diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidator.java index 24b3a1cc..bff087f4 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidator.java @@ -182,26 +182,36 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator validate(final HsHostingAsset assetEntity, final String referenceFieldName) { - final var actualEntity = referencedEntityGetter.apply(assetEntity); - final var actualEntityType = actualEntity != null ? referencedEntityTypeGetter.apply(actualEntity) : null; + final var referencedEntity = referencedEntityGetter.apply(assetEntity); + final var referencedEntityType = referencedEntity != null ? referencedEntityTypeGetter.apply(referencedEntity) : null; switch (policy) { case REQUIRED: - if (!referencedEntityTypes.contains(actualEntityType)) { - return List.of(actualEntityType == null + if (!referencedEntityTypes.contains(referencedEntityType)) { + return List.of(referencedEntityType == null ? referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is null" - : referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is of type " + actualEntityType); + : referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is of type " + referencedEntityType); + } + break; + case TERMINATORY: + if (assetEntity.getParentAsset() != null && assetEntity.getBookingItem() != null) { + return List.of(referenceFieldName + "' or parentItem must be null but is of type " + referencedEntityType); + } + if (assetEntity.getParentAsset() == null && !referencedEntityTypes.contains(referencedEntityType)) { + return List.of(referencedEntityType == null + ? referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is null" + : referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is of type " + referencedEntityType); } break; case OPTIONAL: - if (actualEntityType != null && !referencedEntityTypes.contains(actualEntityType)) { + if (referencedEntityType != null && !referencedEntityTypes.contains(referencedEntityType)) { return List.of(referenceFieldName + "' must be null or of type " + toDisplay(referencedEntityTypes) + " but is of type " - + actualEntityType); + + referencedEntityType); } break; case FORBIDDEN: - if (actualEntityType != null) { - return List.of(referenceFieldName + "' must be null but is of type " + actualEntityType); + if (referencedEntityType != null) { + return List.of(referenceFieldName + "' must be null but is of type " + referencedEntityType); } break; } diff --git a/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6200-hs-booking-item.sql b/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6200-hs-booking-item.sql index 33a93c48..4796ac58 100644 --- a/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6200-hs-booking-item.sql +++ b/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6200-hs-booking-item.sql @@ -8,7 +8,8 @@ create type HsBookingItemType as enum ( 'PRIVATE_CLOUD', 'CLOUD_SERVER', 'MANAGED_SERVER', - 'MANAGED_WEBSPACE' + 'MANAGED_WEBSPACE', + 'DOMAIN_SETUP' ); CREATE CAST (character varying as HsBookingItemType) WITH INOUT AS IMPLICIT; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java index ddd3c5e0..7195126e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import jakarta.persistence.EntityManager; import jakarta.validation.ValidationException; +import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.DOMAIN_SETUP; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVATE_CLOUD; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER; @@ -53,6 +54,6 @@ class HsBookingItemEntityValidatorUnitTest { final var result = HsBookingItemEntityValidatorRegistry.types(); // then - assertThat(result).containsExactlyInAnyOrder(PRIVATE_CLOUD, CLOUD_SERVER, MANAGED_SERVER, MANAGED_WEBSPACE); + assertThat(result).containsExactlyInAnyOrder(PRIVATE_CLOUD, CLOUD_SERVER, MANAGED_SERVER, MANAGED_WEBSPACE, DOMAIN_SETUP); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java index c668c6c9..306337bb 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java @@ -249,6 +249,15 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup void globalAdmin_canAddTopLevelAsset() { context.define("superuser-alex@hostsharing.net"); + final var givenProject = realProjectRepo.findByCaption("D-1000111 default project").stream() + .findAny().orElseThrow(); + final var bookingItem = givenSomeTemporaryBookingItem(() -> + HsBookingItemRealEntity.builder() + .project(givenProject) + .type(HsBookingItemType.DOMAIN_SETUP) + .caption("some temp domain setup booking item") + .build() + ); final var location = RestAssured // @formatter:off .given() @@ -256,12 +265,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup .contentType(ContentType.JSON) .body(""" { + "bookingItemUuid": "%s", "type": "DOMAIN_SETUP", "identifier": "example.com", "caption": "some unrelated domain-setup", "config": {} } - """) + """.formatted(bookingItem.getUuid())) .port(port) .when() .post("http://localhost/api/hs/hosting/assets") @@ -729,6 +739,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup }).assertSuccessful().returnedValue(); } + private HsBookingItemRealEntity givenSomeTemporaryBookingItem(final Supplier newBookingItem) { + return jpaAttempt.transacted(() -> { + context.define("superuser-alex@hostsharing.net"); // needed to determine creator + return toCleanup(realBookingItemRepo.save(newBookingItem.get())); + }).assertSuccessful().returnedValue(); + } + HsHostingAssetRealEntity givenParentAsset(final HsHostingAssetType assetType, final String assetIdentifier) { final var givenAsset = realAssetRepo.findByIdentifier(assetIdentifier).stream() .filter(a -> a.getType() == assetType) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetTypeUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetTypeUnitTest.java index 9e518831..cc700850 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetTypeUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetTypeUnitTest.java @@ -15,18 +15,19 @@ class HsHostingAssetTypeUnitTest { ### Server+Webspace - + ```plantuml @startuml left to right direction - + package Booking #feb28c { entity BI_PRIVATE_CLOUD entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } - + package Hosting #feb28c{ package Server #99bcdb { entity HA_CLOUD_SERVER @@ -34,19 +35,19 @@ class HsHostingAssetTypeUnitTest { entity HA_IPV4_NUMBER entity HA_IPV6_NUMBER } - + package Webspace #99bcdb { entity HA_MANAGED_WEBSPACE entity HA_UNIX_USER entity HA_EMAIL_ALIAS } - + } - + BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER - + HA_CLOUD_SERVER *==> BI_CLOUD_SERVER HA_MANAGED_SERVER *==> BI_MANAGED_SERVER HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE @@ -59,7 +60,7 @@ class HsHostingAssetTypeUnitTest { HA_IPV6_NUMBER o..> HA_CLOUD_SERVER HA_IPV6_NUMBER o..> HA_MANAGED_SERVER HA_IPV6_NUMBER o..> HA_MANAGED_WEBSPACE - + package Legend #white { SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY @@ -68,20 +69,21 @@ class HsHostingAssetTypeUnitTest { } Booking -down[hidden]->Legend ``` - + ### Domain - + ```plantuml @startuml left to right direction - + package Booking #feb28c { entity BI_PRIVATE_CLOUD entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } - + package Hosting #feb28c{ package Domain #99bcdb { entity HA_DOMAIN_SETUP @@ -91,22 +93,23 @@ class HsHostingAssetTypeUnitTest { entity HA_DOMAIN_MBOX_SETUP entity HA_EMAIL_ADDRESS } - + package Webspace #99bcdb { entity HA_MANAGED_WEBSPACE entity HA_UNIX_USER entity HA_EMAIL_ALIAS } - + } - + BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER - + HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE + HA_DOMAIN_SETUP *..> BI_DOMAIN_SETUP HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP o--> HA_MANAGED_WEBSPACE @@ -117,7 +120,7 @@ class HsHostingAssetTypeUnitTest { HA_DOMAIN_MBOX_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_MBOX_SETUP o--> HA_MANAGED_WEBSPACE HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_SETUP - + package Legend #white { SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY @@ -126,46 +129,47 @@ class HsHostingAssetTypeUnitTest { } Booking -down[hidden]->Legend ``` - + ### MariaDB - + ```plantuml @startuml left to right direction - + package Booking #feb28c { entity BI_PRIVATE_CLOUD entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } - + package Hosting #feb28c{ package MariaDB #99bcdb { entity HA_MARIADB_INSTANCE entity HA_MARIADB_USER entity HA_MARIADB_DATABASE } - + package Webspace #99bcdb { entity HA_MANAGED_WEBSPACE entity HA_UNIX_USER entity HA_EMAIL_ALIAS } - + } - + BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER - + HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE HA_MARIADB_USER o--> HA_MARIADB_INSTANCE HA_MARIADB_DATABASE *==> HA_MARIADB_USER - + package Legend #white { SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY @@ -174,46 +178,47 @@ class HsHostingAssetTypeUnitTest { } Booking -down[hidden]->Legend ``` - + ### PostgreSQL - + ```plantuml @startuml left to right direction - + package Booking #feb28c { entity BI_PRIVATE_CLOUD entity BI_CLOUD_SERVER entity BI_MANAGED_SERVER entity BI_MANAGED_WEBSPACE + entity BI_DOMAIN_SETUP } - + package Hosting #feb28c{ package PostgreSQL #99bcdb { entity HA_PGSQL_INSTANCE entity HA_PGSQL_USER entity HA_PGSQL_DATABASE } - + package Webspace #99bcdb { entity HA_MANAGED_WEBSPACE entity HA_UNIX_USER entity HA_EMAIL_ALIAS } - + } - + BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER - + HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE HA_PGSQL_USER o--> HA_PGSQL_INSTANCE HA_PGSQL_DATABASE *==> HA_PGSQL_USER - + package Legend #white { SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY @@ -222,7 +227,7 @@ class HsHostingAssetTypeUnitTest { } Booking -down[hidden]->Legend ``` - + This code generated was by HsHostingAssetType.main, do not amend manually. """); } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java index 3c8c8e2c..6f451556 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java @@ -20,6 +20,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest { static HsHostingAssetRbacEntity.HsHostingAssetRbacEntityBuilder validEntityBuilder() { return HsHostingAssetRbacEntity.builder() .type(DOMAIN_SETUP) + .bookingItem(HsBookingItemRealEntity.builder().type(HsBookingItemType.DOMAIN_SETUP).build()) .identifier("example.org"); } @@ -93,20 +94,33 @@ class HsDomainSetupHostingAssetValidatorUnitTest { @Test void validatesReferencedEntities() { // given - final var mangedServerHostingAssetEntity = validEntityBuilder() + final var domainSetupHostingAssetEntity = validEntityBuilder() .parentAsset(HsHostingAssetRealEntity.builder().type(CLOUD_SERVER).build()) .assignedToAsset(HsHostingAssetRealEntity.builder().type(MANAGED_SERVER).build()) .bookingItem(HsBookingItemRealEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build()) .build(); - final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); + final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType()); // when - final var result = validator.validateEntity(mangedServerHostingAssetEntity); + final var result = validator.validateEntity(domainSetupHostingAssetEntity); // then assertThat(result).containsExactlyInAnyOrder( - "'DOMAIN_SETUP:example.org.bookingItem' must be null but is of type CLOUD_SERVER", + "'DOMAIN_SETUP:example.org.bookingItem' or parentItem must be null but is of type CLOUD_SERVER", "'DOMAIN_SETUP:example.org.parentAsset' must be null or of type DOMAIN_SETUP but is of type CLOUD_SERVER", "'DOMAIN_SETUP:example.org.assignedToAsset' must be null but is of type MANAGED_SERVER"); } + + @Test + void expectsEitherParentAssetOrBookingItem() { + // given + final var domainSetupHostingAssetEntity = validEntityBuilder().build(); + final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType()); + + // when + final var result = validator.validateEntity(domainSetupHostingAssetEntity); + + // then + assertThat(result).isEmpty(); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java index 677d808b..e96e7c6e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java @@ -513,15 +513,15 @@ public class ImportHostingAssets extends BaseOfficeDataImport { assertThat(firstOfEach(12, domainSetupAssets)).isEqualToIgnoringWhitespace(""" { - 4531=HsHostingAsset(DOMAIN_SETUP, l-u-g.org, l-u-g.org), - 4532=HsHostingAsset(DOMAIN_SETUP, linuxfanboysngirls.de, linuxfanboysngirls.de), - 4534=HsHostingAsset(DOMAIN_SETUP, lug-mars.de, lug-mars.de), - 4581=HsHostingAsset(DOMAIN_SETUP, 1981.ist-im-netz.de, 1981.ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de), - 4587=HsHostingAsset(DOMAIN_SETUP, mellis.de, mellis.de), - 4589=HsHostingAsset(DOMAIN_SETUP, ist-im-netz.de, ist-im-netz.de), - 4600=HsHostingAsset(DOMAIN_SETUP, waera.de, waera.de), - 4604=HsHostingAsset(DOMAIN_SETUP, xn--wra-qla.de, wära.de), - 7662=HsHostingAsset(DOMAIN_SETUP, dph-netzwerk.de, dph-netzwerk.de) + 4531=HsHostingAsset(DOMAIN_SETUP, l-u-g.org, l-u-g.org, D-1000300:mim default project:BI l-u-g.org), + 4532=HsHostingAsset(DOMAIN_SETUP, linuxfanboysngirls.de, linuxfanboysngirls.de, D-1000300:mim default project:BI linuxfanboysngirls.de), + 4534=HsHostingAsset(DOMAIN_SETUP, lug-mars.de, lug-mars.de, D-1000300:mim default project:BI lug-mars.de), + 4581=HsHostingAsset(DOMAIN_SETUP, 1981.ist-im-netz.de, 1981.ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de), + 4587=HsHostingAsset(DOMAIN_SETUP, mellis.de, mellis.de, D-1000300:mim default project:BI mellis.de), + 4589=HsHostingAsset(DOMAIN_SETUP, ist-im-netz.de, ist-im-netz.de, D-1000300:mim default project:BI ist-im-netz.de), + 4600=HsHostingAsset(DOMAIN_SETUP, waera.de, waera.de, D-1000300:mim default project:BI waera.de), + 4604=HsHostingAsset(DOMAIN_SETUP, xn--wra-qla.de, wära.de, D-1000300:mim default project:BI xn--wra-qla.de), + 7662=HsHostingAsset(DOMAIN_SETUP, dph-netzwerk.de, dph-netzwerk.de, D-1101900:dph default project:BI dph-netzwerk.de) } """); @@ -1441,6 +1441,7 @@ public class ImportHostingAssets extends BaseOfficeDataImport { // Domain Setup final var domainSetupAsset = HsHostingAssetRealEntity.builder() + // .bookingItem(bookingItem) are set once we've collected all domains .type(DOMAIN_SETUP) // .parentAsset(parentDomainSetupAsset) are set once we've collected all of them .identifier(domain_name) @@ -1542,10 +1543,27 @@ public class ImportHostingAssets extends BaseOfficeDataImport { final var parentDomainSetup = domainSetupsByName.get(parentDomainName); if (parentDomainSetup != null) { domainSetup.setParentAsset(parentDomainSetup); + } else { + final var relatedProject = domainSetup.getSubHostingAssets().stream() + .map(ha -> ha.getAssignedToAsset() != null ? ha.getAssignedToAsset().getRelatedProject() : null) + .findAny().orElseThrow(); + final var bookingItem = HsBookingItemRealEntity.builder() + .type(HsBookingItemType.DOMAIN_SETUP) + .caption("BI " + domainSetup.getIdentifier()) + .project((HsBookingProjectRealEntity) relatedProject) + //.validity(toPostgresDateRange(created, cancelled)) + .build(); + domainSetup.setBookingItem(bookingItem); + bookingItems.put(nextAvailableBookingItemId(), bookingItem); + } }); } + private static @NotNull Integer nextAvailableBookingItemId() { + return bookingItems.keySet().stream().max(Long::compare).map(id -> id + 1).orElseThrow(); + } + private String withDefault(final String givenValue, final Object defaultValue) { if (defaultValue instanceof String defaultStringValue) { return givenValue != null && !givenValue.isBlank() ? givenValue : defaultStringValue;