From 12f55eb8322661b6d73224cfe81d44add919d0fb Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 12 Jul 2016 17:52:25 +0200 Subject: [PATCH] SONAR-7837 Change WS api/permissions/template_users to return all permissions --- .../permission/ws/TemplateUsersAction.java | 125 ++++---- .../permission/ws/template_users-example.json | 12 +- .../permission/ws/PermissionsWsTest.java | 5 +- .../ws/TemplateUsersActionTest.java | 271 +++++++++++++----- .../template/PermissionTemplateDao.java | 29 +- .../template/PermissionTemplateMapper.java | 7 +- .../template/PermissionTemplateMapper.xml | 62 +++- .../UserWithPermissionTemplateDaoTest.java | 151 ++++------ .../users_with_permissions.xml | 3 +- 9 files changed, 415 insertions(+), 250 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/TemplateUsersAction.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/TemplateUsersAction.java index 7925b465429..fb82ff7dcc0 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/TemplateUsersAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/TemplateUsersAction.java @@ -19,25 +19,33 @@ */ package org.sonar.server.permission.ws; +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.stream.Collectors; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; -import org.sonar.api.server.ws.WebService.SelectionMode; +import org.sonar.api.utils.Paging; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.permission.OldPermissionQuery; +import org.sonar.db.permission.PermissionQuery; import org.sonar.db.permission.template.PermissionTemplateDto; -import org.sonar.db.permission.UserWithPermissionDto; +import org.sonar.db.permission.template.PermissionTemplateUserDto; +import org.sonar.db.user.UserDto; import org.sonar.server.user.UserSession; import org.sonarqube.ws.WsPermissions; -import org.sonarqube.ws.WsPermissions.OldUser; -import org.sonarqube.ws.WsPermissions.OldUsersWsResponse; - -import static java.lang.String.format; +import org.sonarqube.ws.WsPermissions.UsersWsResponse; + +import static org.sonar.api.server.ws.WebService.Param.PAGE; +import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; +import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY; +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.SEARCH_QUERY_MIN_LENGTH; import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser; -import static org.sonar.server.permission.ws.PermissionQueryParser.fromSelectionModeToMembership; import static org.sonar.server.permission.ws.PermissionRequestValidator.validateProjectPermission; import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectPermissionParameter; import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createTemplateParameters; @@ -61,19 +69,19 @@ public class TemplateUsersAction implements PermissionsWsAction { WebService.NewAction action = context .createAction("template_users") .setSince("5.2") - .setDescription( - format("Lists the users that have been granted the specified permission as individual users rather than through group affiliation on the chosen template.
" + - "If the query parameter '%s' is specified, the '%s' parameter is forced to '%s'.
" + - "It requires administration permissions to access.
", - Param.TEXT_QUERY, Param.SELECTED, SelectionMode.ALL.value())) - .addPagingParams(100) - .addSearchQuery("stas", "names") - .addSelectionModeParam() + .setDescription("Lists the users with their permission as individual users rather than through group affiliation on the chosen template.
" + + "This service defaults to all users, but can be limited to users with a specific permission by providing the desired permission.
" + + "It requires administration permissions to access.
") + .addPagingParams(DEFAULT_PAGE_SIZE, RESULTS_MAX_SIZE) .setInternal(true) .setResponseExample(getClass().getResource("template_users-example.json")) .setHandler(this); - createProjectPermissionParameter(action); + action.createParam(Param.TEXT_QUERY) + .setDescription("Limit search to user names that contain the supplied string. Must have at least %d characters.
" + + "When this parameter is not set, only users having at least one permission are returned.", SEARCH_QUERY_MIN_LENGTH) + .setExampleValue("eri"); + createProjectPermissionParameter(action).setRequired(false); createTemplateParameters(action); } @@ -85,58 +93,61 @@ public class TemplateUsersAction implements PermissionsWsAction { WsTemplateRef templateRef = WsTemplateRef.fromRequest(wsRequest); PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateRef); - OldPermissionQuery query = buildQuery(wsRequest, template); - WsPermissions.OldUsersWsResponse templateUsersResponse = buildResponse(dbSession, query, template); + PermissionQuery query = buildQuery(wsRequest, template); + int total = dbClient.permissionTemplateDao().countUserLoginsByQueryAndTemplate(dbSession, query, template.getId()); + Paging paging = Paging.forPageIndex(wsRequest.mandatoryParamAsInt(PAGE)).withPageSize(wsRequest.mandatoryParamAsInt(PAGE_SIZE)).andTotal(total); + List users = findUsers(dbSession, query, template); + List permissionTemplateUsers = dbClient.permissionTemplateDao().selectUserPermissionsByTemplateIdAndUserLogins(dbSession, template.getId(), + users.stream().map(UserDto::getLogin).collect(Collectors.toList())); + WsPermissions.UsersWsResponse templateUsersResponse = buildResponse(users, permissionTemplateUsers, paging); writeProtobuf(templateUsersResponse, wsRequest, wsResponse); } finally { dbClient.closeSession(dbSession); } } - private static OldPermissionQuery buildQuery(Request wsRequest, PermissionTemplateDto template) { - String permission = validateProjectPermission(wsRequest.mandatoryParam(PARAM_PERMISSION)); - - return OldPermissionQuery.builder() - .template(template.getUuid()) - .permission(permission) - .membership(fromSelectionModeToMembership(wsRequest.mandatoryParam(Param.SELECTED))) - .pageIndex(wsRequest.mandatoryParamAsInt(Param.PAGE)) - .pageSize(wsRequest.mandatoryParamAsInt(Param.PAGE_SIZE)) - .search(wsRequest.param(Param.TEXT_QUERY)) - .build(); - } - - private OldUsersWsResponse buildResponse(DbSession dbSession, OldPermissionQuery query, PermissionTemplateDto template) { - List usersWithPermission = dbClient.permissionTemplateDao().selectUsers(dbSession, query, template.getId(), query.pageOffset(), query.pageSize()); - int total = dbClient.permissionTemplateDao().countUsers(dbSession, query, template.getId()); - - OldUsersWsResponse.Builder responseBuilder = OldUsersWsResponse.newBuilder(); - for (UserWithPermissionDto userWithPermission : usersWithPermission) { - responseBuilder.addUsers(userDtoToUserResponse(userWithPermission)); + private static PermissionQuery buildQuery(Request wsRequest, PermissionTemplateDto template) { + String textQuery = wsRequest.param(TEXT_QUERY); + String permission = wsRequest.param(PARAM_PERMISSION); + PermissionQuery.Builder query = PermissionQuery.builder() + .setTemplate(template.getUuid()) + .setPermission(permission != null ? validateProjectPermission(permission) : null) + .setPageIndex(wsRequest.mandatoryParamAsInt(PAGE)) + .setPageSize(wsRequest.mandatoryParamAsInt(PAGE_SIZE)) + .setSearchQuery(textQuery); + if (textQuery == null) { + query.withPermissionOnly(); } + return query.build(); + } + private WsPermissions.UsersWsResponse buildResponse(List users, List permissionTemplateUsers, Paging paging) { + Multimap permissionsByUserId = TreeMultimap.create(); + permissionTemplateUsers.forEach(userPermission -> permissionsByUserId.put(userPermission.getUserId(), userPermission.getPermission())); + + UsersWsResponse.Builder responseBuilder = UsersWsResponse.newBuilder(); + users.forEach(user -> { + WsPermissions.User.Builder userResponse = responseBuilder.addUsersBuilder() + .setLogin(user.getLogin()) + .addAllPermissions(permissionsByUserId.get(user.getId())); + if (user.getEmail() != null) { + userResponse.setEmail(user.getEmail()); + } + if (user.getName() != null) { + userResponse.setName(user.getName()); + } + }); responseBuilder.getPagingBuilder() - .setPageIndex(query.pageIndex()) - .setPageSize(query.pageSize()) - .setTotal(total) + .setPageIndex(paging.pageIndex()) + .setPageSize(paging.pageSize()) + .setTotal(paging.total()) .build(); - return responseBuilder.build(); } - private static OldUser userDtoToUserResponse(UserWithPermissionDto userWithPermission) { - OldUser.Builder userBuilder = OldUser.newBuilder(); - userBuilder.setLogin(userWithPermission.getLogin()); - String email = userWithPermission.getEmail(); - if (email != null) { - userBuilder.setEmail(email); - } - String name = userWithPermission.getName(); - if (name != null) { - userBuilder.setName(name); - } - userBuilder.setSelected(userWithPermission.getPermission() != null); - - return userBuilder.build(); + public List findUsers(DbSession dbSession, PermissionQuery query, PermissionTemplateDto template) { + List orderedLogins = dbClient.permissionTemplateDao().selectUserLoginsByQueryAndTemplate(dbSession, query, template.getId()); + return Ordering.explicit(orderedLogins).onResultOf(UserDto::getLogin).immutableSortedCopy(dbClient.userDao().selectByLogins(dbSession, orderedLogins)); } + } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template_users-example.json b/server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template_users-example.json index 343d96563a0..2e21d9a21f8 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template_users-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template_users-example.json @@ -1,7 +1,7 @@ { "paging": { "pageIndex": 1, - "pageSize": 100, + "pageSize": 20, "total": 2 }, "users": [ @@ -9,14 +9,18 @@ "login": "admin", "name": "Administrator", "email": "admin@admin.com", - "selected": true + "permissions": [ + "codeviewer" + ] }, { "login": "george.orwell", "name": "George Orwell", "email": "george.orwell@1984.net", - "selected": true + "permissions": [ + "admin", + "codeviewer" + ] } ] } - diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsTest.java index 76943256ce7..2bd4726d54b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsTest.java @@ -28,6 +28,7 @@ import org.sonar.server.ws.WsTester; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION; public class PermissionsWsTest { @@ -62,7 +63,7 @@ public class PermissionsWsTest { assertThat(action.isPost()).isFalse(); assertThat(action.isInternal()).isTrue(); assertThat(action.since()).isEqualTo("5.2"); - assertThat(action.param(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION).isRequired()).isTrue(); + assertThat(action.param(PARAM_PERMISSION).isRequired()).isFalse(); } @Test @@ -73,7 +74,7 @@ public class PermissionsWsTest { assertThat(action.isPost()).isFalse(); assertThat(action.isInternal()).isTrue(); assertThat(action.since()).isEqualTo("5.2"); - assertThat(action.param(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION).isRequired()).isTrue(); + assertThat(action.param(PARAM_PERMISSION).isRequired()).isTrue(); } private WebService.Controller controller() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/TemplateUsersActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/TemplateUsersActionTest.java index 1adc1b4fcd6..724c06c0681 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/TemplateUsersActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/TemplateUsersActionTest.java @@ -22,14 +22,12 @@ package org.sonar.server.permission.ws; import java.io.IOException; import java.io.InputStream; import javax.annotation.Nullable; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.resources.Qualifiers; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; -import org.sonar.api.web.UserRole; import org.sonar.core.permission.GlobalPermissions; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -47,16 +45,20 @@ import org.sonar.server.tester.UserSessionRule; import org.sonar.server.usergroups.ws.UserGroupFinder; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; -import org.sonarqube.ws.WsPermissions.OldUsersWsResponse; +import org.sonarqube.ws.WsPermissions; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.api.web.UserRole.CODEVIEWER; +import static org.sonar.api.web.UserRole.ISSUE_ADMIN; +import static org.sonar.api.web.UserRole.USER; import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateDto; import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateUserDto; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.MediaTypes.PROTOBUF; -import static org.sonarqube.ws.WsPermissions.OldUsersWsResponse.parseFrom; - +import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION; +import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID; +import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME; public class TemplateUsersActionTest { @@ -66,154 +68,262 @@ public class TemplateUsersActionTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule public DbTester db = DbTester.create(System2.INSTANCE); + ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV"); + DbClient dbClient = db.getDbClient(); - final DbSession dbSession = db.getSession(); - WsActionTester ws; + DbSession dbSession = db.getSession(); - TemplateUsersAction underTest; + PermissionDependenciesFinder dependenciesFinder = new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient), new UserGroupFinder(dbClient), resourceTypes); - PermissionTemplateDto template1; - PermissionTemplateDto template2; + TemplateUsersAction underTest = new TemplateUsersAction(dbClient, userSession, dependenciesFinder); + WsActionTester ws = new WsActionTester(underTest); - @Before - public void setUp() { - PermissionDependenciesFinder dependenciesFinder = new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient), new UserGroupFinder(dbClient), resourceTypes); - underTest = new TemplateUsersAction(dbClient, userSession, dependenciesFinder); - ws = new WsActionTester(underTest); + @Test + public void search_for_users_with_response_example() { + setSysAdminUser(); - userSession.login("login").setGlobalPermissions(ADMIN); + 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")); + + PermissionTemplateDto template1 = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + + addUserToTemplate(newPermissionTemplateUser(CODEVIEWER, template1.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(CODEVIEWER, template1.getId(), user2.getId())); + addUserToTemplate(newPermissionTemplateUser(ADMIN, template1.getId(), user2.getId())); + + commit(); + + String result = newRequest(null, template1.getUuid()).execute().getInput(); + assertJson(result).isSimilarTo(getClass().getResource("template_users-example.json")); + } - template1 = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); - template2 = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2")); + @Test + public void search_for_users_by_template_name() throws IOException { + setSysAdminUser(); UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1")); UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2")); UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3")); - addUserToTemplate(newPermissionTemplateUser(UserRole.USER, template1.getId(), user1.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.USER, template1.getId(), user2.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.ISSUE_ADMIN, template1.getId(), user1.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.ISSUE_ADMIN, template1.getId(), user3.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.USER, template2.getId(), user1.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.USER, template2.getId(), user2.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.USER, template2.getId(), user3.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.ISSUE_ADMIN, template2.getId(), user1.getId())); + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId())); + PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2")); + addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId())); commit(); + + InputStream responseStream = newRequest(null, null) + .setParam(PARAM_TEMPLATE_NAME, template.getName()) + .setMediaType(PROTOBUF) + .execute().getInputStream(); + + WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream); + assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2", "login-3"); + assertThat(response.getUsers(0).getPermissionsList()).containsOnly("issueadmin", "user"); + assertThat(response.getUsers(1).getPermissionsList()).containsOnly("user"); + assertThat(response.getUsers(2).getPermissionsList()).containsOnly("issueadmin"); } @Test - public void search_for_users_with_response_example() { - 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")); - addUserToTemplate(newPermissionTemplateUser(UserRole.CODEVIEWER, template1.getId(), user1.getId())); - addUserToTemplate(newPermissionTemplateUser(UserRole.CODEVIEWER, template1.getId(), user2.getId())); + public void search_using_text_query() throws IOException { + setSysAdminUser(); + + UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1")); + UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2")); + UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3")); + + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId())); + + PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2")); + addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId())); commit(); - String result = newRequest(UserRole.CODEVIEWER, template1.getUuid()).execute().getInput(); + InputStream responseStream = newRequest(null, null) + .setParam(PARAM_TEMPLATE_NAME, template.getName()) + .setParam(WebService.Param.TEXT_QUERY, "ame-1") + .setMediaType(PROTOBUF) + .execute().getInputStream(); - assertJson(result).isSimilarTo(getClass().getResource("template_users-example.json")); + WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream); + assertThat(response.getUsersList()).extracting("login").containsOnly("login-1"); } @Test - public void search_for_users_by_template_name() throws IOException { - InputStream responseStream = newRequest(UserRole.USER, null) - .setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME, template1.getName()) - .setMediaType(PROTOBUF) - .execute().getInputStream(); + public void search_using_permission() throws IOException { + setSysAdminUser(); - OldUsersWsResponse response = parseFrom(responseStream); + UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1")); + UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2")); + UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3")); + + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId())); + + PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2")); + addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId())); + commit(); + InputStream responseStream = newRequest(USER, template.getUuid()) + .setMediaType(PROTOBUF) + .execute().getInputStream(); + WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream); assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2"); + assertThat(response.getUsers(0).getPermissionsList()).containsOnly("issueadmin", "user"); + assertThat(response.getUsers(1).getPermissionsList()).containsOnly("user"); } @Test - public void search_using_text_query() throws IOException { - InputStream responseStream = newRequest(UserRole.USER, null) - .setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME, template1.getName()) - .setParam(WebService.Param.TEXT_QUERY, "ame-1") + public void search_with_pagination() throws IOException { + setSysAdminUser(); + + UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1")); + UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2")); + UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3")); + + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId())); + + PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2")); + addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId())); + commit(); + + InputStream responseStream = newRequest(USER, null) + .setParam(PARAM_TEMPLATE_NAME, template.getName()) + .setParam(WebService.Param.SELECTED, "all") + .setParam(WebService.Param.PAGE, "2") + .setParam(WebService.Param.PAGE_SIZE, "1") .setMediaType(PROTOBUF) .execute().getInputStream(); - OldUsersWsResponse response = parseFrom(responseStream); - - assertThat(response.getUsersList()).extracting("login").containsOnly("login-1"); + WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream); + assertThat(response.getUsersList()).extracting("login").containsOnly("login-2"); } @Test - public void search_using_selected() throws IOException { - InputStream responseStream = newRequest(UserRole.USER, null) - .setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME, template1.getName()) - .setParam(WebService.Param.SELECTED, "all") + public void users_are_sorted_by_name() throws IOException { + setSysAdminUser(); + + UserDto user1 = insertUser(new UserDto().setLogin("login-2").setName("name-2")); + UserDto user2 = insertUser(new UserDto().setLogin("login-3").setName("name-3")); + UserDto user3 = insertUser(new UserDto().setLogin("login-1").setName("name-1")); + + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId())); + addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId())); + addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId())); + commit(); + + InputStream responseStream = newRequest(null, null) + .setParam(PARAM_TEMPLATE_NAME, template.getName()) .setMediaType(PROTOBUF) .execute().getInputStream(); - OldUsersWsResponse response = OldUsersWsResponse.parseFrom(responseStream); - + WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream); assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2", "login-3"); - assertThat(response.getUsers(2).getSelected()).isFalse(); } @Test - public void search_with_pagination() throws IOException { - InputStream responseStream = newRequest(UserRole.USER, null) - .setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME, template1.getName()) - .setParam(WebService.Param.SELECTED, "all") - .setParam(WebService.Param.PAGE, "2") - .setParam(WebService.Param.PAGE_SIZE, "1") + public void empty_result_when_no_user_on_template() throws IOException { + setSysAdminUser(); + + UserDto user = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1")); + + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + + PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2")); + addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user.getId())); + commit(); + + InputStream responseStream = newRequest(null, null) + .setParam(PARAM_TEMPLATE_NAME, template.getName()) .setMediaType(PROTOBUF) .execute().getInputStream(); - OldUsersWsResponse response = parseFrom(responseStream); - - assertThat(response.getUsersList()).extracting("login").containsOnly("login-2"); + WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream); + assertThat(response.getUsersList()).isEmpty(); } @Test public void fail_if_not_a_project_permission() throws IOException { + setSysAdminUser(); + + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + commit(); + expectedException.expect(BadRequestException.class); + newRequest(GlobalPermissions.PROVISIONING, template.getUuid()) + .execute(); + } + + @Test + public void fail_if_no_template_param() { + setSysAdminUser(); - newRequest(GlobalPermissions.PROVISIONING, template1.getUuid()) + expectedException.expect(BadRequestException.class); + newRequest(null, null) .execute(); } @Test public void fail_if_template_does_not_exist() { - expectedException.expect(NotFoundException.class); + setSysAdminUser(); - newRequest(UserRole.USER, "unknown-template-uuid") + expectedException.expect(NotFoundException.class); + newRequest(null, "unknown-template-uuid") .execute(); } @Test public void fail_if_template_uuid_and_name_provided() { - expectedException.expect(BadRequestException.class); + setSysAdminUser(); - newRequest(UserRole.USER, template1.getUuid()) - .setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME, template1.getName()) + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + commit(); + + expectedException.expect(BadRequestException.class); + newRequest(null, template.getUuid()) + .setParam(PARAM_TEMPLATE_NAME, template.getName()) .execute(); } @Test public void fail_if_not_logged_in() { - expectedException.expect(UnauthorizedException.class); userSession.anonymous(); - newRequest(UserRole.USER, template1.getUuid()).execute(); + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + commit(); + + expectedException.expect(UnauthorizedException.class); + newRequest(null, template.getUuid()).execute(); } @Test public void fail_if_insufficient_privileges() { - expectedException.expect(ForbiddenException.class); userSession.login("login"); - newRequest(UserRole.USER, template1.getUuid()).execute(); + PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1")); + commit(); + + expectedException.expect(ForbiddenException.class); + newRequest(null, template.getUuid()).execute(); } private UserDto insertUser(UserDto userDto) { - UserDto user = dbClient.userDao().insert(dbSession, userDto.setActive(true)); - return user; + return dbClient.userDao().insert(dbSession, userDto.setActive(true)); } private void addUserToTemplate(PermissionTemplateUserDto userRoleDto) { @@ -231,13 +341,18 @@ public class TemplateUsersActionTest { .setUserId(userId); } - private TestRequest newRequest(String permission, @Nullable String templateUuid) { + private TestRequest newRequest(@Nullable String permission, @Nullable String templateUuid) { TestRequest request = ws.newRequest(); - request.setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION, permission); + if (permission != null) { + request.setParam(PARAM_PERMISSION, permission); + } if (templateUuid != null) { - request.setParam(org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID, templateUuid); + request.setParam(PARAM_TEMPLATE_ID, templateUuid); } - return request; } + + private void setSysAdminUser() { + userSession.login("login").setGlobalPermissions(ADMIN); + } } diff --git a/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateDao.java b/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateDao.java index 667b708533c..f62df9e463f 100644 --- a/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateDao.java +++ b/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateDao.java @@ -19,6 +19,7 @@ */ package org.sonar.db.permission.template; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -36,11 +37,13 @@ import org.sonar.db.MyBatis; import org.sonar.db.permission.CountByProjectAndPermissionDto; import org.sonar.db.permission.GroupWithPermissionDto; import org.sonar.db.permission.OldPermissionQuery; +import org.sonar.db.permission.PermissionQuery; import org.sonar.db.permission.UserWithPermissionDto; import static java.lang.String.format; import static org.sonar.api.security.DefaultGroups.ANYONE; import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.db.DatabaseUtils.executeLargeInputs; import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput; public class PermissionTemplateDao implements Dao { @@ -55,15 +58,28 @@ public class PermissionTemplateDao implements Dao { this.system = system; } - /** - * @return a paginated list of users. - */ + @Deprecated public List selectUsers(DbSession session, OldPermissionQuery query, Long templateId, int offset, int limit) { return mapper(session).selectUsers(query, templateId, new RowBounds(offset, limit)); } - public int countUsers(DbSession session, OldPermissionQuery query, Long templateId) { - return mapper(session).countUsers(query, templateId); + /** + * @return a paginated list of user logins. + */ + public List selectUserLoginsByQueryAndTemplate(DbSession session, PermissionQuery query, long templateId) { + return mapper(session).selectUserLoginsByQueryAndTemplate(query, templateId, new RowBounds(query.getPageOffset(), query.getPageSize())); + } + + public int countUserLoginsByQueryAndTemplate(DbSession session, PermissionQuery query, long templateId) { + return mapper(session).countUserLoginsByQueryAndTemplate(query, templateId); + } + + public List selectUserPermissionsByTemplateIdAndUserLogins(DbSession dbSession, long templateId, List logins) { + return executeLargeInputs(logins, l -> mapper(dbSession).selectUserPermissionsByTemplateIdAndUserLogins(templateId, l)); + } + + public List selectUserPermissionsByTemplateId(DbSession dbSession, long templateId) { + return mapper(dbSession).selectUserPermissionsByTemplateIdAndUserLogins(templateId, Collections.emptyList()); } /** @@ -124,7 +140,7 @@ public class PermissionTemplateDao implements Dao { return null; } - List userPermissions = mapper.selectUserPermissionsByTemplateId(template.getId()); + List userPermissions = selectUserPermissionsByTemplateId(session, template.getId()); List groupPermissions = mapper.selectGroupPermissionsByTemplateId(template.getId()); PermissionTemplateCharacteristicMapper characteristicMapper = session.getMapper(PermissionTemplateCharacteristicMapper.class); List characteristics = characteristicMapper.selectByTemplateId(template.getId()); @@ -200,6 +216,7 @@ public class PermissionTemplateDao implements Dao { public void groupsCountByTemplateIdAndPermission(DbSession dbSession, List templateIds, ResultHandler resultHandler) { Map parameters = new HashMap<>(2); parameters.put(ANYONE_GROUP_PARAMETER, ANYONE); + executeLargeInputsWithoutOutput( templateIds, partitionedTemplateIds -> { diff --git a/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateMapper.java b/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateMapper.java index 6f3e5e2ad12..7b86fc0dc60 100644 --- a/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/permission/template/PermissionTemplateMapper.java @@ -27,6 +27,7 @@ import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.sonar.db.permission.GroupWithPermissionDto; import org.sonar.db.permission.OldPermissionQuery; +import org.sonar.db.permission.PermissionQuery; import org.sonar.db.permission.UserWithPermissionDto; /** @@ -50,7 +51,7 @@ public interface PermissionTemplateMapper { PermissionTemplateDto selectByUuid(String templateUuid); - List selectUserPermissionsByTemplateId(long templateId); + List selectUserPermissionsByTemplateIdAndUserLogins(@Param("templateId") long templateId, @Param("logins") List logins); List selectGroupPermissionsByTemplateId(long templateId); @@ -67,7 +68,9 @@ public interface PermissionTemplateMapper { PermissionTemplateDto selectByName(String name); - int countUsers(@Param("query") OldPermissionQuery query, @Param("templateId") long templateId); + List selectUserLoginsByQueryAndTemplate(@Param("query") PermissionQuery query, @Param("templateId") long templateId, RowBounds rowBounds); + + int countUserLoginsByQueryAndTemplate(@Param("query") PermissionQuery query, @Param("templateId") long templateId); int countGroups(@Param("query") OldPermissionQuery query, @Param("templateId") long templateId, @Param("anyoneGroup") String anyoneGroup, @Param("projectAdminPermission") String projectAdminPermission, @Nullable @Param("groupName") String groupName); diff --git a/sonar-db/src/main/resources/org/sonar/db/permission/template/PermissionTemplateMapper.xml b/sonar-db/src/main/resources/org/sonar/db/permission/template/PermissionTemplateMapper.xml index 23e49049240..d2f93bac737 100644 --- a/sonar-db/src/main/resources/org/sonar/db/permission/template/PermissionTemplateMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/permission/template/PermissionTemplateMapper.xml @@ -66,15 +66,42 @@ WHERE group_id = #{groupId} - + SELECT u.login FROM + (SELECT DISTINCT u.login AS login, u.name AS name + + ) u ORDER BY u.name - + SELECT count(1) + FROM ( + SELECT DISTINCT u.login AS login, u.name AS name + ) u + + + + FROM users u + LEFT JOIN perm_templates_users ptu ON ptu.user_id=u.id AND ptu.template_id=#{templateId} + + u.active = ${_true} + + AND lower(u.name) like #{query.searchQueryToSql} ESCAPE '/' + + + and ptu.permission_reference is not null + + and ptu.permission_reference=#{query.permission} + + + + + + @@ -107,9 +134,9 @@ AND ptg.template_id=#{templateId} - UNION - -- Add Anyone group permission - SELECT + UNION + -- Add Anyone group permission + SELECT #{anyoneGroup} as name, NULL as description, (select ptg.permission_reference @@ -119,7 +146,7 @@ AND ptg.template_id=#{templateId} AND ptg.group_id IS NULL ) as permission - FROM groups g + FROM groups g ) groups @@ -218,8 +245,7 @@ WHERE UPPER(name)=#{templateName} - + SELECT + FROM perm_templates_users ptu INNER JOIN users u ON u.id = ptu.user_id AND u.active = ${_true} - WHERE ptu.template_id = #{templateId} + + AND ptu.template_id = #{templateId} + + AND u.login IN + #{login} + + +