Skip to content

Commit

Permalink
SONAR-7835 WS permissions/users return permissions in response
Browse files Browse the repository at this point in the history
  • Loading branch information
teryk authored and stas-vilchik committed Jul 12, 2016
1 parent a51fcb2 commit 2990ede
Show file tree
Hide file tree
Showing 21 changed files with 372 additions and 398 deletions.
Expand Up @@ -45,7 +45,7 @@
import org.sonarqube.ws.client.permission.RemoveProjectCreatorFromTemplateWsRequest; import org.sonarqube.ws.client.permission.RemoveProjectCreatorFromTemplateWsRequest;
import org.sonarqube.ws.client.permission.RemoveUserFromTemplateWsRequest; import org.sonarqube.ws.client.permission.RemoveUserFromTemplateWsRequest;
import org.sonarqube.ws.client.permission.SearchTemplatesWsRequest; import org.sonarqube.ws.client.permission.SearchTemplatesWsRequest;
import org.sonarqube.ws.client.permission.OldUsersWsRequest; import org.sonarqube.ws.client.permission.UsersWsRequest;
import util.QaOnly; import util.QaOnly;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -106,8 +106,7 @@ public void permission_web_services() {
assertThat(searchGlobalPermissionsWsResponse.getPermissionsList().get(0).getGroupsCount()).isEqualTo(2); assertThat(searchGlobalPermissionsWsResponse.getPermissionsList().get(0).getGroupsCount()).isEqualTo(2);


WsPermissions.UsersWsResponse users = permissionsWsClient WsPermissions.UsersWsResponse users = permissionsWsClient
.users(new OldUsersWsRequest() .users(new UsersWsRequest().setPermission("admin"));
.setPermission("admin"));
assertThat(users.getUsersList()).extracting("login").contains(LOGIN); assertThat(users.getUsersList()).extracting("login").contains(LOGIN);


WsPermissions.WsGroupsResponse groupsResponse = permissionsWsClient WsPermissions.WsGroupsResponse groupsResponse = permissionsWsClient
Expand Down
Expand Up @@ -35,9 +35,8 @@
import org.sonar.db.component.ResourceDto; import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ResourceQuery; import org.sonar.db.component.ResourceQuery;
import org.sonar.db.permission.GroupWithPermissionDto; import org.sonar.db.permission.GroupWithPermissionDto;
import org.sonar.db.permission.PermissionDao;
import org.sonar.db.permission.OldPermissionQuery; import org.sonar.db.permission.OldPermissionQuery;
import org.sonar.db.permission.UserWithPermissionDto; import org.sonar.db.permission.PermissionDao;
import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.NotFoundException;


import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
Expand All @@ -55,12 +54,6 @@ public PermissionFinder(DbClient dbClient) {
this.permissionDao = dbClient.permissionDao(); this.permissionDao = dbClient.permissionDao();
} }


public List<UserWithPermissionDto> findUsersWithPermission(DbSession dbSession, OldPermissionQuery query) {
Long componentId = componentId(query.component());
int limit = query.pageSize();
return permissionDao.selectUsers(dbSession, query, componentId, offset(query), limit);
}

/** /**
* Paging for groups search is done in Java in order to correctly handle the 'Anyone' group * Paging for groups search is done in Java in order to correctly handle the 'Anyone' group
*/ */
Expand Down Expand Up @@ -93,12 +86,6 @@ private static List<GroupWithPermissionDto> toGroupQueryResult(List<GroupWithPer
return pagedGroups(filteredDtos, paging); return pagedGroups(filteredDtos, paging);
} }


private static int offset(OldPermissionQuery query) {
int pageSize = query.pageSize();
int pageIndex = query.pageIndex();
return (pageIndex - 1) * pageSize;
}

private static List<GroupWithPermissionDto> filterMembership(List<GroupWithPermissionDto> dtos, OldPermissionQuery query) { private static List<GroupWithPermissionDto> filterMembership(List<GroupWithPermissionDto> dtos, OldPermissionQuery query) {
return newArrayList(Iterables.filter(dtos, new GroupWithPermissionMatchQuery(query))); return newArrayList(Iterables.filter(dtos, new GroupWithPermissionMatchQuery(query)));
} }
Expand Down
Expand Up @@ -48,7 +48,10 @@ private PermissionRequestValidator() {
// static methods only // static methods only
} }


