diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java index 4c9620564b..f77823eaac 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java @@ -23,7 +23,9 @@ public class ConfigDto extends HalRepresentation { private boolean disableGroupingGrid; private String dateFormat; private boolean anonymousAccessEnabled; + @NoBlankStrings private Set adminGroups; + @NoBlankStrings private Set adminUsers; private String baseUrl; private boolean forceBaseUrl; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigResource.java index bf3a11fb9c..c646dceab4 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigResource.java @@ -9,6 +9,7 @@ import sonia.scm.util.ScmConfigurationUtil; import sonia.scm.web.VndMediaType; import javax.inject.Inject; +import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PUT; @@ -71,7 +72,7 @@ public class ConfigResource { @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - public Response update(ConfigDto configDto) { + public Response update(@Valid ConfigDto configDto) { // This *could* be moved to ScmConfiguration or ScmConfigurationUtil classes. // But to where to check? load() or store()? Leave it for now, SCMv1 legacy that can be cleaned up later. diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/NoBlankStrings.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/NoBlankStrings.java new file mode 100644 index 0000000000..ba5e20ffbd --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/NoBlankStrings.java @@ -0,0 +1,26 @@ +package sonia.scm.api.v2.resources; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE}) +@Retention(RUNTIME) +@Constraint(validatedBy = NoBlankStringsValidator.class) +@Documented +public @interface NoBlankStrings { + + String message() default "collection must not contain empty strings"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/NoBlankStringsValidator.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/NoBlankStringsValidator.java new file mode 100644 index 0000000000..6bae44164e --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/NoBlankStringsValidator.java @@ -0,0 +1,23 @@ +package sonia.scm.api.v2.resources; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Collection; + +public class NoBlankStringsValidator implements ConstraintValidator { + + @Override + public void initialize(NoBlankStrings constraintAnnotation) { + } + + @Override + public boolean isValid(Collection object, ConstraintValidatorContext constraintContext) { + if ( object == null || object.isEmpty()) { + return true; + } + return object.stream() + .map(x -> x.toString()) + .map(s -> ((String) s).trim()) + .noneMatch(s -> ((String) s).isEmpty()); + } +}