Compare commits
3 Commits
e1fda412ae
...
99a9358679
Author | SHA1 | Date | |
---|---|---|---|
|
99a9358679 | ||
|
20f154c145 | ||
|
9ee9e1e74b |
@ -38,8 +38,8 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> unixUsers() {
|
private static TriFunction<HsBookingItemEntity, IntegerProperty<?>, Integer, List<String>> unixUsers() {
|
||||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
return (final HsBookingItemEntity entity, final IntegerProperty<?> prop, final Integer factor) -> {
|
||||||
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
||||||
.map(ha -> ha.getSubHostingAssets().stream()
|
.map(ha -> ha.getSubHostingAssets().stream()
|
||||||
.filter(subAsset -> subAsset.getType() == UNIX_USER)
|
.filter(subAsset -> subAsset.getType() == UNIX_USER)
|
||||||
@ -53,8 +53,8 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databaseUsers() {
|
private static TriFunction<HsBookingItemEntity, IntegerProperty<?>, Integer, List<String>> databaseUsers() {
|
||||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
return (final HsBookingItemEntity entity, final IntegerProperty<?> prop, final Integer factor) -> {
|
||||||
final var dbUserCount = ofNullable(entity.getRelatedHostingAsset())
|
final var dbUserCount = ofNullable(entity.getRelatedHostingAsset())
|
||||||
.map(ha -> ha.getSubHostingAssets().stream()
|
.map(ha -> ha.getSubHostingAssets().stream()
|
||||||
.filter(bi -> bi.getType() == PGSQL_USER || bi.getType() == MARIADB_USER )
|
.filter(bi -> bi.getType() == PGSQL_USER || bi.getType() == MARIADB_USER )
|
||||||
@ -68,8 +68,8 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databases() {
|
private static TriFunction<HsBookingItemEntity, IntegerProperty<?>, Integer, List<String>> databases() {
|
||||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
return (final HsBookingItemEntity entity, final IntegerProperty<?> prop, final Integer factor) -> {
|
||||||
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
||||||
.map(ha -> ha.getSubHostingAssets().stream()
|
.map(ha -> ha.getSubHostingAssets().stream()
|
||||||
.filter(bi -> bi.getType()==PGSQL_USER || bi.getType()==MARIADB_USER )
|
.filter(bi -> bi.getType()==PGSQL_USER || bi.getType()==MARIADB_USER )
|
||||||
@ -85,8 +85,8 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> eMailAddresses() {
|
private static TriFunction<HsBookingItemEntity, IntegerProperty<?>, Integer, List<String>> eMailAddresses() {
|
||||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
return (final HsBookingItemEntity entity, final IntegerProperty<?> prop, final Integer factor) -> {
|
||||||
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
||||||
.map(ha -> ha.getSubHostingAssets().stream()
|
.map(ha -> ha.getSubHostingAssets().stream()
|
||||||
.filter(bi -> bi.getType() == DOMAIN_MBOX_SETUP)
|
.filter(bi -> bi.getType() == DOMAIN_MBOX_SETUP)
|
||||||
|
@ -72,7 +72,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
|||||||
|
|
||||||
final var entity = mapper.map(body, HsHostingAssetEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
final var entity = mapper.map(body, HsHostingAssetEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
||||||
|
|
||||||
final var mapped = new HostingAssetEntitySaveProcessor(entity)
|
final var mapped = new HostingAssetEntitySaveProcessor(em, entity)
|
||||||
.preprocessEntity()
|
.preprocessEntity()
|
||||||
.validateEntity()
|
.validateEntity()
|
||||||
.prepareForSave()
|
.prepareForSave()
|
||||||
@ -133,7 +133,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
|||||||
|
|
||||||
new HsHostingAssetEntityPatcher(em, entity).apply(body);
|
new HsHostingAssetEntityPatcher(em, entity).apply(body);
|
||||||
|
|
||||||
final var mapped = new HostingAssetEntitySaveProcessor(entity)
|
final var mapped = new HostingAssetEntitySaveProcessor(em, entity)
|
||||||
.preprocessEntity()
|
.preprocessEntity()
|
||||||
.validateEntity()
|
.validateEntity()
|
||||||
.prepareForSave()
|
.prepareForSave()
|
||||||
@ -162,5 +162,5 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final BiConsumer<HsHostingAssetEntity, HsHostingAssetResource> ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource)
|
final BiConsumer<HsHostingAssetEntity, HsHostingAssetResource> ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource)
|
||||||
-> resource.setConfig(HostingAssetEntityValidatorRegistry.forType(entity.getType())
|
-> resource.setConfig(HostingAssetEntityValidatorRegistry.forType(entity.getType())
|
||||||
.revampProperties(entity, (Map<String, Object>) resource.getConfig()));
|
.revampProperties(em, entity, (Map<String, Object>) resource.getConfig()));
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetResource;
|
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetResource;
|
||||||
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@ -15,10 +16,12 @@ public class HostingAssetEntitySaveProcessor {
|
|||||||
|
|
||||||
private final HsEntityValidator<HsHostingAssetEntity> validator;
|
private final HsEntityValidator<HsHostingAssetEntity> validator;
|
||||||
private String expectedStep = "preprocessEntity";
|
private String expectedStep = "preprocessEntity";
|
||||||
|
private final EntityManager em;
|
||||||
private HsHostingAssetEntity entity;
|
private HsHostingAssetEntity entity;
|
||||||
private HsHostingAssetResource resource;
|
private HsHostingAssetResource resource;
|
||||||
|
|
||||||
public HostingAssetEntitySaveProcessor(final HsHostingAssetEntity entity) {
|
public HostingAssetEntitySaveProcessor(final EntityManager em, final HsHostingAssetEntity entity) {
|
||||||
|
this.em = em;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.validator = HostingAssetEntityValidatorRegistry.forType(entity.getType());
|
this.validator = HostingAssetEntityValidatorRegistry.forType(entity.getType());
|
||||||
}
|
}
|
||||||
@ -41,7 +44,7 @@ public class HostingAssetEntitySaveProcessor {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public HostingAssetEntitySaveProcessor prepareForSave() {
|
public HostingAssetEntitySaveProcessor prepareForSave() {
|
||||||
step("prepareForSave", "saveUsing");
|
step("prepareForSave", "saveUsing");
|
||||||
validator.prepareProperties(entity);
|
validator.prepareProperties(em, entity);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +73,7 @@ public class HostingAssetEntitySaveProcessor {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public HsHostingAssetResource revampProperties() {
|
public HsHostingAssetResource revampProperties() {
|
||||||
step("revampProperties", null);
|
step("revampProperties", null);
|
||||||
final var revampedProps = validator.revampProperties(entity, (Map<String, Object>) resource.getConfig());
|
final var revampedProps = validator.revampProperties(em, entity, (Map<String, Object>) resource.getConfig());
|
||||||
resource.setConfig(revampedProps);
|
resource.setConfig(revampedProps);
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
|
|||||||
|
|
||||||
class HsEMailAddressHostingAssetValidator extends HostingAssetEntityValidator {
|
class HsEMailAddressHostingAssetValidator extends HostingAssetEntityValidator {
|
||||||
|
|
||||||
private static final String UNIX_USER_REGEX = "^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9]+)?$"; // also accepts legacy pac-names
|
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 EMAIL_ADDRESS_LOCAL_PART_REGEX = "[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+"; // RFC 5322
|
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_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 EMAIL_ADDRESS_FULL_REGEX = "^" + EMAIL_ADDRESS_LOCAL_PART_REGEX + "@" + EMAIL_ADDRESS_DOMAIN_PART_REGEX + "$";
|
||||||
|
@ -10,8 +10,10 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
|
|||||||
|
|
||||||
class HsEMailAliasHostingAssetValidator extends HostingAssetEntityValidator {
|
class HsEMailAliasHostingAssetValidator extends HostingAssetEntityValidator {
|
||||||
|
|
||||||
private static final String UNIX_USER_REGEX = "^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9]+)?$"; // also accepts legacy pac-names
|
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 EMAIL_ADDRESS_REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; // RFC 5322
|
private static final String EMAIL_ADDRESS_REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; // RFC 5322
|
||||||
|
private static final String INCLUDE_REGEX = "^:include:/.*$";
|
||||||
|
private static final String PIPE_REGEX = "^|.*$";
|
||||||
public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322
|
public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322
|
||||||
|
|
||||||
HsEMailAliasHostingAssetValidator() {
|
HsEMailAliasHostingAssetValidator() {
|
||||||
@ -19,13 +21,13 @@ class HsEMailAliasHostingAssetValidator extends HostingAssetEntityValidator {
|
|||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
arrayOf(
|
arrayOf(
|
||||||
stringProperty("target").maxLength(EMAIL_ADDRESS_MAX_LENGTH).matchesRegEx(UNIX_USER_REGEX, EMAIL_ADDRESS_REGEX)
|
stringProperty("target").maxLength(EMAIL_ADDRESS_MAX_LENGTH).matchesRegEx(UNIX_USER_REGEX, EMAIL_ADDRESS_REGEX, INCLUDE_REGEX, PIPE_REGEX)
|
||||||
).required().minLength(1));
|
).required().minLength(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||||
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
|
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
|
||||||
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"-[a-z0-9]+$");
|
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"-[a-z0-9][a-z0-9\\.-]*$");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.hs.validation.PropertiesProvider;
|
|||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty;
|
import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty;
|
import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty;
|
||||||
@ -21,23 +22,26 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator {
|
|||||||
HsHostingAssetType.UNIX_USER,
|
HsHostingAssetType.UNIX_USER,
|
||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
integerProperty("SSD hard quota").unit("GB").maxFrom("SSD").optional(),
|
booleanProperty("locked").readOnly(),
|
||||||
integerProperty("SSD soft quota").unit("GB").maxFrom("SSD hard quota").optional(),
|
integerProperty("userid").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeUserId),
|
||||||
integerProperty("HDD hard quota").unit("GB").maxFrom("HDD").optional(),
|
|
||||||
integerProperty("HDD soft quota").unit("GB").maxFrom("HDD hard quota").optional(),
|
integerProperty("SSD hard quota").unit("MB").maxFrom("SSD").withFactor(1024).optional(),
|
||||||
|
integerProperty("SSD soft quota").unit("MB").maxFrom("SSD hard quota").optional(),
|
||||||
|
integerProperty("HDD hard quota").unit("MB").maxFrom("HDD").withFactor(1024).optional(),
|
||||||
|
integerProperty("HDD soft quota").unit("MB").maxFrom("HDD hard quota").optional(),
|
||||||
enumerationProperty("shell")
|
enumerationProperty("shell")
|
||||||
.values("/bin/false", "/bin/bash", "/bin/csh", "/bin/dash", "/usr/bin/tcsh", "/usr/bin/zsh", "/usr/bin/passwd")
|
.values("/bin/false", "/bin/bash", "/bin/csh", "/bin/dash", "/usr/bin/tcsh", "/usr/bin/zsh", "/usr/bin/passwd")
|
||||||
.withDefault("/bin/false"),
|
.withDefault("/bin/false"),
|
||||||
stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir),
|
stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir),
|
||||||
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(),
|
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(),
|
||||||
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(HashGenerator.Algorithm.LINUX_SHA512).writeOnly());
|
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(HashGenerator.Algorithm.LINUX_SHA512).writeOnly());
|
||||||
// TODO.spec: public SSH keys?
|
// TODO.spec: public SSH keys? (only if hsadmin-ng is only accessible with 2FA)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||||
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
|
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
|
||||||
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"-[a-z0-9]+$");
|
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"-[a-z0-9\\.-]+$");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String computeHomedir(final PropertiesProvider propertiesProvider) {
|
private static String computeHomedir(final PropertiesProvider propertiesProvider) {
|
||||||
@ -46,4 +50,8 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator {
|
|||||||
return "/home/pacs/" + webspaceName
|
return "/home/pacs/" + webspaceName
|
||||||
+ "/users/" + entity.getIdentifier().substring(webspaceName.length()+DASH_LENGTH);
|
+ "/users/" + entity.getIdentifier().substring(webspaceName.length()+DASH_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Integer computeUserId(PropertiesProvider propertiesProvider) {
|
||||||
|
return 0; // FIXME: from a specific numeric rage and unique per hive?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.validation;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -106,21 +107,21 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
|
|||||||
throw new IllegalArgumentException("Integer value (or null) expected, but got " + value);
|
throw new IllegalArgumentException("Integer value (or null) expected, but got " + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareProperties(final E entity) {
|
public void prepareProperties(final EntityManager em, final E entity) {
|
||||||
stream(propertyValidators).forEach(p -> {
|
stream(propertyValidators).forEach(p -> {
|
||||||
if ( p.isWriteOnly() && p.isComputed()) {
|
if ( p.isWriteOnly() && p.isComputed()) {
|
||||||
entity.directProps().put(p.propertyName, p.compute(entity));
|
entity.directProps().put(p.propertyName, p.compute(em, entity));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> revampProperties(final E entity, final Map<String, Object> config) {
|
public Map<String, Object> revampProperties(final EntityManager em, final E entity, final Map<String, Object> config) {
|
||||||
final var copy = new HashMap<>(config);
|
final var copy = new HashMap<>(config);
|
||||||
stream(propertyValidators).forEach(p -> {
|
stream(propertyValidators).forEach(p -> {
|
||||||
if (p.isWriteOnly()) {
|
if (p.isWriteOnly()) {
|
||||||
copy.remove(p.propertyName);
|
copy.remove(p.propertyName);
|
||||||
} else if (p.isReadOnly() && p.isComputed()) {
|
} else if (p.isReadOnly() && p.isComputed()) {
|
||||||
copy.put(p.propertyName, p.compute(entity));
|
copy.put(p.propertyName, p.compute(em, entity));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return copy;
|
return copy;
|
||||||
|
@ -7,7 +7,7 @@ import org.apache.commons.lang3.Validate;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
public class IntegerProperty extends ValidatableProperty<IntegerProperty, Integer> {
|
public class IntegerProperty<P extends IntegerProperty<P>> extends ValidatableProperty<P, Integer> {
|
||||||
|
|
||||||
private final static String[] KEY_ORDER = Array.join(
|
private final static String[] KEY_ORDER = Array.join(
|
||||||
ValidatableProperty.KEY_ORDER_HEAD,
|
ValidatableProperty.KEY_ORDER_HEAD,
|
||||||
@ -19,10 +19,11 @@ public class IntegerProperty extends ValidatableProperty<IntegerProperty, Intege
|
|||||||
private String minFrom;
|
private String minFrom;
|
||||||
private Integer max;
|
private Integer max;
|
||||||
private String maxFrom;
|
private String maxFrom;
|
||||||
|
private Integer factor;
|
||||||
private Integer step;
|
private Integer step;
|
||||||
|
|
||||||
public static IntegerProperty integerProperty(final String propertyName) {
|
public static IntegerProperty<?> integerProperty(final String propertyName) {
|
||||||
return new IntegerProperty(propertyName);
|
return new IntegerProperty<>(propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntegerProperty(final String propertyName) {
|
private IntegerProperty(final String propertyName) {
|
||||||
@ -35,14 +36,19 @@ public class IntegerProperty extends ValidatableProperty<IntegerProperty, Intege
|
|||||||
Validate.isTrue(max == null || maxFrom == null, "max and maxFrom are exclusive, but both are given");
|
Validate.isTrue(max == null || maxFrom == null, "max and maxFrom are exclusive, but both are given");
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntegerProperty minFrom(final String propertyName) {
|
public P minFrom(final String propertyName) {
|
||||||
minFrom = propertyName;
|
minFrom = propertyName;
|
||||||
return this;
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntegerProperty maxFrom(final String propertyName) {
|
public P maxFrom(final String propertyName) {
|
||||||
maxFrom = propertyName;
|
maxFrom = propertyName;
|
||||||
return this;
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public P withFactor(final int factor) {
|
||||||
|
this.factor = factor;
|
||||||
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -62,10 +68,10 @@ public class IntegerProperty extends ValidatableProperty<IntegerProperty, Intege
|
|||||||
result.add(propertyName + "' is expected to be multiple of " + step + " but is " + propValue);
|
result.add(propertyName + "' is expected to be multiple of " + step + " but is " + propValue);
|
||||||
}
|
}
|
||||||
if (minFrom != null) {
|
if (minFrom != null) {
|
||||||
validateMin(result, propertyName, propValue, propProvider.getContextValue(minFrom, Integer.class));
|
validateMin(result, propertyName, propValue, propProvider.getContextValue(minFrom, Integer.class) * ((factor != null) ? factor : 1));
|
||||||
}
|
}
|
||||||
if (maxFrom != null) {
|
if (maxFrom != null) {
|
||||||
validateMax(result, propertyName, propValue, propProvider.getContextValue(maxFrom, Integer.class, 0));
|
validateMax(result, propertyName, propValue, propProvider.getContextValue(maxFrom, Integer.class, 0) * ((factor != null) ? factor : 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
|||||||
import net.hostsharing.hsadminng.mapper.Array;
|
import net.hostsharing.hsadminng.mapper.Array;
|
||||||
import org.apache.commons.lang3.function.TriFunction;
|
import org.apache.commons.lang3.function.TriFunction;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -137,8 +138,8 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
|
|||||||
if (asTotalLimitValidators == null) {
|
if (asTotalLimitValidators == null) {
|
||||||
asTotalLimitValidators = new ArrayList<>();
|
asTotalLimitValidators = new ArrayList<>();
|
||||||
}
|
}
|
||||||
final TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> validator =
|
final TriFunction<HsBookingItemEntity, IntegerProperty<?>, Integer, List<String>> validator =
|
||||||
(final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
(final HsBookingItemEntity entity, final IntegerProperty<?> prop, final Integer factor) -> {
|
||||||
|
|
||||||
final var total = entity.getSubBookingItems().stream()
|
final var total = entity.getSubBookingItems().stream()
|
||||||
.map(server -> server.getResources().get(propertyName))
|
.map(server -> server.getResources().get(propertyName))
|
||||||
@ -169,11 +170,11 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
|
|||||||
return thresholdPercentage;
|
return thresholdPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidatableProperty<P, T> eachComprising(final int factor, final TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> validator) {
|
public ValidatableProperty<P, T> eachComprising(final int factor, final TriFunction<HsBookingItemEntity, IntegerProperty<?>, Integer, List<String>> validator) {
|
||||||
if (asTotalLimitValidators == null) {
|
if (asTotalLimitValidators == null) {
|
||||||
asTotalLimitValidators = new ArrayList<>();
|
asTotalLimitValidators = new ArrayList<>();
|
||||||
}
|
}
|
||||||
asTotalLimitValidators.add((final HsBookingItemEntity entity) -> validator.apply(entity, (IntegerProperty)this, factor));
|
asTotalLimitValidators.add((final HsBookingItemEntity entity) -> validator.apply(entity, (IntegerProperty<?>)this, factor));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +308,7 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
|
|||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <E extends PropertiesProvider> T compute(final E entity) {
|
public <E extends PropertiesProvider> T compute(final EntityManager em, final E entity) {
|
||||||
return computedBy.apply(entity);
|
return computedBy.apply(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.mapper;
|
|||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -56,16 +57,19 @@ public class PatchableMapWrapper<T> implements Map<String, T> {
|
|||||||
return "{\n"
|
return "{\n"
|
||||||
+ (
|
+ (
|
||||||
keySet().stream().sorted()
|
keySet().stream().sorted()
|
||||||
.map(k -> " \"" + k + "\": " + optionallyQuoted(get(k))))
|
.map(k -> " \"" + k + "\": " + formatted(get(k))))
|
||||||
.collect(joining(",\n")
|
.collect(joining(",\n")
|
||||||
)
|
)
|
||||||
+ "\n}\n";
|
+ "\n}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object optionallyQuoted(final Object value) {
|
private Object formatted(final Object value) {
|
||||||
if ( value instanceof Number || value instanceof Boolean ) {
|
if ( value == null || value instanceof Number || value instanceof Boolean ) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
if ( value.getClass().isArray() ) {
|
||||||
|
return "\"" + Arrays.toString( (Object[]) value) + "\"";
|
||||||
|
}
|
||||||
return "\"" + value + "\"";
|
return "\"" + value + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -24,6 +25,8 @@ class HsMariaDbUserHostingAssetValidatorUnitTest {
|
|||||||
.caption("some valid test MariaDB-Instance")
|
.caption("some valid test MariaDB-Instance")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
private EntityManager em = null; // not actually needed in these test cases
|
||||||
|
|
||||||
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
|
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
|
||||||
return HsHostingAssetEntity.builder()
|
return HsHostingAssetEntity.builder()
|
||||||
.type(MARIADB_USER)
|
.type(MARIADB_USER)
|
||||||
@ -58,7 +61,7 @@ class HsMariaDbUserHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // not needed for mysql_native_password
|
// HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // not needed for mysql_native_password
|
||||||
validator.prepareProperties(givenMariaDbUserHostingAsset);
|
validator.prepareProperties(em, givenMariaDbUserHostingAsset);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
||||||
|
@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -27,6 +28,8 @@ class HsPostgreSqlUserHostingAssetValidatorUnitTest {
|
|||||||
.caption("some valid test PgSql-Instance")
|
.caption("some valid test PgSql-Instance")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
private EntityManager em = null; // not actually needed in these test cases
|
||||||
|
|
||||||
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
|
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
|
||||||
return HsHostingAssetEntity.builder()
|
return HsHostingAssetEntity.builder()
|
||||||
.type(PGSQL_USER)
|
.type(PGSQL_USER)
|
||||||
@ -61,7 +64,7 @@ class HsPostgreSqlUserHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
HashGenerator.nextSalt(new String(Base64.getDecoder().decode("L1QxSVNyTU81b3NZS1djNg=="), Charset.forName("latin1")));
|
HashGenerator.nextSalt(new String(Base64.getDecoder().decode("L1QxSVNyTU81b3NZS1djNg=="), Charset.forName("latin1")));
|
||||||
validator.prepareProperties(givenMariaDbUserHostingAsset);
|
validator.prepareProperties(em, givenMariaDbUserHostingAsset);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
||||||
|
@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -43,6 +44,8 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
|||||||
)))
|
)))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
private EntityManager em = null; // not actually needed in these test cases
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void preparesUnixUser() {
|
void preparesUnixUser() {
|
||||||
// given
|
// given
|
||||||
@ -51,7 +54,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
HashGenerator.nextSalt("Ly3LbsArtL5u4EVt");
|
HashGenerator.nextSalt("Ly3LbsArtL5u4EVt");
|
||||||
validator.prepareProperties(unixUserHostingAsset);
|
validator.prepareProperties(em, unixUserHostingAsset);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(unixUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
assertThat(unixUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
||||||
@ -142,7 +145,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
HashGenerator.nextSalt("Ly3LbsArtL5u4EVt");
|
HashGenerator.nextSalt("Ly3LbsArtL5u4EVt");
|
||||||
final var result = validator.revampProperties(unixUserHostingAsset, unixUserHostingAsset.getConfig());
|
final var result = validator.revampProperties(em, unixUserHostingAsset, unixUserHostingAsset.getConfig());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
assertThat(result).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
||||||
|
@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.migration;
|
|||||||
import com.opencsv.CSVParserBuilder;
|
import com.opencsv.CSVParserBuilder;
|
||||||
import com.opencsv.CSVReader;
|
import com.opencsv.CSVReader;
|
||||||
import com.opencsv.CSVReaderBuilder;
|
import com.opencsv.CSVReaderBuilder;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
|
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||||
@ -37,6 +38,7 @@ import static java.lang.Boolean.parseBoolean;
|
|||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
|
import static net.hostsharing.hsadminng.mapper.Array.emptyArray;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
@ -113,6 +115,14 @@ public class CsvDataImport extends ContextBasedTest {
|
|||||||
return records.subList(1, records.size());
|
return records.subList(1, records.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static String[] parseCsvLine(final String csvLine) {
|
||||||
|
try (final var reader = new CSVReader(new StringReader(csvLine))) {
|
||||||
|
return ofNullable(reader.readNext()).orElse(emptyArray(String.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String[] trimAll(final String[] record) {
|
String[] trimAll(final String[] record) {
|
||||||
for (int i = 0; i < record.length; ++i) {
|
for (int i = 0; i < record.length; ++i) {
|
||||||
if (record[i] != null) {
|
if (record[i] != null) {
|
||||||
|
@ -23,18 +23,23 @@ import org.springframework.test.annotation.Commit;
|
|||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
|
import static java.util.Map.entry;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
import static java.util.stream.Collectors.toMap;
|
import static java.util.stream.Collectors.toMap;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.EMAIL_ALIAS;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4_NUMBER;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4_NUMBER;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER;
|
||||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
@ -91,6 +96,7 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
static final Integer IP_NUMBER_ID_OFFSET = 1000000;
|
static final Integer IP_NUMBER_ID_OFFSET = 1000000;
|
||||||
static final Integer HIVE_ID_OFFSET = 2000000;
|
static final Integer HIVE_ID_OFFSET = 2000000;
|
||||||
static final Integer PACKET_ID_OFFSET = 3000000;
|
static final Integer PACKET_ID_OFFSET = 3000000;
|
||||||
|
static final Integer UNIXUSER_ID_OFFSET = 4000000;
|
||||||
|
|
||||||
record Hive(int hive_id, String hive_name, int inet_addr_id, AtomicReference<HsHostingAssetEntity> serverRef) {}
|
record Hive(int hive_id, String hive_name, int inet_addr_id, AtomicReference<HsHostingAssetEntity> serverRef) {}
|
||||||
|
|
||||||
@ -261,6 +267,74 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14010)
|
||||||
|
void importUnixUsers() {
|
||||||
|
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/unixuser.csv")) {
|
||||||
|
final var lines = readAllLines(reader);
|
||||||
|
importUnixUsers(justHeader(lines), withoutHeader(lines));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14019)
|
||||||
|
void verifyUnixUsers() {
|
||||||
|
assumeThatWeAreImportingControlledTestData();
|
||||||
|
|
||||||
|
// no contacts yet => mostly null values
|
||||||
|
assertThat(firstOfEachType(15, UNIX_USER)).isEqualToIgnoringWhitespace("""
|
||||||
|
{
|
||||||
|
4005803=HsHostingAssetEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102090}),
|
||||||
|
4005805=HsHostingAssetEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102091}),
|
||||||
|
4005809=HsHostingAssetEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102093}),
|
||||||
|
4005811=HsHostingAssetEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102094}),
|
||||||
|
4005813=HsHostingAssetEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102095}),
|
||||||
|
4005835=HsHostingAssetEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102106}),
|
||||||
|
4005964=HsHostingAssetEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102147}),
|
||||||
|
4005966=HsHostingAssetEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "shell": "/bin/bash", "userid": 102148}),
|
||||||
|
4005990=HsHostingAssetEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102160}),
|
||||||
|
4100705=HsHostingAssetEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 10003}),
|
||||||
|
4100824=HsHostingAssetEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 10000}),
|
||||||
|
4167846=HsHostingAssetEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 110568}),
|
||||||
|
4169546=HsHostingAssetEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110593}),
|
||||||
|
4169596=HsHostingAssetEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110594})
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14020)
|
||||||
|
void importEmailAliases() {
|
||||||
|
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/emailalias.csv")) {
|
||||||
|
final var lines = readAllLines(reader);
|
||||||
|
importEmailAliases(justHeader(lines), withoutHeader(lines));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14029)
|
||||||
|
void verifyEmailAliases() {
|
||||||
|
assumeThatWeAreImportingControlledTestData();
|
||||||
|
|
||||||
|
// no contacts yet => mostly null values
|
||||||
|
assertThat(firstOfEachType(15, EMAIL_ALIAS)).isEqualToIgnoringWhitespace("""
|
||||||
|
{
|
||||||
|
4002403=HsHostingAssetEntity(EMAIL_ALIAS, lug00, lug00, MANAGED_WEBSPACE:lug00, { "target": "[michael.mellis@example.com]"}),
|
||||||
|
4002405=HsHostingAssetEntity(EMAIL_ALIAS, lug00-wla-listar, lug00-wla-listar, MANAGED_WEBSPACE:lug00, { "target": "[|/home/pacs/lug00/users/in/mailinglist/listar]"}),
|
||||||
|
4002429=HsHostingAssetEntity(EMAIL_ALIAS, mim00, mim00, MANAGED_WEBSPACE:mim00, { "target": "[mim12-mi@mim12.hostsharing.net]"}),
|
||||||
|
4002431=HsHostingAssetEntity(EMAIL_ALIAS, mim00-abruf, mim00-abruf, MANAGED_WEBSPACE:mim00, { "target": "[michael.mellis@hostsharing.net]"}),
|
||||||
|
4002449=HsHostingAssetEntity(EMAIL_ALIAS, mim00-hhfx, mim00-hhfx, MANAGED_WEBSPACE:mim00, { "target": "[mim00-hhfx, |/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l]"}),
|
||||||
|
4002451=HsHostingAssetEntity(EMAIL_ALIAS, mim00-hhfx-l, mim00-hhfx-l, MANAGED_WEBSPACE:mim00, { "target": "[:include:/home/pacs/mim00/etc/hhfx.list]"})
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(11400)
|
@Order(11400)
|
||||||
void validateBookingItems() {
|
void validateBookingItems() {
|
||||||
@ -278,7 +352,7 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
void validateHostingAssets() {
|
void validateHostingAssets() {
|
||||||
hostingAssets.forEach((id, ha) -> {
|
hostingAssets.forEach((id, ha) -> {
|
||||||
try {
|
try {
|
||||||
new HostingAssetEntitySaveProcessor(ha)
|
new HostingAssetEntitySaveProcessor(em, ha)
|
||||||
.preprocessEntity()
|
.preprocessEntity()
|
||||||
.validateEntity();
|
.validateEntity();
|
||||||
} catch (final Exception exc) {
|
} catch (final Exception exc) {
|
||||||
@ -287,6 +361,8 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(19000)
|
@Order(19000)
|
||||||
@Commit
|
@Commit
|
||||||
@ -308,6 +384,8 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
persistHostingAssetsOfType(MANAGED_SERVER);
|
persistHostingAssetsOfType(MANAGED_SERVER);
|
||||||
persistHostingAssetsOfType(MANAGED_WEBSPACE);
|
persistHostingAssetsOfType(MANAGED_WEBSPACE);
|
||||||
persistHostingAssetsOfType(IPV4_NUMBER);
|
persistHostingAssetsOfType(IPV4_NUMBER);
|
||||||
|
persistHostingAssetsOfType(UNIX_USER);
|
||||||
|
persistHostingAssetsOfType(EMAIL_ALIAS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -323,12 +401,14 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
persist(key, HsBookingItemEntityValidatorRegistry.validated(bi));
|
persist(key, HsBookingItemEntityValidatorRegistry.validated(bi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================================
|
||||||
|
|
||||||
private void persistHostingAssetsOfType(final HsHostingAssetType hsHostingAssetType) {
|
private void persistHostingAssetsOfType(final HsHostingAssetType hsHostingAssetType) {
|
||||||
jpaAttempt.transacted(() -> {
|
jpaAttempt.transacted(() -> {
|
||||||
context(rbacSuperuser);
|
context(rbacSuperuser);
|
||||||
hostingAssets.forEach((key, ha) -> {
|
hostingAssets.forEach((key, ha) -> {
|
||||||
if (ha.getType() == hsHostingAssetType) {
|
if (ha.getType() == hsHostingAssetType) {
|
||||||
new HostingAssetEntitySaveProcessor(ha)
|
new HostingAssetEntitySaveProcessor(em, ha)
|
||||||
.preprocessEntity()
|
.preprocessEntity()
|
||||||
.validateEntity()
|
.validateEntity()
|
||||||
.prepareForSave()
|
.prepareForSave()
|
||||||
@ -402,12 +482,17 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
bookingItems.put(PACKET_ID_OFFSET + packet_id, bookingItem);
|
bookingItems.put(PACKET_ID_OFFSET + packet_id, bookingItem);
|
||||||
final var haType = determineHaType(basepacket_code);
|
final var haType = determineHaType(basepacket_code);
|
||||||
|
|
||||||
logError(() -> assertThat(!free || haType == MANAGED_WEBSPACE || bookingItem.getRelatedProject().getDebitor().getDefaultPrefix().equals("hsh"))
|
logError(() -> assertThat(!free || haType == MANAGED_WEBSPACE || bookingItem.getRelatedProject()
|
||||||
.as("packet.free only supported for Hostsharing-Assets and ManagedWebspace in customer-ManagedServer, but is set for " + packet_name)
|
.getDebitor()
|
||||||
|
.getDefaultPrefix()
|
||||||
|
.equals("hsh"))
|
||||||
|
.as("packet.free only supported for Hostsharing-Assets and ManagedWebspace in customer-ManagedServer, but is set for "
|
||||||
|
+ packet_name)
|
||||||
.isTrue());
|
.isTrue());
|
||||||
|
|
||||||
final var asset = HsHostingAssetEntity.builder()
|
final var asset = HsHostingAssetEntity.builder()
|
||||||
.isLoaded(haType == MANAGED_WEBSPACE) // this turns off identifier validation to accept former default prefixes
|
.isLoaded(haType
|
||||||
|
== MANAGED_WEBSPACE) // this turns off identifier validation to accept former default prefixes
|
||||||
.type(haType)
|
.type(haType)
|
||||||
.identifier(packet_name)
|
.identifier(packet_name)
|
||||||
.bookingItem(bookingItem)
|
.bookingItem(bookingItem)
|
||||||
@ -537,7 +622,62 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
<V> V returning(final V value, final Object... assignments) {
|
private void importUnixUsers(final String[] header, final List<String[]> records) {
|
||||||
|
final var columns = new Columns(header);
|
||||||
|
records.stream()
|
||||||
|
.map(this::trimAll)
|
||||||
|
.map(row -> new Record(columns, row))
|
||||||
|
.forEach(rec -> {
|
||||||
|
final var unixuser_id = rec.getInteger("unixuser_id");
|
||||||
|
final var packet_id = rec.getInteger("packet_id");
|
||||||
|
final var unixUserAsset = HsHostingAssetEntity.builder()
|
||||||
|
.type(UNIX_USER)
|
||||||
|
.parentAsset(hostingAssets.get(PACKET_ID_OFFSET+packet_id))
|
||||||
|
.identifier(rec.getString("name"))
|
||||||
|
.caption(rec.getString("comment"))
|
||||||
|
.config(new HashMap<>(Map.ofEntries(
|
||||||
|
entry("shell", rec.getString("shell")),
|
||||||
|
// entry("homedir", rec.getString("homedir")), do not import, it's calculated
|
||||||
|
entry("locked", rec.getBoolean("locked")),
|
||||||
|
entry("userid", rec.getInteger("userid")),
|
||||||
|
entry("SSD soft quota", rec.getInteger("quota_softlimit")),
|
||||||
|
entry("SSD hard quota", rec.getInteger("quota_hardlimit")),
|
||||||
|
entry("HDD soft quota", rec.getInteger("storage_softlimit")),
|
||||||
|
entry("HDD hard quota", rec.getInteger("storage_hardlimit"))
|
||||||
|
)))
|
||||||
|
.build();
|
||||||
|
hostingAssets.put(UNIXUSER_ID_OFFSET + unixuser_id, unixUserAsset);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importEmailAliases(final String[] header, final List<String[]> records) {
|
||||||
|
final var columns = new Columns(header);
|
||||||
|
records.stream()
|
||||||
|
.map(this::trimAll)
|
||||||
|
.map(row -> new Record(columns, row))
|
||||||
|
.forEach(rec -> {
|
||||||
|
final var unixuser_id = rec.getInteger("emailalias_id");
|
||||||
|
final var packet_id = rec.getInteger("pac_id");
|
||||||
|
final var targets = parseCsvLine(rec.getString("target"));
|
||||||
|
final var unixUserAsset = HsHostingAssetEntity.builder()
|
||||||
|
.type(EMAIL_ALIAS)
|
||||||
|
.parentAsset(hostingAssets.get(PACKET_ID_OFFSET+packet_id))
|
||||||
|
.identifier(rec.getString("name"))
|
||||||
|
.caption(rec.getString("name"))
|
||||||
|
.config(Map.ofEntries(
|
||||||
|
entry("target", targets)
|
||||||
|
))
|
||||||
|
.build();
|
||||||
|
hostingAssets.put(UNIXUSER_ID_OFFSET + unixuser_id, unixUserAsset);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================================
|
||||||
|
|
||||||
|
<V> V returning(
|
||||||
|
final V value,
|
||||||
|
@SuppressWarnings("unused") final Object... assignments // DSL-hack: just used for side effects on caller-side
|
||||||
|
) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,7 +722,11 @@ public class ImportHostingAssets extends ImportOfficeData {
|
|||||||
.filter(hae -> hae.getValue().getType() == t)
|
.filter(hae -> hae.getValue().getType() == t)
|
||||||
.limit(maxCount)
|
.limit(maxCount)
|
||||||
)
|
)
|
||||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, ImportHostingAssets::uniqueKeys, TreeMap::new)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static <V> V uniqueKeys(final V v1, final V v2) {
|
||||||
|
throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String firstOfEachType(
|
private String firstOfEachType(
|
||||||
|
@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -19,6 +20,7 @@ class PasswordPropertyUnitTest {
|
|||||||
private final ValidatableProperty<PasswordProperty, String> passwordProp =
|
private final ValidatableProperty<PasswordProperty, String> passwordProp =
|
||||||
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LINUX_SHA512).writeOnly();
|
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LINUX_SHA512).writeOnly();
|
||||||
private final List<String> violations = new ArrayList<>();
|
private final List<String> violations = new ArrayList<>();
|
||||||
|
private EntityManager em = null; // not actually needed in these test cases
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {
|
@ValueSource(strings = {
|
||||||
@ -99,7 +101,7 @@ class PasswordPropertyUnitTest {
|
|||||||
void shouldComputeHash() {
|
void shouldComputeHash() {
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = passwordProp.compute(new PropertiesProvider() {
|
final var result = passwordProp.compute(em, new PropertiesProvider() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> directProps() {
|
public Map<String, Object> directProps() {
|
||||||
|
7
src/test/resources/migration/hosting/emailalias.csv
Normal file
7
src/test/resources/migration/hosting/emailalias.csv
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
emailalias_id;pac_id;name;target
|
||||||
|
2403;1094;lug00;michael.mellis@example.com
|
||||||
|
2405;1094;lug00-wla-listar;|/home/pacs/lug00/users/in/mailinglist/listar
|
||||||
|
2429;1112;mim00;mim12-mi@mim12.hostsharing.net
|
||||||
|
2431;1112;mim00-abruf;michael.mellis@hostsharing.net
|
||||||
|
2449;1112;mim00-hhfx;"mim00-hhfx,""|/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l"""
|
||||||
|
2451;1112;mim00-hhfx-l;:include:/home/pacs/mim00/etc/hhfx.list
|
|
19
src/test/resources/migration/hosting/unixuser.csv
Normal file
19
src/test/resources/migration/hosting/unixuser.csv
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
unixuser_id;name;comment;shell;homedir;locked;packet_id;userid;quota_softlimit;quota_hardlimit;storage_softlimit;storage_hardlimit
|
||||||
|
100824;hsh00;Hostsharing Paket;/bin/bash;/home/pacs/hsh00;0;630;10000;0;0;0;0
|
||||||
|
|
||||||
|
5803;lug00;LUGs;/bin/bash;/home/pacs/lug00;0;1094;102090;0;0;0;0
|
||||||
|
5805;lug00-wla.1;Paul Klemm;/bin/bash;/home/pacs/lug00/users/deaf;0;1094;102091;0;0;0;0
|
||||||
|
5809;lug00-wla.2;Walter Müller;/bin/bash;/home/pacs/lug00/users/marl;0;1094;102093;0;0;0;0
|
||||||
|
5811;lug00-ola.a;LUG OLA - POP a;/usr/bin/passwd;/home/pacs/lug00/users/marl.a;1;1094;102094;0;0;0;0
|
||||||
|
5813;lug00-ola.b;LUG OLA - POP b;/usr/bin/passwd;/home/pacs/lug00/users/marl.b;1;1094;102095;0;0;0;0
|
||||||
|
5835;lug00-test;Test;/usr/bin/passwd;/home/pacs/lug00/users/test;0;1094;102106;0;0;0;0
|
||||||
|
|
||||||
|
100705;hsh00-mim;Michael Mellis;/bin/false;/home/pacs/hsh00/users/mi;0;630;10003;0;0;0;0
|
||||||
|
5964;mim00;Michael Mellis;/bin/bash;/home/pacs/mim00;0;1112;102147;0;0;0;0
|
||||||
|
5966;mim00-1981;Jahrgangstreffen 1981;/bin/bash;/home/pacs/mim00/users/1981;0;1112;102148;128;256;0;0
|
||||||
|
5990;mim00-mail;Mailbox;/bin/bash;/home/pacs/mim00/users/mail;0;1112;102160;0;0;0;0
|
||||||
|
|
||||||
|
167846;hsh00-dph;hsh00-uph;/bin/false;/home/pacs/hsh00/users/uph;0;630;110568;0;0;0;0
|
||||||
|
169546;dph00;Reinhard Wiese;/bin/bash;/home/pacs/dph00;0;19959;110593;0;0;0;0
|
||||||
|
169596;dph00-uph;Domain admin;/bin/bash;/home/pacs/dph00/users/uph;0;19959;110594;0;0;0;0
|
||||||
|
|
|
Loading…
Reference in New Issue
Block a user