aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>2015-05-05 15:38:14 +0200
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>2015-05-07 16:40:09 +0200
commit912e9886ae4a982781c99afd7881dd9b0e934565 (patch)
tree020d8a2efeb1ccc2a73253e5886bb6a755f96399 /server
parentf7c5f42cf3ca81ff948ae08afe50d15c09412bfc (diff)
downloadsonarqube-912e9886ae4a982781c99afd7881dd9b0e934565.tar.gz
sonarqube-912e9886ae4a982781c99afd7881dd9b0e934565.zip
SONAR-6470 New Java WS to show a user's groups
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java139
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-groups.json9
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java199
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all.json8
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_admin.json7
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page1.json8
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_page2.json8
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/all_users.json7
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/deselected.json7
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/empty.json5
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/ws/GroupsActionTest/selected.json7
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