diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml index f1bd9ed043..f7dc62dc12 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml @@ -63,6 +63,7 @@ parent="org_alfresco_module_rm_BaseBehaviour"> + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java index a0b5a1077a..703babff3c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService; import org.alfresco.repo.node.NodeServicePolicies; @@ -29,11 +30,13 @@ import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.site.SiteModel; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; @@ -47,27 +50,32 @@ import org.alfresco.util.PropertyMap; */ public class RmSiteType implements RecordsManagementModel, NodeServicePolicies.OnCreateNodePolicy, - NodeServicePolicies.OnUpdatePropertiesPolicy + NodeServicePolicies.OnUpdatePropertiesPolicy, + NodeServicePolicies.BeforeDeleteNodePolicy { /** Constant values */ public static final String COMPONENT_DOCUMENT_LIBRARY = "documentLibrary"; public static final String DEFAULT_SITE_NAME = "rm"; /** Policy component */ - private PolicyComponent policyComponent; + protected PolicyComponent policyComponent; /** Site service */ - private SiteService siteService; + protected SiteService siteService; /** Node service */ - private NodeService nodeService; + protected NodeService nodeService; /** Record Management Search Service */ - private RecordsManagementSearchService recordsManagementSearchService; + protected RecordsManagementSearchService recordsManagementSearchService; + + /** Capability service */ + protected CapabilityService capabilityService; /** Behaviour */ JavaBehaviour onCreateNode = new JavaBehaviour(this, "onCreateNode", NotificationFrequency.FIRST_EVENT); JavaBehaviour onUpdateProperties = new JavaBehaviour(this, "onUpdateProperties", NotificationFrequency.FIRST_EVENT); + JavaBehaviour beforeDelete = new JavaBehaviour(this, "beforeDeleteNode", NotificationFrequency.FIRST_EVENT); /** * Set the policy component @@ -104,6 +112,14 @@ public class RmSiteType implements RecordsManagementModel, this.recordsManagementSearchService = recordsManagementSearchService; } + /** + * @param capabilityService capability service + */ + public void setCapabilityService(CapabilityService capabilityService) + { + this.capabilityService = capabilityService; + } + /** * Bean initialisation method */ @@ -116,6 +132,10 @@ public class RmSiteType implements RecordsManagementModel, policyComponent.bindClassBehaviour(NodeServicePolicies.OnUpdatePropertiesPolicy.QNAME, TYPE_RM_SITE, onUpdateProperties); + + policyComponent.bindClassBehaviour(NodeServicePolicies.BeforeDeleteNodePolicy.QNAME, + TYPE_RM_SITE, + beforeDelete); } /** @@ -184,4 +204,36 @@ public class RmSiteType implements RecordsManagementModel, } } } + + /** + * @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public void beforeDeleteNode(NodeRef nodeRef) + { + final SiteInfo siteInfo = siteService.getSite(nodeRef); + if (siteInfo != null) + { + // grab the file plan for the RM site + NodeRef filePlan = AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public NodeRef doWork() throws Exception + { + return siteService.getContainer(siteInfo.getShortName(), COMPONENT_DOCUMENT_LIBRARY); + } + + }); + + if (filePlan != null) + { + // determine whether the current user has delete capability on the file plan node + AccessStatus accessStatus = capabilityService.getCapabilityAccessState(filePlan, "Delete"); + if (AccessStatus.DENIED.equals(accessStatus) == true) + { + throw new AlfrescoRuntimeException("The records management site can not be deleted, because the user doesn't have sufficient privillages to delete the file plan."); + } + } + } + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/IssueTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/IssueTestSuite.java index 30daf78cff..8da2f5b7e5 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/IssueTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/IssueTestSuite.java @@ -23,6 +23,7 @@ import org.alfresco.module.org_alfresco_module_rm.test.issue.RM1027Test; import org.alfresco.module.org_alfresco_module_rm.test.issue.RM1030Test; import org.alfresco.module.org_alfresco_module_rm.test.issue.RM1039Test; import org.alfresco.module.org_alfresco_module_rm.test.issue.RM452Test; +import org.alfresco.module.org_alfresco_module_rm.test.issue.RM804Test; import org.alfresco.module.org_alfresco_module_rm.test.issue.RM994Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -42,7 +43,8 @@ import org.junit.runners.Suite.SuiteClasses; RM1008Test.class, RM1030Test.class, RM1027Test.class, - RM1039Test.class + RM1039Test.class, + RM804Test.class }) public class IssueTestSuite { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/issue/RM804Test.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/issue/RM804Test.java new file mode 100644 index 0000000000..7105d692ce --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/issue/RM804Test.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco 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. + * + * Alfresco 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 Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.test.issue; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.site.SiteRole; + + +/** + * Unit test for RM-804 .. site managers are able to delete file plans + * + * @author Roy Wetherall + * @since 2.1 + */ +public class RM804Test extends BaseRMTestCase +{ + @Override + protected void initServices() + { + super.initServices(); + } + + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + @Override + protected boolean isUserTest() + { + return true; + } + + public void testUsersHaveDeletePermissionsOnFilePlan() throws Exception + { + // as rmuser + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertEquals(AccessStatus.ALLOWED, capabilityService.getCapabilityAccessState(filePlan, "Delete")); + + return null; + } + }, "rmadmin"); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertEquals(AccessStatus.ALLOWED, capabilityService.getCapabilityAccessState(filePlan, "Delete")); + + return null; + } + }, "admin"); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertEquals(AccessStatus.ALLOWED, capabilityService.getCapabilityAccessState(filePlan, "Delete")); + + return null; + } + }, rmAdminName); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertEquals(AccessStatus.DENIED, capabilityService.getCapabilityAccessState(filePlan, "Delete")); + + return null; + } + }, rmUserName); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertEquals(AccessStatus.DENIED, capabilityService.getCapabilityAccessState(filePlan, "Delete")); + + return null; + } + }, userName); + } + + public void testTryAndDeleteSiteAsSiteManagerOnly() + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + siteService.setMembership(siteId, userName, SiteRole.SiteManager.toString()); + + return null; + } + }, "admin"); + + doTestInTransaction(new FailureTest + ( + "Should not be able to delete site as a site manager only.", + AlfrescoRuntimeException.class + ) + { + @Override + public void run() throws Exception + { + siteService.deleteSite(siteId); + + } + }, userName); + + // give the user a RM role (but not sufficient to delete the file plan node ref) + doTestInTransaction(new Test() + { + @Override + public Void run() + { + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_NAME_USER, userName); + + return null; + } + }, "admin"); + + doTestInTransaction(new FailureTest + ( + "Should not be able to delete site as a site manager with an RM role that doesn't have the capability.", + AlfrescoRuntimeException.class + ) + { + @Override + public void run() throws Exception + { + siteService.deleteSite(siteId); + + } + }, userName); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_NAME_ADMINISTRATOR, userName); + + return null; + } + }, "admin"); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + siteService.deleteSite(siteId); + + return null; + } + }, userName); + + } + +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java index 9f6ff57ae4..520b9b7d94 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java @@ -406,20 +406,29 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase filter.disableBehaviour(); try { - Set holds = freezeService.getHolds(filePlan); - for (NodeRef hold : holds) + if (nodeService.exists(filePlan) == true) { - freezeService.relinquish(hold); + Set holds = freezeService.getHolds(filePlan); + for (NodeRef hold : holds) + { + freezeService.relinquish(hold); + } } - // Delete the folder - nodeService.deleteNode(folder); - - // Delete the site - siteService.deleteSite(siteId); + if (nodeService.exists(folder) == true) + { + // Delete the folder + nodeService.deleteNode(folder); + } + + if (siteService.getSite(siteId) != null) + { + // Delete the site + siteService.deleteSite(siteId); + } // delete the collaboration site (if required) - if (isCollaborationSiteTest() == true) + if (isCollaborationSiteTest() == true && siteService.getSite(COLLABORATION_SITE_ID) != null) { siteService.deleteSite(COLLABORATION_SITE_ID); }