add-domain-setup-validation #71
@ -73,6 +73,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
final var entity = mapper.map(body, HsHostingAssetEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
||||
|
||||
final var mapped = new HsHostingAssetEntityProcessor(entity)
|
||||
.preprocessEntity()
|
||||
.validateEntity()
|
||||
.prepareForSave()
|
||||
.saveUsing(assetRepo::save)
|
||||
@ -133,6 +134,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
new HsHostingAssetEntityPatcher(em, entity).apply(body);
|
||||
|
||||
final var mapped = new HsHostingAssetEntityProcessor(entity)
|
||||
.preprocessEntity()
|
||||
.validateEntity()
|
||||
.prepareForSave()
|
||||
.saveUsing(assetRepo::save)
|
||||
|
@ -9,6 +9,7 @@ import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf;
|
||||
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
|
||||
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
||||
@ -50,7 +51,7 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
||||
booleanProperty("auto-WILDCARD-MX-RR").withDefault(true),
|
||||
booleanProperty("auto-WILDCARD-A-RR").withDefault(true),
|
||||
booleanProperty("auto-WILDCARD-AAAA-RR").withDefault(true),
|
||||
booleanProperty("auto-WILDCARD-DKIM-RR").withDefault(true), // TODO.spec: @Peter
|
||||
booleanProperty("auto-WILDCARD-DKIM-RR").withDefault(true), // TODO.spec: check, if that really works
|
||||
booleanProperty("auto-WILDCARD-SPF-RR").withDefault(true),
|
||||
arrayOf(
|
||||
stringProperty("user-RR").matchesRegEx(RR_REGEX_TTL_IN, RR_REGEX_IN_TTL).required()
|
||||
@ -59,10 +60,17 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
||||
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||
// FIXME: should be auto-initialized
|
||||
return Pattern.compile("^" + assetEntity.getParentAsset().getIdentifier() + "$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessEntity(final HsHostingAssetEntity entity) {
|
||||
super.preprocessEntity(entity);
|
||||
if (entity.getIdentifier() == null) {
|
||||
ofNullable(entity.getParentAsset()).ifPresent(pa -> entity.setIdentifier(pa.getIdentifier()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public List<String> validateContext(final HsHostingAssetEntity assetEntity) {
|
||||
@ -80,6 +88,7 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
||||
}
|
||||
|
||||
String toZonefileString(final HsHostingAssetEntity assetEntity) {
|
||||
// TODO.spec: we need to expand the templates (auto-...) in the same way as in Saltstack
|
||||
return """
|
||||
$ORIGIN {domain}.
|
||||
$TTL {ttl}
|
||||
|
@ -14,6 +14,7 @@ import java.util.function.Function;
|
||||
public class HsHostingAssetEntityProcessor {
|
||||
|
||||
private final HsEntityValidator<HsHostingAssetEntity> validator;
|
||||
private String expectedStep = "preprocessEntity";
|
||||
private HsHostingAssetEntity entity;
|
||||
private HsHostingAssetResource resource;
|
||||
|
||||
@ -22,8 +23,16 @@ public class HsHostingAssetEntityProcessor {
|
||||
this.validator = HsHostingAssetEntityValidatorRegistry.forType(entity.getType());
|
||||
}
|
||||
|
||||
/// initial step allowing to set default values before any validations
|
||||
public HsHostingAssetEntityProcessor preprocessEntity() {
|
||||
step("preprocessEntity", "validateEntity");
|
||||
validator.preprocessEntity(entity);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// validates the entity itself including its properties
|
||||
public HsHostingAssetEntityProcessor validateEntity() {
|
||||
step("validateEntity", "prepareForSave");
|
||||
MultiValidationException.throwIfNotEmpty(validator.validateEntity(entity));
|
||||
return this;
|
||||
}
|
||||
@ -31,17 +40,20 @@ public class HsHostingAssetEntityProcessor {
|
||||
/// hashing passwords etc.
|
||||
@SuppressWarnings("unchecked")
|
||||
public HsHostingAssetEntityProcessor prepareForSave() {
|
||||
step("prepareForSave", "saveUsing");
|
||||
validator.prepareProperties(entity);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HsHostingAssetEntityProcessor saveUsing(final Function<HsHostingAssetEntity, HsHostingAssetEntity> saveFunction) {
|
||||
step("saveUsing", "validateContext");
|
||||
entity = saveFunction.apply(entity);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// validates the entity within it's parent and child hierarchy (e.g. totals validators and other limits)
|
||||
public HsHostingAssetEntityProcessor validateContext() {
|
||||
step("validateContext", "mapUsing");
|
||||
MultiValidationException.throwIfNotEmpty(validator.validateContext(entity));
|
||||
return this;
|
||||
}
|
||||
@ -49,6 +61,7 @@ public class HsHostingAssetEntityProcessor {
|
||||
/// maps entity to JSON resource representation
|
||||
public HsHostingAssetEntityProcessor mapUsing(
|
||||
final Function<HsHostingAssetEntity, HsHostingAssetResource> mapFunction) {
|
||||
step("mapUsing", "revampProperties");
|
||||
resource = mapFunction.apply(entity);
|
||||
return this;
|
||||
}
|
||||
@ -56,8 +69,18 @@ public class HsHostingAssetEntityProcessor {
|
||||
/// removes write-only-properties and ads computed-properties
|
||||
@SuppressWarnings("unchecked")
|
||||
public HsHostingAssetResource revampProperties() {
|
||||
step("revampProperties", null);
|
||||
final var revampedProps = validator.revampProperties(entity, (Map<String, Object>) resource.getConfig());
|
||||
resource.setConfig(revampedProps);
|
||||
return resource;
|
||||
}
|
||||
|
||||
// Makes sure that the steps are called in the correct order.
|
||||
// Could also be implemented using an interface per method, but that seems exaggerated.
|
||||
private void step(final String current, final String next) {
|
||||
if (!expectedStep.equals(current)) {
|
||||
throw new IllegalStateException("expected " + expectedStep + " but got " + current);
|
||||
}
|
||||
expectedStep = next;
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,13 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
|
||||
.collect(Collectors.toMap(p -> p.get("propertyName").toString(), p -> p));
|
||||
}
|
||||
|
||||
/**
|
||||
Gets called before any validations take place.
|
||||
Allows to initialize fields and properties to default values.
|
||||
*/
|
||||
public void preprocessEntity(final E entity) {
|
||||
}
|
||||
|
||||
protected ArrayList<String> validateProperties(final PropertiesProvider propsProvider) {
|
||||
final var result = new ArrayList<String>();
|
||||
|
||||
|
@ -43,6 +43,19 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
void preprocessesTakesIdentifierFromParent() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
validator.preprocessEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(givenEntity.getIdentifier()).isEqualTo(givenEntity.getParentAsset().getIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidIdentifier() {
|
||||
// given
|
||||
|
Loading…
Reference in New Issue
Block a user