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());
+ }
+}