add-domain-setup-validation #71

Merged
hsh-michaelhoennig merged 13 commits from add-domain-setup-validation into master 2024-07-05 11:56:32 +02:00
5 changed files with 56 additions and 2 deletions
Showing only changes of commit 4c54abb742 - Show all commits

View File

@ -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)

View File

@ -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}

View File

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

View File

@ -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>();

View File

@ -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