mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 17:05:43 +01:00
add autocomplete endpoint
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
public class AutoCompleteBadParamException extends Exception {
|
||||
|
||||
public static final String PARAMETER_IS_REQUIRED = "The parameter is required.";
|
||||
public static final String INVALID_PARAMETER_LENGTH = "Invalid parameter length.";
|
||||
|
||||
public AutoCompleteBadParamException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
@Provider
|
||||
public class AutoCompleteBadParamExceptionMapper implements ExceptionMapper<AutoCompleteBadParamException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(AutoCompleteBadParamException exception) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(exception.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static sonia.scm.api.v2.resources.AutoCompleteBadParamException.INVALID_PARAMETER_LENGTH;
|
||||
import static sonia.scm.api.v2.resources.AutoCompleteBadParamException.PARAMETER_IS_REQUIRED;
|
||||
|
||||
@Path(AutoCompleteResource.PATH)
|
||||
public class AutoCompleteResource {
|
||||
public static final String PATH = "v2/autocomplete/";
|
||||
public static final String DEFAULT_LIMIT = "5";
|
||||
public static final int MIN_SEARCHED_CHARS = 1;
|
||||
|
||||
private ReducedObjectModelToDtoMapper mapper;
|
||||
|
||||
private UserManager userManager;
|
||||
private GroupManager groupManager;
|
||||
private RepositoryManager repositoryManager;
|
||||
|
||||
@Inject
|
||||
public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager, RepositoryManager repositoryManager) {
|
||||
this.mapper = mapper;
|
||||
this.userManager = userManager;
|
||||
this.groupManager = groupManager;
|
||||
this.repositoryManager = repositoryManager;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("user")
|
||||
@Produces(VndMediaType.AUTOCOMPLETE)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "if the searched string contains less than 2 characters"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"user:autocomplete\" privilege"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response searchUser(@QueryParam("filter") String filter,
|
||||
@DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) throws AutoCompleteBadParamException {
|
||||
validateParams(filter);
|
||||
return Response.ok(userManager.getFiltered(filter, limit)
|
||||
.stream()
|
||||
.map(mapper::map)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("group")
|
||||
@Produces(VndMediaType.AUTOCOMPLETE)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "if the searched string contains less than 2 characters"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"group:autocomplete\" privilege"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response searchGroup(@Valid @QueryParam("filter") String filter,
|
||||
@DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) throws AutoCompleteBadParamException {
|
||||
validateParams(filter);
|
||||
return Response.ok(groupManager.getFiltered(filter, limit)
|
||||
.stream()
|
||||
.map(mapper::map)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("repository")
|
||||
@Produces(VndMediaType.AUTOCOMPLETE)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "if the searched string contains less than 2 characters"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository:autocomplete\" privilege"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response searchRepo(@Valid @QueryParam("filter") String filter,
|
||||
@DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) throws AutoCompleteBadParamException {
|
||||
validateParams(filter);
|
||||
return Response.ok(repositoryManager.getFiltered(filter, limit)
|
||||
.stream()
|
||||
.map(mapper::map)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
}
|
||||
|
||||
void validateParams(String filter) throws AutoCompleteBadParamException {
|
||||
if (StringUtils.isBlank(filter)) {
|
||||
throw new AutoCompleteBadParamException(PARAMETER_IS_REQUIRED);
|
||||
}
|
||||
if (filter.length() <= MIN_SEARCHED_CHARS) {
|
||||
throw new AutoCompleteBadParamException(INVALID_PARAMETER_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,6 +37,8 @@ public class MapperModule extends AbstractModule {
|
||||
bind(FileObjectToFileObjectDtoMapper.class).to(Mappers.getMapper(FileObjectToFileObjectDtoMapper.class).getClass());
|
||||
bind(ModificationsToDtoMapper.class).to(Mappers.getMapper(ModificationsToDtoMapper.class).getClass());
|
||||
|
||||
bind(ReducedObjectModelToDtoMapper.class).to(Mappers.getMapper(ReducedObjectModelToDtoMapper.class).getClass());
|
||||
|
||||
// no mapstruct required
|
||||
bind(UIPluginDtoMapper.class);
|
||||
bind(UIPluginDtoCollectionMapper.class);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ReducedObjectModelDto extends HalRepresentation {
|
||||
|
||||
private String id;
|
||||
|
||||
private String displayName;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import sonia.scm.ReducedModelObject;
|
||||
|
||||
@Mapper
|
||||
public abstract class ReducedObjectModelToDtoMapper {
|
||||
|
||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||
public abstract ReducedObjectModelDto map(ReducedModelObject modelObject);
|
||||
|
||||
}
|
||||
@@ -242,6 +242,11 @@ public class DefaultGroupManager extends AbstractGroupManager
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Group> getFiltered(String filter, int limit) {
|
||||
GroupPermissions.autocomplete().check();
|
||||
return groupDAO.getFiltered(filter, limit);
|
||||
}
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -243,6 +243,12 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
||||
return repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Repository> getFiltered(String filter, int limit) {
|
||||
RepositoryPermissions.autocomplete().check();
|
||||
return repositoryDAO.getFiltered(filter, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Repository> getAll(Comparator<Repository> comparator) {
|
||||
List<Repository> repositories = Lists.newArrayList();
|
||||
|
||||
@@ -52,9 +52,11 @@ import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.group.GroupNames;
|
||||
import sonia.scm.group.GroupPermissions;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryDAO;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserPermissions;
|
||||
import sonia.scm.util.Util;
|
||||
@@ -256,6 +258,9 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
||||
collectGlobalPermissions(builder, user, groups);
|
||||
collectRepositoryPermissions(builder, user, groups);
|
||||
builder.add(canReadOwnUser(user));
|
||||
builder.add(getUserAutocompletePermission());
|
||||
builder.add(getGroupAutocompletePermission());
|
||||
builder.add(getRepoAutocompletePermission());
|
||||
permissions = builder.build();
|
||||
}
|
||||
|
||||
@@ -264,6 +269,18 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
||||
return info;
|
||||
}
|
||||
|
||||
private String getRepoAutocompletePermission() {
|
||||
return RepositoryPermissions.autocomplete().asShiroString();
|
||||
}
|
||||
|
||||
private String getGroupAutocompletePermission() {
|
||||
return GroupPermissions.autocomplete().asShiroString();
|
||||
}
|
||||
|
||||
private String getUserAutocompletePermission() {
|
||||
return UserPermissions.autocomplete().asShiroString();
|
||||
}
|
||||
|
||||
private String canReadOwnUser(User user) {
|
||||
return UserPermissions.read(user.getName()).asShiroString();
|
||||
}
|
||||
|
||||
@@ -300,6 +300,12 @@ public class DefaultUserManager extends AbstractUserManager
|
||||
return getAll(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<User> getFiltered(String filter, int limit) {
|
||||
UserPermissions.autocomplete().check();
|
||||
return userDAO.getFiltered(filter, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user