diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java index 62898d8133..23c58fdcd9 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java @@ -39,6 +39,7 @@ import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService; import org.alfresco.repo.copy.CopyBehaviourCallback; import org.alfresco.repo.copy.CopyDetails; +import org.alfresco.repo.copy.CopyServicePolicies; import org.alfresco.repo.copy.DefaultCopyBehaviourCallback; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; @@ -65,7 +66,8 @@ public class RecordAspect extends AbstractDisposableItem implements NodeServicePolicies.OnCreateChildAssociationPolicy, RecordsManagementPolicies.OnCreateReference, RecordsManagementPolicies.OnRemoveReference, - NodeServicePolicies.OnMoveNodePolicy + NodeServicePolicies.OnMoveNodePolicy, + CopyServicePolicies.OnCopyCompletePolicy { /** Well-known location of the scripts folder. */ // TODO make configurable @@ -305,4 +307,33 @@ public class RecordAspect extends AbstractDisposableItem scriptService.executeScript(scriptNodeRef, null, objectModel); } } + + /** + * On copy complete behaviour for record aspect. + * + * @param classRef + * @param sourceNodeRef + * @param targetNodeRef + * @param copyToNewNode + * @param copyMap + */ + @Override + @Behaviour + ( + kind = BehaviourKind.CLASS + ) + public void onCopyComplete(QName classRef, + NodeRef sourceNodeRef, + NodeRef targetNodeRef, + boolean copyToNewNode, + Map copyMap) + { + // given the node exists and is a record + if (nodeService.exists(targetNodeRef) && + nodeService.hasAspect(targetNodeRef, ASPECT_RECORD)) + { + // then remove any extended security from the newly copied record + extendedSecurityService.remove(targetNodeRef); + } + } } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java index 8a25952a77..b972d7823a 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java @@ -70,6 +70,8 @@ public class InplaceRecordPermissionTest extends BaseRMTestCase /** test data */ private NodeRef contribDoc; private NodeRef deleteUserDoc; + private NodeRef copiedDoc; + private NodeRef copyDoc; private String deletedUser; /** services */ @@ -247,14 +249,14 @@ public class InplaceRecordPermissionTest extends BaseRMTestCase private void checkInPlaceAccess(NodeRef nodeRef, AccessStatus ... accessStatus) { // check permission access - assertEquals(accessStatus[0], permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS)); - assertEquals(accessStatus[1], permissionService.hasPermission(nodeRef, RMPermissionModel.FILING)); + assertEquals("Incorrect read record permission access.", accessStatus[0], permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS)); + assertEquals("Incorrect filling permission access.", accessStatus[1], permissionService.hasPermission(nodeRef, RMPermissionModel.FILING)); // check capability access Map access = capabilityService.getCapabilitiesAccessState(nodeRef, CAPABILITIES); - assertEquals(accessStatus[2], access.get(viewRecordsCapability)); - assertEquals(accessStatus[3], access.get(editNonRecordMetadataCapability)); - assertEquals(accessStatus[4], access.get(editRecordMetadataCapability)); + assertEquals("Incorrect view records capability access", accessStatus[2], access.get(viewRecordsCapability)); + assertEquals("Incorrect edit non record metadata capability access", accessStatus[3], access.get(editNonRecordMetadataCapability)); + assertEquals("Incorrect edit record metadata capability access", accessStatus[4], access.get(editRecordMetadataCapability)); } /** @@ -777,7 +779,7 @@ public class InplaceRecordPermissionTest extends BaseRMTestCase * Given a user is the cm:creator of a document * And the user is deleted * When the document is declared as a record by a manager - * Then it succesfully becomes a record + * Then it successfully becomes a record */ public void testCmCreatorDeletedBeforeRecordDeclaration() { @@ -808,6 +810,101 @@ public class InplaceRecordPermissionTest extends BaseRMTestCase ; } + /** + * Given a document created by the collaborator + * And declared as a record by the collaborator + * And filed by the records manager + * When the records manager copies the record + * Then the collaborator has no access to the record copy + * And a site contributor has no access to the record copy + * And the consumer has no access to the record copy + * And a user that is not in the site has no access to the record copy + */ + public void testNoPermissionsOnCopy() + { + test() + .given() + .as(dmCollaborator) + .perform(() -> + { + // Given a document created by the collaborator + copiedDoc = fileFolderService.create(dmFolder, "copiedDoc.txt" , ContentModel.TYPE_CONTENT).getNodeRef(); + dbNodeService.addAspect(copiedDoc, ContentModel.ASPECT_AUDITABLE, null); + + // And declared as a record by the collaborator + recordService.createRecord(filePlan, copiedDoc); + }) + .asAdmin() + + // And filed by the records manager + .perform(() -> fileFolderService.move(copiedDoc, rmFolder, null)) + + .as(dmCollaborator) + .perform(() -> + checkInPlaceAccess(copiedDoc, + AccessStatus.ALLOWED, // read record permission + AccessStatus.ALLOWED, // filing permission + AccessStatus.ALLOWED, // view record capability + AccessStatus.ALLOWED, // edit non record metadata capability + AccessStatus.DENIED)) // edit record metadata capability + + .when() + .asAdmin() + + // When the records manager copies the record + .perform(() -> copyDoc = fileFolderService.copy(copiedDoc, rmFolder, "newRecord.txt").getNodeRef()) + + .then() + + // Then the collaborator has no access to the record copy + .as(dmCollaborator) + .perform(() -> + checkInPlaceAccess(copyDoc, + AccessStatus.DENIED, // read record permission + AccessStatus.DENIED, // filing permission + AccessStatus.DENIED, // view record capability + AccessStatus.DENIED, // edit non record metadata capability + AccessStatus.DENIED)) // edit record metadata capability + .perform(() -> + checkInPlaceAccess(copiedDoc, + AccessStatus.ALLOWED, // read record permission + AccessStatus.ALLOWED, // filing permission + AccessStatus.ALLOWED, // view record capability + AccessStatus.ALLOWED, // edit non record metadata capability + AccessStatus.DENIED)) // edit record metadata capability + + // And a site contributor has no access to the record copy + .as(dmContributor) + .perform(() -> + checkInPlaceAccess(copyDoc, + AccessStatus.DENIED, // read record permission + AccessStatus.DENIED, // filing permission + AccessStatus.DENIED, // view record capability + AccessStatus.DENIED, // edit non record metadata capability + AccessStatus.DENIED)) // edit record metadata capability + + // And the consumer has no access to the record copy + .as(dmConsumer) + .perform(() -> + checkInPlaceAccess(copyDoc, + AccessStatus.DENIED, // read record permission + AccessStatus.DENIED, // filing permission + AccessStatus.DENIED, // view record capability + AccessStatus.DENIED, // edit non record metadata capability + AccessStatus.DENIED)) // edit record metadata capability + + // And a user that is not in the site has no access to the record copy + .as(userName) + .perform(() -> + checkInPlaceAccess(copyDoc, + AccessStatus.DENIED, // read record permission + AccessStatus.DENIED, // filing permission + AccessStatus.DENIED, // view record capability + AccessStatus.DENIED, // edit non record metadata capability + AccessStatus.DENIED)); // edit record metadata capability + ; + } + /** * Test group reuse */