--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+ }
+}
CreateAction.class,
DeleteAction.class,
UpdateAction.class,
- UsersAction.class);
+ UsersAction.class,
+ AddUserAction.class,
+ RemoveUserAction.class);
}
}
--- /dev/null
+/*
+ * 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<String, String> 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));
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+}