ceate bookingitems for domain-setup hostingassets (#95)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #95
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-09-04 11:15:37 +02:00
parent e57f4bf0c8
commit fbd17a21e2
12 changed files with 159 additions and 63 deletions

View File

@ -12,6 +12,7 @@ package Booking #feb28c {
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
@ -67,6 +68,7 @@ package Booking #feb28c {
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
@ -94,6 +96,7 @@ BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_DOMAIN_SETUP *==> BI_DOMAIN_SETUP
HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP
HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_DNS_SETUP o--> HA_MANAGED_WEBSPACE HA_DOMAIN_DNS_SETUP o--> HA_MANAGED_WEBSPACE
@ -125,6 +128,7 @@ package Booking #feb28c {
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
@ -173,6 +177,7 @@ package Booking #feb28c {
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{

View File

@ -9,7 +9,8 @@ public enum HsBookingItemType implements Node {
PRIVATE_CLOUD, PRIVATE_CLOUD,
CLOUD_SERVER(PRIVATE_CLOUD), CLOUD_SERVER(PRIVATE_CLOUD),
MANAGED_SERVER(PRIVATE_CLOUD), MANAGED_SERVER(PRIVATE_CLOUD),
MANAGED_WEBSPACE(MANAGED_SERVER); MANAGED_WEBSPACE(MANAGED_SERVER),
DOMAIN_SETUP;
private final HsBookingItemType parentItemType; private final HsBookingItemType parentItemType;

View File

@ -13,6 +13,7 @@ import java.util.Set;
import static java.util.Arrays.stream; 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.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_SERVER;
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE;
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVATE_CLOUD; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVATE_CLOUD;
@ -25,6 +26,7 @@ public class HsBookingItemEntityValidatorRegistry {
register(CLOUD_SERVER, new HsCloudServerBookingItemValidator()); register(CLOUD_SERVER, new HsCloudServerBookingItemValidator());
register(MANAGED_SERVER, new HsManagedServerBookingItemValidator()); register(MANAGED_SERVER, new HsManagedServerBookingItemValidator());
register(MANAGED_WEBSPACE, new HsManagedWebspaceBookingItemValidator()); register(MANAGED_WEBSPACE, new HsManagedWebspaceBookingItemValidator());
register(DOMAIN_SETUP, new HsDomainSetupBookingItemValidator());
} }
private static void register(final Enum<HsBookingItemType> type, final HsEntityValidator<HsBookingItem> validator) { private static void register(final Enum<HsBookingItemType> type, final HsEntityValidator<HsBookingItem> validator) {

View File

@ -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?
);
}
}

View File

@ -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.optionallyAssignedTo;
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.requiredParent; 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.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.OPTIONAL;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.REQUIRED; 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.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.BOOKING_ITEM;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.PARENT_ASSET; 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 DOMAIN_SETUP( // named e.g. example.org
inGroup("Domain"), inGroup("Domain"),
terminatory(HsBookingItemType.DOMAIN_SETUP),
optionalParent(SAME_TYPE) optionalParent(SAME_TYPE)
), ),
@ -339,7 +342,7 @@ public enum HsHostingAssetType implements Node {
} }
public enum RelationPolicy { public enum RelationPolicy {
FORBIDDEN, OPTIONAL, REQUIRED FORBIDDEN, OPTIONAL, TERMINATORY, REQUIRED
} }
public enum RelationType { public enum RelationType {
@ -376,6 +379,15 @@ class EntityTypeRelation<E, T extends Node> {
return (Set<R>) result; return (Set<R>) result;
} }
static EntityTypeRelation<HsBookingItem, HsBookingItemType> terminatory(final HsBookingItemType bookingItemType) {
return new EntityTypeRelation<>(
TERMINATORY,
BOOKING_ITEM,
HsHostingAssetRbacEntity::getBookingItem,
bookingItemType,
" *..> ");
}
static EntityTypeRelation<HsBookingItem, HsBookingItemType> requires(final HsBookingItemType bookingItemType) { static EntityTypeRelation<HsBookingItem, HsBookingItemType> requires(final HsBookingItemType bookingItemType) {
return new EntityTypeRelation<>( return new EntityTypeRelation<>(
REQUIRED, REQUIRED,

View File

@ -182,26 +182,36 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
List<String> validate(final HsHostingAsset assetEntity, final String referenceFieldName) { List<String> validate(final HsHostingAsset assetEntity, final String referenceFieldName) {
final var actualEntity = referencedEntityGetter.apply(assetEntity); final var referencedEntity = referencedEntityGetter.apply(assetEntity);
final var actualEntityType = actualEntity != null ? referencedEntityTypeGetter.apply(actualEntity) : null; final var referencedEntityType = referencedEntity != null ? referencedEntityTypeGetter.apply(referencedEntity) : null;
switch (policy) { switch (policy) {
case REQUIRED: case REQUIRED:
if (!referencedEntityTypes.contains(actualEntityType)) { if (!referencedEntityTypes.contains(referencedEntityType)) {
return List.of(actualEntityType == null return List.of(referencedEntityType == null
? referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is 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; break;
case OPTIONAL: 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 " return List.of(referenceFieldName + "' must be null or of type " + toDisplay(referencedEntityTypes) + " but is of type "
+ actualEntityType); + referencedEntityType);
} }
break; break;
case FORBIDDEN: case FORBIDDEN:
if (actualEntityType != null) { if (referencedEntityType != null) {
return List.of(referenceFieldName + "' must be null but is of type " + actualEntityType); return List.of(referenceFieldName + "' must be null but is of type " + referencedEntityType);
} }
break; break;
} }

View File

@ -8,7 +8,8 @@ create type HsBookingItemType as enum (
'PRIVATE_CLOUD', 'PRIVATE_CLOUD',
'CLOUD_SERVER', 'CLOUD_SERVER',
'MANAGED_SERVER', 'MANAGED_SERVER',
'MANAGED_WEBSPACE' 'MANAGED_WEBSPACE',
'DOMAIN_SETUP'
); );
CREATE CAST (character varying as HsBookingItemType) WITH INOUT AS IMPLICIT; CREATE CAST (character varying as HsBookingItemType) WITH INOUT AS IMPLICIT;

View File

@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.validation.ValidationException; 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.PRIVATE_CLOUD;
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER;
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER;
@ -53,6 +54,6 @@ class HsBookingItemEntityValidatorUnitTest {
final var result = HsBookingItemEntityValidatorRegistry.types(); final var result = HsBookingItemEntityValidatorRegistry.types();
// then // 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);
} }
} }

View File

@ -249,6 +249,15 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
void globalAdmin_canAddTopLevelAsset() { void globalAdmin_canAddTopLevelAsset() {
context.define("superuser-alex@hostsharing.net"); 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 final var location = RestAssured // @formatter:off
.given() .given()
@ -256,12 +265,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"bookingItemUuid": "%s",
"type": "DOMAIN_SETUP", "type": "DOMAIN_SETUP",
"identifier": "example.com", "identifier": "example.com",
"caption": "some unrelated domain-setup", "caption": "some unrelated domain-setup",
"config": {} "config": {}
} }
""") """.formatted(bookingItem.getUuid()))
.port(port) .port(port)
.when() .when()
.post("http://localhost/api/hs/hosting/assets") .post("http://localhost/api/hs/hosting/assets")
@ -729,6 +739,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
}).assertSuccessful().returnedValue(); }).assertSuccessful().returnedValue();
} }
private HsBookingItemRealEntity givenSomeTemporaryBookingItem(final Supplier<HsBookingItemRealEntity> 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) { HsHostingAssetRealEntity givenParentAsset(final HsHostingAssetType assetType, final String assetIdentifier) {
final var givenAsset = realAssetRepo.findByIdentifier(assetIdentifier).stream() final var givenAsset = realAssetRepo.findByIdentifier(assetIdentifier).stream()
.filter(a -> a.getType() == assetType) .filter(a -> a.getType() == assetType)

View File

@ -15,18 +15,19 @@ class HsHostingAssetTypeUnitTest {
### Server+Webspace ### Server+Webspace
```plantuml ```plantuml
@startuml @startuml
left to right direction left to right direction
package Booking #feb28c { package Booking #feb28c {
entity BI_PRIVATE_CLOUD entity BI_PRIVATE_CLOUD
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
package Server #99bcdb { package Server #99bcdb {
entity HA_CLOUD_SERVER entity HA_CLOUD_SERVER
@ -34,19 +35,19 @@ class HsHostingAssetTypeUnitTest {
entity HA_IPV4_NUMBER entity HA_IPV4_NUMBER
entity HA_IPV6_NUMBER entity HA_IPV6_NUMBER
} }
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
entity HA_EMAIL_ALIAS entity HA_EMAIL_ALIAS
} }
} }
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
@ -59,7 +60,7 @@ class HsHostingAssetTypeUnitTest {
HA_IPV6_NUMBER o..> HA_CLOUD_SERVER HA_IPV6_NUMBER o..> HA_CLOUD_SERVER
HA_IPV6_NUMBER o..> HA_MANAGED_SERVER HA_IPV6_NUMBER o..> HA_MANAGED_SERVER
HA_IPV6_NUMBER o..> HA_MANAGED_WEBSPACE HA_IPV6_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
@ -68,20 +69,21 @@ class HsHostingAssetTypeUnitTest {
} }
Booking -down[hidden]->Legend Booking -down[hidden]->Legend
``` ```
### Domain ### Domain
```plantuml ```plantuml
@startuml @startuml
left to right direction left to right direction
package Booking #feb28c { package Booking #feb28c {
entity BI_PRIVATE_CLOUD entity BI_PRIVATE_CLOUD
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
package Domain #99bcdb { package Domain #99bcdb {
entity HA_DOMAIN_SETUP entity HA_DOMAIN_SETUP
@ -91,22 +93,23 @@ class HsHostingAssetTypeUnitTest {
entity HA_DOMAIN_MBOX_SETUP entity HA_DOMAIN_MBOX_SETUP
entity HA_EMAIL_ADDRESS entity HA_EMAIL_ADDRESS
} }
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
entity HA_EMAIL_ALIAS entity HA_EMAIL_ALIAS
} }
} }
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_DOMAIN_SETUP *..> BI_DOMAIN_SETUP
HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP
HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_DNS_SETUP o--> HA_MANAGED_WEBSPACE 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 *==> HA_DOMAIN_SETUP
HA_DOMAIN_MBOX_SETUP o--> HA_MANAGED_WEBSPACE HA_DOMAIN_MBOX_SETUP o--> HA_MANAGED_WEBSPACE
HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_SETUP HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_SETUP
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
@ -126,46 +129,47 @@ class HsHostingAssetTypeUnitTest {
} }
Booking -down[hidden]->Legend Booking -down[hidden]->Legend
``` ```
### MariaDB ### MariaDB
```plantuml ```plantuml
@startuml @startuml
left to right direction left to right direction
package Booking #feb28c { package Booking #feb28c {
entity BI_PRIVATE_CLOUD entity BI_PRIVATE_CLOUD
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
package MariaDB #99bcdb { package MariaDB #99bcdb {
entity HA_MARIADB_INSTANCE entity HA_MARIADB_INSTANCE
entity HA_MARIADB_USER entity HA_MARIADB_USER
entity HA_MARIADB_DATABASE entity HA_MARIADB_DATABASE
} }
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
entity HA_EMAIL_ALIAS entity HA_EMAIL_ALIAS
} }
} }
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE
HA_MARIADB_USER o--> HA_MARIADB_INSTANCE HA_MARIADB_USER o--> HA_MARIADB_INSTANCE
HA_MARIADB_DATABASE *==> HA_MARIADB_USER HA_MARIADB_DATABASE *==> HA_MARIADB_USER
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
@ -174,46 +178,47 @@ class HsHostingAssetTypeUnitTest {
} }
Booking -down[hidden]->Legend Booking -down[hidden]->Legend
``` ```
### PostgreSQL ### PostgreSQL
```plantuml ```plantuml
@startuml @startuml
left to right direction left to right direction
package Booking #feb28c { package Booking #feb28c {
entity BI_PRIVATE_CLOUD entity BI_PRIVATE_CLOUD
entity BI_CLOUD_SERVER entity BI_CLOUD_SERVER
entity BI_MANAGED_SERVER entity BI_MANAGED_SERVER
entity BI_MANAGED_WEBSPACE entity BI_MANAGED_WEBSPACE
entity BI_DOMAIN_SETUP
} }
package Hosting #feb28c{ package Hosting #feb28c{
package PostgreSQL #99bcdb { package PostgreSQL #99bcdb {
entity HA_PGSQL_INSTANCE entity HA_PGSQL_INSTANCE
entity HA_PGSQL_USER entity HA_PGSQL_USER
entity HA_PGSQL_DATABASE entity HA_PGSQL_DATABASE
} }
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
entity HA_EMAIL_ALIAS entity HA_EMAIL_ALIAS
} }
} }
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE
HA_PGSQL_USER o--> HA_PGSQL_INSTANCE HA_PGSQL_USER o--> HA_PGSQL_INSTANCE
HA_PGSQL_DATABASE *==> HA_PGSQL_USER HA_PGSQL_DATABASE *==> HA_PGSQL_USER
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
@ -222,7 +227,7 @@ class HsHostingAssetTypeUnitTest {
} }
Booking -down[hidden]->Legend Booking -down[hidden]->Legend
``` ```
This code generated was by HsHostingAssetType.main, do not amend manually. This code generated was by HsHostingAssetType.main, do not amend manually.
"""); """);
} }

