add DomainSetup-HostingAssets for new BookingItem via created-event #111
@ -15,11 +15,9 @@ import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
|||||||
import jakarta.validation.ValidationException;
|
import jakarta.validation.ValidationException;
|
||||||
import java.net.IDN;
|
import java.net.IDN;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static java.util.Optional.ofNullable;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_DNS_SETUP;
|
||||||
import static net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetTypeResource.DOMAIN_DNS_SETUP;
|
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_HTTP_SETUP;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_HTTP_SETUP;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_MBOX_SETUP;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_MBOX_SETUP;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP;
|
||||||
@ -37,33 +35,62 @@ public class DomainSetupHostingAssetFactory extends HostingAssetFactory {
|
|||||||
@Override
|
@Override
|
||||||
protected HsHostingAsset create() {
|
protected HsHostingAsset create() {
|
||||||
final var domainSetupAsset = createDomainSetupAsset(getDomainName());
|
final var domainSetupAsset = createDomainSetupAsset(getDomainName());
|
||||||
|
final var subHostingAssets = domainSetupAsset.getSubHostingAssets();
|
||||||
|
|
||||||
// TODO.legacy: as long as we need to be compatible, we always do all technical domain-setups
|
// TODO.legacy: as long as we need to be compatible, we always do all technical domain-setups
|
||||||
|
|
||||||
final var subHostingAssetResources = getSubHostingAssetResources();
|
final var subHostingAssetResources = getSubHostingAssetResources();
|
||||||
|
|
||||||
|
subHostingAssets.add(
|
||||||
|
createDomainSubSetupAssetEntity(
|
||||||
|
domainSetupAsset,
|
||||||
|
DOMAIN_HTTP_SETUP,
|
||||||
|
builder -> builder
|
||||||
|
.assignedToAsset(assignedToUnixUserAsset.getParentAsset())
|
||||||
|
.identifier(getDomainName() + "|MBOX")
|
||||||
|
.caption("HTTP-Setup für " + IDN.toUnicode(getDomainName())))
|
||||||
|
);
|
||||||
|
|
||||||
|
domainHttpSetupAsset.setParentAsset(domainSetupAsset);
|
||||||
|
final var assignedToUnixUserAsset =
|
||||||
|
emw.find(HsHostingAssetRealEntity.class, domainHttpSetupAssetResource.getAssignedToAssetUuid());
|
||||||
|
domainHttpSetupAsset.setAssignedToAsset(assignedToUnixUserAsset);
|
||||||
|
|
||||||
|
|
||||||
final var domainHttpSetupAsset = createDomainHttpSetupAssetEntity(
|
final var domainHttpSetupAsset = createDomainHttpSetupAssetEntity(
|
||||||
subHostingAssetResources,
|
subHostingAssetResources,
|
||||||
getDomainName(),
|
getDomainName(),
|
||||||
domainSetupAsset);
|
domainSetupAsset);
|
||||||
final var assignedToUnixUserAsset = domainHttpSetupAsset.getAssignedToAsset();
|
final var assignedToUnixUserAsset = domainHttpSetupAsset.getAssignedToAsset();
|
||||||
|
|
||||||
// TODO.legacy: don't create DNS setup as long as we need to remain support legacy web-ui etc.
|
// do not add to subHostingAssets, in compatibility mode, DNS setup works via file system
|
||||||
assertDomainDnsSetupAssetNotSupplied(domainSetupAsset);
|
|
||||||
|
|
||||||
createDomainSubSetupAssetEntity(
|
createDomainSubSetupAssetEntity(
|
||||||
domainSetupAsset,
|
domainSetupAsset,
|
||||||
DOMAIN_MBOX_SETUP,
|
DOMAIN_DNS_SETUP,
|
||||||
builder -> builder
|
builder -> builder
|
||||||
.assignedToAsset(assignedToUnixUserAsset.getParentAsset())
|
.assignedToAsset(assignedToUnixUserAsset.getParentAsset())
|
||||||
.identifier(getDomainName() + "|MBOX")
|
.identifier(getDomainName() + "|DNS")
|
||||||
.caption("HTTP-Setup für " + IDN.toUnicode(getDomainName())));
|
.caption("HTTP-Setup für " + IDN.toUnicode(getDomainName())));
|
||||||
|
|
||||||
createDomainSubSetupAssetEntity(
|
subHostingAssets.add(
|
||||||
domainSetupAsset,
|
createDomainSubSetupAssetEntity(
|
||||||
DOMAIN_SMTP_SETUP,
|
domainSetupAsset,
|
||||||
builder -> builder
|
DOMAIN_MBOX_SETUP,
|
||||||
.assignedToAsset(assignedToUnixUserAsset.getParentAsset())
|
builder -> builder
|
||||||
.identifier(getDomainName() + "|SMTP")
|
.assignedToAsset(assignedToUnixUserAsset.getParentAsset())
|
||||||
.caption("HTTP-Setup für " + IDN.toUnicode(getDomainName())));
|
.identifier(getDomainName() + "|MBOX")
|
||||||
|
.caption("HTTP-Setup für " + IDN.toUnicode(getDomainName())))
|
||||||
|
);
|
||||||
|
|
||||||
|
subHostingAssets.add(
|
||||||
|
createDomainSubSetupAssetEntity(
|
||||||
|
domainSetupAsset,
|
||||||
|
DOMAIN_SMTP_SETUP,
|
||||||
|
builder -> builder
|
||||||
|
.assignedToAsset(assignedToUnixUserAsset.getParentAsset())
|
||||||
|
.identifier(getDomainName() + "|SMTP")
|
||||||
|
.caption("HTTP-Setup für " + IDN.toUnicode(getDomainName())))
|
||||||
|
);
|
||||||
|
|
||||||
return domainSetupAsset;
|
return domainSetupAsset;
|
||||||
}
|
}
|
||||||
@ -75,68 +102,41 @@ public class DomainSetupHostingAssetFactory extends HostingAssetFactory {
|
|||||||
.identifier(domainName)
|
.identifier(domainName)
|
||||||
.caption(asset.getCaption() != null ? asset.getCaption() : domainName)
|
.caption(asset.getCaption() != null ? asset.getCaption() : domainName)
|
||||||
.alarmContact(ref(HsOfficeContactRealEntity.class, asset.getAlarmContactUuid()))
|
.alarmContact(ref(HsOfficeContactRealEntity.class, asset.getAlarmContactUuid()))
|
||||||
.subHostingAssets( // FIXME: is this even used?
|
// the sub-hosting-assets get added later
|
||||||
standardMapper.mapList(getSubHostingAssetResources(), HsHostingAssetRealEntity.class)
|
|
||||||
)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsHostingAssetRealEntity createDomainHttpSetupAssetEntity(
|
private HsHostingAssetRealEntity createDomainSubSetupAssetEntity(
|
||||||
final List<HsHostingAssetSubInsertResource> subHostingAssetResources,
|
|
||||||
final String domainName,
|
|
||||||
final HsHostingAssetRealEntity domainSetupAsset) {
|
|
||||||
final var domainHttpSetupAssetResource = subHostingAssetResources.stream()
|
|
||||||
.filter(ha -> ha.getType() == HsHostingAssetTypeResource.DOMAIN_HTTP_SETUP)
|
|
||||||
.findFirst().orElseThrow(() -> new ValidationException(
|
|
||||||
domainName + ": missing target unix user (assignedToHostingAssetUuid) for DOMAIN_HTTP_SETUP "));
|
|
||||||
final var domainHttpSetupAsset = domainSetupAsset.getSubHostingAssets()
|
|
||||||
.stream()
|
|
||||||
.filter(sha -> sha.getType() == DOMAIN_HTTP_SETUP)
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow();
|
|
||||||
domainHttpSetupAsset.setParentAsset(domainSetupAsset);
|
|
||||||
final var assignedToUnixUserAsset =
|
|
||||||
emw.find(HsHostingAssetRealEntity.class, domainHttpSetupAssetResource.getAssignedToAssetUuid());
|
|
||||||
domainHttpSetupAsset.setAssignedToAsset(assignedToUnixUserAsset);
|
|
||||||
return domainHttpSetupAsset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertDomainDnsSetupAssetNotSupplied(final HsHostingAssetRealEntity domainSetupAsset) {
|
|
||||||
if (getSubHostingAssetResources().stream().anyMatch(ha -> ha.getType() == DOMAIN_DNS_SETUP)) {
|
|
||||||
throw new ValidationException("domain DNS setup not allowed for legacy compatibility");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createDomainSubSetupAssetEntity(
|
|
||||||
final HsHostingAssetRealEntity domainSetupAsset,
|
final HsHostingAssetRealEntity domainSetupAsset,
|
||||||
final HsHostingAssetType subAssetType,
|
final HsHostingAssetType subAssetType,
|
||||||
final Function<HsHostingAssetRealEntity.HsHostingAssetRealEntityBuilder<?, ?>, HsHostingAssetRealEntity.HsHostingAssetRealEntityBuilder<?, ?>> builderTransformer) {
|
final Function<HsHostingAssetRealEntity.HsHostingAssetRealEntityBuilder<?, ?>, HsHostingAssetRealEntity.HsHostingAssetRealEntityBuilder<?, ?>> builderTransformer) {
|
||||||
final var resourceType = HsHostingAssetTypeResource.valueOf(subAssetType.name());
|
final var resourceType = HsHostingAssetTypeResource.valueOf(subAssetType.name());
|
||||||
final var subAssetResource = getSubHostingAssetResources().stream()
|
|
||||||
|
final var subAssetResourceOptional = getSubHostingAssetResources().stream()
|
||||||
.filter(ha -> ha.getType() == resourceType)
|
.filter(ha -> ha.getType() == resourceType)
|
||||||
.reduce(Reducer::toSingleElement);
|
.reduce(Reducer::toSingleElement);
|
||||||
final var subAssetEntity = builderTransformer.apply(
|
|
||||||
|
subAssetResourceOptional.ifPresentOrElse(
|
||||||
|
subAssetResource -> verifyNotOverspecified(subAssetResource),
|
||||||
|
() -> { throw new ValidationException("sub-asset of type " + resourceType.name() + " required in legacy mode, but missing"); }
|
||||||
|
);
|
||||||
|
|
||||||
|
return builderTransformer.apply(
|
||||||
HsHostingAssetRealEntity.builder()
|
HsHostingAssetRealEntity.builder()
|
||||||
.type(subAssetType)
|
.type(subAssetType)
|
||||||
.parentAsset(domainSetupAsset))
|
.parentAsset(domainSetupAsset))
|
||||||
.build();
|
.build();
|
||||||
domainSetupAsset.getSubHostingAssets().add(subAssetEntity);
|
}
|
||||||
subAssetResource.ifPresent(
|
|
||||||
res -> {
|
|
||||||
ofNullable(res.getAssignedToAssetUuid())
|
|
||||||
.map(uuid -> emw.find(HsHostingAssetRealEntity.class, uuid))
|
|
||||||
.ifPresent(subAssetEntity::setAssignedToAsset);
|
|
||||||
ofNullable(res.getAlarmContactUuid())
|
|
||||||
.map(uuid -> emw.find(HsOfficeContactRealEntity.class, uuid))
|
|
||||||
.ifPresent(subAssetEntity::setAlarmContact);
|
|
||||||
ofNullable(res.getIdentifier()).ifPresent(subAssetEntity::setIdentifier);
|
|
||||||
ofNullable(res.getCaption()).ifPresent(subAssetEntity::setCaption);
|
|
||||||
res.getConfig();
|
|
||||||
res.get
|
|
||||||
|
|
||||||
|
// TODO.legacy: while we need to stay compatible, only default values can be used, thus only the type can be specified
|
||||||
|
private void verifyNotOverspecified(final HsHostingAssetSubInsertResource givenSubAssetResource) {
|
||||||
|
final var convert = new ToStringConverter().ignoring("assignedToAssetUuid");
|
||||||
|
final var expectedSubAssetResource = new HsHostingAssetSubInsertResource();
|
||||||
|
expectedSubAssetResource.setType(givenSubAssetResource.getType());
|
||||||
|
if ( !convert.from(givenSubAssetResource).equals(convert.from(expectedSubAssetResource)) ) {
|
||||||
|
throw new ValidationException("sub asset " + givenSubAssetResource.getType() + " is over-specified, in compatibilty mode, only default values allowed");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDomainName() {
|
private String getDomainName() {
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hosting.asset.factories;
|
||||||
|
import net.hostsharing.hsadminng.mapper.Array;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.joining;
|
||||||
|
|
||||||
|
public class ToStringConverter {
|
||||||
|
|
||||||
|
final public Set<String> ignoredFields = new HashSet<>();
|
||||||
|
|
||||||
|
public ToStringConverter ignoring(final String fieldName) {
|
||||||
|
ignoredFields.add(fieldName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String from(Object obj) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
return "{ " +
|
||||||
|
Arrays.stream(obj.getClass().getDeclaredFields())
|
||||||
|
.filter(f -> !ignoredFields.contains(f.getName()))
|
||||||
|
.map(field -> {
|
||||||
|
try {
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field.getName() + ": " + field.get(obj);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
// ignore inaccessible fields
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(joining(", "))
|
||||||
|
+ " }";
|
||||||
|
}
|
||||||
|
}
|
@ -201,33 +201,33 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
.header("current-subject", "superuser-alex@hostsharing.net")
|
.header("current-subject", "superuser-alex@hostsharing.net")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"projectUuid": "{projectUuid}",
|
"projectUuid": "{projectUuid}",
|
||||||
"type": "DOMAIN_SETUP",
|
"type": "DOMAIN_SETUP",
|
||||||
"caption": "Domain-Setup for example.org",
|
"caption": "Domain-Setup for example.org",
|
||||||
"resources": {
|
"resources": {
|
||||||
"domainName": "example.org",
|
"domainName": "example.org",
|
||||||
"verificationCode": "just-a-fake-verification-code"
|
"verificationCode": "just-a-fake-verification-code"
|
||||||
},
|
},
|
||||||
"asset": { // FIXME: rename to hostingAsset
|
"asset": { // FIXME: rename to hostingAsset
|
||||||
"identifier": "example.org", // also as default for all subAssets
|
"identifier": "example.org", // also as default for all subAssets
|
||||||
"subHostingAssets": [
|
"subHostingAssets": [
|
||||||
{
|
{
|
||||||
"type": "DOMAIN_DNS_SETUP"
|
"type": "DOMAIN_DNS_SETUP"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "DOMAIN_HTTP_SETUP",
|
"type": "DOMAIN_HTTP_SETUP",
|
||||||
"assignedToAssetUuid": "{unixUserUuid}"
|
"assignedToAssetUuid": "{unixUserUuid}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "DOMAIN_MBOX_SETUP"
|
"type": "DOMAIN_MBOX_SETUP"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "DOMAIN_SMTP_SETUP"
|
"type": "DOMAIN_SMTP_SETUP"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
.replace("{projectUuid}", givenProject.getUuid().toString())
|
.replace("{projectUuid}", givenProject.getUuid().toString())
|
||||||
.replace("{unixUserUuid}", givenUnixUser.getUuid().toString())
|
.replace("{unixUserUuid}", givenUnixUser.getUuid().toString())
|
||||||
|
Loading…
Reference in New Issue
Block a user