public static void validatePermission(String permission, Optional<WsProjectRef> projectRef) { public static void validatePermission(@Nullable String permission, Optional<WsProjectRef> projectRef) {
if (permission == null) {
return;
}
if (projectRef.isPresent()) { if (projectRef.isPresent()) {
validateProjectPermission(permission); validateProjectPermission(permission);
} else { } else {
Expand Down
Expand Up @@ -46,6 +46,7 @@ protected void configureModule() {
RemoveGroupAction.class, RemoveGroupAction.class,
RemoveUserAction.class, RemoveUserAction.class,
OldUsersAction.class, OldUsersAction.class,
UsersAction.class,
GroupsAction.class, GroupsAction.class,
SearchGlobalPermissionsAction.class, SearchGlobalPermissionsAction.class,
SearchProjectPermissionsAction.class, SearchProjectPermissionsAction.class,
Expand Down
Expand Up @@ -20,7 +20,11 @@
package org.sonar.server.permission.ws; package org.sonar.server.permission.ws;


import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
Expand All @@ -29,24 +33,25 @@
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.OldPermissionQuery;
import org.sonar.db.permission.PermissionQuery; import org.sonar.db.permission.PermissionQuery;
import org.sonar.db.permission.UserWithPermissionDto; import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserPermissionDto;
import org.sonar.server.permission.PermissionFinder; import org.sonar.server.permission.PermissionFinder;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsPermissions; import org.sonarqube.ws.WsPermissions;
import org.sonarqube.ws.WsPermissions.UsersWsResponse; import org.sonarqube.ws.WsPermissions.UsersWsResponse;
import org.sonarqube.ws.client.permission.UsersWsRequest; import org.sonarqube.ws.client.permission.UsersWsRequest;


import static com.google.common.base.Strings.nullToEmpty; import static java.util.Collections.emptyList;
import static org.sonar.api.utils.Paging.forPageIndex;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE; import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE; import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentDto; import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentDto;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission; import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter; import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters; import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef; import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION; import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID; import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
Expand Down Expand Up @@ -80,7 +85,8 @@ public void define(WebService.NewController context) {
.setHandler(this); .setHandler(this);


action.createParam(Param.TEXT_QUERY) action.createParam(Param.TEXT_QUERY)
.setDescription("Limit search to user names that contain the supplied string. Must have at least %d characters.", PermissionQuery.SEARCH_QUERY_MIN_LENGTH) .setDescription("Limit search to user names that contain the supplied string. Must have at least %d characters.<br/>" +
"When this parameter is not set, only users having at least one permission are returned.", SEARCH_QUERY_MIN_LENGTH)
.setExampleValue("eri"); .setExampleValue("eri");
createPermissionParameter(action).setRequired(false); createPermissionParameter(action).setRequired(false);
createProjectParameters(action); createProjectParameters(action);
Expand All @@ -99,59 +105,85 @@ private UsersWsResponse doHandle(UsersWsRequest request) {
try { try {
Optional<ComponentDto> project = dependenciesFinder.searchProject(dbSession, wsProjectRef); Optional<ComponentDto> project = dependenciesFinder.searchProject(dbSession, wsProjectRef);
checkProjectAdminUserByComponentDto(userSession, project); checkProjectAdminUserByComponentDto(userSession, project);
OldPermissionQuery permissionQuery = buildPermissionQuery(request, project); PermissionQuery dbQuery = buildPermissionQuery(request, project);
Long projectIdIfPresent = project.isPresent() ? project.get().getId() : null; List<UserDto> users = findUsers(dbSession, dbQuery);
int total = dbClient.permissionDao().countUsers(dbSession, permissionQuery, projectIdIfPresent); int total = dbClient.permissionDao().countUsersByQuery(dbSession, dbQuery);
List<UserWithPermissionDto> usersWithPermission = permissionFinder.findUsersWithPermission(dbSession, permissionQuery); List<UserPermissionDto> userPermissions = findUserPermissions(dbSession, users);
return buildResponse(usersWithPermission, forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal(total)); Paging paging = Paging.forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal(total);
return buildResponse(users, userPermissions, paging);
} finally { } finally {
dbClient.closeSession(dbSession); dbClient.closeSession(dbSession);
} }
} }


private static UsersWsRequest toUsersWsRequest(Request request) { private static UsersWsRequest toUsersWsRequest(Request request) {
return new UsersWsRequest() UsersWsRequest usersRequest = new UsersWsRequest()
.setPermission(request.mandatoryParam(PARAM_PERMISSION)) .setPermission(request.param(PARAM_PERMISSION))
.setProjectId(request.param(PARAM_PROJECT_ID)) .setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY)) .setProjectKey(request.param(PARAM_PROJECT_KEY))
.setQuery(request.param(Param.TEXT_QUERY)) .setQuery(request.param(Param.TEXT_QUERY))
.setPage(request.mandatoryParamAsInt(Param.PAGE)) .setPage(request.mandatoryParamAsInt(Param.PAGE))
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)); .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE));

String searchQuery = usersRequest.getQuery();
checkRequest(searchQuery == null || searchQuery.length() >= SEARCH_QUERY_MIN_LENGTH,
"The '%s' parameter must have at least %d characters", Param.TEXT_QUERY, SEARCH_QUERY_MIN_LENGTH);
return usersRequest;
} }


