diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-09-15 17:38:14 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-09-15 17:38:14 +0200 |
commit | 5931c7b499951578606a1fcb3ee2412bd0ae90b4 (patch) | |
tree | 595fc167fa6c3faa1de9ae4f229e4237837f334a /server | |
parent | a31b72f90bc2fb0f04abf6f9646436e257204d27 (diff) | |
download | sonarqube-5931c7b499951578606a1fcb3ee2412bd0ae90b4.tar.gz sonarqube-5931c7b499951578606a1fcb3ee2412bd0ae90b4.zip |
SONAR-5613 Update Issues Authorization Index when deleting a project
Diffstat (limited to 'server')
9 files changed, 219 insertions, 20 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java new file mode 100644 index 00000000000..79b36089bc5 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -0,0 +1,59 @@ +/* + * 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.component; + +import org.sonar.api.ServerComponent; +import org.sonar.api.resources.Scopes; +import org.sonar.core.component.AuthorizedComponentDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.purge.PurgeDao; +import org.sonar.server.db.DbClient; + +public class ComponentCleanerService implements ServerComponent { + + private final DbClient dbClient; + private final PurgeDao purgeDao; + + public ComponentCleanerService(DbClient dbClient, PurgeDao purgeDao) { + this.dbClient = dbClient; + this.purgeDao = purgeDao; + } + + public void delete(String projectKey) { + DbSession session = dbClient.openSession(false); + try { + AuthorizedComponentDto project = dbClient.componentDao().getAuthorizedComponentByKey(projectKey, session); + if (!Scopes.PROJECT.equals(project.scope())) { + throw new IllegalArgumentException("Only project can be deleted"); + } + purgeDao.deleteResourceTree(project.getId()); + deletePermissionIndexes(session, projectKey); + session.commit(); + } finally { + session.close(); + } + } + + private void deletePermissionIndexes(DbSession session, String projectKey) { + dbClient.issueAuthorizationDao().deleteByKey(session, projectKey); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/component/package-info.java new file mode 100644 index 00000000000..03729ae4c0e --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/component/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +@ParametersAreNonnullByDefault +package org.sonar.server.component; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index cb48dbeff87..ace8404adfe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -79,6 +79,7 @@ import org.sonar.server.activity.ws.ActivityMapping; import org.sonar.server.authentication.ws.AuthenticationWs; import org.sonar.server.batch.*; import org.sonar.server.charts.ChartFactory; +import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.DefaultComponentFinder; import org.sonar.server.component.DefaultRubyComponentService; import org.sonar.server.component.db.ComponentDao; @@ -458,6 +459,7 @@ class ServerComponents { pico.addSingleton(ProjectsWs.class); pico.addSingleton(ComponentAppAction.class); pico.addSingleton(EventsWs.class); + pico.addSingleton(ComponentCleanerService.class); // issues pico.addSingleton(ServerIssueStorage.class); diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index f77088beb21..300589c85f4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -30,17 +30,13 @@ import org.sonar.api.platform.PluginRepository; import org.sonar.api.resources.Language; import org.sonar.api.resources.ResourceType; import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.web.Footer; -import org.sonar.api.web.NavigationSection; -import org.sonar.api.web.Page; -import org.sonar.api.web.RubyRailsWebservice; -import org.sonar.api.web.Widget; +import org.sonar.api.web.*; import org.sonar.core.persistence.Database; import org.sonar.core.preview.PreviewCache; -import org.sonar.core.purge.PurgeDao; import org.sonar.core.resource.ResourceIndexerDao; import org.sonar.core.resource.ResourceKeyUpdaterDao; import org.sonar.core.timemachine.Periods; +import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.db.migrations.DatabaseMigrator; import org.sonar.server.measure.MeasureFilterEngine; import org.sonar.server.measure.MeasureFilterResult; @@ -48,11 +44,7 @@ import org.sonar.server.platform.Platform; import org.sonar.server.platform.ServerIdGenerator; import org.sonar.server.platform.ServerSettings; import org.sonar.server.platform.SettingsChangeNotifier; -import org.sonar.server.plugins.InstalledPluginReferentialFactory; -import org.sonar.server.plugins.PluginDownloader; -import org.sonar.server.plugins.ServerPluginJarsInstaller; -import org.sonar.server.plugins.ServerPluginRepository; -import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.server.plugins.*; import org.sonar.server.rule.RuleRepositories; import org.sonar.server.source.CodeColorizers; import org.sonar.server.user.NewUserNotifier; @@ -338,11 +330,11 @@ public final class JRubyFacade { get(ResourceIndexerDao.class).indexResource(resourceId); } - public void deleteResourceTree(long rootProjectId) { + public void deleteResourceTree(String projectKey) { try { - get(PurgeDao.class).deleteResourceTree(rootProjectId); + get(ComponentCleanerService.class).delete(projectKey); } catch (RuntimeException e) { - LoggerFactory.getLogger(JRubyFacade.class).error("Fail to delete resource with ID: " + rootProjectId, e); + LoggerFactory.getLogger(JRubyFacade.class).error("Fail to delete resource with key: " + projectKey, e); throw e; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceMediumTest.java new file mode 100644 index 00000000000..f87765e1147 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceMediumTest.java @@ -0,0 +1,118 @@ +/* + * 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.component; + +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Scopes; +import org.sonar.api.security.DefaultGroups; +import org.sonar.api.web.UserRole; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.permission.PermissionFacade; +import org.sonar.core.persistence.DbSession; +import org.sonar.server.db.DbClient; +import org.sonar.server.issue.index.IssueAuthorizationIndex; +import org.sonar.server.tester.ServerTester; + +import java.util.Date; + +import static org.fest.assertions.Assertions.assertThat; + +public class ComponentCleanerServiceMediumTest { + + @ClassRule + public static ServerTester tester = new ServerTester(); + + DbClient db; + DbSession session; + + ComponentCleanerService service; + + @Before + public void setUp() throws Exception { + tester.clearDbAndIndexes(); + + db = tester.get(DbClient.class); + session = db.openSession(false); + service = tester.get(ComponentCleanerService.class); + } + + @After + public void after() { + session.close(); + } + + @Test + public void delete_project() throws Exception { + ComponentDto project = new ComponentDto() + .setId(1L) + .setKey("MyProject") + .setScope(Scopes.PROJECT) + .setQualifier(Qualifiers.PROJECT) + .setProjectId(1L); + db.componentDao().insert(session, project); + session.commit(); + + service.delete(project.getKey()); + + assertThat(db.componentDao().getNullableByKey(session, project.key())).isNull(); + } + + @Test + public void remove_issue_permission_index_when_deleting_a_project() throws Exception { + ComponentDto project = new ComponentDto() + .setId(1L) + .setKey("MyProject") + .setScope(Scopes.PROJECT) + .setQualifier(Qualifiers.PROJECT) + .setProjectId(1L); + db.componentDao().insert(session, project); + + // project can be seen by anyone + tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); + db.issueAuthorizationDao().synchronizeAfter(session, new Date(0)); + + session.commit(); + + assertThat(tester.get(IssueAuthorizationIndex.class).getByKey(project.getKey())).isNotNull(); + + service.delete(project.getKey()); + + assertThat(tester.get(IssueAuthorizationIndex.class).getByKey(project.getKey())).isNull(); + } + + @Test(expected = IllegalArgumentException.class) + public void fail_to_delete_not_project() throws Exception { + ComponentDto project = new ComponentDto() + .setId(1L) + .setKey("MyProject") + .setScope(Scopes.DIRECTORY) + .setQualifier(Qualifiers.DIRECTORY) + .setProjectId(1L); + db.componentDao().insert(session, project); + session.commit(); + + service.delete(project.getKey()); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java index f710f66d1a4..4cad5f9e86c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java @@ -187,7 +187,10 @@ public class ComponentDaoTest extends AbstractDaoTestCase { AuthorizedComponentDto result = dao.getNullableAuthorizedComponentById(4L, session); assertThat(result).isNotNull(); - assertThat(result.key()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java"); + assertThat(result.getId()).isEqualTo(4); + assertThat(result.getKey()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java"); + assertThat(result.qualifier()).isEqualTo("FIL"); + assertThat(result.scope()).isEqualTo("FIL"); assertThat(dao.getNullableAuthorizedComponentById(111L, session)).isNull(); } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/provisioning_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/provisioning_controller.rb index eaa7d6d8e46..4eb61160379 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/provisioning_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/provisioning_controller.rb @@ -45,12 +45,12 @@ class ProvisioningController < ApplicationController bad_request('provisioning.missing.name') if @name.blank? if @id.nil? or @id.empty? - new_id = Internal.component_api.createComponent(@key, @name, 'TRK') + Internal.component_api.createComponent(@key, @name, 'TRK') begin Internal.permissions.applyDefaultPermissionTemplate(@key) rescue # Programmatic transaction rollback - Java::OrgSonarServerUi::JRubyFacade.getInstance().deleteResourceTree(new_id) + Java::OrgSonarServerUi::JRubyFacade.getInstance().deleteResourceTree(@key) raise end else @@ -80,7 +80,8 @@ class ProvisioningController < ApplicationController access_denied unless has_role?("provisioning") @id = params[:id].to_i - Java::OrgSonarServerUi::JRubyFacade.getInstance().deleteResourceTree(@id) + project = Project.first(:conditions => {:id => @id}) + Java::OrgSonarServerUi::JRubyFacade.getInstance().deleteResourceTree(project.key) flash.now[:notice]= Api::Utils.message('resource_viewer.resource_deleted') redirect_to :action => 'index' end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb index 533a9c0fe35..9b8d332ec12 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb @@ -54,7 +54,7 @@ class Project < ActiveRecord::Base def self.delete_resource_tree(project) java_facade = Java::OrgSonarServerUi::JRubyFacade.getInstance() if project && java_facade.getResourceTypeBooleanProperty(project.qualifier, 'deletable') - java_facade.deleteResourceTree(project.id) + java_facade.deleteResourceTree(project.key) end end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/models/resource_deletion_manager.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/models/resource_deletion_manager.rb index e880e4fbadd..a62824b7a16 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/models/resource_deletion_manager.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/models/resource_deletion_manager.rb @@ -103,7 +103,7 @@ class ResourceDeletionManager @message = Api::Utils.message('bulk_deletion.deletion_manager.currently_deleting_x_out_of_x', :params => [(index+1).to_s, resource_ids.size.to_s]) if resource && java_facade.getResourceTypeBooleanProperty(resource.qualifier, 'deletable') begin - java_facade.deleteResourceTree(resource.id) + java_facade.deleteResourceTree(resource.key) rescue Exception => e @failed_deletions << resource.name # no need to rethrow the exception as it has been logged by the Java component |