View File

@ -20,6 +20,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
static HsHostingAssetRbacEntity.HsHostingAssetRbacEntityBuilder<?, ?> validEntityBuilder() { static HsHostingAssetRbacEntity.HsHostingAssetRbacEntityBuilder<?, ?> validEntityBuilder() {
return HsHostingAssetRbacEntity.builder() return HsHostingAssetRbacEntity.builder()
.type(DOMAIN_SETUP) .type(DOMAIN_SETUP)
.bookingItem(HsBookingItemRealEntity.builder().type(HsBookingItemType.DOMAIN_SETUP).build())
.identifier("example.org"); .identifier("example.org");
} }
@ -93,20 +94,33 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
@Test @Test
void validatesReferencedEntities() { void validatesReferencedEntities() {
// given // given
final var mangedServerHostingAssetEntity = validEntityBuilder() final var domainSetupHostingAssetEntity = validEntityBuilder()
.parentAsset(HsHostingAssetRealEntity.builder().type(CLOUD_SERVER).build()) .parentAsset(HsHostingAssetRealEntity.builder().type(CLOUD_SERVER).build())
.assignedToAsset(HsHostingAssetRealEntity.builder().type(MANAGED_SERVER).build()) .assignedToAsset(HsHostingAssetRealEntity.builder().type(MANAGED_SERVER).build())
.bookingItem(HsBookingItemRealEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build()) .bookingItem(HsBookingItemRealEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.build(); .build();
final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(domainSetupHostingAssetEntity);
// then // then
assertThat(result).containsExactlyInAnyOrder( 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.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"); "'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();
}
} }

View File

@ -513,15 +513,15 @@ public class ImportHostingAssets extends BaseOfficeDataImport {
assertThat(firstOfEach(12, domainSetupAssets)).isEqualToIgnoringWhitespace(""" assertThat(firstOfEach(12, domainSetupAssets)).isEqualToIgnoringWhitespace("""
{ {
4531=HsHostingAsset(DOMAIN_SETUP, l-u-g.org, l-u-g.org), 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), 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), 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), 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), 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), 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), 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), 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) 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 // Domain Setup
final var domainSetupAsset = HsHostingAssetRealEntity.builder() final var domainSetupAsset = HsHostingAssetRealEntity.builder()
// .bookingItem(bookingItem) are set once we've collected all domains
.type(DOMAIN_SETUP) .type(DOMAIN_SETUP)
// .parentAsset(parentDomainSetupAsset) are set once we've collected all of them // .parentAsset(parentDomainSetupAsset) are set once we've collected all of them
.identifier(domain_name) .identifier(domain_name)
@ -1542,10 +1543,27 @@ public class ImportHostingAssets extends BaseOfficeDataImport {
final var parentDomainSetup = domainSetupsByName.get(parentDomainName); final var parentDomainSetup = domainSetupsByName.get(parentDomainName);
if (parentDomainSetup != null) { if (parentDomainSetup != null) {
domainSetup.setParentAsset(parentDomainSetup); 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) { private String withDefault(final String givenValue, final Object defaultValue) {
if (defaultValue instanceof String defaultStringValue) { if (defaultValue instanceof String defaultStringValue) {
return givenValue != null && !givenValue.isBlank() ? givenValue : defaultStringValue; return givenValue != null && !givenValue.isBlank() ? givenValue : defaultStringValue;