From 7be47f79a7915070631088cd9c35e9b84ff1f8dd Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lievremont Date: Wed, 27 May 2015 16:47:06 +0200 Subject: [PATCH] SONAR-6476 SONAR-6477 New WS to add/remove a user to/from a group --- .../server/usergroups/ws/AddUserAction.java | 101 +++++++++ .../usergroups/ws/RemoveUserAction.java | 93 ++++++++ .../usergroups/ws/UserGroupsModule.java | 4 +- .../usergroups/ws/AddUserActionTest.java | 207 ++++++++++++++++++ .../usergroups/ws/RemoveUserActionTest.java | 187 ++++++++++++++++ 5 files changed, 591 insertions(+), 1 deletion(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/AddUserActionTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/RemoveUserActionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java new file mode 100644 index 00000000000..0a8ff5781d8 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java @@ -0,0 +1,101 @@ +/* + * 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.usergroups.ws; + +import java.util.Arrays; +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.core.permission.GlobalPermissions; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.user.GroupDto; +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.UserSession; + +import static org.sonar.core.persistence.MyBatis.closeQuietly; + +public class AddUserAction implements UserGroupsWsAction { + + private static final String PARAM_ID = "id"; + private static final String PARAM_LOGIN = "login"; + + private final DbClient dbClient; + private final UserSession userSession; + + public AddUserAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; + this.userSession = userSession; + } + + @Override + public void define(NewController context) { + NewAction action = context.createAction("add_user") + .setDescription("Add a user to a group.") + .setHandler(this) + .setPost(true) + .setSince("5.2"); + + action.createParam(PARAM_ID) + .setDescription("ID of the group") + .setExampleValue("42") + .setRequired(true); + + action.createParam(PARAM_LOGIN) + .setDescription("Login of the user.") + .setExampleValue("g.hopper") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + userSession.checkLoggedIn().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN); + + Long groupId = request.mandatoryParamAsLong(PARAM_ID); + String login = request.param(PARAM_LOGIN); + + DbSession dbSession = dbClient.openSession(false); + try { + GroupDto group = dbClient.groupDao().selectById(dbSession, groupId); + UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login); + if (user == null) { + throw new NotFoundException(String.format("Could not find a user with login '%s'", login)); + } + + if (!userIsAlreadyMemberOf(dbSession, login, group)) { + UserGroupDto userGroup = new UserGroupDto().setGroupId(group.getId()).setUserId(user.getId()); + dbClient.userGroupDao().insert(dbSession, userGroup); + dbSession.commit(); + } + + response.noContent(); + } finally { + closeQuietly(dbSession); + } + + } + + private boolean userIsAlreadyMemberOf(DbSession dbSession, String login, GroupDto group) { + return dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, Arrays.asList(login)).get(login).contains(group.getName()); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java new file mode 100644 index 00000000000..1e5dcc66d30 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java @@ -0,0 +1,93 @@ +/* + * 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.usergroups.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.core.permission.GlobalPermissions; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.user.GroupDto; +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.UserSession; + +import static org.sonar.core.persistence.MyBatis.closeQuietly; + +public class RemoveUserAction implements UserGroupsWsAction { + + private static final String PARAM_ID = "id"; + private static final String PARAM_LOGIN = "login"; + + private final DbClient dbClient; + private final UserSession userSession; + + public RemoveUserAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; + this.userSession = userSession; + } + + @Override + public void define(NewController context) { + NewAction action = context.createAction("remove_user") + .setDescription("Remove a user from a group.") + .setHandler(this) + .setPost(true) + .setSince("5.2"); + + action.createParam(PARAM_ID) + .setDescription("ID of the group") + .setExampleValue("42") + .setRequired(true); + + action.createParam(PARAM_LOGIN) + .setDescription("Login of the user.") + .setExampleValue("g.hopper") + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + userSession.checkLoggedIn().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN); + + Long groupId = request.mandatoryParamAsLong(PARAM_ID); + String login = request.param(PARAM_LOGIN); + + DbSession dbSession = dbClient.openSession(false); + try { + GroupDto group = dbClient.groupDao().selectById(dbSession, groupId); + UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login); + if (user == null) { + throw new NotFoundException(String.format("Could not find a user with login '%s'", login)); + } + + UserGroupDto userGroup = new UserGroupDto().setGroupId(group.getId()).setUserId(user.getId()); + dbClient.userGroupDao().delete(dbSession, userGroup); + dbSession.commit(); + response.noContent(); + } finally { + closeQuietly(dbSession); + } + + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java index f02fcaca448..6824b69aad8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java @@ -32,7 +32,9 @@ public class UserGroupsModule extends Module { CreateAction.class, DeleteAction.class, UpdateAction.class, - UsersAction.class); + UsersAction.class, + AddUserAction.class, + RemoveUserAction.class); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/AddUserActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/AddUserActionTest.java new file mode 100644 index 00000000000..db56d1a1afd --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/AddUserActionTest.java @@ -0,0 +1,207 @@ +/* + * 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.usergroups.ws; + +import com.google.common.collect.Multimap; +import java.util.Arrays; +import org.apache.commons.lang.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.core.permission.GlobalPermissions; +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.tester.UserSessionRule; +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; +import org.sonar.test.DbTests; + +import static org.assertj.core.api.Assertions.assertThat; + +@Category(DbTests.class) +public class AddUserActionTest { + + @ClassRule + public static final DbTester dbTester = new DbTester(); + + @Rule + public final UserSessionRule userSession = UserSessionRule.standalone(); + + @Rule + public final ExpectedException expectedException = ExpectedException.none(); + + private WsTester tester; + private GroupDao groupDao; + private UserDao userDao; + private GroupMembershipDao groupMembershipDao; + private UserGroupDao userGroupDao; + private DbSession session; + + @Before + public void setUp() { + dbTester.truncateTables(); + + groupDao = new GroupDao(System2.INSTANCE); + userDao = new UserDao(dbTester.myBatis(), System2.INSTANCE); + groupMembershipDao = new GroupMembershipDao(dbTester.myBatis()); + userGroupDao = new UserGroupDao(); + + DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), groupDao, userDao, userGroupDao, groupMembershipDao); + + tester = new WsTester(new UserGroupsWs(new AddUserAction(dbClient, userSession))); + + session = dbClient.openSession(false); + } + + @After + public void after() { + session.close(); + } + + @Test + public void add_user_nominal() throws Exception { + GroupDto group = insertGroup("admins"); + UserDto user = insertUser("my-admin"); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "add_user") + .setParam("id", group.getId().toString()) + .setParam("login", user.getLogin()) + .execute() + .assertNoContent(); + + assertThat(groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user.getLogin())).get(user.getLogin())) + .containsOnly(group.getName()); + } + + @Test + public void add_user_to_another_group() throws Exception { + GroupDto admins = insertGroup("admins"); + GroupDto users = insertGroup("users"); + UserDto user = insertUser("my-admin"); + insertMember(users.getId(), user.getId()); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "add_user") + .setParam("id", admins.getId().toString()) + .setParam("login", user.getLogin()) + .execute() + .assertNoContent(); + + assertThat(groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user.getLogin())).get(user.getLogin())) + .containsOnly(admins.getName(), users.getName()); + } + + @Test + public void add_user_already_in_group() throws Exception { + GroupDto users = insertGroup("users"); + UserDto user = insertUser("my-admin"); + insertMember(users.getId(), user.getId()); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "add_user") + .setParam("id", users.getId().toString()) + .setParam("login", user.getLogin()) + .execute() + .assertNoContent(); + + assertThat(groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user.getLogin())).get(user.getLogin())) + .containsOnly(users.getName()); + } + + @Test + public void add_another_user_to_group() throws Exception { + GroupDto users = insertGroup("user"); + UserDto user1 = insertUser("user1"); + UserDto user2 = insertUser("user2"); + insertMember(users.getId(), user1.getId()); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "add_user") + .setParam("id", users.getId().toString()) + .setParam("login", user2.getLogin()) + .execute() + .assertNoContent(); + + Multimap groupsByLogins = groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user1.getLogin(), user2.getLogin())); + assertThat(groupsByLogins.get(user1.getLogin())).containsOnly(users.getName()); + assertThat(groupsByLogins.get(user2.getLogin())).containsOnly(users.getName()); + } + + @Test + public void unknown_group() throws Exception { + UserDto user = insertUser("my-admin"); + session.commit(); + + expectedException.expect(NotFoundException.class); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "add_user") + .setParam("id", "42") + .setParam("login", user.getLogin()) + .execute(); + } + + @Test + public void unknown_user() throws Exception { + GroupDto group = insertGroup("admins"); + session.commit(); + + expectedException.expect(NotFoundException.class); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "add_user") + .setParam("id", group.getId().toString()) + .setParam("login", "my-admin") + .execute(); + } + + private GroupDto insertGroup(String groupName) { + return groupDao.insert(session, new GroupDto() + .setName(groupName) + .setDescription(StringUtils.capitalize(groupName))); + } + + private UserDto insertUser(String login) { + return userDao.insert(session, new UserDto().setLogin(login).setName(login).setActive(true)); + } + + private void insertMember(long groupId, long userId) { + userGroupDao.insert(session, new UserGroupDto().setGroupId(groupId).setUserId(userId)); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/RemoveUserActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/RemoveUserActionTest.java new file mode 100644 index 00000000000..106671a5e07 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/RemoveUserActionTest.java @@ -0,0 +1,187 @@ +/* + * 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.usergroups.ws; + +import java.util.Arrays; +import org.apache.commons.lang.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.core.permission.GlobalPermissions; +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.tester.UserSessionRule; +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; +import org.sonar.test.DbTests; + +import static org.assertj.core.api.Assertions.assertThat; + +@Category(DbTests.class) +public class RemoveUserActionTest { + + @ClassRule + public static final DbTester dbTester = new DbTester(); + + @Rule + public final UserSessionRule userSession = UserSessionRule.standalone(); + + @Rule + public final ExpectedException expectedException = ExpectedException.none(); + + private WsTester tester; + private GroupDao groupDao; + private UserDao userDao; + private GroupMembershipDao groupMembershipDao; + private UserGroupDao userGroupDao; + private DbSession session; + + @Before + public void setUp() { + dbTester.truncateTables(); + + groupDao = new GroupDao(System2.INSTANCE); + userDao = new UserDao(dbTester.myBatis(), System2.INSTANCE); + groupMembershipDao = new GroupMembershipDao(dbTester.myBatis()); + userGroupDao = new UserGroupDao(); + + DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), groupDao, userDao, userGroupDao, groupMembershipDao); + + tester = new WsTester(new UserGroupsWs(new RemoveUserAction(dbClient, userSession))); + + session = dbClient.openSession(false); + } + + @After + public void after() { + session.close(); + } + + @Test + public void remove_user_not_in_group() throws Exception { + GroupDto group = insertGroup("admins"); + UserDto user = insertUser("my-admin"); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "remove_user") + .setParam("id", group.getId().toString()) + .setParam("login", user.getLogin()) + .execute() + .assertNoContent(); + + assertThat(groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user.getLogin())).get(user.getLogin())) + .isEmpty(); + } + + @Test + public void remove_user_nominal() throws Exception { + GroupDto users = insertGroup("users"); + UserDto user = insertUser("my-admin"); + insertMember(users.getId(), user.getId()); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "remove_user") + .setParam("id", users.getId().toString()) + .setParam("login", user.getLogin()) + .execute() + .assertNoContent(); + + assertThat(groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user.getLogin())).get(user.getLogin())) + .isEmpty(); + } + + @Test + public void remove_user_only_from_one_group() throws Exception { + GroupDto users = insertGroup("user"); + GroupDto admins = insertGroup("admins"); + UserDto user = insertUser("user"); + insertMember(users.getId(), user.getId()); + insertMember(admins.getId(), user.getId()); + session.commit(); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "remove_user") + .setParam("id", admins.getId().toString()) + .setParam("login", user.getLogin()) + .execute() + .assertNoContent(); + + assertThat(groupMembershipDao.selectGroupsByLogins(session, Arrays.asList(user.getLogin())).get(user.getLogin())) + .containsOnly(users.getName()); + } + + @Test + public void unknown_group() throws Exception { + UserDto user = insertUser("my-admin"); + session.commit(); + + expectedException.expect(NotFoundException.class); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "remove_user") + .setParam("id", "42") + .setParam("login", user.getLogin()) + .execute(); + } + + @Test + public void unknown_user() throws Exception { + GroupDto group = insertGroup("admins"); + session.commit(); + + expectedException.expect(NotFoundException.class); + + userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + tester.newPostRequest("api/usergroups", "remove_user") + .setParam("id", group.getId().toString()) + .setParam("login", "my-admin") + .execute(); + } + + private GroupDto insertGroup(String groupName) { + return groupDao.insert(session, new GroupDto() + .setName(groupName) + .setDescription(StringUtils.capitalize(groupName))); + } + + private UserDto insertUser(String login) { + return userDao.insert(session, new UserDto().setLogin(login).setName(login).setActive(true)); + } + + private void insertMember(long groupId, long userId) { + userGroupDao.insert(session, new UserGroupDto().setGroupId(groupId).setUserId(userId)); + } +} -- 2.39.5