Add bean validation to user, group and repository

The validations are taken from the isValid methods of the corresponding
model objects.
This commit is contained in:
René Pfeuffer
2018-08-24 14:35:58 +02:00
parent 2761edb9f6
commit 128961b745
8 changed files with 24 additions and 6 deletions

View File

@@ -11,6 +11,7 @@ import sonia.scm.group.GroupManager;
import sonia.scm.web.VndMediaType; import sonia.scm.web.VndMediaType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -85,7 +86,7 @@ public class GroupCollectionResource {
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created group")) @ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created group"))
public Response create(GroupDto groupDto) throws AlreadyExistsException { public Response create(@Valid GroupDto groupDto) throws AlreadyExistsException {
return adapter.create(groupDto, return adapter.create(groupDto,
() -> dtoToGroupMapper.map(groupDto), () -> dtoToGroupMapper.map(groupDto),
group -> resourceLinks.group().self(group.getName())); group -> resourceLinks.group().self(group.getName()));

View File

@@ -6,7 +6,9 @@ import de.otto.edison.hal.Links;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -18,7 +20,9 @@ public class GroupDto extends HalRepresentation {
private String description; private String description;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
private Instant lastModified; private Instant lastModified;
@Pattern(regexp = "^[A-z0-9\\.\\-_@]|[^ ]([A-z0-9\\.\\-_@ ]*[A-z0-9\\.\\-_@]|[^ ])?$")
private String name; private String name;
@NotEmpty
private String type; private String type;
private Map<String, String> properties; private Map<String, String> properties;
private List<String> members; private List<String> members;

View File

@@ -9,6 +9,7 @@ import sonia.scm.group.GroupManager;
import sonia.scm.web.VndMediaType; import sonia.scm.web.VndMediaType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -96,7 +97,7 @@ public class GroupResource {
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
public Response update(@PathParam("id") String name, GroupDto groupDto) throws NotFoundException { public Response update(@PathParam("id") String name, @Valid GroupDto groupDto) throws NotFoundException {
return adapter.update(name, existing -> dtoToGroupMapper.map(groupDto)); return adapter.update(name, existing -> dtoToGroupMapper.map(groupDto));
} }
} }

View File

@@ -6,6 +6,7 @@ import de.otto.edison.hal.Links;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern; import javax.validation.constraints.Pattern;
import java.time.Instant; import java.time.Instant;
@@ -23,9 +24,10 @@ public class RepositoryDto extends HalRepresentation {
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
private Instant lastModified; private Instant lastModified;
private String namespace; private String namespace;
@Pattern(regexp = "[\\w-]+", message = "The name can only contain numbers, letters, underscore and hyphen") @Pattern(regexp = "(?!^\\.\\.$)(?!^\\.$)(?!.*[\\\\\\[\\]])^[A-z0-9\\.][A-z0-9\\.\\-_/]*$")
private String name; private String name;
private boolean archived = false; private boolean archived = false;
@NotEmpty
private String type; private String type;
protected Map<String, String> properties; protected Map<String, String> properties;

View File

@@ -12,6 +12,7 @@ import sonia.scm.web.VndMediaType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider; import javax.inject.Provider;
import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -125,7 +126,7 @@ public class RepositoryResource {
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, RepositoryDto repositoryDto) throws NotFoundException { public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryDto repositoryDto) throws NotFoundException {
return adapter.update( return adapter.update(
loadBy(namespace, name), loadBy(namespace, name),
existing -> dtoToRepositoryMapper.map(repositoryDto, existing.getId()), existing -> dtoToRepositoryMapper.map(repositoryDto, existing.getId()),

View File

@@ -11,6 +11,7 @@ import sonia.scm.user.UserManager;
import sonia.scm.web.VndMediaType; import sonia.scm.web.VndMediaType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -87,7 +88,7 @@ public class UserCollectionResource {
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created user")) @ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created user"))
public Response create(UserDto userDto) throws AlreadyExistsException { public Response create(@Valid UserDto userDto) throws AlreadyExistsException {
return adapter.create(userDto, return adapter.create(userDto,
() -> dtoToUserMapper.map(userDto, ""), () -> dtoToUserMapper.map(userDto, ""),
user -> resourceLinks.user().self(user.getName())); user -> resourceLinks.user().self(user.getName()));

View File

@@ -6,7 +6,10 @@ import de.otto.edison.hal.Links;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.time.Instant; import java.time.Instant;
import java.util.Map; import java.util.Map;
@@ -15,12 +18,16 @@ public class UserDto extends HalRepresentation {
private boolean active; private boolean active;
private boolean admin; private boolean admin;
private Instant creationDate; private Instant creationDate;
@NotEmpty
private String displayName; private String displayName;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
private Instant lastModified; private Instant lastModified;
@NotEmpty @Email
private String mail; private String mail;
@Pattern(regexp = "^[A-z0-9\\.\\-_@]|[^ ]([A-z0-9\\.\\-_@ ]*[A-z0-9\\.\\-_@]|[^ ])?$")
private String name; private String name;
private String password; private String password;
@NotEmpty
private String type; private String type;
private Map<String, String> properties; private Map<String, String> properties;

View File

@@ -9,6 +9,7 @@ import sonia.scm.user.UserManager;
import sonia.scm.web.VndMediaType; import sonia.scm.web.VndMediaType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -96,7 +97,7 @@ public class UserResource {
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
public Response update(@PathParam("id") String name, UserDto userDto) throws NotFoundException { public Response update(@PathParam("id") String name, @Valid UserDto userDto) throws NotFoundException {
return adapter.update(name, existing -> dtoToUserMapper.map(userDto, existing.getPassword())); return adapter.update(name, existing -> dtoToUserMapper.map(userDto, existing.getPassword()));
} }
} }