mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-11 16:05:44 +01:00
First step for sub resources
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package sonia.scm.api.rest.resources;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
|
||||
class LinkMapBuilder {
|
||||
private final UriInfo uriInfo;
|
||||
private final Class[] classes;
|
||||
private final Map<String, Link> links = new LinkedHashMap<>();
|
||||
|
||||
LinkMapBuilder(UriInfo uriInfo, Class... classes) {
|
||||
this.uriInfo = uriInfo;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
Builder add(String linkName) {
|
||||
return new ConcreteBuilder(linkName);
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
Parameters method(String method);
|
||||
}
|
||||
|
||||
interface Parameters {
|
||||
Builder parameters(String... parameters);
|
||||
}
|
||||
|
||||
private class ConcreteBuilder implements Builder {
|
||||
|
||||
private final String linkName;
|
||||
private final List<Call> calls = new LinkedList<>();
|
||||
|
||||
private int callCount = 0;
|
||||
|
||||
ConcreteBuilder(String linkName) {
|
||||
this.linkName = linkName;
|
||||
}
|
||||
|
||||
public Parameters method(String method) {
|
||||
return new ParametersImpl(method);
|
||||
}
|
||||
|
||||
private class ParametersImpl implements Parameters {
|
||||
|
||||
private final String method;
|
||||
|
||||
ParametersImpl(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public Builder parameters(String... parameters) {
|
||||
return ConcreteBuilder.this.add(method, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
private Builder add(String method, String[] parameters) {
|
||||
this.calls.add(new Call(LinkMapBuilder.this.classes[callCount], method, parameters));
|
||||
++callCount;
|
||||
if (callCount >= classes.length) {
|
||||
links.put(linkName, createLink());
|
||||
return x -> {
|
||||
throw new IllegalStateException("no more classes for methods");
|
||||
};
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Link createLink() {
|
||||
URI baseUri = uriInfo.getBaseUri();
|
||||
URI relativeUri = createRelativeUri();
|
||||
URI absoluteUri = baseUri.resolve(relativeUri);
|
||||
return new Link(absoluteUri);
|
||||
}
|
||||
|
||||
private URI createRelativeUri() {
|
||||
UriBuilder uriBuilder = userUriBuilder();
|
||||
calls.forEach(call -> uriBuilder.path(call.clazz, call.method));
|
||||
String[] concatenatedParameters = calls
|
||||
.stream()
|
||||
.map(call -> call.parameters)
|
||||
.flatMap(Arrays::stream)
|
||||
.toArray(String[]::new);
|
||||
return uriBuilder.build(concatenatedParameters);
|
||||
}
|
||||
|
||||
private UriBuilder userUriBuilder() {
|
||||
return UriBuilder.fromResource(classes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Link> getLinkMap() {
|
||||
return Collections.unmodifiableMap(links);
|
||||
}
|
||||
|
||||
private static class Call {
|
||||
private final Class clazz;
|
||||
private final String method;
|
||||
private final String[] parameters;
|
||||
|
||||
private Call(Class clazz, String method, String[] parameters) {
|
||||
this.clazz = clazz;
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
package sonia.scm.api.rest.resources;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Context;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import sonia.scm.security.Role;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
@@ -25,43 +24,17 @@ public abstract class User2UserDtoMapper {
|
||||
|
||||
@AfterMapping
|
||||
void appendLinks(@MappingTarget UserDto target, @Context UriInfo uriInfo) {
|
||||
LinkMapBuilder builder = new LinkMapBuilder(uriInfo);
|
||||
builder.add("self", "get", target.getName());
|
||||
builder.add("delete", "delete", target.getName());
|
||||
builder.add("update", "update", target.getName());
|
||||
builder.add("create", "create");
|
||||
target.setLinks(builder.getLinkMap());
|
||||
}
|
||||
|
||||
private static class LinkMapBuilder {
|
||||
private final UriInfo uriInfo;
|
||||
private final Map<String, Link> links = new LinkedHashMap<>();
|
||||
|
||||
private LinkMapBuilder(UriInfo uriInfo) {
|
||||
this.uriInfo = uriInfo;
|
||||
}
|
||||
|
||||
void add(String linkName, String methodName, String... parameters) {
|
||||
links.put(linkName, createLink(methodName, parameters));
|
||||
}
|
||||
|
||||
Map<String, Link> getLinkMap() {
|
||||
return Collections.unmodifiableMap(links);
|
||||
}
|
||||
|
||||
private Link createLink(String methodName, String... parameters) {
|
||||
URI baseUri = uriInfo.getBaseUri();
|
||||
URI relativeUri = createRelativeUri(methodName, parameters);
|
||||
URI absoluteUri = baseUri.resolve(relativeUri);
|
||||
return new Link(absoluteUri);
|
||||
}
|
||||
|
||||
private URI createRelativeUri(String methodName, Object[] parameters) {
|
||||
return userUriBuilder().path(UserNewResource.class, methodName).build(parameters);
|
||||
}
|
||||
|
||||
private UriBuilder userUriBuilder() {
|
||||
return UriBuilder.fromResource(UserNewResource.class);
|
||||
LinkMapBuilder userLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserNewResource.UserSubResource.class);
|
||||
LinkMapBuilder collectionLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserNewResource.UsersResource.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();
|
||||
}
|
||||
Map<String, Link> join = new HashMap<>();
|
||||
join.putAll(userLinkBuilder.getLinkMap());
|
||||
join.putAll(collectionLinkBuilder.getLinkMap());
|
||||
target.setLinks(join);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,105 +51,124 @@ public class UserNewResource extends AbstractManagerResource<User, UserException
|
||||
return PATH_PART;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all users. <strong>Note:</strong> 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
|
||||
@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<User> items = fetchItems(sortby, desc, start, limit);
|
||||
List<UserDto> collect = items.stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList());
|
||||
return Response.ok(new GenericEntity<Collection<UserDto>>(collect) {}).build();
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{id}")
|
||||
@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 super.update(name, user);
|
||||
}
|
||||
|
||||
@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)
|
||||
public UsersResource getUsersResource()
|
||||
{
|
||||
User user = dtoToUserMapper.userDtoToUser(userDto, "");
|
||||
return super.create(uriInfo, user);
|
||||
return new UsersResource();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@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)
|
||||
@Override
|
||||
public Response delete(@PathParam("id") String name)
|
||||
public class UsersResource
|
||||
{
|
||||
return super.delete(name);
|
||||
/**
|
||||
* Returns all users. <strong>Note:</strong> 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<User> items = fetchItems(sortby, desc, start, limit);
|
||||
List<UserDto> collect = items.stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList());
|
||||
return Response.ok(new GenericEntity<Collection<UserDto>>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user