diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-03-17 17:14:45 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-03-21 13:05:50 +0100 |
commit | 5acc864451b7a727c55697093fbf0439af6994bf (patch) | |
tree | 4a63fa16ae21c5a73dd181e5fcc1ec1f4fd435fc | |
parent | 14cbaf7f117d8e6fac992459a4e32089b1a81fbe (diff) | |
download | sonarqube-5acc864451b7a727c55697093fbf0439af6994bf.tar.gz sonarqube-5acc864451b7a727c55697093fbf0439af6994bf.zip |
SONAR-8968 Add organization parameter in api/users/groups
15 files changed, 252 insertions, 93 deletions
diff --git a/it/it-tests/src/test/java/it/organization/OrganizationTest.java b/it/it-tests/src/test/java/it/organization/OrganizationTest.java index dcde71a0995..cf1783c879c 100644 --- a/it/it-tests/src/test/java/it/organization/OrganizationTest.java +++ b/it/it-tests/src/test/java/it/organization/OrganizationTest.java @@ -312,7 +312,7 @@ public class OrganizationTest { } @Test - public void deleting_an_organization_also_deletes_group_permissions_and_projects_and_check_security() { + public void deleting_an_organization_also_deletes_projects_and_check_security() { verifyNoExtraOrganization(); String orgKeyAndName = "org-key"; @@ -343,10 +343,6 @@ public class OrganizationTest { adminOrganizationService.delete(orgKeyAndName); expect404HttpError(() -> searchSampleProject(orgKeyAndName, componentsService)); - assertThat(groupManagement.getUserGroups("bob").getGroups()) - .extracting(Groups.Group::getName) - .doesNotContain("grp1", "grp2"); - verifyNoExtraOrganization(); } diff --git a/it/it-tests/src/test/java/util/user/UserRule.java b/it/it-tests/src/test/java/util/user/UserRule.java index 51dc8b95683..038e0f150eb 100644 --- a/it/it-tests/src/test/java/util/user/UserRule.java +++ b/it/it-tests/src/test/java/util/user/UserRule.java @@ -218,8 +218,7 @@ public class UserRule extends ExternalResource implements GroupManagement { .setParam("login", userLogin) .setParam("selected", "selected"); addOrganizationParam(request); - WsResponse response = adminWsClient().wsConnector().call(request); - assertThat(response.code()).isEqualTo(200); + WsResponse response = adminWsClient().wsConnector().call(request).failIfNotSuccessful(); return Groups.parse(response.content()); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipDao.java index 4c30022d770..e3077809c0f 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipDao.java @@ -36,12 +36,12 @@ import static org.sonar.db.DatabaseUtils.executeLargeInputs; public class GroupMembershipDao implements Dao { public List<GroupMembershipDto> selectGroups(DbSession session, GroupMembershipQuery query, Integer userId, int offset, int limit) { - Map<String, Object> params = ImmutableMap.of("query", query, "userId", userId); + Map<String, Object> params = ImmutableMap.of("query", query, "userId", userId, "organizationUuid", query.organizationUuid()); return mapper(session).selectGroups(params, new RowBounds(offset, limit)); } public int countGroups(DbSession session, GroupMembershipQuery query, Integer userId) { - Map<String, Object> params = ImmutableMap.of("query", query, "userId", userId); + Map<String, Object> params = ImmutableMap.of("query", query, "userId", userId, "organizationUuid", query.organizationUuid()); return mapper(session).countGroups(params); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipQuery.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipQuery.java index 165a3bc52f1..6b1dee75f06 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipQuery.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/GroupMembershipQuery.java @@ -27,6 +27,7 @@ import org.apache.commons.lang.StringUtils; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; public class GroupMembershipQuery { @@ -38,6 +39,7 @@ public class GroupMembershipQuery { public static final String OUT = "OUT"; public static final Set<String> AVAILABLE_MEMBERSHIP = ImmutableSet.of(ANY, IN, OUT); + private final String organizationUuid; private final String membership; private final String groupSearch; @@ -51,9 +53,10 @@ public class GroupMembershipQuery { // index of selected page. Start with 1. private final int pageIndex; - private GroupMembershipQuery(Builder builder) { + private GroupMembershipQuery(Builder builder, String organizationUuid) { this.membership = builder.membership; this.groupSearch = builder.groupSearch; + this.organizationUuid = organizationUuid; this.groupSearchSql = groupSearchToSql(groupSearch); this.pageSize = builder.pageSize; @@ -70,6 +73,10 @@ public class GroupMembershipQuery { return sql; } + public String organizationUuid() { + return organizationUuid; + } + @CheckForNull public String membership() { return membership; @@ -96,15 +103,22 @@ public class GroupMembershipQuery { } public static class Builder { + private String organizationUuid; private String membership; private String groupSearch; private Integer pageIndex = DEFAULT_PAGE_INDEX; + private Integer pageSize = DEFAULT_PAGE_SIZE; private Builder() { } + public Builder organizationUuid(String organizationUuid) { + this.organizationUuid = organizationUuid; + return this; + } + public Builder membership(@Nullable String membership) { this.membership = membership; return this; @@ -141,10 +155,11 @@ public class GroupMembershipQuery { } public GroupMembershipQuery build() { + checkNotNull(organizationUuid, "Organization uuid cant be null"); initMembership(); initPageIndex(); initPageSize(); - return new GroupMembershipQuery(this); + return new GroupMembershipQuery(this, organizationUuid); } } } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/user/GroupMembershipMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/user/GroupMembershipMapper.xml index 57bbdba073c..a24001488b7 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/user/GroupMembershipMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/user/GroupMembershipMapper.xml @@ -7,6 +7,7 @@ FROM groups g LEFT JOIN groups_users gu ON gu.group_id=g.id AND gu.user_id=#{userId} <where> + AND g.organization_uuid=#{organizationUuid} <choose> <when test="query.membership() == 'IN'"> AND gu.user_id IS NOT NULL diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipDaoTest.java index 1fcb01f82c8..4585ef0a145 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipDaoTest.java @@ -71,17 +71,27 @@ public class GroupMembershipDaoTest { db.users().insertMember(group2, user2); // user1 is member of 3 groups - assertThat(underTest.countGroups(db.getSession(), builder().membership(IN).build(), user1.getId())).isEqualTo(3); - assertThat(underTest.countGroups(db.getSession(), builder().membership(OUT).build(), user1.getId())).isZero(); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user1.getId())).isEqualTo(3); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), user1.getId())).isZero(); // user2 is member of 1 group on 3 - assertThat(underTest.countGroups(db.getSession(), builder().membership(IN).build(), user2.getId())).isEqualTo(1); - assertThat(underTest.countGroups(db.getSession(), builder().membership(OUT).build(), user2.getId())).isEqualTo(2); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user2.getId())).isEqualTo(1); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), user2.getId())).isEqualTo(2); // user3 is member of 0 group - assertThat(underTest.countGroups(db.getSession(), builder().membership(IN).build(), user3.getId())).isZero(); - assertThat(underTest.countGroups(db.getSession(), builder().membership(OUT).build(), user3.getId())).isEqualTo(3); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user3.getId())).isZero(); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), user3.getId())).isEqualTo(3); // unknown user is member of 0 group - assertThat(underTest.countGroups(db.getSession(), builder().membership(IN).build(), 999)).isZero(); - assertThat(underTest.countGroups(db.getSession(), builder().membership(OUT).build(), 999)).isEqualTo(3); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), 999)).isZero(); + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), 999)).isEqualTo(3); + } + + @Test + public void count_groups_only_from_given_organization() throws Exception { + OrganizationDto otherOrganization = db.organizations().insert(); + GroupDto otherGroup = db.users().insertGroup(otherOrganization, "sonar-administrators-other_orga"); + db.users().insertMember(group1, user1); + db.users().insertMember(otherGroup, user1); + + assertThat(underTest.countGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user1.getId())).isEqualTo(1); } @Test @@ -92,17 +102,27 @@ public class GroupMembershipDaoTest { db.users().insertMember(group2, user2); // user1 is member of 3 groups - assertThat(underTest.selectGroups(db.getSession(), builder().membership(IN).build(), user1.getId(), 0, 10)).hasSize(3); - assertThat(underTest.selectGroups(db.getSession(), builder().membership(OUT).build(), user1.getId(), 0, 10)).isEmpty(); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user1.getId(), 0, 10)).hasSize(3); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), user1.getId(), 0, 10)).isEmpty(); // user2 is member of 1 group on 3 - assertThat(underTest.selectGroups(db.getSession(), builder().membership(IN).build(), user2.getId(), 0, 10)).hasSize(1); - assertThat(underTest.selectGroups(db.getSession(), builder().membership(OUT).build(), user2.getId(), 0, 10)).hasSize(2); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user2.getId(), 0, 10)).hasSize(1); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), user2.getId(), 0, 10)).hasSize(2); // user3 is member of 0 group - assertThat(underTest.selectGroups(db.getSession(), builder().membership(IN).build(), user3.getId(), 0, 10)).isEmpty(); - assertThat(underTest.selectGroups(db.getSession(), builder().membership(OUT).build(), user3.getId(), 0, 10)).hasSize(3); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user3.getId(), 0, 10)).isEmpty(); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), user3.getId(), 0, 10)).hasSize(3); // unknown user is member of 0 group - assertThat(underTest.selectGroups(db.getSession(), builder().membership(IN).build(), 999, 0, 10)).isEmpty(); - assertThat(underTest.selectGroups(db.getSession(), builder().membership(OUT).build(), 999, 0, 10)).hasSize(3); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), 999, 0, 10)).isEmpty(); + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(OUT).build(), 999, 0, 10)).hasSize(3); + } + + @Test + public void select_groups_only_from_given_organization() { + OrganizationDto otherOrganization = db.organizations().insert(); + GroupDto otherGroup = db.users().insertGroup(otherOrganization, "sonar-administrators-other_orga"); + db.users().insertMember(group1, user1); + db.users().insertMember(otherGroup, user1); + + assertThat(underTest.selectGroups(db.getSession(), builder().organizationUuid(organizationDto.getUuid()).membership(IN).build(), user1.getId(), 0, 10)).hasSize(1); } @Test diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipQueryTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipQueryTest.java index efab0b1935b..34fb8d5adc0 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipQueryTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/user/GroupMembershipQueryTest.java @@ -19,24 +19,53 @@ */ package org.sonar.db.user; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; public class GroupMembershipQueryTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void create_query() throws Exception { + GroupMembershipQuery underTest = GroupMembershipQuery.builder() + .groupSearch("sonar-users") + .membership(GroupMembershipQuery.IN) + .pageIndex(2) + .pageSize(10) + .organizationUuid("organization_uuid") + .build(); + + assertThat(underTest.groupSearch()).isEqualTo("sonar-users"); + assertThat(underTest.membership()).isEqualTo("IN"); + assertThat(underTest.pageIndex()).isEqualTo(2); + assertThat(underTest.pageSize()).isEqualTo(10); + assertThat(underTest.organizationUuid()).isEqualTo("organization_uuid"); + } + + @Test + public void fail_on_null_organization() { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("Organization uuid cant be null"); + + GroupMembershipQuery.builder() + .organizationUuid(null) + .build(); + } + @Test public void fail_on_invalid_membership() { - GroupMembershipQuery.Builder builder = GroupMembershipQuery.builder(); - builder.membership("unknwown"); - - try { - builder.build(); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Membership is not valid (got unknwown). Availables values are [ANY, IN, OUT]"); - } + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Membership is not valid (got unknwown). Availables values are [ANY, IN, OUT]"); + + GroupMembershipQuery.builder() + .organizationUuid("organization_uuid") + .membership("unknwown") + .build(); } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java index f3489463912..c3fee7a2912 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java @@ -417,7 +417,7 @@ public class UserDaoTest { assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setKey(property.getKey()).build(), session)).isEmpty(); assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(session, user.getId(), db.getDefaultOrganization().getUuid())).isEmpty(); - assertThat(dbClient.groupMembershipDao().countGroups(session, builder().membership(IN).build(), user.getId())).isZero(); + assertThat(dbClient.groupMembershipDao().countGroups(session, builder().organizationUuid(db.getDefaultOrganization().getUuid()).membership(IN).build(), user.getId())).isZero(); } @Test diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java index e13adec5c81..e6691c3a46e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java @@ -20,6 +20,8 @@ package org.sonar.server.user.ws; import java.util.List; +import java.util.Optional; +import javax.annotation.Nullable; import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -30,9 +32,12 @@ import org.sonar.api.utils.Paging; import org.sonar.core.util.Protobuf; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.permission.OrganizationPermission; import org.sonar.db.user.GroupMembershipDto; import org.sonar.db.user.GroupMembershipQuery; import org.sonar.db.user.UserDto; +import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.user.UserSession; import org.sonarqube.ws.WsUsers.GroupsWsResponse; import org.sonarqube.ws.WsUsers.GroupsWsResponse.Group; @@ -44,17 +49,21 @@ import static org.sonar.api.server.ws.WebService.Param.SELECTED; import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY; import static org.sonar.api.utils.Paging.forPageIndex; import static org.sonar.server.ws.WsUtils.checkFound; +import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_ORGANIZATION; public class GroupsAction implements UsersWsAction { private final DbClient dbClient; private final UserSession userSession; + private final DefaultOrganizationProvider defaultOrganizationProvider; - public GroupsAction(DbClient dbClient, UserSession userSession) { + public GroupsAction(DbClient dbClient, UserSession userSession, DefaultOrganizationProvider defaultOrganizationProvider) { this.dbClient = dbClient; this.userSession = userSession; + this.defaultOrganizationProvider = defaultOrganizationProvider; } @Override @@ -73,26 +82,34 @@ public class GroupsAction implements UsersWsAction { .setDescription("A user login") .setExampleValue("admin") .setRequired(true); + + action.createParam(PARAM_ORGANIZATION) + .setDescription("Organization key") + .setExampleValue("my-org") + .setInternal(true) + .setSince("6.4"); } @Override public void handle(Request request, Response response) throws Exception { - userSession.checkLoggedIn().checkIsSystemAdministrator(); GroupsWsResponse groupsWsResponse = doHandle(toGroupsRequest(request)); writeProtobuf(groupsWsResponse, request, response); } private GroupsWsResponse doHandle(GroupsRequest request) { - GroupMembershipQuery query = GroupMembershipQuery.builder() - .login(request.getLogin()) - .groupSearch(request.getQuery()) - .membership(getMembership(request.getSelected())) - .pageIndex(request.getPage()) - .pageSize(request.getPageSize()) - .build(); try (DbSession dbSession = dbClient.openSession(false)) { + OrganizationDto organization = findOrganizationByKey(dbSession, request.getOrganization()); + userSession.checkPermission(OrganizationPermission.ADMINISTER, organization); + String login = request.getLogin(); + GroupMembershipQuery query = GroupMembershipQuery.builder() + .organizationUuid(organization.getUuid()) + .groupSearch(request.getQuery()) + .membership(getMembership(request.getSelected())) + .pageIndex(request.getPage()) + .pageSize(request.getPageSize()) + .build(); UserDto user = checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, login), "Unknown user: %s", login); int total = dbClient.groupMembershipDao().countGroups(dbSession, query, user.getId()); Paging paging = forPageIndex(query.pageIndex()).withPageSize(query.pageSize()).andTotal(total); @@ -101,9 +118,17 @@ public class GroupsAction implements UsersWsAction { } } + private OrganizationDto findOrganizationByKey(DbSession dbSession, @Nullable String key) { + String effectiveKey = key == null ? defaultOrganizationProvider.get().getKey() : key; + Optional<OrganizationDto> org = dbClient.organizationDao().selectByKey(dbSession, effectiveKey); + checkFoundWithOptional(org, "No organization with key '%s'", key); + return org.get(); + } + private static GroupsRequest toGroupsRequest(Request request) { return GroupsRequest.builder() .setLogin(request.mandatoryParam(PARAM_LOGIN)) + .setOrganization(request.param(PARAM_ORGANIZATION)) .setSelected(request.mandatoryParam(SELECTED)) .setQuery(request.param(TEXT_QUERY)) .setPage(request.mandatoryParamAsInt(PAGE)) diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java index 99b59f5ee3b..205d54bce0b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java @@ -26,12 +26,13 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; -import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; @@ -41,59 +42,36 @@ import org.sonarqube.ws.WsUsers.GroupsWsResponse; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.Mockito.mock; import static org.sonar.api.server.ws.WebService.SelectionMode.ALL; import static org.sonar.api.server.ws.WebService.SelectionMode.DESELECTED; import static org.sonar.api.server.ws.WebService.SelectionMode.SELECTED; +import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; import static org.sonar.db.user.GroupTesting.newGroupDto; import static org.sonar.db.user.UserTesting.newUserDto; import static org.sonar.test.JsonAssert.assertJson; public class GroupsActionTest { - private System2 system2 = mock(System2.class); + private static final String USER_LOGIN = "john"; @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule - public DbTester db = DbTester.create(system2); + public DbTester db = DbTester.create(); @Rule - public UserSessionRule userSession = UserSessionRule.standalone().logIn().setSystemAdministrator(); + public UserSessionRule userSession = UserSessionRule.standalone().logIn().setRoot(); - private WsActionTester ws = new WsActionTester(new GroupsAction(db.getDbClient(), userSession)); + private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - @Test - public void fail_on_unknown_user() throws Exception { - expectedException.expect(NotFoundException.class); - - call(ws.newRequest().setParam("login", "john")); - } - - @Test - public void fail_on_disabled_user() throws Exception { - UserDto userDto = db.users().insertUser(user -> user.setActive(false)); - - expectedException.expect(NotFoundException.class); - - call(ws.newRequest().setParam("login", userDto.getLogin())); - } - - @Test - public void fail_on_missing_permission() throws Exception { - userSession.logIn("not-admin"); - - expectedException.expect(ForbiddenException.class); - - call(ws.newRequest().setParam("login", "john")); - } + private WsActionTester ws = new WsActionTester(new GroupsAction(db.getDbClient(), userSession, defaultOrganizationProvider)); @Test public void empty_groups() throws Exception { insertUser(); - GroupsWsResponse response = call(ws.newRequest().setParam("login", "john")); + GroupsWsResponse response = call(ws.newRequest().setParam("login", USER_LOGIN)); assertThat(response.getGroupsList()).isEmpty(); } @@ -105,7 +83,7 @@ public class GroupsActionTest { GroupDto adminGroup = insertGroup("sonar-admins", "Sonar Admins"); addUserToGroup(user, usersGroup); - GroupsWsResponse response = call(ws.newRequest().setParam("login", "john").setParam(Param.SELECTED, ALL.value())); + GroupsWsResponse response = call(ws.newRequest().setParam("login", USER_LOGIN).setParam(Param.SELECTED, ALL.value())); assertThat(response.getGroupsList()) .extracting(GroupsWsResponse.Group::getId, GroupsWsResponse.Group::getName, GroupsWsResponse.Group::getDescription, GroupsWsResponse.Group::getSelected) @@ -121,7 +99,7 @@ public class GroupsActionTest { insertGroup("sonar-admins", "Sonar Admins"); addUserToGroup(user, usersGroup); - GroupsWsResponse response = call(ws.newRequest().setParam("login", "john").setParam(Param.SELECTED, SELECTED.value())); + GroupsWsResponse response = call(ws.newRequest().setParam("login", USER_LOGIN).setParam(Param.SELECTED, SELECTED.value())); assertThat(response.getGroupsList()) .extracting(GroupsWsResponse.Group::getId, GroupsWsResponse.Group::getName, GroupsWsResponse.Group::getDescription, GroupsWsResponse.Group::getSelected) @@ -135,7 +113,7 @@ public class GroupsActionTest { insertGroup("sonar-admins", "Sonar Admins"); addUserToGroup(user, usersGroup); - GroupsWsResponse response = call(ws.newRequest().setParam("login", "john")); + GroupsWsResponse response = call(ws.newRequest().setParam("login", USER_LOGIN)); assertThat(response.getGroupsList()) .extracting(GroupsWsResponse.Group::getId, GroupsWsResponse.Group::getName, GroupsWsResponse.Group::getDescription, GroupsWsResponse.Group::getSelected) @@ -149,7 +127,7 @@ public class GroupsActionTest { GroupDto adminGroup = insertGroup("sonar-admins", "Sonar Admins"); addUserToGroup(user, usersGroup); - GroupsWsResponse response = call(ws.newRequest().setParam("login", "john").setParam(Param.SELECTED, DESELECTED.value())); + GroupsWsResponse response = call(ws.newRequest().setParam("login", USER_LOGIN).setParam(Param.SELECTED, DESELECTED.value())); assertThat(response.getGroupsList()) .extracting(GroupsWsResponse.Group::getId, GroupsWsResponse.Group::getName, GroupsWsResponse.Group::getDescription, GroupsWsResponse.Group::getSelected) @@ -175,7 +153,7 @@ public class GroupsActionTest { addUserToGroup(user, groupDto); } - GroupsWsResponse response = call(ws.newRequest().setParam("login", "john") + GroupsWsResponse response = call(ws.newRequest().setParam("login", USER_LOGIN) .setParam(Param.PAGE_SIZE, "3") .setParam(Param.PAGE, "2") .setParam(Param.SELECTED, ALL.value())); @@ -193,13 +171,80 @@ public class GroupsActionTest { GroupDto adminGroup = insertGroup("sonar-admins", "Sonar Admins"); addUserToGroup(user, usersGroup); - assertThat(call(ws.newRequest().setParam("login", "john").setParam("q", "admin").setParam(Param.SELECTED, ALL.value())).getGroupsList()) + assertThat(call(ws.newRequest().setParam("login", USER_LOGIN).setParam("q", "admin").setParam(Param.SELECTED, ALL.value())).getGroupsList()) .extracting(GroupsWsResponse.Group::getName).containsOnly(adminGroup.getName()); - assertThat(call(ws.newRequest().setParam("login", "john").setParam("q", "users").setParam(Param.SELECTED, ALL.value())).getGroupsList()) + assertThat(call(ws.newRequest().setParam("login", USER_LOGIN).setParam("q", "users").setParam(Param.SELECTED, ALL.value())).getGroupsList()) .extracting(GroupsWsResponse.Group::getName).containsOnly(usersGroup.getName()); } @Test + public void return_groups_from_given_organization() throws Exception { + UserDto user = insertUser(); + OrganizationDto organizationDto = db.organizations().insert(); + OrganizationDto otherOrganizationDto = db.organizations().insert(); + GroupDto group = db.users().insertGroup(organizationDto, "group1"); + GroupDto otherGroup = db.users().insertGroup(otherOrganizationDto, "group2"); + addUserToGroup(user, group); + addUserToGroup(user, otherGroup); + + GroupsWsResponse response = call(ws.newRequest() + .setParam("login", USER_LOGIN) + .setParam("organization", organizationDto.getKey()) + .setParam(Param.SELECTED, ALL.value())); + + assertThat(response.getGroupsList()) + .extracting(GroupsWsResponse.Group::getId, GroupsWsResponse.Group::getName, GroupsWsResponse.Group::getDescription, GroupsWsResponse.Group::getSelected) + .containsOnly(tuple(group.getId().longValue(), group.getName(), group.getDescription(), true)); + } + + @Test + public void fail_on_unknown_user() throws Exception { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Unknown user: john"); + + call(ws.newRequest().setParam("login", USER_LOGIN)); + } + + @Test + public void fail_on_disabled_user() throws Exception { + UserDto userDto = db.users().insertUser(user -> user.setLogin("disabled").setActive(false)); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Unknown user: disabled"); + + call(ws.newRequest().setParam("login", userDto.getLogin())); + } + + @Test + public void fail_on_unknown_organization() throws Exception { + insertUser(); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("No organization with key 'unknown'"); + + call(ws.newRequest().setParam("login", USER_LOGIN).setParam("organization", "unknown")); + } + + @Test + public void fail_on_missing_permission() throws Exception { + OrganizationDto organizationDto = db.organizations().insert(); + userSession.logIn().addPermission(ADMINISTER, organizationDto); + + expectedException.expect(ForbiddenException.class); + + call(ws.newRequest().setParam("login", USER_LOGIN)); + } + + @Test + public void fail_when_no_permission() throws Exception { + userSession.logIn("not-admin"); + + expectedException.expect(ForbiddenException.class); + + call(ws.newRequest().setParam("login", USER_LOGIN)); + } + + @Test public void test_json_example() { UserDto user = insertUser(); GroupDto usersGroup = insertGroup("sonar-users", "Sonar Users"); @@ -208,7 +253,7 @@ public class GroupsActionTest { String response = ws.newRequest() .setMediaType(MediaTypes.JSON) - .setParam("login", "john") + .setParam("login", USER_LOGIN) .setParam(Param.SELECTED, ALL.value()) .setParam(Param.PAGE_SIZE, "25") .setParam(Param.PAGE, "1") @@ -225,14 +270,21 @@ public class GroupsActionTest { assertThat(action.isInternal()).isFalse(); assertThat(action.responseExampleAsString()).isNotEmpty(); - assertThat(action.params()).extracting(Param::key).containsOnly("p", "q", "ps", "login", "selected"); + assertThat(action.params()).extracting(Param::key).containsOnly("p", "q", "ps", "login", "selected", "organization"); WebService.Param qualifiers = action.param("login"); assertThat(qualifiers.isRequired()).isTrue(); + + WebService.Param organization = action.param("organization"); + assertThat(organization.isRequired()).isFalse(); + assertThat(organization.description()).isEqualTo("Organization key"); + assertThat(organization.isInternal()).isTrue(); + assertThat(organization.exampleValue()).isEqualTo("my-org"); + assertThat(organization.since()).isEqualTo("6.4"); } private GroupDto insertGroup(String name, String description) { - return db.users().insertGroup(newGroupDto().setName(name).setDescription(description)); + return db.users().insertGroup(newGroupDto().setName(name).setDescription(description).setOrganizationUuid(db.getDefaultOrganization().getUuid())); } private void addUserToGroup(UserDto user, GroupDto usersGroup) { @@ -243,7 +295,7 @@ public class GroupsActionTest { return db.users().insertUser(newUserDto() .setActive(true) .setEmail("john@email.com") - .setLogin("john") + .setLogin(USER_LOGIN) .setName("John") .setScmAccounts(singletonList("jn"))); } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/GroupsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/GroupsRequest.java index 4b44f65ff43..161a388e385 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/GroupsRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/GroupsRequest.java @@ -30,6 +30,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; public class GroupsRequest { private final String login; + private final String organization; private final String query; private final String selected; private final Integer page; @@ -37,6 +38,7 @@ public class GroupsRequest { private GroupsRequest(Builder builder) { this.login = builder.login; + this.organization = builder.organization; this.query = builder.query; this.selected = builder.selected; this.page = builder.page; @@ -48,6 +50,11 @@ public class GroupsRequest { } @CheckForNull + public String getOrganization() { + return organization; + } + + @CheckForNull public String getQuery() { return query; } @@ -73,6 +80,7 @@ public class GroupsRequest { public static class Builder { private String login; + private String organization; private String query; private String selected; private Integer page; @@ -87,6 +95,11 @@ public class GroupsRequest { return this; } + public Builder setOrganization(@Nullable String organization) { + this.organization = organization; + return this; + } + public Builder setQuery(@Nullable String query) { this.query = query; return this; diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java index 1a55512f6e0..d984c5ea55b 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java @@ -37,6 +37,7 @@ import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOCAL; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_PASSWORD; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNT; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SELECTED; @@ -69,6 +70,7 @@ public class UsersService extends BaseService { public GroupsWsResponse groups(GroupsRequest request) { return call(new GetRequest(path(ACTION_GROUPS)) .setParam(PARAM_LOGIN, request.getLogin()) + .setParam(PARAM_ORGANIZATION, request.getOrganization()) .setParam(PARAM_SELECTED, request.getSelected()) .setParam(TEXT_QUERY, request.getQuery()) .setParam(PAGE, request.getPage()) diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java index cf1946786b3..ba674caf9d3 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java @@ -27,6 +27,7 @@ public class UsersWsParameters { public static final String ACTION_UPDATE = "update"; public static final String ACTION_GROUPS = "groups"; + public static final String PARAM_ORGANIZATION = "organization"; public static final String PARAM_LOGIN = "login"; public static final String PARAM_PASSWORD = "password"; public static final String PARAM_NAME = "name"; diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/GroupsRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/GroupsRequestTest.java index 082e5f720b6..58270e89608 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/GroupsRequestTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/GroupsRequestTest.java @@ -37,6 +37,7 @@ public class GroupsRequestTest { public void create_request() { GroupsRequest result = underTest .setLogin("john") + .setOrganization("orga-uuid") .setSelected("all") .setQuery("sonar-users") .setPage(10) @@ -44,6 +45,7 @@ public class GroupsRequestTest { .build(); assertThat(result.getLogin()).isEqualTo("john"); + assertThat(result.getOrganization()).isEqualTo("orga-uuid"); assertThat(result.getSelected()).isEqualTo("all"); assertThat(result.getQuery()).isEqualTo("sonar-users"); assertThat(result.getPage()).isEqualTo(10); @@ -52,9 +54,12 @@ public class GroupsRequestTest { @Test public void create_request_wih_minimal_fields() { - GroupsRequest result = underTest.setLogin("john").build(); + GroupsRequest result = underTest + .setLogin("john") + .build(); assertThat(result.getLogin()).isEqualTo("john"); + assertThat(result.getOrganization()).isNull(); assertThat(result.getSelected()).isNull(); assertThat(result.getQuery()).isNull(); assertThat(result.getPage()).isNull(); @@ -66,9 +71,7 @@ public class GroupsRequestTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Login is mandatory and must not be empty"); - underTest - .setLogin("") - .build(); + underTest.setLogin("").build(); } @Test diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java index 37902de632c..c92f7619ffe 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java @@ -36,6 +36,7 @@ import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOCAL; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_PASSWORD; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNT; import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SELECTED; @@ -90,6 +91,7 @@ public class UsersServiceTest { public void groups() { underTest.groups(GroupsRequest.builder() .setLogin("john") + .setOrganization("orga-uuid") .setSelected("all") .setQuery("sonar-users") .setPage(10) @@ -99,6 +101,7 @@ public class UsersServiceTest { assertThat(serviceTester.getGetParser()).isSameAs(GroupsWsResponse.parser()); serviceTester.assertThat(serviceTester.getGetRequest()) .hasParam(PARAM_LOGIN, "john") + .hasParam(PARAM_ORGANIZATION, "orga-uuid") .hasParam(PARAM_SELECTED, "all") .hasParam(TEXT_QUERY, "sonar-users") .hasParam(PAGE, 10) |