]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6474 New WS to delete a group
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 25 May 2015 12:46:08 +0000 (14:46 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Wed, 27 May 2015 07:37:02 +0000 (09:37 +0200)
28 files changed:
server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java
server/sonar-server/src/main/java/org/sonar/server/user/db/UserGroupDao.java
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/CreateAction.java
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/DeleteAction.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/user/db/UserGroupDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/DeleteActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/user/db/UserGroupDaoTest/delete_members_by_group_id-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/user/db/UserGroupDaoTest/delete_members_by_group_id.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/permission/PermissionTemplateDao.java
sonar-core/src/main/java/org/sonar/core/user/GroupMapper.java
sonar-core/src/main/java/org/sonar/core/user/RoleDao.java
sonar-core/src/main/java/org/sonar/core/user/RoleMapper.java
sonar-core/src/main/java/org/sonar/core/user/UserGroupMapper.java
sonar-core/src/main/resources/org/sonar/core/user/GroupMapper.xml
sonar-core/src/main/resources/org/sonar/core/user/RoleMapper.xml
sonar-core/src/main/resources/org/sonar/core/user/UserGroupMapper.xml
sonar-core/src/test/java/org/sonar/core/user/RoleDaoTest.java
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/deleteGroupPermissionsByGroupId-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/deleteGroupPermissionsByGroupId.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/globalGroupPermissions-result.xml
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/globalGroupPermissions.xml
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/globalUserPermissions-result.xml
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/globalUserPermissions.xml
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/resourceGroupPermissions-result.xml
sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/resourceGroupPermissions.xml

index 6e6df811f34fde5fa7526bc25c9c5487cf452249..356a52645477368d47fc9fcb7122183aa607e26f 100644 (file)
  */
 package org.sonar.server.db;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.IdentityHashMap;
+import java.util.Map;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.issue.db.ActionPlanDao;
 import org.sonar.core.issue.db.IssueChangeDao;
 import org.sonar.core.issue.db.IssueFilterDao;
+import org.sonar.core.permission.PermissionTemplateDao;
 import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.Database;
 import org.sonar.core.persistence.DbSession;
@@ -36,6 +43,7 @@ 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.core.user.RoleDao;
 import org.sonar.server.activity.db.ActivityDao;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.component.db.ComponentIndexDao;
@@ -56,13 +64,6 @@ import org.sonar.server.user.db.GroupDao;
 import org.sonar.server.user.db.UserDao;
 import org.sonar.server.user.db.UserGroupDao;
 
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.IdentityHashMap;
-import java.util.Map;
-
 /**
  * Facade for all db components, mainly DAOs
  */
@@ -88,6 +89,8 @@ public class DbClient {
   private final GroupDao groupDao;
   private final UserGroupDao userGroupDao;
   private final GroupMembershipDao groupMembershipDao;
+  private final RoleDao roleDao;
+  private final PermissionTemplateDao permissionTemplateDao;
   private final IssueDao issueDao;
   private final IssueFilterDao issueFilterDao;
   private final IssueChangeDao issueChangeDao;
@@ -128,6 +131,8 @@ public class DbClient {
     groupDao = getDao(map, GroupDao.class);
     userGroupDao = getDao(map, UserGroupDao.class);
     groupMembershipDao = getDao(map, GroupMembershipDao.class);
+    roleDao = getDao(map, RoleDao.class);
+    permissionTemplateDao = getDao(map, PermissionTemplateDao.class);
     issueDao = getDao(map, IssueDao.class);
     issueFilterDao = getDao(map, IssueFilterDao.class);
     issueChangeDao = getDao(map, IssueChangeDao.class);
@@ -232,6 +237,14 @@ public class DbClient {
     return groupMembershipDao;
   }
 
+  public RoleDao roleDao() {
+    return roleDao;
+  }
+
+  public PermissionTemplateDao permissionTemplateDao() {
+    return permissionTemplateDao;
+  }
+
   public ActionPlanDao actionPlanDao() {
     return actionPlanDao;
   }
index f79a14e72ca62f73de8cd16812f98bf89895bd6a..22c6112ca22af2b2e94e4ca1c7fdfd31a77bd797 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.platform.platformlevel;
 
+import java.util.List;
 import org.sonar.api.config.EmailSettings;
 import org.sonar.api.issue.action.Actions;
 import org.sonar.api.profiles.AnnotationProfileParser;
@@ -290,8 +291,6 @@ import org.sonar.server.view.index.ViewIndexer;
 import org.sonar.server.ws.ListingWs;
 import org.sonar.server.ws.WebServiceEngine;
 
-import java.util.List;
-
 public class PlatformLevel4 extends PlatformLevel {
 
   private final List<Object> level4AddedComponents;
@@ -498,6 +497,7 @@ public class PlatformLevel4 extends PlatformLevel {
       UserGroupsWs.class,
       org.sonar.server.usergroups.ws.SearchAction.class,
       org.sonar.server.usergroups.ws.CreateAction.class,
+      org.sonar.server.usergroups.ws.DeleteAction.class,
 
       // permissions
       PermissionFacade.class,
index eda1a1ad2a3bcd8f7e96daf504a53474f6865658..88229ea14f38ea2149269a65d3f92ee355e73446 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.user.db;
 
 import java.util.Date;
 import java.util.List;
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ibatis.session.RowBounds;
@@ -30,6 +31,7 @@ import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.user.GroupDto;
 import org.sonar.core.user.GroupMapper;
+import org.sonar.server.exceptions.NotFoundException;
 
 /**
  * @since 3.2
@@ -44,9 +46,27 @@ public class GroupDao implements DaoComponent {
   }
 
   public GroupDto selectByKey(DbSession session, String key) {
+    GroupDto group = selectNullableByKey(session, key);
+    if (group == null) {
+      throw new NotFoundException(String.format("Could not find a group with name '%s'", key));
+    }
+    return group;
+  }
+
+  @CheckForNull
+  public GroupDto selectNullableByKey(DbSession session, String key) {
     return mapper(session).selectByKey(key);
   }
 
+  @CheckForNull
+  public GroupDto selectById(DbSession dbSession, long groupId) {
+    return mapper(dbSession).selectById(groupId);
+  }
+
+  public void deleteById(DbSession dbSession, long groupId) {
+    mapper(dbSession).deleteById(groupId);
+  }
+
   public int countByQuery(DbSession session, @Nullable String query) {
     return mapper(session).countByQuery(groupSearchToSql(query));
   }
index 60e29f3c1e1a0bd311d130fc7e05d7e206ca4b62..6fc14f52b407973b32b07c20cc8facba54d475c6 100644 (file)
@@ -32,6 +32,14 @@ public class UserGroupDao implements DaoComponent {
     return dto;
   }
 
+  public void delete(DbSession session, UserGroupDto dto) {
+    mapper(session).delete(dto);
+  }
+
+  public void deleteMembersByGroupId(DbSession session, long groupId) {
+    mapper(session).deleteMembersByGroup(groupId);
+  }
+
   protected UserGroupMapper mapper(DbSession session) {
     return session.getMapper(UserGroupMapper.class);
   }
index edfb2e8aeee5b44e8c46a1624117c177efff48ef..cdc9ad5fcf0223e02a7e2cd16f8f56b0cf39411d 100644 (file)
@@ -121,7 +121,7 @@ public class CreateAction implements UserGroupsWsAction {
     // There is no database constraint on column groups.name
     // because MySQL cannot create a unique index
     // on a UTF-8 VARCHAR larger than 255 characters on InnoDB
-    if (dbClient.groupDao().selectByKey(session, name) != null) {
+    if (dbClient.groupDao().selectNullableByKey(session, name) != null) {
       throw new ServerException(HttpURLConnection.HTTP_CONFLICT, String.format("Name '%s' is already taken", name));
     }
   }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/DeleteAction.java
new file mode 100644 (file)
index 0000000..71e6c7e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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.base.Preconditions;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.user.GroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+
+public class DeleteAction implements UserGroupsWsAction {
+
+  private static final String PARAM_ID = "id";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+  private final Settings settings;
+
+  public DeleteAction(DbClient dbClient, UserSession userSession, Settings settings) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+    this.settings = settings;
+  }
+
+  @Override
+  public void define(NewController context) {
+    context.createAction("delete")
+      .setDescription("Delete a group. The default group cannot be deleted. Requires System Administrator permission.")
+      .setHandler(this)
+      .setSince("5.2")
+      .setPost(true)
+      .createParam(PARAM_ID)
+      .setDescription("ID of the group to delete.")
+      .setRequired(true);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkLoggedIn().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
+
+    long groupId = request.mandatoryParamAsLong(PARAM_ID);
+
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      if (dbClient.groupDao().selectById(dbSession, groupId) == null) {
+        throw new NotFoundException(String.format("Could not find a group with id=%d", groupId));
+      }
+
+      checkNotTryingToDeleteDefaultGroup(dbSession, groupId);
+
+      removeGroupMembers(groupId, dbSession);
+      removeGroupPermissions(groupId, dbSession);
+      removeFromPermissionTemplates(groupId, dbSession);
+      dbClient.groupDao().deleteById(dbSession, groupId);
+
+      dbSession.commit();
+      response.noContent();
+    } finally {
+      MyBatis.closeQuietly(dbSession);
+    }
+  }
+
+  private void checkNotTryingToDeleteDefaultGroup(DbSession dbSession, long groupId) {
+    String defaultGroupName = settings.getString(CoreProperties.CORE_DEFAULT_GROUP);
+    GroupDto defaultGroup = dbClient.groupDao().selectByKey(dbSession, defaultGroupName);
+    Preconditions.checkArgument(groupId != defaultGroup.getId(),
+      String.format("Default group '%s' cannot be deleted", defaultGroupName));
+  }
+
+  private void removeGroupMembers(long groupId, DbSession dbSession) {
+    dbClient.userGroupDao().deleteMembersByGroupId(dbSession, groupId);
+  }
+
+  private void removeGroupPermissions(long groupId, DbSession dbSession) {
+    dbClient.roleDao().deleteGroupRolesByGroupId(dbSession, groupId);
+  }
+
+  private void removeFromPermissionTemplates(long groupId, DbSession dbSession) {
+    dbClient.permissionTemplateDao().removeByGroup(groupId, dbSession);
+  }
+}
index bb0efb8baf1dc5285d517d8281584027bacf6b73..c30587992b556221910ebb858e70fc624aed3b8f 100644 (file)
@@ -72,6 +72,19 @@ public class GroupDaoTest {
     assertThat(group.getUpdatedAt()).isEqualTo(DateUtils.parseDate("2014-09-08"));
   }
 
+  @Test
+  public void select_by_id() {
+    dbTester.prepareDbUnit(getClass(), "select_by_key.xml");
+
+    GroupDto group = new GroupDao(system2).selectById(session, 1L);
+    assertThat(group).isNotNull();
+    assertThat(group.getId()).isEqualTo(1L);
+    assertThat(group.getName()).isEqualTo("sonar-users");
+    assertThat(group.getDescription()).isEqualTo("Sonar Users");
+    assertThat(group.getCreatedAt()).isEqualTo(DateUtils.parseDate("2014-09-07"));
+    assertThat(group.getUpdatedAt()).isEqualTo(DateUtils.parseDate("2014-09-08"));
+  }
+
   @Test
   public void find_by_user_login() {
     dbTester.prepareDbUnit(getClass(), "find_by_user_login.xml");
@@ -144,4 +157,16 @@ public class GroupDaoTest {
     // Filter on name
     assertThat(new GroupDao(system2).countByQuery(session, "sonar")).isEqualTo(2);
   }
+
+  @Test
+  public void delete_by_id() {
+    dbTester.prepareDbUnit(getClass(), "select_by_key.xml");
+
+    GroupDao groupDao = new GroupDao(system2);
+    groupDao.deleteById(session, 1L);
+    session.commit();
+
+    assertThat(groupDao.countByQuery(session, null)).isZero();
+  }
+
 }
index 3be2dd038e5209365a9a27bda868ef113858a488..a1b72ef3831ee13a89cc96d198e15333c3f944d8 100644 (file)
@@ -59,4 +59,12 @@ public class UserGroupDaoTest {
 
     db.assertDbUnit(getClass(), "insert-result.xml", "groups_users");
   }
+
+  @Test
+  public void delete_members_by_group_id() {
+    db.prepareDbUnit(getClass(), "delete_members_by_group_id.xml");
+    dao.deleteMembersByGroupId(session, 1L);
+    session.commit();
+    db.assertDbUnit(getClass(), "delete_members_by_group_id-result.xml", "groups_users");
+  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/DeleteActionTest.java
new file mode 100644 (file)
index 0000000..82c96a9
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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.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.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.permission.PermissionTemplateDao;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.user.GroupDto;
+import org.sonar.core.user.GroupRoleDto;
+import org.sonar.core.user.RoleDao;
+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.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 DeleteActionTest {
+
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  private WsTester tester;
+
+  private GroupDao groupDao;
+
+  private UserGroupDao userGroupDao;
+
+  private RoleDao roleDao;
+
+  private PermissionTemplateDao permissionTemplateDao;
+
+  private DbSession session;
+
+  private Long defaultGroupId;
+
+  @Before
+  public void setUp() {
+    dbTester.truncateTables();
+
+    groupDao = new GroupDao(System2.INSTANCE);
+    userGroupDao = new UserGroupDao();
+    roleDao = new RoleDao();
+    permissionTemplateDao = new PermissionTemplateDao(dbTester.myBatis(), System2.INSTANCE);
+
+    DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(),
+      groupDao, userGroupDao, roleDao, permissionTemplateDao);
+
+    session = dbClient.openSession(false);
+
+    Settings settings = new Settings().setProperty(CoreProperties.CORE_DEFAULT_GROUP, CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE);
+    GroupDto defaultGroup = groupDao.insert(session, new GroupDto().setName(CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE));
+    defaultGroupId = defaultGroup.getId();
+    session.commit();
+
+    tester = new WsTester(new UserGroupsWs(new DeleteAction(dbClient, userSession, settings)));
+  }
+
+  @After
+  public void after() {
+    session.close();
+  }
+
+  @Test
+  public void delete_simple() throws Exception {
+    GroupDto group = groupDao.insert(session, new GroupDto().setName("to-delete"));
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "delete")
+      .setParam("id", group.getId().toString())
+      .execute().assertNoContent();
+  }
+
+  @Test
+  public void delete_with_members() throws Exception {
+    GroupDto group = groupDao.insert(session, new GroupDto().setName("to-delete"));
+    userGroupDao.insert(session, new UserGroupDto().setGroupId(group.getId()).setUserId(42L));
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "delete")
+      .setParam("id", group.getId().toString())
+      .execute().assertNoContent();
+
+    assertThat(dbTester.select("SELECT group_id FROM groups_users")).isEmpty();
+  }
+
+  @Test
+  public void delete_with_permissions() throws Exception {
+    GroupDto group = groupDao.insert(session, new GroupDto().setName("to-delete"));
+    roleDao.insertGroupRole(new GroupRoleDto().setGroupId(group.getId()).setResourceId(42L).setRole(UserRole.ADMIN), session);
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "delete")
+      .setParam("id", group.getId().toString())
+      .execute().assertNoContent();
+
+    assertThat(dbTester.select("SELECT group_id FROM group_roles")).isEmpty();
+  }
+
+  @Test
+  public void delete_with_permission_templates() throws Exception {
+    GroupDto group = groupDao.insert(session, new GroupDto().setName("to-delete"));
+    permissionTemplateDao.addGroupPermission(42L, group.getId(), UserRole.ADMIN);
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "delete")
+      .setParam("id", group.getId().toString())
+      .execute().assertNoContent();
+
+    assertThat(dbTester.select("SELECT group_id FROM perm_templates_groups")).isEmpty();
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void not_found() throws Exception {
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "delete")
+      .setParam("id", "42")
+      .execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void cannot_delete_default_group() throws Exception {
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "delete")
+      .setParam("id", defaultGroupId.toString())
+      .execute();
+  }
+
+  private void loginAsAdmin() {
+    userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+  }
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/db/UserGroupDaoTest/delete_members_by_group_id-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/user/db/UserGroupDaoTest/delete_members_by_group_id-result.xml
new file mode 100644 (file)
index 0000000..edac414
--- /dev/null
@@ -0,0 +1,6 @@
+<dataset>
+
+  <groups_users user_id="1" group_id="2"/>
+  <groups_users user_id="2" group_id="2"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/db/UserGroupDaoTest/delete_members_by_group_id.xml b/server/sonar-server/src/test/resources/org/sonar/server/user/db/UserGroupDaoTest/delete_members_by_group_id.xml
new file mode 100644 (file)
index 0000000..2430e53
--- /dev/null
@@ -0,0 +1,8 @@
+<dataset>
+
+  <groups_users user_id="1" group_id="1"/>
+  <groups_users user_id="2" group_id="1"/>
+  <groups_users user_id="1" group_id="2"/>
+  <groups_users user_id="2" group_id="2"/>
+
+</dataset>
index 35fe96d9803cfbb29896b02a9daf4584d2da9e79..b83ed5090441ca915a3c0498a90cb373d736529d 100644 (file)
 package org.sonar.core.permission;
 
 import com.google.common.annotations.VisibleForTesting;
+import java.text.Normalizer;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.apache.commons.lang.time.DateFormatUtils;
 import org.apache.ibatis.session.RowBounds;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.batch.BatchSide;
-import org.sonar.api.server.ServerSide;
 import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.text.Normalizer;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
 import static com.google.common.collect.Maps.newHashMap;
 
 @BatchSide
 @ServerSide
-public class PermissionTemplateDao {
+public class PermissionTemplateDao implements DaoComponent {
 
   public static final String QUERY_PARAMETER = "query";
   public static final String TEMPLATE_ID_PARAMETER = "templateId";
index 24dfd2e6768c8099d88373c050813f2168fcc21f..de36b36af7c5714fb5a68e0e4932feb788820ce2 100644 (file)
@@ -29,6 +29,9 @@ public interface GroupMapper {
   @CheckForNull
   GroupDto selectByKey(String name);
 
+  @CheckForNull
+  GroupDto selectById(long groupId);
+
   List<GroupDto> selectByUserLogin(String userLogin);
 
   void insert(GroupDto groupDto);
@@ -36,4 +39,7 @@ public interface GroupMapper {
   List<GroupDto> selectByQuery(String query, RowBounds rowBounds);
 
   int countByQuery(String query);
+
+  void deleteById(long groupId);
+
 }
index 194f700dd353f81b1108333e3fb17bb156bfca09..7bde8163199fc423462a2e36ce19deb069b98887 100644 (file)
 
 package org.sonar.core.user;
 
+import java.util.List;
+import javax.annotation.Nullable;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.batch.BatchSide;
-import org.sonar.api.server.ServerSide;
 import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.server.ServerSide;
+import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
 
-import javax.annotation.Nullable;
-
-import java.util.List;
-
 @ServerSide
 @BatchSide
-public class RoleDao {
+public class RoleDao implements DaoComponent {
 
   public List<String> selectUserPermissions(DbSession session, String userLogin, @Nullable Long resourceId) {
     return session.getMapper(RoleMapper.class).selectUserPermissions(userLogin, resourceId);
@@ -43,41 +42,42 @@ public class RoleDao {
   }
 
   public void insertGroupRole(GroupRoleDto groupRole, SqlSession session) {
-    RoleMapper mapper = session.getMapper(RoleMapper.class);
-    mapper.insertGroupRole(groupRole);
+    mapper(session).insertGroupRole(groupRole);
   }
 
   public void insertUserRole(UserRoleDto userRole, SqlSession session) {
-    RoleMapper mapper = session.getMapper(RoleMapper.class);
-    mapper.insertUserRole(userRole);
+    mapper(session).insertUserRole(userRole);
   }
 
   public void deleteUserRole(UserRoleDto userRole, SqlSession session) {
-    RoleMapper mapper = session.getMapper(RoleMapper.class);
-    mapper.deleteUserRole(userRole);
+    mapper(session).deleteUserRole(userRole);
   }
 
   public void deleteGroupRole(GroupRoleDto groupRole, SqlSession session) {
-    RoleMapper mapper = session.getMapper(RoleMapper.class);
-    mapper.deleteGroupRole(groupRole);
+    mapper(session).deleteGroupRole(groupRole);
   }
 
   public void deleteGroupRolesByResourceId(Long resourceId, SqlSession session) {
-    RoleMapper mapper = session.getMapper(RoleMapper.class);
-    mapper.deleteGroupRolesByResourceId(resourceId);
+    mapper(session).deleteGroupRolesByResourceId(resourceId);
   }
 
   public void deleteUserRolesByResourceId(Long resourceId, SqlSession session) {
-    RoleMapper mapper = session.getMapper(RoleMapper.class);
-    mapper.deleteUserRolesByResourceId(resourceId);
+    mapper(session).deleteUserRolesByResourceId(resourceId);
   }
 
   public int countResourceGroupRoles(DbSession session, Long resourceId) {
-    return session.getMapper(RoleMapper.class).countResourceGroupRoles(resourceId);
+    return mapper(session).countResourceGroupRoles(resourceId);
   }
 
   public int countResourceUserRoles(DbSession session, Long resourceId) {
-    return session.getMapper(RoleMapper.class).countResourceUserRoles(resourceId);
+    return mapper(session).countResourceUserRoles(resourceId);
   }
 
+  public void deleteGroupRolesByGroupId(DbSession session, long groupId) {
+    mapper(session).deleteGroupRolesByGroupId(groupId);
+  }
+
+  private static RoleMapper mapper(SqlSession session) {
+    return session.getMapper(RoleMapper.class);
+  }
 }
index 2728b91cbe61d6197bf913c914eda51dd0f2b1a1..c4d2ca4dbd469e269505dbd92c9a00f05e4975e1 100644 (file)
  */
 package org.sonar.core.user;
 
-import org.apache.ibatis.annotations.Param;
-
-import javax.annotation.Nullable;
 import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * @since 3.2
@@ -55,4 +54,6 @@ public interface RoleMapper {
 
   int countResourceUserRoles(Long resourceId);
 
+  void deleteGroupRolesByGroupId(long groupId);
+
 }
index 328abc4d1b8c9f22f078cf29176deff8b9141cee..3381852a229240539d42095561cea067e5a31652 100644 (file)
@@ -24,4 +24,7 @@ public interface UserGroupMapper {
 
   void insert(UserGroupDto userGroupDto);
 
+  void delete(UserGroupDto dto);
+
+  void deleteMembersByGroup(long groupId);
 }
index b2ffcb622962d0b0be21f49afd1d60edeb74b926..132edb40784b0c8915de21fc164d6e4f2d2a9804 100644 (file)
     </where>
   </select>
 
+  <select id="selectById" parameterType="long" resultType="Group">
+    SELECT <include refid="groupColumns"/>
+    FROM groups g
+    <where>
+      g.id=#{id}
+    </where>
+  </select>
+
+  <delete id="deleteById" parameterType="long">
+    DELETE FROM groups
+    <where>
+      id=#{id}
+    </where>
+  </delete>
+
   <select id="selectByUserLogin" parameterType="string" resultType="Group">
     SELECT <include refid="groupColumns"/>
     FROM groups g
index ad7a4b02f21fff8cf5538a35c08dddc4548a915d..5cc000c61f6a66c9f61301a456d3ca05fe9ec5e7 100644 (file)
     SELECT count(id)
     FROM group_roles WHERE resource_id=#{id}
   </select>
+
+  <delete id="deleteGroupRolesByGroupId" parameterType="long">
+    delete from group_roles where group_id=#{id}
+  </delete>
 </mapper>
index ce48eeae26104766e6850b108f53367691ce6c38..8b6b828ec954b9e83e850f949464345295f8829d 100644 (file)
@@ -8,4 +8,19 @@
     VALUES (#{userId}, #{groupId})
   </insert>
 
+  <delete id="delete" parameterType="UserGroup">
+    DELETE FROM groups_users
+    <where>
+    AND user_id = #{userId}
+    AND group_id = #{groupId}
+    </where>
+  </delete>
+
+  <delete id="deleteMembersByGroup" parameterType="long">
+    DELETE FROM groups_users
+    <where>
+    AND group_id = #{groupId}
+    </where>
+  </delete>
+
 </mapper>
index 932f25c874ab135f3bfd1516923a25ed183d47ba..0538f2771118cf6a2fe473c368fe2e596b4b5bb2 100644 (file)
@@ -22,16 +22,23 @@ package org.sonar.core.user;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.sonar.api.security.DefaultGroups;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.test.DbTests;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class RoleDaoTest extends AbstractDaoTestCase {
+@Category(DbTests.class)
+public class RoleDaoTest {
+
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
 
   DbSession session;
 
@@ -39,7 +46,8 @@ public class RoleDaoTest extends AbstractDaoTestCase {
 
   @Before
   public void setUp() {
-    session = getMyBatis().openSession(false);
+    dbTester.truncateTables();
+    session = dbTester.myBatis().openSession(false);
     dao = new RoleDao();
   }
 
@@ -50,7 +58,7 @@ public class RoleDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void retrieve_global_user_permissions() {
-    setupData("globalUserPermissions");
+    dbTester.prepareDbUnit(getClass(), "globalUserPermissions.xml");
 
     assertThat(dao.selectUserPermissions(session, "admin_user", null)).containsOnly(GlobalPermissions.SYSTEM_ADMIN, GlobalPermissions.QUALITY_PROFILE_ADMIN);
     assertThat(dao.selectUserPermissions(session, "profile_admin_user", null)).containsOnly(GlobalPermissions.QUALITY_PROFILE_ADMIN);
@@ -58,7 +66,7 @@ public class RoleDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void retrieve_resource_user_permissions() {
-    setupData("resourceUserPermissions");
+    dbTester.prepareDbUnit(getClass(), "resourceUserPermissions.xml");
 
     assertThat(dao.selectUserPermissions(session, "admin_user", 1L)).containsOnly(UserRole.ADMIN, UserRole.USER);
     assertThat(dao.selectUserPermissions(session, "browse_admin_user", 1L)).containsOnly(UserRole.USER);
@@ -66,7 +74,7 @@ public class RoleDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void retrieve_global_group_permissions() {
-    setupData("globalGroupPermissions");
+    dbTester.prepareDbUnit(getClass(), "globalGroupPermissions.xml");
 
     assertThat(dao.selectGroupPermissions(session, "sonar-administrators", null)).containsOnly(GlobalPermissions.SYSTEM_ADMIN, GlobalPermissions.QUALITY_PROFILE_ADMIN,
       GlobalPermissions.DASHBOARD_SHARING);
@@ -78,7 +86,7 @@ public class RoleDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void retrieve_resource_group_permissions() {
-    setupData("resourceGroupPermissions");
+    dbTester.prepareDbUnit(getClass(), "resourceGroupPermissions.xml");
 
     assertThat(dao.selectGroupPermissions(session, "sonar-administrators", 1L)).containsOnly(UserRole.ADMIN, UserRole.CODEVIEWER);
     assertThat(dao.selectGroupPermissions(session, "sonar-users", 1L)).containsOnly(UserRole.CODEVIEWER);
@@ -86,50 +94,59 @@ public class RoleDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void delete_global_user_permission() {
-    setupData("globalUserPermissions");
+    dbTester.prepareDbUnit(getClass(), "globalUserPermissions.xml");
 
     UserRoleDto userRoleToDelete = new UserRoleDto().setUserId(200L).setRole(GlobalPermissions.QUALITY_PROFILE_ADMIN);
 
     dao.deleteUserRole(userRoleToDelete, session);
     session.commit();
 
-    checkTable("globalUserPermissions", "user_roles", "user_id", "role");
+    dbTester.assertDbUnit(getClass(), "globalUserPermissions-result.xml", "user_roles");
   }
 
   @Test
   public void delete_resource_user_permission() {
-    setupData("resourceUserPermissions");
+    dbTester.prepareDbUnit(getClass(), "resourceUserPermissions.xml");
 
     UserRoleDto userRoleToDelete = new UserRoleDto().setUserId(200L).setRole(UserRole.USER).setResourceId(1L);
 
     dao.deleteUserRole(userRoleToDelete, session);
     session.commit();
 
-    checkTable("resourceUserPermissions", "user_roles", "user_id", "role");
+    dbTester.assertDbUnit(getClass(), "resourceUserPermissions-result.xml", "user_roles");
   }
 
   @Test
   public void delete_global_group_permission() {
-    setupData("globalGroupPermissions");
+    dbTester.prepareDbUnit(getClass(), "globalGroupPermissions.xml");
 
     GroupRoleDto groupRoleToDelete = new GroupRoleDto().setGroupId(100L).setRole(GlobalPermissions.QUALITY_PROFILE_ADMIN);
 
     dao.deleteGroupRole(groupRoleToDelete, session);
     session.commit();
 
-    checkTable("globalGroupPermissions", "group_roles", "group_id", "role");
+    dbTester.assertDbUnit(getClass(), "globalGroupPermissions-result.xml", "group_roles");
   }
 
   @Test
   public void delete_resource_group_permission() {
-    setupData("resourceGroupPermissions");
+    dbTester.prepareDbUnit(getClass(), "resourceGroupPermissions.xml");
 
     GroupRoleDto groupRoleToDelete = new GroupRoleDto().setGroupId(100L).setRole(UserRole.CODEVIEWER).setResourceId(1L);
 
     dao.deleteGroupRole(groupRoleToDelete, session);
     session.commit();
 
-    checkTable("resourceGroupPermissions", "group_roles", "group_id", "role");
+    dbTester.assertDbUnit(getClass(), "resourceGroupPermissions-result.xml", "group_roles");
   }
 
+  @Test
+  public void delete_all_group_permissions_by_group_id() {
+    dbTester.prepareDbUnit(getClass(), "deleteGroupPermissionsByGroupId.xml");
+
+    dao.deleteGroupRolesByGroupId(session, 100L);
+    session.commit();
+
+    dbTester.assertDbUnit(getClass(), "deleteGroupPermissionsByGroupId-result.xml", "group_roles");
+  }
 }
diff --git a/sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/deleteGroupPermissionsByGroupId-result.xml b/sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/deleteGroupPermissionsByGroupId-result.xml
new file mode 100644 (file)
index 0000000..a9effb1
--- /dev/null
@@ -0,0 +1,13 @@
+<dataset>
+
+  <groups id="100" name="sonar-administrators"/>
+  <groups id="101" name="sonar-users"/>
+
+  <group_roles id="4" group_id="101" role="shareDashboard" resource_id="[null]"/>
+
+  <group_roles id="5" group_id="[null]" role="scan" resource_id="[null]"/>
+  <group_roles id="6" group_id="[null]" role="dryRunScan" resource_id="[null]"/>
+
+  <group_roles id="7" group_id="102" role="admin" resource_id="1"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/deleteGroupPermissionsByGroupId.xml b/sonar-core/src/test/resources/org/sonar/core/user/RoleDaoTest/deleteGroupPermissionsByGroupId.xml
new file mode 100644 (file)
index 0000000..f05b0ae
--- /dev/null
@@ -0,0 +1,18 @@
+<dataset>
+
+  <groups id="100" name="sonar-administrators"/>
+  <groups id="101" name="sonar-users"/>
+
+  <!-- All 3 lines with group_id 100 will be deleted -->
+  <group_roles id="1" group_id="100" role="admin" resource_id="[null]"/>
+  <group_roles id="2" group_id="100" role="profileadmin" resource_id="1"/>
+  <group_roles id="3" group_id="100" role="shareDashboard" resource_id="[null]"/>
+
+  <group_roles id="4" group_id="101" role="shareDashboard" resource_id="[null]"/>
+
+  <group_roles id="5" group_id="[null]" role="scan" resource_id="[null]"/>
+  <group_roles id="6" group_id="[null]" role="dryRunScan" resource_id="[null]"/>
+
+  <group_roles id="7" group_id="102" role="admin" resource_id="1"/>
+
+</dataset>
index de8f3571616f4e759b645796d69c1be7f1738ba2..d87bfe95e0710a18224bd8ec202b8bcd39fe28bc 100644 (file)
@@ -3,13 +3,13 @@
   <groups id="100" name="sonar-administrators"/>
   <groups id="101" name="sonar-users"/>
 
-  <group_roles id="1" group_id="100" role="admin"/>
-  <group_roles id="3" group_id="100" role="shareDashboard"/>
-  <group_roles id="4" group_id="101" role="shareDashboard"/>
+  <group_roles id="1" group_id="100" role="admin" resource_id="[null]"/>
+  <group_roles id="3" group_id="100" role="shareDashboard" resource_id="[null]"/>
+  <group_roles id="4" group_id="101" role="shareDashboard" resource_id="[null]"/>
 
   <!-- Group 'anyone' has a NULL group_id -->
-  <group_roles id="5" group_id="[null]" role="scan"/>
-  <group_roles id="6" group_id="[null]" role="dryRunScan"/>
+  <group_roles id="5" group_id="[null]" role="scan" resource_id="[null]"/>
+  <group_roles id="6" group_id="[null]" role="dryRunScan" resource_id="[null]"/>
 
   <group_roles id="7" group_id="102" role="admin" resource_id="1"/>
 
index 750883651eb571b4626a0ed9170f7a8fc53f7727..2e76afcd3be08c378f3ec3c7ecfad8b36bcde36a 100644 (file)
@@ -3,14 +3,14 @@
   <groups id="100" name="sonar-administrators"/>
   <groups id="101" name="sonar-users"/>
 
-  <group_roles id="1" group_id="100" role="admin"/>
-  <group_roles id="2" group_id="100" role="profileadmin"/>
-  <group_roles id="3" group_id="100" role="shareDashboard"/>
-  <group_roles id="4" group_id="101" role="shareDashboard"/>
+  <group_roles id="1" group_id="100" role="admin" resource_id="[null]"/>
+  <group_roles id="2" group_id="100" role="profileadmin" resource_id="[null]"/>
+  <group_roles id="3" group_id="100" role="shareDashboard" resource_id="[null]"/>
+  <group_roles id="4" group_id="101" role="shareDashboard" resource_id="[null]"/>
 
   <!-- Group 'anyone' has a NULL group_id -->
-  <group_roles id="5" group_id="[null]" role="scan"/>
-  <group_roles id="6" group_id="[null]" role="dryRunScan"/>
+  <group_roles id="5" group_id="[null]" role="scan" resource_id="[null]"/>
+  <group_roles id="6" group_id="[null]" role="dryRunScan" resource_id="[null]"/>
 
   <!-- Component permission, it should not be returned with global permissions -->
   <group_roles id="7" group_id="102" role="admin" resource_id="1"/>
index 83fec77b3af0e34563ba48d3358411e23464e8a0..5fd4509c33004be6f77432d15fa1b9dbe3313461 100644 (file)
@@ -3,8 +3,8 @@
   <users id="200" login="admin_user" name="admin_user" active="[true]"/>
   <users id="201" login="profile_admin_user" name="profile_admin_user" active="[true]"/>
 
-  <user_roles id="1" user_id="200" role="admin"/>
-  <user_roles id="3" user_id="201" role="profileadmin"/>
+  <user_roles id="1" user_id="200" role="admin" resource_id="[null]"/>
+  <user_roles id="3" user_id="201" role="profileadmin" resource_id="[null]"/>
 
   <user_roles id="4" user_id="200" role="admin" resource_id="1"/>
 
index e382ca66a8c2af6fe3e5147d563eab273b4fb157..4d95c91f03d157b88edf5933600c76bd77ffbfa9 100644 (file)
@@ -3,9 +3,9 @@
   <users id="200" login="admin_user" name="admin_user" active="[true]"/>
   <users id="201" login="profile_admin_user" name="profile_admin_user" active="[true]"/>
 
-  <user_roles id="1" user_id="200" role="admin"/>
-  <user_roles id="2" user_id="200" role="profileadmin"/>
-  <user_roles id="3" user_id="201" role="profileadmin"/>
+  <user_roles id="1" user_id="200" role="admin" resource_id="[null]"/>
+  <user_roles id="2" user_id="200" role="profileadmin" resource_id="[null]"/>
+  <user_roles id="3" user_id="201" role="profileadmin" resource_id="[null]"/>
 
   <!-- Component permission, it should not be returned with global permissions -->
   <user_roles id="4" user_id="200" role="admin" resource_id="1"/>
index cdfb5b510b384206ca9e1f7627432f262dedb4f0..71650eb675acb2778d7204c3d136c788390797f8 100644 (file)
@@ -3,12 +3,12 @@
   <groups id="100" name="sonar-administrators"/>
   <groups id="101" name="sonar-users"/>
 
-  <group_roles id="1" group_id="100" role="admin"/>
-  <group_roles id="3" group_id="101" role="codeviewer"/>
+  <group_roles id="1" group_id="100" role="admin" resource_id="1"/>
+  <group_roles id="3" group_id="101" role="codeviewer" resource_id="1"/>
 
   <!-- Group 'anyone' has a NULL group_id -->
-  <group_roles id="4" group_id="[null]" role="user"/>
+  <group_roles id="4" group_id="[null]" role="user" resource_id="1"/>
 
-  <group_roles id="5" group_id="100" role="admin"/>
+  <group_roles id="5" group_id="100" role="admin" resource_id="[null]"/>
 
 </dataset>
index 424faca8a36e7da12ba82dfcf564a7c29d83ba6b..8fb07128af71a8c94f1bdae68d7d244c85761e26 100644 (file)
@@ -11,6 +11,6 @@
   <group_roles id="4" group_id="[null]" role="user" resource_id="1"/>
 
   <!-- Global permission, it should not be returned with component permissions -->
-  <group_roles id="5" group_id="100" role="admin"/>
+  <group_roles id="5" group_id="100" role="admin" resource_id="[null]"/>
 
 </dataset>