private static UsersWsResponse buildResponse(List<UserWithPermissionDto> usersWithPermission, Paging paging) { private static UsersWsResponse buildResponse(List<UserDto> users, List<UserPermissionDto> userPermissions, Paging paging) {
UsersWsResponse.Builder userResponse = UsersWsResponse.newBuilder(); Multimap<Long, String> permissionsByUserId = TreeMultimap.create();
WsPermissions.User.Builder user = WsPermissions.User.newBuilder(); userPermissions.forEach(userPermission -> permissionsByUserId.put(userPermission.getUserId(), userPermission.getPermission()));
for (UserWithPermissionDto userWithPermission : usersWithPermission) {
userResponse.addUsers( UsersWsResponse.Builder response = UsersWsResponse.newBuilder();
user users.forEach(user -> {
.clear() WsPermissions.User.Builder userResponse = response.addUsersBuilder()
.setLogin(userWithPermission.getLogin()) .setLogin(user.getLogin())
.setName(nullToEmpty(userWithPermission.getName())) .addAllPermissions(permissionsByUserId.get(user.getId()));
.setEmail(nullToEmpty(userWithPermission.getEmail()))
.setSelected(userWithPermission.getPermission() != null));
}


userResponse.getPagingBuilder() if (user.getEmail() != null) {
.clear() userResponse.setEmail(user.getEmail());
}
if (user.getName() != null) {
userResponse.setName(user.getName());
}
});

response.getPagingBuilder()
.setPageIndex(paging.pageIndex()) .setPageIndex(paging.pageIndex())
.setPageSize(paging.pageSize()) .setPageSize(paging.pageSize())
.setTotal(paging.total()) .setTotal(paging.total())
.build(); .build();


return userResponse.build(); return response.build();
} }


private static OldPermissionQuery buildPermissionQuery(UsersWsRequest request, Optional<ComponentDto> project) { private static PermissionQuery buildPermissionQuery(UsersWsRequest request, Optional<ComponentDto> project) {
OldPermissionQuery.Builder permissionQuery = OldPermissionQuery.builder() PermissionQuery.Builder dbQuery = PermissionQuery.builder()
.permission(request.getPermission()) .setPermission(request.getPermission())
.pageIndex(request.getPage()) .setPageIndex(request.getPage())
.pageSize(request.getPageSize()) .setPageSize(request.getPageSize())
.search(request.getQuery()); .setSearchQuery(request.getQuery());
if (project.isPresent()) { if (project.isPresent()) {
permissionQuery.component(project.get().getKey()); dbQuery.setComponentUuid(project.get().uuid());
}
if (request.getQuery() == null) {
dbQuery.withPermissionOnly();
} }


return permissionQuery.build(); return dbQuery.build();
}

private List<UserDto> findUsers(DbSession dbSession, PermissionQuery dbQuery) {
List<String> orderedLogins = dbClient.permissionDao().selectLoginsByPermissionQuery(dbSession, dbQuery);
return Ordering.explicit(orderedLogins).onResultOf(UserDto::getLogin).immutableSortedCopy(dbClient.userDao().selectByLogins(dbSession, orderedLogins));
}

private List<UserPermissionDto> findUserPermissions(DbSession dbSession, List<UserDto> users) {
if (users.isEmpty()) {
return emptyList();
}
List<String> logins = users.stream().map(UserDto::getLogin).collect(Collectors.toList());
return dbClient.permissionDao().selectUserPermissionsByLogins(dbSession, logins);
} }
} }
@@ -1,22 +1,28 @@
{ {
"paging": {
"pageIndex": 1,
"pageSize": 20,
"total": 2
},
"users": [ "users": [
{ {
"login": "admin", "login": "admin",
"name": "Administrator", "name": "Administrator",
"email": "admin@admin.com", "email": "admin@admin.com",
"selected": true "permissions": [
"admin",
"gateadmin",
"profileadmin"
]
}, },
{ {
"login": "george.orwell", "login": "george.orwell",
"name": "George Orwell", "name": "George Orwell",
"email": "george.orwell@1984.net", "email": "george.orwell@1984.net",
"selected": true "permissions": [
"scan"
]
} }
], ]
"paging": {
"pageSize": 100,
"total": 2,
"pageIndex": 1
}
} }


