From dba85373ab5c5113c6f0814dfd2b306d6a423bbc Mon Sep 17 00:00:00 2001 From: Ramona Popa Date: Fri, 28 Apr 2017 13:07:22 +0100 Subject: [PATCH] RM-4926 - added onRemoveAspect policy for RecordAspect --- .../UpdateRecordsTests.java | 103 +++++++++++++++ .../rm-model-context.xml | 5 + .../model/RecordsManagementModel.java | 1 + .../model/rma/aspect/ProtectedAspects.java | 99 ++++++++++++++ .../record/UpdateRecordAspectsTest.java | 125 ++++++++++++++++++ 5 files changed, 333 insertions(+) create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/ProtectedAspects.java create mode 100644 rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/UpdateRecordAspectsTest.java diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/fileplancomponents/UpdateRecordsTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/fileplancomponents/UpdateRecordsTests.java index c0b7ce55f2..356171f399 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/fileplancomponents/UpdateRecordsTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/fileplancomponents/UpdateRecordsTests.java @@ -26,7 +26,11 @@ */ package org.alfresco.rest.rm.community.fileplancomponents; +import static org.alfresco.rest.rm.community.base.TestData.NONELECTRONIC_RECORD_NAME; +import static org.alfresco.rest.rm.community.base.TestData.RECORD_FOLDER_NAME; +import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS; import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS; +import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.NON_ELECTRONIC_RECORD_TYPE; import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE; import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE; import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel; @@ -39,16 +43,23 @@ import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.FORBIDDEN; import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.alfresco.rest.rm.community.base.BaseRMRestTest; import org.alfresco.rest.rm.community.model.record.Record; import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild; import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChild; +import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildCollection; +import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildProperties; import org.alfresco.rest.rm.community.model.user.UserPermissions; import org.alfresco.rest.rm.community.model.user.UserRoles; +import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RMUserAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI; @@ -59,6 +70,7 @@ import org.alfresco.test.AlfrescoTest; import org.alfresco.utility.constants.UserRole; import org.alfresco.utility.model.SiteModel; import org.alfresco.utility.model.UserModel; +import org.testng.annotations.AfterClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -326,4 +338,95 @@ public class UpdateRecordsTests extends BaseRMRestTest { return MODIFIED_PREFIX + originalValue; } + /** + *
+     * Given a created record
+     * When I try to update the record aspects with an empty list
+     * Then it fails
+     * 
+ * @throws Exception + */ + @Test(description = "Cannot remove mandatory aspects from record") + @AlfrescoTest(jira = "RM-4926") + public void electronicRecordMandatoryAspectsCannotBeRemoved() throws Exception + { + // Get the recordsAPI + RecordsAPI recordsAPI = getRestAPIFactory().getRecordsAPI(); + RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI(); + + RecordCategoryChild recordFolder = createCategoryFolderInFilePlan(); + + // Create an electronic record + Record recordModel = createElectronicRecordModel(); + String recordId = recordFolderAPI.createRecord(recordModel, recordFolder.getId(), getFile(IMAGE_FILE)).getId(); + + Record electronicRecord = recordsAPI.getRecord(recordId); + List aspects = electronicRecord.getAspectNames(); + + // this operation is only valid for records + assertTrue(aspects.contains("rma:record")); + assertTrue(aspects.contains("rma:filePlanComponent")); + assertTrue(aspects.contains("rma:recordComponentIdentifier")); + assertTrue(aspects.contains("rma:commonRecordDetails")); + + List emptyAspectList = new ArrayList(); + Record recordModelToUpdate = Record.builder().aspectNames(emptyAspectList).build(); + + // Update record + recordsAPI.updateRecord(recordModelToUpdate, electronicRecord.getId()); + assertStatusCode(UNPROCESSABLE_ENTITY); + + // Get the recordsAPI + UnfiledRecordFolderAPI unfiledRecordFolderAPI = getRestAPIFactory().getUnfiledRecordFoldersAPI(); + + // Create root unfiled record folder + UnfiledContainerChild unfiledFolder = createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS, RECORD_FOLDER_NAME, + UNFILED_RECORD_FOLDER_TYPE); + + // Create an electronic record + UnfiledContainerChild unfiledRecordModel = UnfiledContainerChild.builder() + .properties(UnfiledContainerChildProperties.builder().description(NONELECTRONIC_RECORD_NAME).title("Title").build()) + .name(NONELECTRONIC_RECORD_NAME).nodeType(NON_ELECTRONIC_RECORD_TYPE.toString()).build(); + UnfiledContainerChild unfiledRecord = unfiledRecordFolderAPI.createUnfiledRecordFolderChild(unfiledRecordModel, + unfiledFolder.getId()); + + aspects = unfiledRecord.getAspectNames(); + + assertTrue(aspects.contains("rma:record")); + assertTrue(aspects.contains("rma:filePlanComponent")); + assertTrue(aspects.contains("rma:recordComponentIdentifier")); + assertTrue(aspects.contains("rma:commonRecordDetails")); + + Record recordModelToUpdateToUnfiled = Record.builder().aspectNames(emptyAspectList).build(); + // Update record + recordsAPI.updateRecord(recordModelToUpdateToUnfiled, unfiledRecord.getId()); + assertStatusCode(UNPROCESSABLE_ENTITY); + } + + @AfterClass (alwaysRun = true) + public void tearDown() throws Exception + { + FilePlanAPI filePlansAPI = getRestAPIFactory().getFilePlansAPI(); + RecordCategoryAPI recordCategoryAPI = getRestAPIFactory().getRecordCategoryAPI(); + + filePlansAPI.getRootRecordCategories(FILE_PLAN_ALIAS).getEntries().forEach(recordCategoryEntry -> + { + recordCategoryAPI.deleteRecordCategory(recordCategoryEntry.getEntry().getId()); + }); + + UnfiledContainerChildCollection listedChildren = getRestAPIFactory().getUnfiledContainersAPI() + .getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS); + + listedChildren.getEntries().forEach(UnfiledContainerChildEntry -> + { + if (UnfiledContainerChildEntry.getEntry().getIsRecord()) + { + getRestAPIFactory().getRecordsAPI().deleteRecord(UnfiledContainerChildEntry.getEntry().getId()); + } + else + { + getRestAPIFactory().getUnfiledRecordFoldersAPI().deleteUnfiledRecordFolder(UnfiledContainerChildEntry.getEntry().getId()); + } + }); + } } diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml index aba5909bb3..2c0e185594 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml @@ -120,6 +120,11 @@ + + + + + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java index d7c0308e9c..765b8767d6 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java @@ -117,6 +117,7 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel QName PROP_ORIGIONAL_NAME = QName.createQName(RM_URI, "origionalName"); // Common record details + QName ASPECT_COMMON_RECORD_DETAILS = QName.createQName(RM_URI, "commonRecordDetails"); QName PROP_LOCATION = QName.createQName(RM_URI, "location"); // Fileable aspect diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/ProtectedAspects.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/ProtectedAspects.java new file mode 100644 index 0000000000..80adcc6e5d --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/ProtectedAspects.java @@ -0,0 +1,99 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * 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 . + * #L% + */ + +package org.alfresco.module.org_alfresco_module_rm.model.rma.aspect; + +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +/** + * protected aspects behaviour bean + * allow only System user to remove this aspects + * + * @author Ramona Popa + * @since 2.6 + */ + +public class ProtectedAspects implements NodeServicePolicies.OnRemoveAspectPolicy +{ + private PolicyComponent policyComponent; + private AuthenticationUtil authenticationUtil; + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void setAuthenticationUtil(AuthenticationUtil authenticationUtil) + { + this.authenticationUtil = authenticationUtil; + } + + /** + * Initialise method + */ + public void init() + { + // Watch removal of the aspect rma:record + this.policyComponent.bindClassBehaviour( + NodeServicePolicies.OnRemoveAspectPolicy.QNAME, + RecordsManagementModel.ASPECT_RECORD, + new JavaBehaviour(this, "onRemoveAspect")); + // Watch removal of the aspect rma:filePlanComponent + this.policyComponent.bindClassBehaviour( + NodeServicePolicies.OnRemoveAspectPolicy.QNAME, + RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT, + new JavaBehaviour(this, "onRemoveAspect")); + // Watch removal of the aspect rma:recordComponentIdentifier + this.policyComponent.bindClassBehaviour( + NodeServicePolicies.OnRemoveAspectPolicy.QNAME, + RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID, + new JavaBehaviour(this, "onRemoveAspect")); + // Watch removal of the aspect rma:commonRecordDetails + this.policyComponent.bindClassBehaviour( + NodeServicePolicies.OnRemoveAspectPolicy.QNAME, + RecordsManagementModel.ASPECT_COMMON_RECORD_DETAILS, + new JavaBehaviour(this, "onRemoveAspect")); + + } + + @Override + public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName) + { + if (!authenticationUtil.getRunAsUser().equals(authenticationUtil.getSystemUserName())) + { + throw new IntegrityException("Operation failed. Aspect " + aspectTypeQName.toString() + " is mandatory and cannot be removed.", null); + } + + } +} diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/UpdateRecordAspectsTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/UpdateRecordAspectsTest.java new file mode 100644 index 0000000000..86dc82da50 --- /dev/null +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/UpdateRecordAspectsTest.java @@ -0,0 +1,125 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * 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 . + * #L% + */ + +package org.alfresco.module.org_alfresco_module_rm.test.integration.record; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.repo.node.integrity.IntegrityException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.extensions.webscripts.GUID; + +/** + * remove aspects test + * + * @author Ramona Popa + * @since 2.6 + */ +public class UpdateRecordAspectsTest extends BaseRMTestCase +{ + @Override + protected boolean isUserTest() + { + return true; + } + + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + /** + * RM-4926 + * RM specific aspects can be removed only by System user + */ + public void testRemoveRMAspectsFromElectronicRecord() throws Exception + { + final NodeRef record = doTestInTransaction(new Test() + { + @Override + public NodeRef run() + { + // create file plan structure and a record + NodeRef rc = filePlanService.createRecordCategory(filePlan, GUID.generate()); + NodeRef recordFolder = recordFolderService.createRecordFolder(rc, GUID.generate()); + NodeRef record = recordService.createRecordFromContent(recordFolder, GUID.generate(), TYPE_CONTENT, null, null); + + return record; + } + }); + + doTestInTransaction(new FailureTest(IntegrityException.class) + { + @Override + public void run() + { + nodeService.removeAspect(record, ASPECT_RECORD); + } + }); + + doTestInTransaction(new FailureTest(IntegrityException.class) + { + @Override + public void run() + { + nodeService.removeAspect(record, ASPECT_FILE_PLAN_COMPONENT); + } + }); + + doTestInTransaction(new FailureTest(IntegrityException.class) + { + @Override + public void run() + { + nodeService.removeAspect(record, ASPECT_RECORD_COMPONENT_ID); + } + }); + + doTestInTransaction(new FailureTest(IntegrityException.class) + { + @Override + public void run() + { + nodeService.removeAspect(record, ASPECT_COMMON_RECORD_DETAILS); + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + nodeService.removeAspect(record, ASPECT_RECORD); + nodeService.removeAspect(record, ASPECT_FILE_PLAN_COMPONENT); + nodeService.removeAspect(record, ASPECT_RECORD_COMPONENT_ID); + nodeService.removeAspect(record, ASPECT_COMMON_RECORD_DETAILS); + return null; + } + }, AuthenticationUtil.getSystemUserName()); + } +}