merge + refactoring

This commit is contained in:
Mohamed Karray
2018-10-16 15:58:54 +02:00
24 changed files with 538 additions and 443 deletions

View File

@@ -14,8 +14,8 @@ 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.List;
import java.util.stream.Collectors;
@@ -41,7 +41,7 @@ public class AutoCompleteResource {
}
@GET
@Path("user")
@Path("users")
@Produces(VndMediaType.AUTOCOMPLETE)
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@@ -50,12 +50,12 @@ 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) {
public List<ReducedObjectModelDto> searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) {
return map(userManager.autocomplete(filter));
}
@GET
@Path("group")
@Path("groups")
@Produces(VndMediaType.AUTOCOMPLETE)
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@@ -64,16 +64,15 @@ 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) {
public List<ReducedObjectModelDto> searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) {
return map(groupManager.autocomplete(filter));
}
private <T extends ReducedModelObject> Response map(Collection<T> autocomplete) {
return Response.ok(autocomplete
private <T extends ReducedModelObject> List<ReducedObjectModelDto> map(Collection<T> autocomplete) {
return autocomplete
.stream()
.map(mapper::map)
.collect(Collectors.toList()))
.build();
.collect(Collectors.toList());
}

View File

@@ -6,20 +6,24 @@ import sonia.scm.AlreadyExistsException;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.Manager;
import sonia.scm.ModelObject;
import sonia.scm.NotFoundException;
import sonia.scm.PageResult;
import sonia.scm.user.ChangePasswordNotAllowedException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import sonia.scm.user.UserPermissions;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.AuthenticationUtil;
import javax.ws.rs.core.Response;
import java.text.MessageFormat;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import static sonia.scm.user.ChangePasswordNotAllowedException.WRONG_USER_TYPE;
/**
* Facade for {@link SingleResourceManagerAdapter} and {@link CollectionResourceManagerAdapter}
* for model objects handled by a single id.
@@ -51,7 +55,7 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
* @param usernameToChangePassword the user name of the user we want to change password
* @return function to verify permission
*/
public Function<MODEL_OBJECT, PermissionCheck> getChangePasswordPermission(String usernameToChangePassword) {
private Function<MODEL_OBJECT, PermissionCheck> getChangePasswordPermission(String usernameToChangePassword) {
AssertUtil.assertIsNotEmpty(usernameToChangePassword);
return model -> {
User user = (User) model;
@@ -62,12 +66,32 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
};
}
public Response changePassword(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges, Consumer<MODEL_OBJECT> checker ) throws ConcurrentModificationException {
/**
* Check if a user can modify the password
*
* 1 - the permission changeOwnPassword should be checked
* 2 - Only account of the default type "xml" can change their password
*
*/
private Consumer<MODEL_OBJECT> getChangePasswordChecker() {
return model -> {
User user = (User) model;
UserPermissions.changeOwnPassword().check();
UserManager userManager = (UserManager) manager;
if (!userManager.isTypeDefault(user)) {
throw new ChangePasswordNotAllowedException(MessageFormat.format(WRONG_USER_TYPE, user.getType()));
}
};
}
public Response changePassword(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges ) throws ConcurrentModificationException {
return singleAdapter.changePassword(
loadBy(id),
applyChanges,
idStaysTheSame(id),
checker,
getChangePasswordChecker(),
getChangePasswordPermission(id));
}

View File

@@ -1,5 +1,7 @@
package sonia.scm.api.v2.resources;
import com.google.common.collect.Lists;
import de.otto.edison.hal.Link;
import de.otto.edison.hal.Links;
import org.apache.shiro.SecurityUtils;
import sonia.scm.SCMContextProvider;
@@ -8,6 +10,7 @@ import sonia.scm.group.GroupPermissions;
import sonia.scm.user.UserPermissions;
import javax.inject.Inject;
import java.util.List;
import static de.otto.edison.hal.Link.link;
@@ -24,6 +27,7 @@ public class IndexDtoGenerator {
public IndexDto generate() {
Links.Builder builder = Links.linkingTo();
List<Link> autoCompleteLinks = Lists.newArrayList();
builder.self(resourceLinks.index().self());
builder.single(link("uiPlugins", resourceLinks.uiPluginCollection().self()));
if (SecurityUtils.getSubject().isAuthenticated()) {
@@ -34,6 +38,13 @@ public class IndexDtoGenerator {
if (UserPermissions.list().isPermitted()) {
builder.single(link("users", resourceLinks.userCollection().self()));
}
if (UserPermissions.autocomplete().isPermitted()) {
autoCompleteLinks.add(Link.linkBuilder("autocomplete", resourceLinks.autoComplete().users()).withName("users").build());
}
if (GroupPermissions.autocomplete().isPermitted()) {
autoCompleteLinks.add(Link.linkBuilder("autocomplete", resourceLinks.autoComplete().groups()).withName("groups").build());
}
builder.array(autoCompleteLinks);
if (GroupPermissions.list().isPermitted()) {
builder.single(link("groups", resourceLinks.groupCollection().self()));
}

View File

@@ -83,17 +83,7 @@ public class MeResource {
if (passwordChangeDto.getOldPassword() == null){
throw new ChangePasswordNotAllowedException(ChangePasswordNotAllowedException.OLD_PASSWORD_REQUIRED);
}
return adapter.changePassword(name, user -> user.clone().changePassword(passwordService.encryptPassword(passwordChangeDto.getNewPassword())), userManager.getChangePasswordChecker().andThen(getOldOriginalPasswordChecker(passwordChangeDto.getOldPassword())));
return adapter.changePassword(name, user -> user.clone().changePassword(passwordService.encryptPassword(passwordChangeDto.getNewPassword()), passwordService.encryptPassword(passwordChangeDto.getOldPassword())));
}
/**
* Match given old password from the dto with the stored password before updating
*/
private Consumer<User> getOldOriginalPasswordChecker(String oldPassword) {
return user -> {
if (!user.getPassword().equals(passwordService.encryptPassword(oldPassword))) {
throw new InvalidPasswordException(INVALID_MATCHING);
}
};
}
}

View File

@@ -142,6 +142,26 @@ class ResourceLinks {
}
}
AutoCompleteLinks autoComplete() {
return new AutoCompleteLinks (scmPathInfoStore.get());
}
static class AutoCompleteLinks {
private final LinkBuilder linkBuilder;
AutoCompleteLinks (ScmPathInfo pathInfo) {
linkBuilder = new LinkBuilder(pathInfo, AutoCompleteResource.class);
}
String users() {
return linkBuilder.method("searchUser").parameters().href();
}
String groups() {
return linkBuilder.method("searchGroup").parameters().href();
}
}
ConfigLinks config() {
return new ConfigLinks(scmPathInfoStore.get());
}

View File

@@ -135,7 +135,7 @@ public class UserResource {
if (currentUserName.equals(name) && passwordChangeDto.getOldPassword() == null){
throw new ChangePasswordNotAllowedException(ChangePasswordNotAllowedException.OLD_PASSWORD_REQUIRED);
}
return adapter.changePassword(name, user -> user.changePassword(passwordService.encryptPassword(passwordChangeDto.getNewPassword())), userManager.getChangePasswordChecker());
return adapter.changePassword(name, user -> user.changePassword(passwordService.encryptPassword(passwordChangeDto.getNewPassword())));
}
}

View File

@@ -245,7 +245,8 @@ public class DefaultGroupManager extends AbstractGroupManager
@Override
public Collection<Group> autocomplete(String filter) {
GroupPermissions.autocomplete().check();
return search(new SearchRequest(filter,true, DEFAULT_LIMIT));
SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT);
return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null);
}
/**

View File

@@ -235,6 +235,13 @@ public class DefaultUserManager extends AbstractUserManager
fresh.copyProperties(user);
}
@Override
public Collection<User> 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
*
@@ -264,7 +271,7 @@ public class DefaultUserManager extends AbstractUserManager
}
});
}
private boolean matches(SearchRequest searchRequest, User user) {
return SearchUtil.matchesOne(searchRequest, user.getName(), user.getDisplayName(), user.getMail());
}
@@ -283,7 +290,7 @@ public class DefaultUserManager extends AbstractUserManager
public User get(String id)
{
UserPermissions.read().check(id);
User user = userDAO.get(id);
if (user != null)
@@ -306,12 +313,6 @@ public class DefaultUserManager extends AbstractUserManager
return getAll(null);
}
@Override
public Collection<User> autocomplete(String filter) {
UserPermissions.autocomplete().check();
return search(new SearchRequest(filter,true, DEFAULT_LIMIT));
}
/**
* Method description
*