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