From 76c865e41a41844ed83809d52f676a8dd8a43ca6 Mon Sep 17 00:00:00 2001 From: Ross Gale Date: Mon, 3 Jun 2019 11:10:16 +0100 Subject: [PATCH] RM-6869 removing linked record during rejection --- .../gscore/api/ActionsExecutionAPI.java | 26 ++++ .../community/records/RejectRecordTests.java | 113 ++++++++++++++++++ .../record/RecordServiceImpl.java | 5 +- .../record/RecordServiceImplUnitTest.java | 74 ++++++++++++ 4 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/RejectRecordTests.java diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java index a977db9ad6..a33e2fd3db 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java @@ -75,4 +75,30 @@ public class ActionsExecutionAPI extends RMModelRequest return getRmRestWrapper().withCoreAPI().usingActions() .executeAction(ActionsOnRule.DECLARE_AS_RECORD.getActionValue(), targetNode); } + + /** + * Links a record to a new record folder using v1 actions api + * + * @param targetNode the node on which the action is executed + * @param destination the path of the category/folder to create and place the link + */ + public JSONObject linkRecord(RepoTestModel targetNode, String destination) throws Exception + { + return getRmRestWrapper().withCoreAPI().usingActions() + .executeAction(ActionsOnRule.LINK_TO.getActionValue(), targetNode, + ImmutableMap.of("path", destination, "createRecordPath", "true")); + } + + /** + * Rejects a record using v1 actions api + * + * @param targetNode record to reject + * @param reason reason for rejection + */ + public JSONObject rejectRecord(RepoTestModel targetNode, String reason) throws Exception + { + return getRmRestWrapper().withCoreAPI().usingActions() + .executeAction(ActionsOnRule.REJECT.getActionValue(), targetNode, + ImmutableMap.of("reason", reason)); + } } diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/RejectRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/RejectRecordTests.java new file mode 100644 index 0000000000..f2a8bc6c21 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/RejectRecordTests.java @@ -0,0 +1,113 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2019 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.rest.rm.community.records; + +import static org.alfresco.utility.data.RandomData.getRandomName; +import static org.alfresco.utility.report.log.Step.STEP; +import static org.junit.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.util.Optional; + +import org.alfresco.dataprep.CMISUtil; +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory; +import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild; +import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChildCollection; +import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChildEntry; +import org.alfresco.test.AlfrescoTest; +import org.alfresco.utility.Utility; +import org.alfresco.utility.model.FileModel; +import org.alfresco.utility.model.SiteModel; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * API tests for rejecting records + * @author Ross Gale + * @since 3.1 + */ +public class RejectRecordTests extends BaseRMRestTest +{ + private SiteModel publicSite; + private RecordCategory recordCategory; + private RecordCategoryChild recordFolder; + + @BeforeClass (alwaysRun = true) + public void setUp() throws Exception + { + createRMSiteIfNotExists(); + publicSite = dataSite.usingAdmin().createPublicRandomSite(); + recordCategory = createRootCategory(getRandomName("recordCategory")); + recordFolder = createFolder(recordCategory.getId(), getRandomName("recordFolder")); + } + + /** + * Test that when rejecting a linked record that the link is also removed + */ + @Test + @AlfrescoTest(jira = "RM-6869") + public void declareAndFileToValidLocationUsingActionsAPI() throws Exception + { + STEP("Create a document in the collaboration site"); + FileModel testFile = dataContent.usingSite(publicSite) + .usingAdmin() + .createContent(CMISUtil.DocumentType.TEXT_PLAIN); + + STEP("Declare document as record with a location parameter value"); + getRestAPIFactory().getActionsAPI(getAdminUser()).declareAndFile(testFile, + Utility.buildPath(recordCategory.getName(), recordFolder.getName())); + + STEP("Link record to new folder"); + getRestAPIFactory().getActionsAPI().linkRecord(testFile, recordCategory.getName() + "/" + recordFolder.getName() + "_2"); + RecordCategoryChildCollection recordFolders = getRestAPIFactory().getRecordCategoryAPI().getRecordCategoryChildren(recordCategory.getId()); + Optional linkedFolder = recordFolders.getEntries().stream().filter(child -> child.getEntry().getName().equals(recordFolder.getName() + "_2")) + .findFirst(); + if (linkedFolder.isPresent()) + { + STEP("Verify the linked record has been added"); + assertFalse(getRestAPIFactory().getRecordFolderAPI().getRecordFolderChildren(linkedFolder.get().getEntry().getId()).isEmpty()); + + STEP("Reject record"); + getRestAPIFactory().getActionsAPI().rejectRecord(testFile, "Just because"); + + STEP("Check record has been rejected"); + assertFalse(isMatchingRecordInRecordFolder(testFile, recordFolder)); + + STEP("Verify the linked record has been removed"); + assertTrue(getRestAPIFactory().getRecordFolderAPI().getRecordFolderChildren(linkedFolder.get().getEntry().getId()).isEmpty()); + } + } + + @AfterClass (alwaysRun = true) + public void cleanUp() + { + deleteRecordCategory(recordCategory.getId()); + dataSite.deleteSite(publicSite); + } +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index 6dad811b75..2ef581f610 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -1497,10 +1497,11 @@ public class RecordServiceImpl extends BaseBehaviourBean final List parentAssocs = nodeService.getParentAssocs(nodeRef); for (ChildAssociationRef childAssociationRef : parentAssocs) { - if (!childAssociationRef.isPrimary() && childAssociationRef.getParentRef().equals(originatingLocation)) + if (!childAssociationRef.isPrimary() && + (childAssociationRef.getParentRef().equals(originatingLocation) || + nodeService.getType(childAssociationRef.getParentRef()).equals(TYPE_RECORD_FOLDER))) { nodeService.removeChildAssociation(childAssociationRef); - break; } } diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java index 28f71e3351..b3892b84a6 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java @@ -41,7 +41,10 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -49,10 +52,12 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.notification.RecordsManagementNotificationHelper; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.policy.Behaviour; import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.rendition.RenditionService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AccessStatus; @@ -63,6 +68,7 @@ import org.apache.commons.collections.CollectionUtils; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Spy; /** @@ -81,6 +87,24 @@ public class RecordServiceImplUnitTest extends BaseUnitTest private NodeRef closedRecordFolder; private ChildAssociationRef parentAssoc; + private final String recordId = "recordId"; + private final String documentOwner = "Bob"; + private final String originalName = "originalName"; + private final NodeRef originatingLocation = new NodeRef("workspace://SpacesStore/originalLocation"); + private final NodeRef link = new NodeRef("workspace://SpacesStore/linkLocation"); + + @Mock + private RenditionService mockedRenditionService; + + @Mock + private RecordsManagementNotificationHelper mockedNotificationHelper; + @Mock + private ChildAssociationRef mockedChildAssoc; + @Mock + private ChildAssociationRef mockedLinkAssoc; + @Mock + private ChildAssociationRef mockedParentAssoc; + private static QName TYPE_MY_FILE_PLAN = generateQName(); private static QName ASPECT_FOR_FILE_PLAN = generateQName(); @@ -639,4 +663,54 @@ public class RecordServiceImplUnitTest extends BaseUnitTest when(mockedVersionService.getVersionHistory(dmNodeRef)).thenReturn(null); } + + /** + * Setup the mocks for the reject record scenarios + * @param mockProperties the mock for the node properties + */ + private void setUpReject(Map mockProperties) + { + when(mockedNodeService.getProperties(dmNodeRef)).thenReturn(mockProperties); + when(mockedVersionService.getVersionHistory(dmNodeRef)).thenReturn(null); + when(mockProperties.get(PROP_IDENTIFIER)).thenReturn(recordId); + when(mockProperties.get(PROP_ORIGIONAL_NAME)).thenReturn(originalName); + when(mockProperties.get(PROP_RECORD_ORIGINATING_LOCATION)).thenReturn(originatingLocation); + List assocs = new ArrayList<>(); + assocs.add(mockedChildAssoc); + assocs.add(mockedLinkAssoc); + when(mockedNodeService.getParentAssocs(dmNodeRef)).thenReturn(assocs); + when(mockedChildAssoc.getParentRef()).thenReturn(originatingLocation); + when(mockedLinkAssoc.getParentRef()).thenReturn(dmNodeRef); + when(mockedLinkAssoc.getParentRef()).thenReturn(link); + when(mockedNodeService.getType(link)).thenReturn(TYPE_RECORD_FOLDER); + when(mockedNodeService.getPrimaryParent(dmNodeRef)).thenReturn(mockedParentAssoc); + when(mockedParentAssoc.getQName()).thenReturn(ContentModel.TYPE_CATEGORY); + doNothing().when(recordService).invokeBeforeRecordRejection(dmNodeRef); + doNothing().when(recordService).invokeOnRecordRejection(dmNodeRef); + } + /** + * Test for the reject record method + */ + @Test + public void testRejectRecord() + { + Map mockProperties = mock(HashMap.class); + setUpReject(mockProperties); + when(mockProperties.get(PROP_RECORD_ORIGINATING_USER_ID)).thenReturn(documentOwner); + recordService.rejectRecord(dmNodeRef, "Just because.."); + verify(mockedNodeService, times(1)).removeChildAssociation(mockedChildAssoc); + verify(mockedNodeService, times(1)).removeChildAssociation(mockedLinkAssoc); + } + + /** + * Test for the reject record method throws an error without document owner + */ + @Test (expected = AlfrescoRuntimeException.class) + public void testRejectRecordThrowsErrorWithoutDocumentOwner() + { + Map mockProperties = mock(HashMap.class); + setUpReject(mockProperties); + when(mockProperties.get(PROP_RECORD_ORIGINATING_USER_ID)).thenReturn(null); + recordService.rejectRecord(dmNodeRef, "Just because.."); + } }