]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8681 delete perm,groups&components in api/organizations/delete 1546/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 19 Jan 2017 10:31:16 +0000 (11:31 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 23 Jan 2017 15:56:35 +0000 (16:56 +0100)
server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml

index bd9e560330245d690ee41d42d9ae6b19fd8830a4..5f55af3c5f31dae5262c730ab0b9112fe74688c7 100644 (file)
  */
 package org.sonar.server.organization.ws;
 
+import java.util.List;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.organization.DefaultOrganization;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.user.UserSession;
@@ -40,11 +43,14 @@ public class DeleteAction implements OrganizationsAction {
   private final UserSession userSession;
   private final DbClient dbClient;
   private final DefaultOrganizationProvider defaultOrganizationProvider;
+  private final ComponentCleanerService componentCleanerService;
 
-  public DeleteAction(UserSession userSession, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider) {
+  public DeleteAction(UserSession userSession, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider,
+    ComponentCleanerService componentCleanerService) {
     this.userSession = userSession;
     this.dbClient = dbClient;
     this.defaultOrganizationProvider = defaultOrganizationProvider;
+    this.componentCleanerService = componentCleanerService;
   }
 
   @Override
@@ -78,13 +84,39 @@ public class DeleteAction implements OrganizationsAction {
 
       userSession.checkOrganizationPermission(organizationDto.getUuid(), SYSTEM_ADMIN);
 
-      dbClient.organizationDao().deleteByKey(dbSession, key);
-      dbSession.commit();
+      deleteProjects(dbSession, organizationDto.getUuid());
+      deletePermissions(dbSession, organizationDto.getUuid());
+      deleteGroups(dbSession, organizationDto.getUuid());
+      deleteOrganization(key, dbSession);
 
       response.noContent();
     }
   }
 
+  private void deleteProjects(DbSession dbSession, String organizationUuid) {
+    List<ComponentDto> roots = dbClient.componentDao().selectAllRootsByOrganization(dbSession, organizationUuid);
+    componentCleanerService.delete(dbSession, roots);
+  }
+
+  private void deletePermissions(DbSession dbSession, String organizationUuid) {
+    dbClient.permissionTemplateDao().deleteByOrganization(dbSession, organizationUuid);
+    dbSession.commit();
+    dbClient.userPermissionDao().deleteByOrganization(dbSession, organizationUuid);
+    dbSession.commit();
+    dbClient.groupPermissionDao().deleteByOrganization(dbSession, organizationUuid);
+    dbSession.commit();
+  }
+
+  private void deleteGroups(DbSession dbSession, String organizationUuid) {
+    dbClient.groupDao().deleteByOrganization(dbSession, organizationUuid);
+    dbSession.commit();
+  }
+
+  private void deleteOrganization(String key, DbSession dbSession) {
+    dbClient.organizationDao().deleteByKey(dbSession, key);
+    dbSession.commit();
+  }
+
   private static void preventDeletionOfDefaultOrganization(String key, DefaultOrganization defaultOrganization) {
     checkArgument(!defaultOrganization.getKey().equals(key), "Default Organization can't be deleted");
   }
index a93ef0859529f7de300a7b0d0f4cd3383e2b9283..811f4047b4f78ea2014e7438073cf44eb52fef1d 100644 (file)
  */
 package org.sonar.server.organization.ws;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.api.resources.ResourceType;
+import org.sonar.api.resources.ResourceTypes;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.permission.template.PermissionTemplateDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
+import org.sonar.server.component.ComponentCleanerService;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.component.index.ComponentIndexer;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.test.index.TestIndexer;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
 
+import static com.google.common.collect.ImmutableList.of;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
 import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY;
 
@@ -49,9 +66,21 @@ public class DeleteActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private DeleteAction underTest = new DeleteAction(userSession, dbTester.getDbClient(), TestDefaultOrganizationProvider.from(dbTester));
+  private DbClient dbClient = dbTester.getDbClient();
+  private DbSession session = dbTester.getSession();
+
+  private ResourceTypes resourceTypes = mock(ResourceTypes.class);
+  private ComponentCleanerService componentCleanerService = new ComponentCleanerService(dbTester.getDbClient(),
+    mock(IssueIndexer.class), mock(TestIndexer.class), mock(ProjectMeasuresIndexer.class),
+    mock(ComponentIndexer.class), resourceTypes, new ComponentFinder(dbTester.getDbClient()));
+  private DeleteAction underTest = new DeleteAction(userSession, dbTester.getDbClient(), TestDefaultOrganizationProvider.from(dbTester), componentCleanerService);
   private WsActionTester wsTester = new WsActionTester(underTest);
 
+  @Before
+  public void setUp() throws Exception {
+    when(resourceTypes.get(anyString())).thenAnswer(invocation -> ResourceType.builder((String) invocation.getArguments()[0]).setProperty("deletable", true).build());
+  }
+
   @Test
   public void verify_define() {
     WebService.Action action = wsTester.getDef();
@@ -153,8 +182,85 @@ public class DeleteActionTest {
     verifyOrganizationDoesNotExist(organization);
   }
 
+  @Test
+  public void request_also_deletes_components_of_specified_organization() {
+    userSession.login().setRoot();
+
+    OrganizationDto organization = dbTester.organizations().insert();
+    ComponentDto project = dbTester.components().insertProject(organization);
+    ComponentDto module = dbTester.components().insertComponent(ComponentTesting.newModuleDto(project));
+    ComponentDto directory = dbTester.components().insertComponent(ComponentTesting.newDirectory(module, "a/b"));
+    ComponentDto file = dbTester.components().insertComponent(ComponentTesting.newFileDto(module, directory));
+    ComponentDto view = dbTester.components().insertView(organization, (dto) -> {
+    });
+    ComponentDto subview1 = dbTester.components().insertComponent(ComponentTesting.newSubView(view, "v1", "ksv1"));
+    ComponentDto subview2 = dbTester.components().insertComponent(ComponentTesting.newSubView(subview1, "v2", "ksv2"));
+    ComponentDto projectCopy = dbTester.components().insertComponent(ComponentTesting.newProjectCopy("pc1", project, subview1));
+
+    sendRequest(organization);
+
+    verifyOrganizationDoesNotExist(organization);
+    assertThat(dbTester.getDbClient().componentDao().selectByUuids(
+      session,
+      of(project.uuid(), module.uuid(), directory.uuid(), file.uuid(), view.uuid(), subview1.uuid(), subview2.uuid(), projectCopy.uuid())))
+        .isEmpty();
+  }
+
+  @Test
+  public void request_also_deletes_permissions_templates_and_permissions_and_groups_of_specified_organization() {
+    userSession.login().setRoot();
+
+    OrganizationDto organizationDto = dbTester.organizations().insert();
+    OrganizationDto otherOrganizationDto = dbTester.organizations().insert();
+
+    UserDto user1 = dbTester.users().insertUser();
+    UserDto user2 = dbTester.users().insertUser();
+    GroupDto group1 = dbTester.users().insertGroup(organizationDto);
+    GroupDto group2 = dbTester.users().insertGroup(organizationDto);
+    GroupDto otherGroup1 = dbTester.users().insertGroup(otherOrganizationDto);
+    GroupDto otherGroup2 = dbTester.users().insertGroup(otherOrganizationDto);
+
+    ComponentDto projectDto = dbTester.components().insertProject(organizationDto);
+    ComponentDto otherProjectDto = dbTester.components().insertProject(otherOrganizationDto);
+
+    dbTester.users().insertPermissionOnAnyone(organizationDto, "u1");
+    dbTester.users().insertPermissionOnAnyone(otherOrganizationDto, "not deleted u1");
+    dbTester.users().insertPermissionOnUser(organizationDto, user1, "u2");
+    dbTester.users().insertPermissionOnUser(otherOrganizationDto, user1, "not deleted u2");
+    dbTester.users().insertPermissionOnGroup(group1, "u3");
+    dbTester.users().insertPermissionOnGroup(otherGroup1, "not deleted u3");
+    dbTester.users().insertProjectPermissionOnAnyone(organizationDto, "u4", projectDto);
+    dbTester.users().insertProjectPermissionOnAnyone(otherOrganizationDto, "not deleted u4", otherProjectDto);
+    dbTester.users().insertProjectPermissionOnGroup(group1, "u5", projectDto);
+    dbTester.users().insertProjectPermissionOnGroup(otherGroup1, "not deleted u5", otherProjectDto);
+    dbTester.users().insertProjectPermissionOnUser(user1, "u6", projectDto);
+    dbTester.users().insertProjectPermissionOnUser(user1, "not deleted u6", otherProjectDto);
+
+    PermissionTemplateDto templateDto = dbTester.permissionTemplates().insertTemplate(organizationDto);
+    PermissionTemplateDto otherTemplateDto = dbTester.permissionTemplates().insertTemplate(otherOrganizationDto);
+
+    sendRequest(organizationDto);
+
+    verifyOrganizationDoesNotExist(organizationDto);
+    assertThat(dbClient.groupDao().selectByIds(session, of(group1.getId(), otherGroup1.getId(), group2.getId(), otherGroup2.getId())))
+      .extracting(GroupDto::getId)
+      .containsOnly(otherGroup1.getId(), otherGroup2.getId());
+    assertThat(dbClient.permissionTemplateDao().selectByUuid(session, templateDto.getUuid()))
+      .isNull();
+    assertThat(dbClient.permissionTemplateDao().selectByUuid(session, otherTemplateDto.getUuid()))
+      .isNotNull();
+    assertThat(dbTester.select("select role as \"role\" from USER_ROLES"))
+      .extracting(row -> (String) row.get("role"))
+      .doesNotContain("u2", "u6")
+      .contains("not deleted u2", "not deleted u6");
+    assertThat(dbTester.select("select role as \"role\" from GROUP_ROLES"))
+      .extracting(row -> (String) row.get("role"))
+      .doesNotContain("u1", "u3", "u4", "u5")
+      .contains("not deleted u1", "not deleted u3", "not deleted u4", "not deleted u5");
+  }
+
   private void verifyOrganizationDoesNotExist(OrganizationDto organization) {
-    assertThat(dbTester.getDbClient().organizationDao().selectByKey(dbTester.getSession(), organization.getKey()))
+    assertThat(dbTester.getDbClient().organizationDao().selectByKey(session, organization.getKey()))
       .isEmpty();
   }
 
index 0bc027afb7a7d26cfd79f13e24dd89474269f34a..ad049fc90df42795f8eb804ca0cf4a64fe4bae81 100644 (file)
@@ -198,6 +198,13 @@ public class ComponentDao implements Dao {
     return mapper(session).selectProjects();
   }
 
+  /**
+   * Select all root components (projects and views), including disabled ones, for a given organization.
+   */
+  public List<ComponentDto> selectAllRootsByOrganization(DbSession dbSession, String organizationUuid) {
+    return mapper(dbSession).selectAllRootsByOrganization(organizationUuid);
+  }
+
   public List<ComponentDto> selectProvisionedProjects(DbSession session, int offset, int limit, @Nullable String query) {
     Map<String, Object> parameters = newHashMapWithExpectedSize(2);
     addProjectQualifier(parameters);
index a32a4177b589340f3053e74e971e5d813882103a..9ad0394deb4cc716e3c6b7c389c9bee7087dabe0 100644 (file)
@@ -69,6 +69,8 @@ public interface ComponentMapper {
    */
   List<ComponentDto> selectProjects();
 
+  List<ComponentDto> selectAllRootsByOrganization(@Param("organizationUuid") String organizationUuid);
+
   /**
    * Return all descendant modules (including itself) from a given component uuid and scope
    */
index 92c23601b28f77945f328a8aa2a49e6c320e13b8..6fba079f9d533efd75d40e91d4a9ad3ed8f46d72 100644 (file)
     </where>
   </select>
 
+  <select id="selectAllRootsByOrganization" resultType="Component">
+    select
+      <include refid="componentColumns"/>
+    from projects p
+    where
+      p.scope='PRJ'
+      and (p.qualifier='TRK' or p.qualifier='VW')
+      and p.organization_uuid = #{organizationUuid,jdbcType=VARCHAR}
+  </select>
+
   <select id="selectComponentsByQualifiers" resultType="Component">
     SELECT
     <include refid="componentColumns"/>