diff --git a/scm-core/src/main/java/sonia/scm/GenericDAO.java b/scm-core/src/main/java/sonia/scm/GenericDAO.java index a369c2f8c2..003c73806c 100644 --- a/scm-core/src/main/java/sonia/scm/GenericDAO.java +++ b/scm-core/src/main/java/sonia/scm/GenericDAO.java @@ -115,12 +115,4 @@ public interface GenericDAO */ public Collection getAll(); - /** - * Returns items containing the searched string - * - * @param searched the search character - * @param limit the max count of the result entities. if limit is <= 0 return all filtered entities - * @return searched items - */ - Collection getFiltered(String searched, int limit); } diff --git a/scm-core/src/main/java/sonia/scm/Manager.java b/scm-core/src/main/java/sonia/scm/Manager.java index 62384e41d4..14c458d923 100644 --- a/scm-core/src/main/java/sonia/scm/Manager.java +++ b/scm-core/src/main/java/sonia/scm/Manager.java @@ -47,6 +47,9 @@ public interface Manager extends HandlerBase, LastModifiedAware { + int DEFAULT_LIMIT = 5; + + /** * Reloads a object from store and overwrites all changes. * @@ -77,15 +80,6 @@ public interface Manager */ Collection getAll(); - /** - * Returns a {@link java.util.Collection} of filtered objects - * - * @param filter the searched string - * @param limit the max count of the result entities. if limit is <= 0 return all filtered entities - * @return all object in the store - */ - Collection getFiltered(String filter, int limit); - /** * Returns all object of the store sorted by the given {@link java.util.Comparator} * diff --git a/scm-core/src/main/java/sonia/scm/ManagerDecorator.java b/scm-core/src/main/java/sonia/scm/ManagerDecorator.java index 3938121668..7b3f03ee8c 100644 --- a/scm-core/src/main/java/sonia/scm/ManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/ManagerDecorator.java @@ -91,11 +91,6 @@ public class ManagerDecorator implements Manager { decorated.refresh(object); } - @Override - public Collection getFiltered(String filter, int limit) { - return decorated.getFiltered(filter, limit); - } - @Override public T get(String id) { diff --git a/scm-core/src/main/java/sonia/scm/ModelObject.java b/scm-core/src/main/java/sonia/scm/ModelObject.java index 5c387e9ca4..cca9608ceb 100644 --- a/scm-core/src/main/java/sonia/scm/ModelObject.java +++ b/scm-core/src/main/java/sonia/scm/ModelObject.java @@ -44,7 +44,7 @@ import java.io.Serializable; */ public interface ModelObject extends TypedObject, LastModifiedAware, Cloneable, Validateable, - Serializable, ReducedModelObject + Serializable { /** diff --git a/scm-core/src/main/java/sonia/scm/filter/GZipFilter.java b/scm-core/src/main/java/sonia/scm/filter/GZipFilter.java deleted file mode 100644 index 49fa8ebebf..0000000000 --- a/scm-core/src/main/java/sonia/scm/filter/GZipFilter.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm.filter; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.Priority; -import sonia.scm.util.WebUtil; -import sonia.scm.web.filter.HttpFilter; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Filter for gzip encoding. - * - * @author Sebastian Sdorra - * @since 1.15 - */ -@Priority(Filters.PRIORITY_PRE_BASEURL) -@WebElement(value = Filters.PATTERN_RESOURCE_REGEX, regex = true) -public class GZipFilter extends HttpFilter -{ - - /** - * the logger for GZipFilter - */ - private static final Logger logger = - LoggerFactory.getLogger(GZipFilter.class); - - //~--- get methods ---------------------------------------------------------- - - /** - * Return the configuration for the gzip filter. - * - * - * @return gzip filter configuration - */ - public GZipFilterConfig getConfig() - { - return config; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Encodes the response, if the request has support for gzip encoding. - * - * - * @param request http request - * @param response http response - * @param chain filter chain - * - * @throws IOException - * @throws ServletException - */ - @Override - protected void doFilter(HttpServletRequest request, - HttpServletResponse response, FilterChain chain) - throws IOException, ServletException - { - if (WebUtil.isGzipSupported(request)) - { - if (logger.isTraceEnabled()) - { - logger.trace("compress output with gzip"); - } - - GZipResponseWrapper wrappedResponse = new GZipResponseWrapper(response, - config); - - chain.doFilter(request, wrappedResponse); - wrappedResponse.finishResponse(); - } - else - { - chain.doFilter(request, response); - } - } - - //~--- fields --------------------------------------------------------------- - - /** gzip filter configuration */ - private GZipFilterConfig config = new GZipFilterConfig(); -} diff --git a/scm-core/src/main/java/sonia/scm/filter/GZipResponseFilter.java b/scm-core/src/main/java/sonia/scm/filter/GZipResponseFilter.java new file mode 100644 index 0000000000..1fa525d4fd --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/filter/GZipResponseFilter.java @@ -0,0 +1,24 @@ +package sonia.scm.filter; + +import lombok.extern.slf4j.Slf4j; +import sonia.scm.util.WebUtil; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.util.zip.GZIPOutputStream; + +@Provider +@Slf4j +public class GZipResponseFilter implements ContainerResponseFilter { + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { + if (WebUtil.isGzipSupported(requestContext::getHeaderString)) { + log.trace("compress output with gzip"); + GZIPOutputStream wrappedResponse = new GZIPOutputStream(responseContext.getEntityStream()); + responseContext.getHeaders().add("Content-Encoding", "gzip"); + responseContext.setEntityStream(wrappedResponse); + } + } +} diff --git a/scm-core/src/main/java/sonia/scm/group/Group.java b/scm-core/src/main/java/sonia/scm/group/Group.java index 6ee27be2fc..c0b3c2ee8b 100644 --- a/scm-core/src/main/java/sonia/scm/group/Group.java +++ b/scm-core/src/main/java/sonia/scm/group/Group.java @@ -42,6 +42,7 @@ import com.google.common.base.Objects; import com.google.common.collect.Lists; import sonia.scm.BasicPropertiesAware; import sonia.scm.ModelObject; +import sonia.scm.ReducedModelObject; import sonia.scm.util.Util; import sonia.scm.util.ValidationUtil; @@ -64,7 +65,7 @@ import java.util.List; @XmlRootElement(name = "groups") @XmlAccessorType(XmlAccessType.FIELD) public class Group extends BasicPropertiesAware - implements ModelObject, PermissionObject + implements ModelObject, PermissionObject, ReducedModelObject { /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/group/GroupManager.java b/scm-core/src/main/java/sonia/scm/group/GroupManager.java index 288196894d..08057ae3db 100644 --- a/scm-core/src/main/java/sonia/scm/group/GroupManager.java +++ b/scm-core/src/main/java/sonia/scm/group/GroupManager.java @@ -61,4 +61,14 @@ public interface GroupManager * @return all groups assigned to the given member */ public Collection getGroupsForMember(String member); + + + /** + * Returns a {@link java.util.Collection} of filtered objects + * + * @param filter the searched string + * @return filtered object from the store + */ + Collection autocomplete(String filter); + } diff --git a/scm-core/src/main/java/sonia/scm/group/GroupManagerDecorator.java b/scm-core/src/main/java/sonia/scm/group/GroupManagerDecorator.java index e2367d863c..ef6de4164c 100644 --- a/scm-core/src/main/java/sonia/scm/group/GroupManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/group/GroupManagerDecorator.java @@ -109,6 +109,11 @@ public class GroupManagerDecorator return decorated.getGroupsForMember(member); } + @Override + public Collection autocomplete(String filter) { + return decorated.autocomplete(filter); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/repository/Changeset.java b/scm-core/src/main/java/sonia/scm/repository/Changeset.java index 7d3a8d6dbf..7397fecabe 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Changeset.java +++ b/scm-core/src/main/java/sonia/scm/repository/Changeset.java @@ -256,11 +256,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { return id; } - @Override - public String getDisplayName() { - return id; - } - @Override public void setLastModified(Long timestamp) { throw new UnsupportedOperationException("changesets are immutable"); diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index 97915eeaa5..19c5b31349 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -60,8 +60,7 @@ import java.util.List; */ @StaticPermissions( value = "repository", - permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"}, - globalPermissions = {"create", "autocomplete"} + permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"} ) @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "repositories") @@ -184,11 +183,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per return id; } - @Override - public String getDisplayName() { - return getNamespace() + "/" + getName(); - } - @Override public Long getLastModified() { return lastModified; diff --git a/scm-core/src/main/java/sonia/scm/search/SearchRequest.java b/scm-core/src/main/java/sonia/scm/search/SearchRequest.java index e3998e2c6a..63f34346c2 100644 --- a/scm-core/src/main/java/sonia/scm/search/SearchRequest.java +++ b/scm-core/src/main/java/sonia/scm/search/SearchRequest.java @@ -70,6 +70,12 @@ public class SearchRequest this.ignoreCase = ignoreCase; } + public SearchRequest(String query, boolean ignoreCase, int maxResults) { + this.query = query; + this.ignoreCase = ignoreCase; + this.maxResults = maxResults; + } + //~--- get methods ---------------------------------------------------------- /** diff --git a/scm-core/src/main/java/sonia/scm/user/User.java b/scm-core/src/main/java/sonia/scm/user/User.java index 2a35f920a8..e9dc277e5f 100644 --- a/scm-core/src/main/java/sonia/scm/user/User.java +++ b/scm-core/src/main/java/sonia/scm/user/User.java @@ -41,6 +41,7 @@ import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import sonia.scm.BasicPropertiesAware; import sonia.scm.ModelObject; +import sonia.scm.ReducedModelObject; import sonia.scm.util.Util; import sonia.scm.util.ValidationUtil; @@ -58,7 +59,7 @@ import java.security.Principal; @StaticPermissions(value = "user", globalPermissions = {"create", "list", "autocomplete"}) @XmlRootElement(name = "users") @XmlAccessorType(XmlAccessType.FIELD) -public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject +public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject, ReducedModelObject { /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/user/UserManager.java b/scm-core/src/main/java/sonia/scm/user/UserManager.java index 1f5aee1f19..7829cd9974 100644 --- a/scm-core/src/main/java/sonia/scm/user/UserManager.java +++ b/scm-core/src/main/java/sonia/scm/user/UserManager.java @@ -39,6 +39,7 @@ import sonia.scm.Manager; import sonia.scm.search.Searchable; import java.text.MessageFormat; +import java.util.Collection; import java.util.function.Consumer; import static sonia.scm.user.ChangePasswordNotAllowedException.WRONG_USER_TYPE; @@ -90,5 +91,13 @@ public interface UserManager return getDefaultType().equals(user.getType()); } + /** + * Returns a {@link java.util.Collection} of filtered objects + * + * @param filter the searched string + * @return filtered object from the store + */ + Collection autocomplete(String filter); + } diff --git a/scm-core/src/main/java/sonia/scm/user/UserManagerDecorator.java b/scm-core/src/main/java/sonia/scm/user/UserManagerDecorator.java index 225681f9e6..f291e325c1 100644 --- a/scm-core/src/main/java/sonia/scm/user/UserManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/user/UserManagerDecorator.java @@ -121,6 +121,11 @@ public class UserManagerDecorator extends ManagerDecorator return decorated.getDefaultType(); } + @Override + public Collection autocomplete(String filter) { + return decorated.autocomplete(filter); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/util/WebUtil.java b/scm-core/src/main/java/sonia/scm/util/WebUtil.java index 2fc0876668..a9337b0598 100644 --- a/scm-core/src/main/java/sonia/scm/util/WebUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/WebUtil.java @@ -49,6 +49,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import java.util.function.Function; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -266,7 +267,12 @@ public final class WebUtil */ public static boolean isGzipSupported(HttpServletRequest request) { - String enc = request.getHeader(HEADER_ACCEPTENCODING); + return isGzipSupported(request::getHeader); + } + + public static boolean isGzipSupported(Function headerResolver) + { + String enc = headerResolver.apply(HEADER_ACCEPTENCODING); return (enc != null) && enc.contains("gzip"); } diff --git a/scm-core/src/test/java/sonia/scm/ManagerTest.java b/scm-core/src/test/java/sonia/scm/ManagerTest.java index 309a68e8ca..06c8eb3ea6 100644 --- a/scm-core/src/test/java/sonia/scm/ManagerTest.java +++ b/scm-core/src/test/java/sonia/scm/ManagerTest.java @@ -78,11 +78,6 @@ public class ManagerTest { return IntStream.range(0, givenItemCount).boxed().collect(toList()); } - @Override - public Collection getFiltered(String filter, int limit) { - return null; - } - @Override public Collection getAll(Comparator comparator) { return getAll(); } diff --git a/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java b/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java index ee1affe252..b8d1e6f42e 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java +++ b/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java @@ -237,16 +237,6 @@ public abstract class AbstractXmlDAO getFiltered(String searched, int limit) { - int size = db.values().size(); - AssertUtil.assertIsNotEmpty(searched); - return ImmutableList.copyOf(db.values().stream() - .filter(item -> StringUtils.containsIgnoreCase(item.getId(), searched) || (item.getDisplayName() != null && StringUtils.containsIgnoreCase(item.getDisplayName() , searched))) - .limit(limit <= 0 ? size : limit) - .collect(Collectors.toList())); - } - /** * Method description * diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java index 7cc78180ff..4352299ed5 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java @@ -32,122 +32,45 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.filter.GZipFilter; +import sonia.scm.filter.GZipFilterConfig; +import sonia.scm.filter.GZipResponseWrapper; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.util.WebUtil; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -//~--- JDK imports ------------------------------------------------------------ - -/** - * - * @author Sebastian Sdorra - */ -public class SvnGZipFilter extends GZipFilter implements ScmProviderHttpServlet -{ +class SvnGZipFilter implements ScmProviderHttpServlet { private static final Logger logger = LoggerFactory.getLogger(SvnGZipFilter.class); private final SvnRepositoryHandler handler; private final ScmProviderHttpServlet delegate; - //~--- constructors --------------------------------------------------------- + private GZipFilterConfig config = new GZipFilterConfig(); - /** - * Constructs ... - * - * - * @param handler - */ - public SvnGZipFilter(SvnRepositoryHandler handler, ScmProviderHttpServlet delegate) - { + SvnGZipFilter(SvnRepositoryHandler handler, ScmProviderHttpServlet delegate) { this.handler = handler; this.delegate = delegate; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param filterConfig - * - * @throws ServletException - */ - @Override - public void init(FilterConfig filterConfig) throws ServletException - { - super.init(filterConfig); - getConfig().setBufferResponse(false); - } - - /** - * Method description - * - * - * @param request - * @param response - * @param chain - * - * @throws IOException - * @throws ServletException - */ - @Override - protected void doFilter(HttpServletRequest request, - HttpServletResponse response, FilterChain chain) - throws IOException, ServletException - { - if (handler.getConfig().isEnabledGZip()) - { - if (logger.isTraceEnabled()) - { - logger.trace("encode svn request with gzip"); - } - - super.doFilter(request, response, chain); - } - else - { - if (logger.isTraceEnabled()) - { - logger.trace("skip gzip encoding"); - } - - chain.doFilter(request, response); - } + config.setBufferResponse(false); } @Override public void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { - if (handler.getConfig().isEnabledGZip()) - { - if (logger.isTraceEnabled()) - { - logger.trace("encode svn request with gzip"); - } - - super.doFilter(request, response, (servletRequest, servletResponse) -> delegate.service((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, repository)); - } - else - { - if (logger.isTraceEnabled()) - { - logger.trace("skip gzip encoding"); - } - + if (handler.getConfig().isEnabledGZip() && WebUtil.isGzipSupported(request)) { + logger.trace("compress svn response with gzip"); + GZipResponseWrapper wrappedResponse = new GZipResponseWrapper(response, config); + delegate.service(request, wrappedResponse, repository); + wrappedResponse.finishResponse(); + } else { + logger.trace("skip gzip encoding"); delegate.service(request, response, repository); } } diff --git a/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java b/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java index 059c990718..6b4a29961d 100644 --- a/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java @@ -58,8 +58,10 @@ public class WebResourceServlet extends HttpServlet { LOG.trace("try to load {}", uri); URL url = webResourceLoader.getResource(uri); if (url != null) { + LOG.trace("found {} -- serve as resource {}", uri, url); serveResource(request, response, url); } else { + LOG.trace("could not find {} -- dispatch", uri); dispatch(request, response, uri); } } @@ -79,6 +81,7 @@ public class WebResourceServlet extends HttpServlet { private void serveResource(HttpServletRequest request, HttpServletResponse response, URL url) { try { + LOG.debug("using sender to serve {}", request.getRequestURI()); sender.resource(url).send(request, response); } catch (IOException ex) { LOG.warn("failed to serve resource: {}", url); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java index eebec9baa4..70192973cb 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java @@ -3,26 +3,25 @@ package sonia.scm.api.v2.resources; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import org.hibernate.validator.constraints.NotEmpty; +import sonia.scm.ReducedModelObject; 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.constraints.Size; -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.Collection; import java.util.stream.Collectors; @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 = 2; public static final String PARAMETER_IS_REQUIRED = "The parameter is required."; @@ -33,14 +32,12 @@ public class AutoCompleteResource { private UserManager userManager; private GroupManager groupManager; - private RepositoryManager repositoryManager; @Inject - public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager, RepositoryManager repositoryManager) { + public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager) { this.mapper = mapper; this.userManager = userManager; this.groupManager = groupManager; - this.repositoryManager = repositoryManager; } @GET @@ -53,13 +50,8 @@ public class AutoCompleteResource { @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(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter, - @DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) { - return Response.ok(userManager.getFiltered(filter, limit) - .stream() - .map(mapper::map) - .collect(Collectors.toList())) - .build(); + public Response searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter) { + return map(userManager.autocomplete(filter)); } @GET @@ -72,28 +64,12 @@ public class AutoCompleteResource { @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(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter, - @DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) { - return Response.ok(groupManager.getFiltered(filter, limit) - .stream() - .map(mapper::map) - .collect(Collectors.toList())) - .build(); + public Response searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter) { + return map(groupManager.autocomplete(filter)); } - @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(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter, - @DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) { - return Response.ok(repositoryManager.getFiltered(filter, limit) + private Response map(Collection autocomplete) { + return Response.ok(autocomplete .stream() .map(mapper::map) .collect(Collectors.toList())) diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java index 823ba5a580..327415ec22 100644 --- a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java @@ -243,10 +243,11 @@ public class DefaultGroupManager extends AbstractGroupManager } @Override - public Collection getFiltered(String filter, int limit) { + public Collection autocomplete(String filter) { GroupPermissions.autocomplete().check(); - return groupDAO.getFiltered(filter, limit); + return search(new SearchRequest(filter,true, DEFAULT_LIMIT)); } + /** * Method description * diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java index defd8f2068..8cb325b818 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java @@ -243,12 +243,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { return repository; } - @Override - public Collection getFiltered(String filter, int limit) { - RepositoryPermissions.autocomplete().check(); - return repositoryDAO.getFiltered(filter, limit); - } - @Override public Collection getAll(Comparator comparator) { List repositories = Lists.newArrayList(); diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java index f2e50029bd..36b7f4089d 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -260,7 +260,6 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector builder.add(canReadOwnUser(user)); builder.add(getUserAutocompletePermission()); builder.add(getGroupAutocompletePermission()); - builder.add(getRepoAutocompletePermission()); permissions = builder.build(); } @@ -269,10 +268,6 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector return info; } - private String getRepoAutocompletePermission() { - return RepositoryPermissions.autocomplete().asShiroString(); - } - private String getGroupAutocompletePermission() { return GroupPermissions.autocomplete().asShiroString(); } diff --git a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java index 7757e0382a..19802902b8 100644 --- a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java +++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java @@ -301,9 +301,9 @@ public class DefaultUserManager extends AbstractUserManager } @Override - public Collection getFiltered(String filter, int limit) { + public Collection autocomplete(String filter) { UserPermissions.autocomplete().check(); - return userDAO.getFiltered(filter, limit); + return search(new SearchRequest(filter,true, DEFAULT_LIMIT)); } /** diff --git a/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java index c2d7eef852..41bcac3c6a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java @@ -105,11 +105,6 @@ public class AbstractManagerResourceTest { return id; } - @Override - public String getDisplayName() { - return id; - } - @Override public void setLastModified(Long timestamp) { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java index a6fd5f1f8a..adc396458c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java @@ -14,18 +14,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.SCMContextProvider; -import sonia.scm.config.ScmConfiguration; +import sonia.scm.Manager; import sonia.scm.group.DefaultGroupManager; import sonia.scm.group.Group; import sonia.scm.group.GroupManager; import sonia.scm.group.xml.XmlGroupDAO; -import sonia.scm.repository.DefaultRepositoryManager; -import sonia.scm.repository.NamespaceStrategy; -import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryManager; -import sonia.scm.repository.xml.XmlRepositoryDAO; -import sonia.scm.security.KeyGenerator; import sonia.scm.store.ConfigurationStore; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.user.DefaultUserManager; @@ -37,7 +30,6 @@ import sonia.scm.xml.XmlDatabase; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -45,10 +37,8 @@ import java.util.stream.IntStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @@ -57,22 +47,17 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; public class AutoCompleteResourceTest { public static final String URL = "/" + AutoCompleteResource.PATH; - private final Integer defaultLimit = Integer.valueOf(AutoCompleteResource.DEFAULT_LIMIT); + private final Integer defaultLimit = Manager.DEFAULT_LIMIT; private Dispatcher dispatcher; private final Subject subject = mock(Subject.class); private final ThreadState subjectThreadState = new SubjectThreadState(subject); - - private XmlUserDAO userDaoMock; - - private XmlGroupDAO groupDaoMock; - - private XmlRepositoryDAO repoDaoMock; + private XmlUserDAO userDao; + private XmlGroupDAO groupDao; private XmlDatabase xmlDB; private ObjectMapper jsonObjectMapper = new ObjectMapper(); - @Before public void prepareEnvironment() { initMocks(this); @@ -82,16 +67,13 @@ public class AutoCompleteResourceTest { when(storeConfig.get()).thenReturn(xmlDB); when(storeFactory.getStore(any(), any())).thenReturn(storeConfig); XmlUserDAO userDao = new XmlUserDAO(storeFactory); - userDaoMock = spy(userDao); + this.userDao = spy(userDao); XmlGroupDAO groupDAO = new XmlGroupDAO(storeFactory); - groupDaoMock = spy(groupDAO); - XmlRepositoryDAO repoDao = new XmlRepositoryDAO(storeFactory); - repoDaoMock = spy(repoDao); + groupDao = spy(groupDAO); ReducedObjectModelToDtoMapperImpl mapper = new ReducedObjectModelToDtoMapperImpl(); - UserManager userManager = new DefaultUserManager(userDaoMock); - GroupManager groupManager = new DefaultGroupManager(groupDaoMock); - RepositoryManager repositoryManager = new DefaultRepositoryManager(mock(ScmConfiguration.class), mock(SCMContextProvider.class), mock(KeyGenerator.class), repoDaoMock, new HashSet<>(), mock(NamespaceStrategy.class)); - AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager, repositoryManager); + UserManager userManager = new DefaultUserManager(this.userDao); + GroupManager groupManager = new DefaultGroupManager(groupDao); + AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager); dispatcher = createDispatcher(autoCompleteResource); subjectThreadState.bind(); ThreadContext.bind(subject); @@ -151,23 +133,6 @@ public class AutoCompleteResourceTest { assertTrue(response.getContentAsString().contains("\"displayName\":\"User 2\"")); } - @Test - public void shouldSearchUsersWithLimitLength() throws Exception { - List users = IntStream.range(0, 10).boxed().map(i -> createMockUser("user" + i, "User " + i)).collect(Collectors.toList()); - when(xmlDB.values()).thenReturn(users); - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "user?filter=user&limit=1") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - verify(userDaoMock).getFiltered(eq("user"), eq(1)); - assertResultSize(response, 1); - } - @Test public void shouldSearchUsersWithDefaultLimitLength() throws Exception { List userList = IntStream.range(0, 10).boxed().map(i -> createMockUser("user" + i, "User " + i)).collect(Collectors.toList()); @@ -181,7 +146,6 @@ public class AutoCompleteResourceTest { dispatcher.invoke(request, response); assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - verify(userDaoMock).getFiltered(eq("user"), eq(defaultLimit)); assertResultSize(response, defaultLimit); } @@ -232,23 +196,6 @@ public class AutoCompleteResourceTest { assertTrue(response.getContentAsString().contains("\"displayName\":\"group_2\"")); } - @Test - public void shouldSearchGroupsWithLimitLength() throws Exception { - List groups = IntStream.range(0, 10).boxed().map(i -> createMockGroup("group_" + i)).collect(Collectors.toList()); - when(xmlDB.values()).thenReturn(groups); - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "group?filter=group&limit=1") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - verify(groupDaoMock).getFiltered(eq("group"), eq(1)); - assertResultSize(response, 1); - } - @Test public void shouldSearchGroupsWithDefaultLimitLength() throws Exception { List groups = IntStream.range(0, 10).boxed().map(i -> createMockGroup("group_" + i)).collect(Collectors.toList()); @@ -262,107 +209,21 @@ public class AutoCompleteResourceTest { dispatcher.invoke(request, response); assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - verify(groupDaoMock).getFiltered(eq("group"), eq(defaultLimit)); assertResultSize(response, defaultLimit); } - - @Test - public void shouldGet400OnFailedParameterForRepoSearch() throws Exception { - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "repository") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(400, response.getStatus()); - } - - @Test - public void shouldGet400IfParameterLengthLessThan2CharsForRepoSearch() throws Exception { - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "repository?filter=a") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(400, response.getStatus()); - } - - @Test - public void shouldSearchRepos() throws Exception { - List repos = Lists.newArrayList(createMockRepo("YCannotFindMe"), createMockRepo("repo1"), createMockRepo("repo2")); - when(xmlDB.values()).thenReturn(repos); - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "repository?filter=repo") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - assertResultSize(response, 2); - assertTrue(response.getContentAsString().contains("\"displayName\":\"space/repo1\"")); - assertTrue(response.getContentAsString().contains("\"displayName\":\"space/repo2\"")); - } - - @Test - public void shouldSearchReposWithLimitLength() throws Exception { - List repositories = IntStream.range(0, 10).boxed().map(i -> createMockRepo("repo" + i)).collect(Collectors.toList()); - when(xmlDB.values()).thenReturn(repositories); - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "repository?filter=repo&limit=1") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - verify(repoDaoMock).getFiltered(eq("repo"), eq(1)); - assertResultSize(response, 1); - } - - @Test - public void shouldSearchReposWithDefaultLimitLength() throws Exception { - List repositories = IntStream.range(0, 10).boxed().map(i -> createMockRepo("repo" + i)).collect(Collectors.toList()); - when(xmlDB.values()).thenReturn(repositories); - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "repository?filter=repo") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - verify(repoDaoMock).getFiltered(eq("repo"), eq(defaultLimit)); - assertResultSize(response, defaultLimit); - } - - private User createMockUser(String id, String name) { return new User(id, name, "em@l.de"); } - private Group createMockGroup(String name) { Group group = new Group("type", name); group.setDescription(name); return group; } - private Repository createMockRepo(String repository) { - return new Repository("id", "git", "space", repository); - } - private void assertResultSize(MockHttpResponse response, int size) throws java.io.IOException { ReducedObjectModelDto[] reducedObjectModelDtos = jsonObjectMapper.readValue(response.getContentAsString(), ReducedObjectModelDto[].class); - assertTrue(reducedObjectModelDtos.length == size); + assertEquals(reducedObjectModelDtos.length, size); } } diff --git a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java index 291369e7b8..9155af3b56 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java @@ -161,8 +161,8 @@ public class DefaultAuthorizationCollectorTest { AuthorizationInfo authInfo = collector.collect(); assertThat(authInfo.getRoles(), Matchers.contains(Role.USER)); - assertThat(authInfo.getStringPermissions(), hasSize(4)); - assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete", "repository:autocomplete", "user:read:trillian")); + assertThat(authInfo.getStringPermissions(), hasSize(3)); + assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete", "user:read:trillian")); assertThat(authInfo.getObjectPermissions(), nullValue()); } @@ -209,7 +209,7 @@ public class DefaultAuthorizationCollectorTest { AuthorizationInfo authInfo = collector.collect(); assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER)); assertThat(authInfo.getObjectPermissions(), nullValue()); - assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete","repository:autocomplete", "repository:read,pull:one", "repository:read,pull,push:two", "user:read:trillian")); + assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete", "repository:read,pull:one", "repository:read,pull,push:two", "user:read:trillian")); } /** @@ -230,7 +230,7 @@ public class DefaultAuthorizationCollectorTest { AuthorizationInfo authInfo = collector.collect(); assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER)); assertThat(authInfo.getObjectPermissions(), nullValue()); - assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two", "user:read:trillian", "user:autocomplete" , "group:autocomplete", "repository:autocomplete")); + assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two", "user:read:trillian", "user:autocomplete" , "group:autocomplete" )); } private void authenticate(User user, String group, String... groups) {