Expand Up @@ -20,6 +20,7 @@
package org.sonar.server.permission.ws; package org.sonar.server.permission.ws;


import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
Expand Down Expand Up @@ -82,6 +83,7 @@ public void setUp() {
} }


@Test @Test
@Ignore("will be deleted")
public void search_for_users_with_response_example() { public void search_for_users_with_response_example() {
UserDto user1 = insertUser(new UserDto().setLogin("admin").setName("Administrator").setEmail("admin@admin.com")); UserDto user1 = insertUser(new UserDto().setLogin("admin").setName("Administrator").setEmail("admin@admin.com"));
UserDto user2 = insertUser(new UserDto().setLogin("george.orwell").setName("George Orwell").setEmail("george.orwell@1984.net")); UserDto user2 = insertUser(new UserDto().setLogin("george.orwell").setName("George Orwell").setEmail("george.orwell@1984.net"));
Expand All @@ -95,6 +97,7 @@ public void search_for_users_with_response_example() {
} }


@Test @Test
@Ignore("will be deleted")
public void search_for_users_with_one_permission() { public void search_for_users_with_one_permission() {
insertUsers(); insertUsers();
String result = ws.newRequest().setParam("permission", "scan").execute().getInput(); String result = ws.newRequest().setParam("permission", "scan").execute().getInput();
Expand Down
Expand Up @@ -29,6 +29,6 @@ public class PermissionsWsModuleTest {
public void verify_count_of_added_components() { public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer(); ComponentContainer container = new ComponentContainer();
new PermissionsWsModule().configure(container); new PermissionsWsModule().configure(container);
assertThat(container.size()).isEqualTo(2 + 29); assertThat(container.size()).isEqualTo(2 + 30);
} }
} }
Expand Up @@ -47,16 +47,15 @@
import org.sonar.server.usergroups.ws.UserGroupFinder; import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester; import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.WsPermissions; import org.sonarqube.ws.WsPermissions.OldUsersWsResponse;
import org.sonarqube.ws.WsPermissions.UsersWsResponse;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateDto; import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateDto;
import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateUserDto; import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateUserDto;
import static org.sonar.test.JsonAssert.assertJson; import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.MediaTypes.PROTOBUF; import static org.sonarqube.ws.MediaTypes.PROTOBUF;
import static org.sonarqube.ws.WsPermissions.UsersWsResponse.parseFrom; import static org.sonarqube.ws.WsPermissions.OldUsersWsResponse.parseFrom;




public class TemplateUsersActionTest { public class TemplateUsersActionTest {
Expand Down Expand Up @@ -124,7 +123,7 @@ public void search_for_users_by_template_name() throws IOException {
.setMediaType(PROTOBUF) .setMediaType(PROTOBUF)
.execute().getInputStream(); .execute().getInputStream();


UsersWsResponse response = parseFrom(responseStream); OldUsersWsResponse response = parseFrom(responseStream);


assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2"); assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2");
} }
Expand All @@ -137,7 +136,7 @@ public void search_using_text_query() throws IOException {
.setMediaType(PROTOBUF) .setMediaType(PROTOBUF)
.execute().getInputStream(); .execute().getInputStream();


UsersWsResponse response = parseFrom(responseStream); OldUsersWsResponse response = parseFrom(responseStream);


assertThat(response.getUsersList()).extracting("login").containsOnly("login-1"); assertThat(response.getUsersList()).extracting("login").containsOnly("login-1");
} }
Expand All @@ -150,7 +149,7 @@ public void search_using_selected() throws IOException {
.setMediaType(PROTOBUF) .setMediaType(PROTOBUF)
.execute().getInputStream(); .execute().getInputStream();


WsPermissions.UsersWsResponse response = parseFrom(responseStream); OldUsersWsResponse response = OldUsersWsResponse.parseFrom(responseStream);


assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2", "login-3"); assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2", "login-3");
assertThat(response.getUsers(2).getSelected()).isFalse(); assertThat(response.getUsers(2).getSelected()).isFalse();
Expand All @@ -166,7 +165,7 @@ public void search_with_pagination() throws IOException {
.setMediaType(PROTOBUF) .setMediaType(PROTOBUF)
.execute().getInputStream(); .execute().getInputStream();


WsPermissions.UsersWsResponse response = parseFrom(responseStream); OldUsersWsResponse response = parseFrom(responseStream);


assertThat(response.getUsersList()).extracting("login").containsOnly("login-2"); assertThat(response.getUsersList()).extracting("login").containsOnly("login-2");
} }
Expand Down

0 comments on commit 2990ede

Please sign in to comment.