diff options
author | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2015-05-05 15:38:14 +0200 |
---|---|---|
committer | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2015-05-07 16:40:09 +0200 |
commit | 912e9886ae4a982781c99afd7881dd9b0e934565 (patch) | |
tree | 020d8a2efeb1ccc2a73253e5886bb6a755f96399 /server | |
parent | f7c5f42cf3ca81ff948ae08afe50d15c09412bfc (diff) | |
download | sonarqube-912e9886ae4a982781c99afd7881dd9b0e934565.tar.gz sonarqube-912e9886ae4a982781c99afd7881dd9b0e934565.zip |
SONAR-6470 New Java WS to show a user's groups
Diffstat (limited to 'server')
13 files changed, 412 insertions, 0 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java index d3340efd5fe..78fc76fde3f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java +++ b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java @@ -34,6 +34,7 @@ import org.sonar.core.technicaldebt.db.CharacteristicDao; import org.sonar.core.template.LoadedTemplateDao; import org.sonar.core.user.AuthorDao; import org.sonar.core.user.AuthorizationDao; +import org.sonar.core.user.GroupMembershipDao; import org.sonar.server.activity.db.ActivityDao; import org.sonar.server.component.db.ComponentDao; import org.sonar.server.component.db.ComponentIndexDao; @@ -85,6 +86,7 @@ public class DbClient implements ServerComponent { private final UserDao userDao; private final GroupDao groupDao; private final UserGroupDao userGroupDao; + private final GroupMembershipDao groupMembershipDao; private final IssueDao issueDao; private final IssueFilterDao issueFilterDao; private final IssueChangeDao issueChangeDao; @@ -124,6 +126,7 @@ public class DbClient implements ServerComponent { userDao = getDao(map, UserDao.class); groupDao = getDao(map, GroupDao.class); userGroupDao = getDao(map, UserGroupDao.class); + groupMembershipDao = getDao(map, GroupMembershipDao.class); issueDao = getDao(map, IssueDao.class); issueFilterDao = getDao(map, IssueFilterDao.class); issueChangeDao = getDao(map, IssueChangeDao.class); @@ -224,6 +227,10 @@ public class DbClient implements ServerComponent { return userGroupDao; } + public GroupMembershipDao groupMembershipDao() { + return groupMembershipDao; + } + public ActionPlanDao actionPlanDao() { return actionPlanDao; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 0fd77b02562..b6347f84e61 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -762,6 +762,7 @@ class ServerComponents { pico.addSingleton(org.sonar.server.user.ws.ChangePasswordAction.class); pico.addSingleton(org.sonar.server.user.ws.CurrentUserAction.class); pico.addSingleton(org.sonar.server.user.ws.SearchAction.class); + pico.addSingleton(org.sonar.server.user.ws.GroupsAction.class); pico.addSingleton(org.sonar.server.issue.ws.AuthorsAction.class); pico.addSingleton(FavoritesWs.class); pico.addSingleton(UserPropertiesWs.class); 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 new file mode 100644 index 00000000000..f493c2f4eb0 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java @@ -0,0 +1,139 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.user.ws; + +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService.NewAction; +import org.sonar.api.server.ws.WebService.NewController; +import org.sonar.api.server.ws.WebService.Param; +import org.sonar.api.utils.Paging; +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.user.GroupMembershipDto; +import org.sonar.core.user.GroupMembershipQuery; +import org.sonar.core.user.UserDto; +import org.sonar.server.db.DbClient; + +import javax.annotation.Nullable; + +import java.util.List; + +public class GroupsAction implements BaseUsersWsAction { + + private static final String PARAM_LOGIN = "login"; + private static final String PARAM_SELECTED = "selected"; + private static final String PARAM_QUERY = "q"; + + private static final String SELECTION_ALL = "all"; + private static final String SELECTION_SELECTED = "selected"; + private static final String SELECTION_DESELECTED = "deselected"; + + private final DbClient dbClient; + + public GroupsAction(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public void define(NewController context) { + NewAction action = context.createAction("groups") + .setDescription("List the groups a user belongs to.") + .setHandler(this) + .setResponseExample(getClass().getResource("example-groups.json")) + .setSince("5.2"); + + action.createParam(PARAM_LOGIN) + .setDescription("A user login") + .setExampleValue("admin") + .setRequired(true); + + action.createParam(PARAM_SELECTED) + .setDescription("If specified, only show groups the user is member of (selected) or not (deselected).") + .setPossibleValues(SELECTION_SELECTED, SELECTION_DESELECTED, SELECTION_ALL) + .setDefaultValue(SELECTION_ALL); + + action.createParam(PARAM_QUERY) + .setDescription("If specified, only show groups whose name contains the query.") + .setExampleValue("user"); + + action.addPagingParams(25); + } + + @Override + public void handle(Request request, Response response) throws Exception { + String login = request.mandatoryParam(PARAM_LOGIN); + int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE); + int page = request.mandatoryParamAsInt(Param.PAGE); + String queryString = request.param(PARAM_QUERY); + String selected = request.param(PARAM_SELECTED); + + GroupMembershipQuery query = GroupMembershipQuery.builder() + .login(login) + .groupSearch(queryString) + .membership(getMembership(selected)) + .pageIndex(page) + .pageSize(pageSize) + .build(); + + DbSession session = dbClient.openSession(false); + try { + UserDto user = dbClient.userDao().selectByLogin(session, login); + int total = dbClient.groupMembershipDao().countGroups(session, query, user.getId()); + Paging paging = Paging.create(pageSize, page, total); + List<GroupMembershipDto> groups = dbClient.groupMembershipDao().selectGroups(session, query, user.getId(), paging.offset(), pageSize); + + JsonWriter json = response.newJsonWriter().beginObject(); + writeGroups(json, groups); + writePaging(json, paging); + json.endObject().close(); + } finally { + session.close(); + } + } + + private void writeGroups(JsonWriter json, List<GroupMembershipDto> groups) { + json.name("groups").beginArray(); + for (GroupMembershipDto group : groups) { + json.beginObject() + .prop("name", group.getName()) + .prop("description", group.getDescription()) + .prop("selected", group.getUserId() != null) + .endObject(); + } + json.endArray(); + } + + private void writePaging(JsonWriter json, Paging paging) { + json.prop("p", paging.pageIndex()) + .prop("ps", paging.pageSize()) + .prop("total", paging.total()); + } + + private String getMembership(@Nullable String selected) { + String membership = GroupMembershipQuery.ANY; + if (SELECTION_SELECTED.equals(selected)) { + membership = GroupMembershipQuery.IN; + } else if (SELECTION_DESELECTED.equals(selected)) { + membership = GroupMembershipQuery.OUT; + } + return membership; + } +} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-groups.json b/server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-groups.json new file mode 100644 index 00000000000..ef1ca05b086 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-groups.json @@ -0,0 +1,9 @@ +{ + "p": 1, + "ps": 25, + "total": 2, + "groups": [ + {"name": "sonar-admins", "description": "Sonar Admins", "selected": false}, + {"name": "sonar-users", "description": "Sonar Users", "selected": true} + ] +} 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 new file mode 100644 index 00000000000..487e5168911 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java @@ -0,0 +1,199 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.user.ws; + +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.System2; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.DbTester; +import org.sonar.core.user.GroupDto; +import org.sonar.core.user.GroupMembershipDao; +import org.sonar.core.user.UserDto; +import org.sonar.core.user.UserGroupDto; +import org.sonar.server.db.DbClient; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.user.db.GroupDao; +import org.sonar.server.user.db.UserDao; +import org.sonar.server.user.db.UserGroupDao; +import org.sonar.server.ws.WsTester; + +public class GroupsActionTest { + + @ClassRule + public static final DbTester dbTester = new DbTester(); + + WebService.Controller controller; + + WsTester tester; + + DbClient dbClient; + + DbSession session; + + @Before + public void setUp() throws Exception { + dbTester.truncateTables(); + + System2 system2 = new System2(); + UserDao userDao = new UserDao(dbTester.myBatis(), system2); + GroupDao groupDao = new GroupDao(system2); + UserGroupDao userGroupDao = new UserGroupDao(); + GroupMembershipDao groupMembershipDao = new GroupMembershipDao(dbTester.myBatis()); + + dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), userDao, groupDao, userGroupDao, groupMembershipDao); + session = dbClient.openSession(false); + session.commit(); + + tester = new WsTester(new UsersWs(new GroupsAction(dbClient))); + controller = tester.controller("api/users"); + + } + + @After + public void tearDown() throws Exception { + session.close(); + } + + @Test(expected = NotFoundException.class) + public void fail_on_unknown_user() throws Exception { + tester.newGetRequest("api/users", "groups") + .setParam("login", "john").execute(); + } + + @Test + public void empty_groups() throws Exception { + createUser(); + session.commit(); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .execute() + .assertJson(getClass(), "empty.json"); + } + + @Test + public void all_groups() throws Exception { + UserDto user = createUser(); + GroupDto usersGroup = createGroup("sonar-users", "Sonar Users"); + createGroup("sonar-admins", "Sonar Admins"); + addUserToGroup(user, usersGroup); + session.commit(); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .execute() + .assertJson(getClass(), "all.json"); + } + + @Test + public void selected_groups() throws Exception { + UserDto user = createUser(); + GroupDto usersGroup = createGroup("sonar-users", "Sonar Users"); + createGroup("sonar-admins", "Sonar Admins"); + addUserToGroup(user, usersGroup); + session.commit(); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .setParam("selected", "selected") + .execute() + .assertJson(getClass(), "selected.json"); + } + + @Test + public void deselected_groups() throws Exception { + UserDto user = createUser(); + GroupDto usersGroup = createGroup("sonar-users", "Sonar Users"); + createGroup("sonar-admins", "Sonar Admins"); + addUserToGroup(user, usersGroup); + session.commit(); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .setParam("selected", "deselected") + .execute() + .assertJson(getClass(), "deselected.json"); + } + + private UserDto createUser() { + return dbClient.userDao().insert(session, new UserDto() + .setActive(true) + .setEmail("john@email.com") + .setLogin("john") + .setName("John") + .setScmAccounts("jn")); + } + + @Test + public void paging() throws Exception { + UserDto user = createUser(); + GroupDto usersGroup = createGroup("sonar-users", "Sonar Users"); + createGroup("sonar-admins", "Sonar Admins"); + addUserToGroup(user, usersGroup); + session.commit(); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .setParam("ps", "1") + .execute() + .assertJson(getClass(), "all_page1.json"); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .setParam("ps", "1") + .setParam("p", "2") + .execute() + .assertJson(getClass(), "all_page2.json"); + } + + @Test + public void filtering() throws Exception { + UserDto user = createUser(); + GroupDto usersGroup = createGroup("sonar-users", "Sonar Users"); + createGroup("sonar-admins", "Sonar Admins"); + addUserToGroup(user, usersGroup); + session.commit(); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .setParam("q", "users") + .execute() + .assertJson(getClass(), "all_users.json"); + + tester.newGetRequest("api/users", "groups") + .setParam("login", "john") + .setParam("q", "admin") + .execute() + .assertJson(getClass(), "all_admin.json"); + } + + private GroupDto createGroup(String name, String description) { + return dbClient.groupDao().insert(session, new GroupDto().setName(name).setDescription(description)); + } + + private void addUserToGroup(UserDto user, GroupDto usersGroup) { + dbClient.userGroupDao().insert(session, new UserGroupDto().setUserId(user.getId()).setGroupId(usersGroup.getId())); + } +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all.json new file mode 100644 index 00000000000..af9bb6d1dd2 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all.json @@ -0,0 +1,8 @@ +{ + "p": 1, + "total": 2, + "groups": [ + {"name": "sonar-admins", "description": "Sonar Admins", "selected": false}, + {"name": "sonar-users", "description": "Sonar Users", "selected": true} + ] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_admin.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_admin.json new file mode 100644 index 00000000000..9310fce67e5 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_admin.json @@ -0,0 +1,7 @@ +{ + "p": 1, + "total": 1, + "groups": [ + {"name": "sonar-admins", "description": "Sonar Admins", "selected": false} + ] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page1.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page1.json new file mode 100644 index 00000000000..230e55493eb --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page1.json @@ -0,0 +1,8 @@ +{ + "p": 1, + "ps": 1, + "total": 2, + "groups": [ + {"name": "sonar-admins", "description": "Sonar Admins", "selected": false} + ] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page2.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page2.json new file mode 100644 index 00000000000..054d1f53f7b --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page2.json @@ -0,0 +1,8 @@ +{ + "p": 2, + "ps": 1, + "total": 2, + "groups": [ + {"name": "sonar-users", "description": "Sonar Users", "selected": true} + ] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_users.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_users.json new file mode 100644 index 00000000000..021346810c1 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_users.json @@ -0,0 +1,7 @@ +{ + "p": 1, + "total": 1, + "groups": [ + {"name": "sonar-users", "description": "Sonar Users", "selected": true} + ] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/deselected.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/deselected.json new file mode 100644 index 00000000000..9310fce67e5 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/deselected.json @@ -0,0 +1,7 @@ +{ + "p": 1, + "total": 1, + "groups": [ + {"name": "sonar-admins", "description": "Sonar Admins", "selected": false} + ] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/empty.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/empty.json new file mode 100644 index 00000000000..2160187bbb6 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/empty.json @@ -0,0 +1,5 @@ +{ + "p": 1, + "total": 0, + "groups": [] +}
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/selected.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/selected.json new file mode 100644 index 00000000000..021346810c1 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/selected.json @@ -0,0 +1,7 @@ +{ + "p": 1, + "total": 1, + "groups": [ + {"name": "sonar-users", "description": "Sonar Users", "selected": true} + ] +}
\ No newline at end of file |