import-email-addresses #86
@ -6,8 +6,10 @@ import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAsse
|
||||
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Wraps the steps of the pararation, validation, mapping and revamp around saving of a HsHostingAsset into a readable API.
|
||||
@ -40,12 +42,14 @@ public class HostingAssetEntitySaveProcessor {
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO.impl: remove once the migration of legacy data is done
|
||||
/// validates the entity itself including its properties, but ignoring some error messages for import of legacy data
|
||||
public HostingAssetEntitySaveProcessor validateEntityIgnoring(final String ignoreRegExp) {
|
||||
public HostingAssetEntitySaveProcessor validateEntityIgnoring(final String... ignoreRegExp) {
|
||||
step("validateEntity", "prepareForSave");
|
||||
final var ignoreRegExpPatterns = Arrays.stream(ignoreRegExp).map(Pattern::compile).toList();
|
||||
MultiValidationException.throwIfNotEmpty(
|
||||
validator.validateEntity(entity).stream()
|
||||
.filter(errorMsg -> !errorMsg.matches(ignoreRegExp))
|
||||
.filter(error -> ignoreRegExpPatterns.stream().noneMatch(p -> p.matcher(error).matches() ))
|
||||
.toList()
|
||||
);
|
||||
return this;
|
||||
|
@ -11,11 +11,12 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
|
||||
|
||||
class HsEMailAddressHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
private static final String UNIX_USER_REGEX = "^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\._-]*)?$"; // also accepts legacy pac-names
|
||||
private static final String TARGET_MAILBOX_REGEX = "^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\.+_-]*)?$"; // also accepts legacy pac-names
|
||||
private static final String EMAIL_ADDRESS_LOCAL_PART_REGEX = "[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+"; // RFC 5322
|
||||
private static final String EMAIL_ADDRESS_DOMAIN_PART_REGEX = "[a-zA-Z0-9.-]+";
|
||||
private static final String EMAIL_ADDRESS_FULL_REGEX = "^(" + EMAIL_ADDRESS_LOCAL_PART_REGEX + ")?@" + EMAIL_ADDRESS_DOMAIN_PART_REGEX + "$";
|
||||
private static final String NOBODY_REGEX = "^nobody$";
|
||||
private static final String DEVNULL_REGEX = "^/dev/null$";
|
||||
public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322
|
||||
|
||||
HsEMailAddressHostingAssetValidator() {
|
||||
@ -25,7 +26,7 @@ class HsEMailAddressHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
stringProperty("local-part").matchesRegEx("^" + EMAIL_ADDRESS_LOCAL_PART_REGEX + "$").writeOnce().optional(),
|
||||
stringProperty("sub-domain").matchesRegEx("^" + EMAIL_ADDRESS_LOCAL_PART_REGEX + "$").writeOnce().optional(),
|
||||
arrayOf(
|
||||
stringProperty("target").maxLength(EMAIL_ADDRESS_MAX_LENGTH).matchesRegEx(UNIX_USER_REGEX, EMAIL_ADDRESS_FULL_REGEX, NOBODY_REGEX)
|
||||
stringProperty("target").maxLength(EMAIL_ADDRESS_MAX_LENGTH).matchesRegEx(TARGET_MAILBOX_REGEX, EMAIL_ADDRESS_FULL_REGEX, NOBODY_REGEX, DEVNULL_REGEX)
|
||||
).required().minLength(1));
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,13 @@ class HsEMailAddressHostingAssetValidatorUnitTest {
|
||||
.identifier("old-local-part@example.org")
|
||||
.config(new HashMap<>(ofEntries(
|
||||
entry("local-part", "old-local-part"),
|
||||
entry("target", Array.of("xyz00", "xyz00-abc", "office@example.com"))
|
||||
entry("target", Array.of(
|
||||
"xyz00",
|
||||
"xyz00-abc",
|
||||
"xyz00-xyz+list",
|
||||
"office@example.com",
|
||||
"/dev/null"
|
||||
))
|
||||
)));
|
||||
}
|
||||
|
||||
@ -46,7 +52,7 @@ class HsEMailAddressHostingAssetValidatorUnitTest {
|
||||
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
|
||||
"{type=string, propertyName=local-part, matchesRegEx=[^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+$], writeOnce=true}",
|
||||
"{type=string, propertyName=sub-domain, matchesRegEx=[^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+$], writeOnce=true}",
|
||||
"{type=string[], propertyName=target, elementsOf={type=string, propertyName=target, matchesRegEx=[^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\._-]*)?$, ^([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+)?@[a-zA-Z0-9.-]+$, ^nobody$], maxLength=320}, required=true, minLength=1}");
|
||||
"{type=string[], propertyName=target, elementsOf={type=string, propertyName=target, matchesRegEx=[^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\.+_-]*)?$, ^([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+)?@[a-zA-Z0-9.-]+$, ^nobody$, ^/dev/null$], maxLength=320}, required=true, minLength=1}");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -69,7 +75,11 @@ class HsEMailAddressHostingAssetValidatorUnitTest {
|
||||
.config(new HashMap<>(ofEntries(
|
||||
entry("local-part", "no@allowed"),
|
||||
entry("sub-domain", "no@allowedeither"),
|
||||
entry("target", Array.of("xyz00", "xyz00-abc", "garbage", "office@example.com")))))
|
||||
entry("target", Array.of(
|
||||
"xyz00",
|
||||
"xyz00-abc",
|
||||
"garbage",
|
||||
"office@example.com")))))
|
||||
.build();
|
||||
final var validator = HostingAssetEntityValidatorRegistry.forType(emailAddressHostingAssetEntity.getType());
|
||||
|
||||
@ -80,7 +90,7 @@ class HsEMailAddressHostingAssetValidatorUnitTest {
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'EMAIL_ADDRESS:old-local-part@example.org.config.local-part' is expected to match any of [^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+$] but 'no@allowed' does not match",
|
||||
"'EMAIL_ADDRESS:old-local-part@example.org.config.sub-domain' is expected to match any of [^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+$] but 'no@allowedeither' does not match",
|
||||
"'EMAIL_ADDRESS:old-local-part@example.org.config.target' is expected to match any of [^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\._-]*)?$, ^([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+)?@[a-zA-Z0-9.-]+$, ^nobody$] but 'garbage' does not match any");
|
||||
"'EMAIL_ADDRESS:old-local-part@example.org.config.target' is expected to match any of [^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\.+_-]*)?$, ^([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+)?@[a-zA-Z0-9.-]+$, ^nobody$, ^/dev/null$] but 'garbage' does not match any");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -20,6 +20,7 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.ValidationException;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@ -309,7 +310,7 @@ public class CsvDataImport extends ContextBasedTest {
|
||||
void logError(final Runnable assertion) {
|
||||
try {
|
||||
assertion.run();
|
||||
} catch (final AssertionError exc) {
|
||||
} catch (final AssertionError | ValidationException exc) {
|
||||
logError(exc.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -668,6 +668,9 @@ public class ImportHostingAssets extends ImportOfficeData {
|
||||
if (isImportingControlledTestData()) {
|
||||
expectError("zonedata dom_owner of mellis.de is old00 but expected to be mim00");
|
||||
expectError("\nexpected: \"vm1068\"\n but was: \"vm1093\"");
|
||||
expectError("['EMAIL_ADDRESS:webmaster@hamburg-west.l-u-g.org.config.target' is expected to match any of [^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9][a-z0-9\\.+_-]*)?$, ^([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+)?@[a-zA-Z0-9.-]+$, ^nobody$, ^/dev/null$] but 'raoul.lottmann@example.com peter.lottmann@example.com' does not match any]");
|
||||
expectError("['EMAIL_ADDRESS:abuse@mellis.de.config.target' length is expected to be at min 1 but length of [[]] is 0]");
|
||||
expectError("['EMAIL_ADDRESS:abuse@ist-im-netz.de.config.target' length is expected to be at min 1 but length of [[]] is 0]");
|
||||
}
|
||||
this.assertNoErrors();
|
||||
}
|
||||
@ -920,7 +923,10 @@ public class ImportHostingAssets extends ImportOfficeData {
|
||||
logError(() ->
|
||||
new HostingAssetEntitySaveProcessor(em, entry.getValue())
|
||||
.preprocessEntity()
|
||||
.validateEntityIgnoring("'EMAIL_ALIAS:.*\\.config\\.target' .*")
|
||||
.validateEntityIgnoring(
|
||||
"'EMAIL_ALIAS:.*\\.config\\.target' .*",
|
||||
"'EMAIL_ADDRESS:.*\\.config\\.target' .*"
|
||||
)
|
||||
.prepareForSave()
|
||||
.saveUsing(entity -> persist(entry.getKey(), entity))
|
||||
.validateContext()
|
||||
|
@ -12,7 +12,7 @@ emailaddr_id;domain_id;localpart;subdomain;target
|
||||
54760;4531;info;hamburg-west;peter.lottmann@example.com
|
||||
54761;4531;lugmaster;hamburg-west;raoul.lottmann@example.com
|
||||
54762;4531;postmaster;hamburg-west;raoul.lottmann@example.com
|
||||
54763;4531;webmaster;hamburg-west;raoul.lottmann@example.com
|
||||
54763;4531;webmaster;hamburg-west;raoul.lottmann@example.com peter.lottmann@example.com
|
||||
54764;4531;;eliza;eliza@example.net
|
||||
54765;4531;;;lug00
|
||||
54766;4532;;;nomail
|
||||
@ -22,10 +22,10 @@ emailaddr_id;domain_id;localpart;subdomain;target
|
||||
54963;4581;abuse;;mim00
|
||||
54964;4581;postmaster;;mim00
|
||||
54965;4581;webmaster;;mim00
|
||||
54981;4587;abuse;;mim00
|
||||
54982;4587;postmaster;;mim00
|
||||
54981;4587;abuse;;
|
||||
54982;4587;postmaster;;/dev/null
|
||||
54983;4587;webmaster;;mim00
|
||||
54987;4589;abuse;;mim00
|
||||
54987;4589;abuse;;""
|
||||
54988;4589;postmaster;;mim00
|
||||
54989;4589;webmaster;;mim00
|
||||
55020;4600;abuse;;mim00
|
||||
|
|
Loading…
Reference in New Issue
Block a user