Compare commits

...

2 Commits

Author SHA1 Message Date
Michael Hoennig
c59fb34b8b fixing issues from code-review 2024-06-27 12:28:05 +02:00
Michael Hoennig
94d96548d4 cleanup 2024-06-27 09:06:30 +02:00
8 changed files with 51 additions and 29 deletions

View File

@ -29,7 +29,7 @@ class HsUnixUserHostingAssetValidator extends HsHostingAssetEntityValidator {
.values("/bin/false", "/bin/bash", "/bin/csh", "/bin/dash", "/usr/bin/tcsh", "/usr/bin/zsh", "/usr/bin/passwd")
.withDefault("/bin/false"),
stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir),
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).hidden().writeOnly().optional(),
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(),
passwordProperty("password").minLength(8).maxLength(40).writeOnly());
}

View File

@ -32,20 +32,20 @@ public class EnumerationProperty extends ValidatableProperty<String> {
}
public void deferredInit(final ValidatableProperty<?>[] allProperties) {
if (deferredInit != null) {
if (hasDeferredInit()) {
if (this.values != null) {
throw new IllegalStateException("property " + this + " already has values");
}
this.values = deferredInit.apply(allProperties);
this.values = doDeferredInit(allProperties);
}
}
public ValidatableProperty<String> valuesFromProperties(final String propertyNamePrefix) {
this.deferredInit = (ValidatableProperty<?>[] allProperties) -> stream(allProperties)
this.setDeferredInit( (ValidatableProperty<?>[] allProperties) -> stream(allProperties)
.map(ValidatableProperty::propertyName)
.filter(name -> name.startsWith(propertyNamePrefix))
.map(name -> name.substring(propertyNamePrefix.length()))
.toArray(String[]::new);
.toArray(String[]::new));
return this;
}

View File

@ -92,7 +92,7 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
public Map<String, Object> postProcess(final E entity, final Map<String, Object> config) {
final var copy = new HashMap<>(config);
stream(propertyValidators).forEach(p -> {
if ( p.writeOnly) {
if ( p.isWriteOnly()) {
copy.remove(p.propertyName);
}
if (p.isComputed()) {

View File

@ -10,7 +10,7 @@ public class PasswordProperty extends StringProperty {
private PasswordProperty(final String propertyName) {
super(propertyName);
hidden();
undisclosed();
}
public static PasswordProperty passwordProperty(final String propertyName) {

View File

@ -6,7 +6,6 @@ import net.hostsharing.hsadminng.mapper.Array;
import java.util.List;
import java.util.regex.Pattern;
@Setter
public class StringProperty extends ValidatableProperty<String> {
@ -14,11 +13,11 @@ public class StringProperty extends ValidatableProperty<String> {
ValidatableProperty.KEY_ORDER_HEAD,
Array.of("matchesRegEx", "minLength", "maxLength"),
ValidatableProperty.KEY_ORDER_TAIL,
Array.of("hidden"));
Array.of("undisclosed"));
private Pattern matchesRegEx;
private Integer minLength;
private Integer maxLength;
private boolean hidden;
private boolean undisclosed;
protected StringProperty(final String propertyName) {
super(String.class, propertyName, KEY_ORDER);
@ -43,8 +42,13 @@ public class StringProperty extends ValidatableProperty<String> {
return this;
}
public StringProperty hidden() {
this.hidden = true;
/**
* The property value is not disclosed in error messages.
*
* @return this;
*/
public StringProperty undisclosed() {
this.undisclosed = true;
return this;
}
@ -59,13 +63,13 @@ public class StringProperty extends ValidatableProperty<String> {
if (matchesRegEx != null && !matchesRegEx.matcher(propValue).matches()) {
result.add(propertyName + "' is expected to be match " + matchesRegEx + " but " + display(propValue) + " does not match");
}
if (readOnly && propValue != null) {
if (isReadOnly() && propValue != null) {
result.add(propertyName + "' is readonly but given as " + display(propValue));
}
}
private String display(final String propValue) {
return hidden ? "provided value" : ("'" + propValue + "'");
return undisclosed ? "provided value" : ("'" + propValue + "'");
}
@Override

View File

@ -1,6 +1,8 @@
package net.hostsharing.hsadminng.hs.validation;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.experimental.Accessors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
@ -21,6 +23,7 @@ import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable;
@Getter
@RequiredArgsConstructor
public abstract class ValidatableProperty<T> {
@ -29,16 +32,28 @@ public abstract class ValidatableProperty<T> {
final Class<T> type;
final String propertyName;
@JsonIgnore
private final String[] keyOrder;
private Boolean required;
private T defaultValue;
protected Function<PropertiesProvider, T> computedBy;
protected boolean computed; // used in descriptor, because computedBy cannot be rendered to a text string
protected boolean readOnly;
protected boolean writeOnly;
protected Function<ValidatableProperty<?>[], T[]> deferredInit;
@JsonIgnore
private Function<PropertiesProvider, T> computedBy;
@Accessors(makeFinal = true, chain = true, fluent = false)
private boolean computed; // used in descriptor, because computedBy cannot be rendered to a text string
@Accessors(makeFinal = true, chain = true, fluent = false)
private boolean readOnly;
@Accessors(makeFinal = true, chain = true, fluent = false)
private boolean writeOnly;
private Function<ValidatableProperty<?>[], T[]> deferredInit;
private boolean isTotalsValidator = false;
@JsonIgnore
private List<Function<HsBookingItemEntity, List<String>>> asTotalLimitValidators; // TODO.impl: move to BookingItemIntegerProperty
@ -48,6 +63,17 @@ public abstract class ValidatableProperty<T> {
return null;
}
protected void setDeferredInit(final Function<ValidatableProperty<?>[], T[]> function) {
this.deferredInit = function;
}
public boolean hasDeferredInit() {
return deferredInit != null;
}
public T[] doDeferredInit(final ValidatableProperty<?>[] allProperties) {
return deferredInit.apply(allProperties);
}
public ValidatableProperty<T> writeOnly() {
this.writeOnly = true;
@ -61,7 +87,6 @@ public abstract class ValidatableProperty<T> {
return this;
}
public ValidatableProperty<T> required() {
required = TRUE;
return this;
@ -231,10 +256,6 @@ public abstract class ValidatableProperty<T> {
return this;
}
public boolean isComputed() {
return computedBy != null;
}
public <E extends PropertiesProvider> T compute(final E entity) {
return computedBy.apply(entity);
}

View File

@ -124,8 +124,8 @@ class HsUnixUserHostingAssetValidatorUnitTest {
"{type=integer, propertyName=HDD soft quota, unit=GB, maxFrom=HDD hard quota}",
"{type=enumeration, propertyName=shell, values=[/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd], defaultValue=/bin/false}",
"{type=string, propertyName=homedir, readOnly=true, computed=true}",
"{type=string, propertyName=totpKey, matchesRegEx=^0x([0-9A-Fa-f]{2})+$, minLength=20, maxLength=256, writeOnly=true, hidden=true}",
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, hidden=true}"
"{type=string, propertyName=totpKey, matchesRegEx=^0x([0-9A-Fa-f]{2})+$, minLength=20, maxLength=256, writeOnly=true, undisclosed=true}",
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, undisclosed=true}"
);
}
}

View File

@ -54,8 +54,6 @@ public class JsonMatcher extends BaseMatcher<CharSequence> {
return true;
} catch (final JSONException | JsonProcessingException e) {
throw new AssertionError(e);
} catch (final Exception e ) {
throw e;
}
}
@ -63,5 +61,4 @@ public class JsonMatcher extends BaseMatcher<CharSequence> {
public void describeTo(final Description description) {
description.appendText("leniently matches JSON");
}
}