diff --git a/scm-core/src/main/java/sonia/scm/DisplayManager.java b/scm-core/src/main/java/sonia/scm/DisplayManager.java new file mode 100644 index 0000000000..72113a483d --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/DisplayManager.java @@ -0,0 +1,19 @@ +package sonia.scm; + +import java.util.Collection; +import java.util.Optional; + +public interface DisplayManager { + + int DEFAULT_LIMIT = 5; + + /** + * Returns a {@link Collection} of filtered objects + * + * @param filter the searched string + * @return filtered object from the store + */ + Collection autocomplete(String filter); + + Optional get(String id); +} diff --git a/scm-core/src/main/java/sonia/scm/Manager.java b/scm-core/src/main/java/sonia/scm/Manager.java index 390777958d..9a7f21d3ef 100644 --- a/scm-core/src/main/java/sonia/scm/Manager.java +++ b/scm-core/src/main/java/sonia/scm/Manager.java @@ -47,8 +47,6 @@ public interface Manager extends HandlerBase, LastModifiedAware { - int DEFAULT_LIMIT = 5; - /** * Reloads a object from store and overwrites all changes. diff --git a/scm-core/src/main/java/sonia/scm/TransformFilter.java b/scm-core/src/main/java/sonia/scm/TransformFilter.java index e872ab384f..fa798fe36e 100644 --- a/scm-core/src/main/java/sonia/scm/TransformFilter.java +++ b/scm-core/src/main/java/sonia/scm/TransformFilter.java @@ -39,8 +39,10 @@ package sonia.scm; * @author Sebastian Sdorra * * @param type of objects to transform + * @param result type of the transformation */ -public interface TransformFilter +@FunctionalInterface +public interface TransformFilter { /** @@ -52,5 +54,5 @@ public interface TransformFilter * * @return tranformed object */ - public T accept(T item); + R accept(T item); } diff --git a/scm-core/src/main/java/sonia/scm/group/DisplayGroup.java b/scm-core/src/main/java/sonia/scm/group/DisplayGroup.java new file mode 100644 index 0000000000..a16a3046e9 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/group/DisplayGroup.java @@ -0,0 +1,26 @@ +package sonia.scm.group; + +import sonia.scm.ReducedModelObject; + +public class DisplayGroup implements ReducedModelObject { + + private final String id; + private final String displayName; + + public static DisplayGroup from(Group group) { + return new DisplayGroup(group.getId(), group.getDescription()); + } + + private DisplayGroup(String id, String displayName) { + this.id = id; + this.displayName = displayName; + } + + public String getId() { + return id; + } + + public String getDisplayName() { + return displayName; + } +} diff --git a/scm-core/src/main/java/sonia/scm/group/GroupDisplayManager.java b/scm-core/src/main/java/sonia/scm/group/GroupDisplayManager.java new file mode 100644 index 0000000000..d9188e9402 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/group/GroupDisplayManager.java @@ -0,0 +1,6 @@ +package sonia.scm.group; + +import sonia.scm.DisplayManager; + +public interface GroupDisplayManager extends DisplayManager { +} 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 08057ae3db..288196894d 100644 --- a/scm-core/src/main/java/sonia/scm/group/GroupManager.java +++ b/scm-core/src/main/java/sonia/scm/group/GroupManager.java @@ -61,14 +61,4 @@ 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 ef6de4164c..e2367d863c 100644 --- a/scm-core/src/main/java/sonia/scm/group/GroupManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/group/GroupManagerDecorator.java @@ -109,11 +109,6 @@ 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/search/SearchUtil.java b/scm-core/src/main/java/sonia/scm/search/SearchUtil.java index 90c65e3456..281e00a517 100644 --- a/scm-core/src/main/java/sonia/scm/search/SearchUtil.java +++ b/scm-core/src/main/java/sonia/scm/search/SearchUtil.java @@ -159,17 +159,17 @@ public final class SearchUtil * * @return */ - public static Collection search(SearchRequest searchRequest, - Collection collection, TransformFilter filter) + public static Collection search(SearchRequest searchRequest, + Collection collection, TransformFilter filter) { - List items = new ArrayList(); + List items = new ArrayList<>(); int index = 0; int counter = 0; Iterator it = collection.iterator(); while (it.hasNext()) { - T item = filter.accept(it.next()); + R item = filter.accept(it.next()); if (item != null) { diff --git a/scm-core/src/main/java/sonia/scm/user/DisplayUser.java b/scm-core/src/main/java/sonia/scm/user/DisplayUser.java new file mode 100644 index 0000000000..7a11dfbab4 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/user/DisplayUser.java @@ -0,0 +1,32 @@ +package sonia.scm.user; + +import sonia.scm.ReducedModelObject; + +public class DisplayUser implements ReducedModelObject { + + private final String id; + private final String displayName; + private final String mail; + + public static DisplayUser from(User user) { + return new DisplayUser(user.getId(), user.getDisplayName(), user.getMail()); + } + + private DisplayUser(String id, String displayName, String mail) { + this.id = id; + this.displayName = displayName; + this.mail = mail; + } + + public String getId() { + return id; + } + + public String getDisplayName() { + return displayName; + } + + public String getMail() { + return mail; + } +} diff --git a/scm-core/src/main/java/sonia/scm/user/UserDisplayManager.java b/scm-core/src/main/java/sonia/scm/user/UserDisplayManager.java new file mode 100644 index 0000000000..159025f5ec --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/user/UserDisplayManager.java @@ -0,0 +1,6 @@ +package sonia.scm.user; + +import sonia.scm.DisplayManager; + +public interface UserDisplayManager extends DisplayManager { +} 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 f301c1f2b1..a735918c59 100644 --- a/scm-core/src/main/java/sonia/scm/user/UserManager.java +++ b/scm-core/src/main/java/sonia/scm/user/UserManager.java @@ -75,14 +75,6 @@ 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); - /** * Changes the password of the logged in user. * @param oldPassword The current encrypted password of the user. 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 0384fe1b52..0b88d856ff 100644 --- a/scm-core/src/main/java/sonia/scm/user/UserManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/user/UserManagerDecorator.java @@ -121,11 +121,6 @@ public class UserManagerDecorator extends ManagerDecorator return decorated.getDefaultType(); } - @Override - public Collection autocomplete(String filter) { - return decorated.autocomplete(filter); - } - @Override public void changePasswordForLoggedInUser(String oldPassword, String newPassword) { decorated.changePasswordForLoggedInUser(oldPassword, newPassword); diff --git a/scm-webapp/src/main/java/sonia/scm/GenericDisplayManager.java b/scm-webapp/src/main/java/sonia/scm/GenericDisplayManager.java new file mode 100644 index 0000000000..5ad4f6343a --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/GenericDisplayManager.java @@ -0,0 +1,42 @@ +package sonia.scm; + +import sonia.scm.search.SearchRequest; +import sonia.scm.search.SearchUtil; + +import java.util.Collection; +import java.util.Optional; +import java.util.function.Function; + +import static java.util.Optional.ofNullable; +import static sonia.scm.group.DisplayGroup.from; + +public abstract class GenericDisplayManager implements DisplayManager { + + private final GenericDAO dao; + private final Function transform; + + protected GenericDisplayManager(GenericDAO dao, Function transform) { + this.dao = dao; + this.transform = transform; + } + + @Override + public Collection autocomplete(String filter) { + checkPermission(); + SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); + return SearchUtil.search( + searchRequest, + dao.getAll(), + object -> matches(searchRequest, object)? transform.apply(object): null + ); + } + + protected abstract void checkPermission(); + + protected abstract boolean matches(SearchRequest searchRequest, D object); + + @Override + public Optional get(String id) { + return ofNullable(dao.get(id)).map(transform); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 7c7dec47ff..a3661a25f0 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -46,8 +46,10 @@ import sonia.scm.cache.CacheManager; import sonia.scm.cache.GuavaCacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; +import sonia.scm.group.DefaultGroupDisplayManager; import sonia.scm.group.DefaultGroupManager; import sonia.scm.group.GroupDAO; +import sonia.scm.group.GroupDisplayManager; import sonia.scm.group.GroupManager; import sonia.scm.group.GroupManagerProvider; import sonia.scm.group.xml.XmlGroupDAO; @@ -102,8 +104,10 @@ import sonia.scm.template.MustacheTemplateEngine; import sonia.scm.template.TemplateEngine; import sonia.scm.template.TemplateEngineFactory; import sonia.scm.template.TemplateServlet; +import sonia.scm.user.DefaultUserDisplayManager; import sonia.scm.user.DefaultUserManager; import sonia.scm.user.UserDAO; +import sonia.scm.user.UserDisplayManager; import sonia.scm.user.UserManager; import sonia.scm.user.UserManagerProvider; import sonia.scm.user.xml.XmlUserDAO; @@ -268,8 +272,11 @@ public class ScmServletModule extends ServletModule RepositoryManagerProvider.class); bindDecorated(UserManager.class, DefaultUserManager.class, UserManagerProvider.class); + bind(UserDisplayManager.class, DefaultUserDisplayManager.class); bindDecorated(GroupManager.class, DefaultGroupManager.class, GroupManagerProvider.class); + bind(GroupDisplayManager.class, DefaultGroupDisplayManager.class); + bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class); // bind sslcontext provider 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 005e29e9ea..38b421f573 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 @@ -4,8 +4,8 @@ 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.user.UserManager; +import sonia.scm.group.GroupDisplayManager; +import sonia.scm.user.UserDisplayManager; import sonia.scm.web.VndMediaType; import javax.inject.Inject; @@ -30,14 +30,14 @@ public class AutoCompleteResource { private ReducedObjectModelToDtoMapper mapper; - private UserManager userManager; - private GroupManager groupManager; + private UserDisplayManager userDisplayManager; + private GroupDisplayManager groupDisplayManager; @Inject - public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager) { + public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserDisplayManager userDisplayManager, GroupDisplayManager groupDisplayManager) { this.mapper = mapper; - this.userManager = userManager; - this.groupManager = groupManager; + this.userDisplayManager = userDisplayManager; + this.groupDisplayManager = groupDisplayManager; } @GET @@ -51,7 +51,7 @@ public class AutoCompleteResource { @ResponseCode(code = 500, condition = "internal server error") }) public List searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { - return map(userManager.autocomplete(filter)); + return map(userDisplayManager.autocomplete(filter)); } @GET @@ -65,7 +65,7 @@ public class AutoCompleteResource { @ResponseCode(code = 500, condition = "internal server error") }) public List searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { - return map(groupManager.autocomplete(filter)); + return map(groupDisplayManager.autocomplete(filter)); } private List map(Collection autocomplete) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java index 6e90b4e6ec..e2a6cc797e 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java @@ -6,6 +6,7 @@ import com.webcohesion.enunciate.metadata.rs.TypeHint; import org.apache.shiro.authc.credential.PasswordService; import sonia.scm.user.User; import sonia.scm.user.UserManager; +import sonia.scm.user.UserPermissions; import sonia.scm.web.VndMediaType; import javax.inject.Inject; diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupDisplayManager.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupDisplayManager.java new file mode 100644 index 0000000000..abffa46e41 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupDisplayManager.java @@ -0,0 +1,25 @@ +package sonia.scm.group; + +import sonia.scm.GenericDisplayManager; +import sonia.scm.search.SearchRequest; +import sonia.scm.search.SearchUtil; + +import javax.inject.Inject; + +public class DefaultGroupDisplayManager extends GenericDisplayManager implements GroupDisplayManager { + + @Inject + public DefaultGroupDisplayManager(GroupDAO groupDAO) { + super(groupDAO, DisplayGroup::from); + } + + @Override + protected void checkPermission() { + GroupPermissions.autocomplete().check(); + } + + @Override + protected boolean matches(SearchRequest searchRequest, Group group) { + return SearchUtil.matchesOne(searchRequest, group.getName(), group.getDescription()); + } +} 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 6bf850f99d..3320773e57 100644 --- a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java @@ -195,7 +195,7 @@ public class DefaultGroupManager extends AbstractGroupManager final PermissionActionCheck check = GroupPermissions.read(); return SearchUtil.search(searchRequest, groupDAO.getAll(), - new TransformFilter() + new TransformFilter() { @Override public Group accept(Group group) @@ -241,13 +241,6 @@ public class DefaultGroupManager extends AbstractGroupManager return group; } - @Override - public Collection autocomplete(String filter) { - GroupPermissions.autocomplete().check(); - SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); - return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null); - } - /** * Method description * diff --git a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserDisplayManager.java b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserDisplayManager.java new file mode 100644 index 0000000000..d27b360922 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserDisplayManager.java @@ -0,0 +1,25 @@ +package sonia.scm.user; + +import sonia.scm.GenericDisplayManager; +import sonia.scm.search.SearchRequest; +import sonia.scm.search.SearchUtil; + +import javax.inject.Inject; + +public class DefaultUserDisplayManager extends GenericDisplayManager implements UserDisplayManager { + + @Inject + public DefaultUserDisplayManager(UserDAO userDAO) { + super(userDAO, DisplayUser::from); + } + + @Override + protected void checkPermission() { + UserPermissions.autocomplete().check(); + } + + @Override + protected boolean matches(SearchRequest searchRequest, User user) { + return SearchUtil.matchesOne(searchRequest, user.getName(), user.getDisplayName(), user.getMail()); + } +} 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 3b78267631..a6c40b24f4 100644 --- a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java +++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java @@ -212,13 +212,6 @@ public class DefaultUserManager extends AbstractUserManager fresh.copyProperties(user); } - @Override - public Collection autocomplete(String filter) { - UserPermissions.autocomplete().check(); - SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); - return SearchUtil.search(searchRequest, userDAO.getAll(), user -> matches(searchRequest,user)?user:null); - } - /** * Method description * @@ -236,7 +229,7 @@ public class DefaultUserManager extends AbstractUserManager } final PermissionActionCheck check = UserPermissions.read(); - return SearchUtil.search(searchRequest, userDAO.getAll(), new TransformFilter() { + return SearchUtil.search(searchRequest, userDAO.getAll(), new TransformFilter() { @Override public User accept(User user) { @@ -415,35 +408,6 @@ public class DefaultUserManager extends AbstractUserManager this.modify(user); } - /** - * Method description - * - * - * @param unmarshaller - * @param path - */ - private void createDefaultAccount(Unmarshaller unmarshaller, String path) - { - InputStream input = DefaultUserManager.class.getResourceAsStream(path); - - try - { - User user = (User) unmarshaller.unmarshal(input); - - user.setType(userDAO.getType()); - user.setCreationDate(System.currentTimeMillis()); - userDAO.add(user); - } - catch (Exception ex) - { - logger.error("could not create account", ex); - } - finally - { - IOUtil.close(input); - } - } - //~--- fields --------------------------------------------------------------- private final UserDAO userDAO; 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 d392aefe4e..ac89d02bfb 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,16 +14,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.Manager; -import sonia.scm.group.DefaultGroupManager; +import sonia.scm.DisplayManager; +import sonia.scm.group.DefaultGroupDisplayManager; import sonia.scm.group.Group; -import sonia.scm.group.GroupManager; import sonia.scm.group.xml.XmlGroupDAO; import sonia.scm.store.ConfigurationStore; import sonia.scm.store.ConfigurationStoreFactory; -import sonia.scm.user.DefaultUserManager; +import sonia.scm.user.DefaultUserDisplayManager; import sonia.scm.user.User; -import sonia.scm.user.UserManager; import sonia.scm.user.xml.XmlUserDAO; import sonia.scm.web.VndMediaType; import sonia.scm.xml.XmlDatabase; @@ -51,7 +49,7 @@ public class AutoCompleteResourceTest { public final ShiroRule shiroRule = new ShiroRule(); public static final String URL = "/" + AutoCompleteResource.PATH; - private final Integer defaultLimit = Manager.DEFAULT_LIMIT; + private final Integer defaultLimit = DisplayManager.DEFAULT_LIMIT; private Dispatcher dispatcher; private XmlUserDAO userDao; @@ -73,8 +71,8 @@ public class AutoCompleteResourceTest { XmlGroupDAO groupDAO = new XmlGroupDAO(storeFactory); groupDao = spy(groupDAO); ReducedObjectModelToDtoMapperImpl mapper = new ReducedObjectModelToDtoMapperImpl(); - UserManager userManager = new DefaultUserManager(this.userDao); - GroupManager groupManager = new DefaultGroupManager(groupDao); + DefaultUserDisplayManager userManager = new DefaultUserDisplayManager(this.userDao); + DefaultGroupDisplayManager groupManager = new DefaultGroupDisplayManager(groupDao); AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager); dispatcher = createDispatcher(autoCompleteResource); }