diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/User2UserDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/User2UserDtoMapper.java index 2ecf0f0990..3b1b38e31f 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/User2UserDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/User2UserDtoMapper.java @@ -24,13 +24,13 @@ public abstract class User2UserDtoMapper { @AfterMapping void appendLinks(@MappingTarget UserDto target, @Context UriInfo uriInfo) { - LinkMapBuilder userLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserNewResource.UserSubResource.class); - LinkMapBuilder collectionLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserNewResource.UsersResource.class); + LinkMapBuilder userLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserSubResource.class); + LinkMapBuilder collectionLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserCollectionResource.class); userLinkBuilder.add("self").method("getUserSubResource").parameters(target.getName()).method("get").parameters(); if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) { userLinkBuilder.add("delete").method("getUserSubResource").parameters(target.getName()).method("delete").parameters(); userLinkBuilder.add("update").method("getUserSubResource").parameters(target.getName()).method("update").parameters(); - collectionLinkBuilder.add("create").method("getUsersResource").parameters().method("create").parameters(); + collectionLinkBuilder.add("create").method("getUserCollectionResource").parameters().method("create").parameters(); } Map join = new HashMap<>(); join.putAll(userLinkBuilder.getLinkMap()); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserCollectionResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserCollectionResource.java new file mode 100644 index 0000000000..66860ba7cd --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserCollectionResource.java @@ -0,0 +1,95 @@ +package sonia.scm.api.rest.resources; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.webcohesion.enunciate.metadata.rs.ResponseCode; +import com.webcohesion.enunciate.metadata.rs.ResponseHeader; +import com.webcohesion.enunciate.metadata.rs.StatusCodes; +import com.webcohesion.enunciate.metadata.rs.TypeHint; +import sonia.scm.user.User; +import sonia.scm.user.UserException; +import sonia.scm.user.UserManager; + +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Singleton +public class UserCollectionResource extends AbstractManagerResource { + private final UserDto2UserMapper dtoToUserMapper; + private final User2UserDtoMapper userToDtoMapper; + + @Inject + public UserCollectionResource(UserManager manager, UserDto2UserMapper dtoToUserMapper, User2UserDtoMapper userToDtoMapper) { + super(manager); + this.dtoToUserMapper = dtoToUserMapper; + this.userToDtoMapper = userToDtoMapper; + } + + /** + * Returns all users. Note: This method requires admin privileges. + * + * @param request the current request + * @param start the start value for paging + * @param limit the limit value for paging + * @param sortby sort parameter + * @param desc sort direction desc or aesc + * @return + */ + @GET + @Path("") + @TypeHint(User[].class) + @StatusCodes({ + @ResponseCode(code = 200, condition = "success"), + @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response getAll(@Context Request request, @Context UriInfo uriInfo, @DefaultValue("0") + @QueryParam("start") int start, @DefaultValue("-1") + @QueryParam("limit") int limit, @QueryParam("sortby") String sortby, + @DefaultValue("false") + @QueryParam("desc") boolean desc) { + Collection items = fetchItems(sortby, desc, start, limit); + List collect = items.stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList()); + return Response.ok(new GenericEntity>(collect) {}).build(); + } + + @POST + @Path("") + @StatusCodes({ + @ResponseCode(code = 201, condition = "create success", additionalHeaders = { + @ResponseHeader(name = "Location", description = "uri to the created group") + }), + @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @TypeHint(TypeHint.NO_CONTENT.class) + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response create(@Context UriInfo uriInfo, UserDto userDto) throws IOException, UserException { + User user = dtoToUserMapper.userDtoToUser(userDto, ""); + manager.create(user); + + LinkMapBuilder builder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserSubResource.class); + builder.add("self").method("getUserSubResource").parameters(user.getName()).method("get").parameters(); + return Response.created(builder.getLinkMap().get("self").getHref()).build(); + } + + @Override + protected GenericEntity> createGenericEntity(Collection items) { + throw new UnsupportedOperationException(); + } + + @Override + protected String getId(User item) { + return item.getName(); + } + + @Override + protected String getPathPart() { + throw new UnsupportedOperationException(); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserNewResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserNewResource.java index 12d184e144..4873675746 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserNewResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserNewResource.java @@ -2,173 +2,29 @@ package sonia.scm.api.rest.resources; import com.google.inject.Inject; import com.google.inject.Singleton; -import com.webcohesion.enunciate.metadata.rs.ResponseCode; -import com.webcohesion.enunciate.metadata.rs.ResponseHeader; -import com.webcohesion.enunciate.metadata.rs.StatusCodes; -import com.webcohesion.enunciate.metadata.rs.TypeHint; -import org.apache.shiro.SecurityUtils; -import sonia.scm.security.Role; -import sonia.scm.user.User; -import sonia.scm.user.UserException; -import sonia.scm.user.UserManager; -import javax.ws.rs.*; -import javax.ws.rs.core.*; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; +import javax.ws.rs.Path; @Singleton @Path("usersnew") -public class UserNewResource extends AbstractManagerResource -{ +public class UserNewResource { - /** Field description */ - public static final String PATH_PART = "usersnew"; - - private final UserDto2UserMapper dtoToUserMapper; - private final User2UserDtoMapper userToDtoMapper; + private final UserCollectionResource userCollectionResource; + private final UserSubResource userSubResource; @Inject - public UserNewResource(UserManager userManager, UserDto2UserMapper dtoToUserMapper, User2UserDtoMapper userToDtoMapper) { - super(userManager); - this.dtoToUserMapper = dtoToUserMapper; - this.userToDtoMapper = userToDtoMapper; - } - - @Override - protected GenericEntity> createGenericEntity(Collection items) { - return null; - } - - @Override - protected String getId(User user) { - return user.getName(); - } - - @Override - protected String getPathPart() { - return PATH_PART; + public UserNewResource(UserCollectionResource userCollectionResource, UserSubResource userSubResource) { + this.userCollectionResource = userCollectionResource; + this.userSubResource = userSubResource; } @Path("") - public UsersResource getUsersResource() - { - return new UsersResource(); - } - - public class UsersResource - { - /** - * Returns all users. Note: This method requires admin privileges. - * - * @param request the current request - * @param start the start value for paging - * @param limit the limit value for paging - * @param sortby sort parameter - * @param desc sort direction desc or aesc - * @return - */ - @GET - @Path("") - @TypeHint(User[].class) - @StatusCodes({ - @ResponseCode(code = 200, condition = "success"), - @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), - @ResponseCode(code = 500, condition = "internal server error") - }) - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response getAll(@Context Request request, @Context UriInfo uriInfo, @DefaultValue("0") - @QueryParam("start") int start, @DefaultValue("-1") - @QueryParam("limit") int limit, @QueryParam("sortby") String sortby, - @DefaultValue("false") - @QueryParam("desc") boolean desc) - { - Collection items = fetchItems(sortby, desc, start, limit); - List collect = items.stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList()); - return Response.ok(new GenericEntity>(collect) - { - }).build(); - } - - @POST - @Path("") - @StatusCodes({ - @ResponseCode(code = 201, condition = "create success", additionalHeaders = { - @ResponseHeader(name = "Location", description = "uri to the created group") - }), - @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), - @ResponseCode(code = 500, condition = "internal server error") - }) - @TypeHint(TypeHint.NO_CONTENT.class) - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response create(@Context UriInfo uriInfo, UserDto userDto) - { - User user = dtoToUserMapper.userDtoToUser(userDto, ""); - return UserNewResource.this.create(uriInfo, user); - } + public UserCollectionResource getUserCollectionResource() { + return userCollectionResource; } @Path("{id}") - public UserSubResource getUserSubResource() - { - return new UserSubResource(); - } - - public class UserSubResource - { - @GET - @Path("") - @TypeHint(UserDto.class) - @StatusCodes({ - @ResponseCode(code = 200, condition = "success"), - @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), - @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), - @ResponseCode(code = 500, condition = "internal server error") - }) - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response get(@Context Request request, @Context UriInfo uriInfo, @PathParam("id") String id) - { - if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) - { - User user = manager.get(id); - UserDto userDto = userToDtoMapper.userToUserDto(user, uriInfo); - return Response.ok(userDto).build(); - } - else - { - return Response.status(Response.Status.FORBIDDEN).build(); - } - } - - @PUT - @Path("") - @StatusCodes({ - @ResponseCode(code = 204, condition = "update success"), - @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), - @ResponseCode(code = 500, condition = "internal server error") - }) - @TypeHint(TypeHint.NO_CONTENT.class) - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response update(@Context UriInfo uriInfo, - @PathParam("id") String name, UserDto userDto) - { - String originalPassword = manager.get(name).getPassword(); - User user = dtoToUserMapper.userDtoToUser(userDto, originalPassword); - return UserNewResource.this.update(name, user); - } - - @DELETE - @Path("") - @StatusCodes({ - @ResponseCode(code = 204, condition = "delete success"), - @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), - @ResponseCode(code = 500, condition = "internal server error") - }) - @TypeHint(TypeHint.NO_CONTENT.class) - public Response delete(@PathParam("id") String name) - { - return UserNewResource.this.delete(name); - } + public UserSubResource getUserSubResource() { + return userSubResource; } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserSubResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserSubResource.java new file mode 100644 index 0000000000..0b07188cbc --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserSubResource.java @@ -0,0 +1,96 @@ +package sonia.scm.api.rest.resources; + +import com.google.inject.Inject; +import com.webcohesion.enunciate.metadata.rs.ResponseCode; +import com.webcohesion.enunciate.metadata.rs.StatusCodes; +import com.webcohesion.enunciate.metadata.rs.TypeHint; +import org.apache.shiro.SecurityUtils; +import sonia.scm.security.Role; +import sonia.scm.user.User; +import sonia.scm.user.UserException; +import sonia.scm.user.UserManager; + +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import java.util.Collection; + +public class UserSubResource extends AbstractManagerResource { + private final UserDto2UserMapper dtoToUserMapper; + private final User2UserDtoMapper userToDtoMapper; + + @Inject + public UserSubResource(UserDto2UserMapper dtoToUserMapper, User2UserDtoMapper userToDtoMapper, UserManager manager) { + super(manager); + this.dtoToUserMapper = dtoToUserMapper; + this.userToDtoMapper = userToDtoMapper; + } + + @GET + @Path("") + @TypeHint(UserDto.class) + @StatusCodes({ + @ResponseCode(code = 200, condition = "success"), + @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), + @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response get(@Context Request request, @Context UriInfo uriInfo, @PathParam("id") String id) + { + if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) + { + User user = manager.get(id); + UserDto userDto = userToDtoMapper.userToUserDto(user, uriInfo); + return Response.ok(userDto).build(); + } + else + { + return Response.status(Response.Status.FORBIDDEN).build(); + } + } + + @PUT + @Path("") + @StatusCodes({ + @ResponseCode(code = 204, condition = "update success"), + @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @TypeHint(TypeHint.NO_CONTENT.class) + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response update(@Context UriInfo uriInfo, + @PathParam("id") String name, UserDto userDto) + { + String originalPassword = manager.get(name).getPassword(); + User user = dtoToUserMapper.userDtoToUser(userDto, originalPassword); + return update(name, user); + } + + @DELETE + @Path("") + @StatusCodes({ + @ResponseCode(code = 204, condition = "delete success"), + @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @TypeHint(TypeHint.NO_CONTENT.class) + public Response delete(@PathParam("id") String name) + { + return super.delete(name); + } + + @Override + protected GenericEntity> createGenericEntity(Collection items) { + throw new UnsupportedOperationException(); + } + + @Override + protected String getId(User item) { + return item.getName(); + } + + @Override + protected String getPathPart() { + throw new UnsupportedOperationException(); + } +}