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:
parent
e57f4bf0c8
commit
fbd17a21e2
@ -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{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<HsBookingItemType> type, final HsEntityValidator<HsBookingItem> validator) {
|
||||
|
@ -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?
|
||||
);
|
||||
}
|
||||
}
|
@ -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<E, T extends Node> {
|
||||
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) {
|
||||
return new EntityTypeRelation<>(
|
||||
REQUIRED,
|
||||
|
@ -182,26 +182,36 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
|
||||
|
||||
List<String> 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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<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) {
|
||||
final var givenAsset = realAssetRepo.findByIdentifier(assetIdentifier).stream()
|
||||
.filter(a -> a.getType() == assetType)
|
||||
|
@ -25,6 +25,7 @@ class HsHostingAssetTypeUnitTest {
|
||||
entity BI_CLOUD_SERVER
|
||||
entity BI_MANAGED_SERVER
|
||||
entity BI_MANAGED_WEBSPACE
|
||||
entity BI_DOMAIN_SETUP
|
||||
}
|
||||
|
||||
package Hosting #feb28c{
|
||||
@ -80,6 +81,7 @@ class HsHostingAssetTypeUnitTest {
|
||||
entity BI_CLOUD_SERVER
|
||||
entity BI_MANAGED_SERVER
|
||||
entity BI_MANAGED_WEBSPACE
|
||||
entity BI_DOMAIN_SETUP
|
||||
}
|
||||
|
||||
package Hosting #feb28c{
|
||||
@ -107,6 +109,7 @@ class HsHostingAssetTypeUnitTest {
|
||||
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
|
||||
@ -138,6 +141,7 @@ class HsHostingAssetTypeUnitTest {
|
||||
entity BI_CLOUD_SERVER
|
||||
entity BI_MANAGED_SERVER
|
||||
entity BI_MANAGED_WEBSPACE
|
||||
entity BI_DOMAIN_SETUP
|
||||
}
|
||||
|
||||
package Hosting #feb28c{
|
||||
@ -186,6 +190,7 @@ class HsHostingAssetTypeUnitTest {
|
||||
entity BI_CLOUD_SERVER
|
||||
entity BI_MANAGED_SERVER
|
||||
entity BI_MANAGED_WEBSPACE
|
||||
entity BI_DOMAIN_SETUP
|
||||
}
|
||||
|
||||
package Hosting #feb28c{
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user