From 096b86fedc7da52b377358b83fed38d4a738fcf2 Mon Sep 17 00:00:00 2001 From: rwetherall Date: Wed, 4 Apr 2018 10:45:50 +1000 Subject: [PATCH 01/34] Role and Capability initial technical documentation. --- rm-community/documentation/README.md | 4 +- .../resource/image/CapabilitiesAndRoles.png | Bin 0 -> 27310 bytes .../extendedPermissionService.md | 0 .../security/rolesAndCapabilities.md | 41 ++++++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 rm-community/documentation/resource/image/CapabilitiesAndRoles.png rename rm-community/documentation/{ => security}/extendedPermissionService.md (100%) create mode 100644 rm-community/documentation/security/rolesAndCapabilities.md diff --git a/rm-community/documentation/README.md b/rm-community/documentation/README.md index b4b7911330..fba3b1f15a 100644 --- a/rm-community/documentation/README.md +++ b/rm-community/documentation/README.md @@ -17,8 +17,8 @@ * Retention Schedules and Events * Transfer and Accession * Security - * [Extended permission service](extendedPermissionService.md) - * Roles, Capabilities and Permissions + * [Extended permission service](security/extendedPermissionService.md) + * [Roles and Capabilities](security/rolesAndCapabilities.md) * Discovery * Governance Search * Legal Holds diff --git a/rm-community/documentation/resource/image/CapabilitiesAndRoles.png b/rm-community/documentation/resource/image/CapabilitiesAndRoles.png new file mode 100644 index 0000000000000000000000000000000000000000..606a7d3a73284a873c18ac9a199fa168456a2bc3 GIT binary patch literal 27310 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 AH~;_u literal 0 HcmV?d00001 diff --git a/rm-community/documentation/extendedPermissionService.md b/rm-community/documentation/security/extendedPermissionService.md similarity index 100% rename from rm-community/documentation/extendedPermissionService.md rename to rm-community/documentation/security/extendedPermissionService.md diff --git a/rm-community/documentation/security/rolesAndCapabilities.md b/rm-community/documentation/security/rolesAndCapabilities.md new file mode 100644 index 0000000000..c3372d5b1c --- /dev/null +++ b/rm-community/documentation/security/rolesAndCapabilities.md @@ -0,0 +1,41 @@ +## Alfresco Governance Services' Roles and Capabilities + +![Completeness Badge](https://img.shields.io/badge/Document_Level-InProgress-yellow.svg?style=flat-square) + +![Version Badge](https://img.shields.io/badge/Version-Current-blue.svg?style=flat-square) + +### Purpose + +Roles and capabilities allow the GS system to provide a finer grain security evaluation, determining whether an authority has the capability to perform a perticular action on a node. + +### Overview + +Roles are defined as a collection of capabilities. A capability, generally, has a one to one relationship with an action within the system. + +Authorities are assigned roles. If an authority is assigned to a role then it that authority has the capabilities contained within that role, allowing them to perform the related actions. + +An authority can be assigned many roles, with the associated capabilities being additive. + +Capabilties are evaluated in addition to any ACLs attached to a node, but they are mutally exclusive. A authority may have the capability, but not the permissions on a node and vice versa. + +### Design + +Roles are implementented as groups. So for every role that is created, there is a corresponding group within the system. + +Capabilities are implemented as permissions. In order add a new capability to the system, the extended RM permission model needs to be extended. + +When a capability is added to a role, then the capability group is assigned the capability role on the root file plan node. + +In this way the permissions of the systems roles reflect their capabilities on the file plan via the capability permissions assigned. + +When an authority is assigned to a role, that authority is added as a member of the corresponding role group. In this way they inherit the capability permissions on the file plan that relate to that role group. + +If a user attempts to perform an action on a records management artifact which has a related capability. Assuming the user has permission to see the artifact in the first place, then the users capability to perform the action is evaluated. + +This is done by firstly determining whether the capability is relevant for this 'kind' of records management artifact. For example the addHold capability is not relevant for a record category. + +Then the capability permission is evaluated by traversing to the file plan node and checking whether the current user has the capabilty permission byt virtue of it's membership of the right role group. + +Finally any further conditions attached to the capability are evaluated. + +![](../resource/image/CapabilitiesAndRoles.png) \ No newline at end of file From e11bef00bb661df4dbff8a2c2865d5db04113985 Mon Sep 17 00:00:00 2001 From: Ross Gale Date: Fri, 4 May 2018 15:46:30 +0100 Subject: [PATCH 02/34] Search changes, adding support for search by reason key and 'other source' names --- .../rm-webscript-context.xml | 11 ++ .../slingshot/ClassificationReasonsUtil.java | 86 ++++++++++ .../slingshot/ClassificationSourcesUtil.java | 120 +++++++++++++ .../script/slingshot/RMSearchGet.java | 32 ++++ .../script/slingshot/SearchUtil.java | 98 +++++++++++ .../ClassificationReasonsUtilUnitTest.java | 128 ++++++++++++++ .../ClassificationSourcesUtilUnitTest.java | 161 ++++++++++++++++++ 7 files changed, 636 insertions(+) create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationReasonsUtil.java create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtil.java create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java create mode 100644 rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationReasonsUtilUnitTest.java create mode 100644 rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml index 3c3d0ccf20..f95804c684 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml @@ -467,12 +467,23 @@ + + + + + + + + + + . + * #L% + */ +package org.alfresco.module.org_alfresco_module_rm.script.slingshot; + +import static org.alfresco.model.ContentModel.PROP_NAME; +import static org.alfresco.service.namespace.QName.createQName; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; + +/** + * Method to replace the plain text classification reason id with the correct nodeRef during record search + * @author Ross Gale + * @since 2.7 + */ +public class ClassificationReasonsUtil extends SearchUtil +{ + + public static final String CR_URI = "http://www.alfresco.org/model/securitymarks/1.0"; + public static final QName CLASSIFICATION_REASONS_CONTAINER = createQName(CR_URI,"classificationReasonsContainer"); + public static final QName PROP_CLASSIFICATION_REASON_CODE = createQName(CR_URI, "classificationReasonCode"); + public static final String REASONS_KEY = "clf:classificationReasons:"; + + /** + * Replace plain text reason id with nodeRef + * @param searchQuery String e.g. clf:classificationReasons:1.4(a) + * @return String e.g. clf:classificationReasons:5cc6d344-fa94-4370-9c81-d947b7e8f2ac + */ + public String replaceReasonWithNodeRef(String searchQuery) + { + List queries = new ArrayList<>(Arrays.asList(searchQuery.split(" "))); + StringBuilder stringBuilder = new StringBuilder(); + for (String queryToEdit : queries) + { + if(queryToEdit.contains(REASONS_KEY)) + { + for (String reasonId : retrieveAllNodeIds(getRootContainer(CLASSIFICATION_REASONS_CONTAINER))) + { + NodeRef reasonNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, reasonId); + Map properties = nodeService.getProperties(reasonNodeRef); + if (queryToEdit.equals(REASONS_KEY + properties.get(PROP_CLASSIFICATION_REASON_CODE).toString()) || + queryToEdit.equals(REASONS_KEY +"\""+ properties.get(PROP_CLASSIFICATION_REASON_CODE).toString() + "\"")) + { + queryToEdit = REASONS_KEY + properties.get(PROP_NAME).toString(); + break; + } + } + } + stringBuilder.append(queryToEdit).append(" "); + } + return stringBuilder.toString(); + } + + +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtil.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtil.java new file mode 100644 index 0000000000..8f9a534db1 --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtil.java @@ -0,0 +1,120 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2018 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.script.slingshot; + + +import static org.alfresco.model.ContentModel.PROP_NODE_UUID; +import static org.alfresco.service.namespace.QName.createQName; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; + +/** + * Method to replace the plain text classification source name with all possible nodeRefs during record search + * @author Ross Gale + * @since 2.7 + */ +public class ClassificationSourcesUtil extends SearchUtil +{ + + + public static final String CS_URI = "http://www.alfresco.org/model/classificationsources/1.0"; + public static final QName CLASSIFICATION_SOURCES_CONTAINER = createQName(CS_URI, "classificationSourcesContainer"); + public static final QName PROP_CLASSIFICATION_SOURCE_NAME = createQName(CS_URI, "classificationSourceName"); + public static final String SOURCES_KEY = "cs:appliedSources:"; + public static final String START = "start"; + public static final String END = "end"; + + /** + * Replace plain text source name with all matching nodeRefs + * + * @param searchQuery String e.g. clf:classificationReasons:"Other source" + * @return String e.g. (cs:appliedSources:5cc6d344-fa94-4370-9c81-d947b7e8f2ac OR cs:appliedSources:47afd476-358f-4007-a35e-8f83adb06523) + */ + public String replaceSourceNameWithNodeRef(String searchQuery) + { + Pattern pattern = Pattern.compile("cs:appliedSources:\"[^\"]*\""); + Matcher matcher = pattern.matcher(searchQuery); + StringBuilder builder = new StringBuilder(searchQuery); + Map> index = new HashMap<>(); + int count = 0; + //create a map of where the strings to replace are + while(matcher.find()) + { + index.put(count, new HashMap<>()); + index.get(count).put(START,matcher.start()); + index.get(count).put(END, matcher.end()); + count++; + } + //Go through the string in reverse and replace the plain text reference with nodeIds + for(int i = index.size(); i > 0; i--) + { + Map element = index.get(i-1); + int start = element.get(START); + int end = element.get(END); + builder.replace(start, end, replaceSingleInstance(searchQuery.substring(start, end))); + } + + return builder.toString(); + } + + private String replaceSingleInstance(String str) + { + StringBuilder stringBuilder = new StringBuilder(); + if (str.contains(SOURCES_KEY)) + { + boolean multipleResults = false; + stringBuilder.append('('); + for (String sourceId : retrieveAllNodeIds(getRootContainer(CLASSIFICATION_SOURCES_CONTAINER))) + { + NodeRef reasonNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceId); + Map properties = nodeService.getProperties(reasonNodeRef); + if (str.equals(SOURCES_KEY + "\"" + properties.get(PROP_CLASSIFICATION_SOURCE_NAME).toString() + "\"")) + { + if (multipleResults) + { + stringBuilder.append(" OR "); + } + stringBuilder.append(SOURCES_KEY + "\"" + properties.get(PROP_NODE_UUID).toString() + "\""); + //Sources create a node each time even if all the details are the same this will allow multiple nodeIds to be added for a single string + multipleResults = true; + } + } + } + stringBuilder.append(')'); + return stringBuilder.toString(); + } + + +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java index e8ac49ff96..1755209997 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java @@ -27,6 +27,9 @@ package org.alfresco.module.org_alfresco_module_rm.script.slingshot; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil.REASONS_KEY; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.SOURCES_KEY; + import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @@ -103,6 +106,12 @@ public class RMSearchGet extends DeclarativeWebScript /** Utility class for record categories */ private RecordCategoryUtil recordCategoryUtil; + /** Utility class for classification reasons (enterprise only) */ + private ClassificationReasonsUtil classificationReasonsUtil; + + /** Utility class for classification sources (enterprise only) */ + private ClassificationSourcesUtil classificationSourcesUtil; + /** * @param recordsManagementSearchService records management search service */ @@ -159,6 +168,16 @@ public class RMSearchGet extends DeclarativeWebScript this.recordCategoryUtil = recordCategoryUtil; } + public void setClassificationReasonsUtil(ClassificationReasonsUtil classificationReasonsUtil) + { + this.classificationReasonsUtil = classificationReasonsUtil; + } + + public void setClassificationSourcesUtil(ClassificationSourcesUtil classificationSourcesUtil) + { + this.classificationSourcesUtil = classificationSourcesUtil; + } + /** * @param personService person service */ @@ -198,6 +217,19 @@ public class RMSearchGet extends DeclarativeWebScript String filters = req.getParameter(PARAM_FILTERS); // TODO this is optional + //Replace any plain text reason ids with the appropriate node reference + if(query.contains(REASONS_KEY)) + { + query = classificationReasonsUtil.replaceReasonWithNodeRef(query); + } + + //replace any plain test other source titles with appropriate node ref + if(query.contains(SOURCES_KEY)) + { + query = classificationSourcesUtil.replaceSourceNameWithNodeRef(query); + } + + // Convert into a rm search parameter object RecordsManagementSearchParameters searchParameters = SavedSearchDetailsCompatibility.createSearchParameters(filters, new String[]{",", "/"}, sortby, namespaceService); diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java new file mode 100644 index 0000000000..e088a559eb --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java @@ -0,0 +1,98 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2018 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.script.slingshot; + +import static org.alfresco.model.ContentModel.ASSOC_CHILDREN; +import static org.alfresco.model.ContentModel.TYPE_CONTAINER; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; + + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; + +/** + * Parent class for records search utilities + * @author Ross Gale + * @since 2.7 + */ +public class SearchUtil +{ + /** + * Node service + */ + protected NodeService nodeService; + + /** + * Setter for node service + * @param nodeService Node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Use a container node ref and return the nodeIds of the contents + * @param nodeRef container + * @return list of nodeIds + */ + protected Set retrieveAllNodeIds(NodeRef nodeRef) + { + List childAssocRefs = nodeService.getChildAssocs(nodeRef); + return childAssocRefs.stream().map(assoc -> assoc.getChildRef().getId()).collect(Collectors.toSet()); + } + + /** + * Helper method to get the classification reason root container. + * The method creates the container if it doesn't already exist. + * + * @return reference to the classification reason root container + */ + protected NodeRef getRootContainer(QName container) + { + NodeRef rootNodeRef = nodeService.getRootNode(STORE_REF_WORKSPACE_SPACESSTORE); + List assocRefs = nodeService.getChildAssocs(rootNodeRef, ASSOC_CHILDREN, container); + + if (assocRefs.size() == 0) + { + return nodeService.createNode(rootNodeRef, ASSOC_CHILDREN, container, TYPE_CONTAINER).getChildRef(); + } else if (assocRefs.size() != 1) + { + throw new AlfrescoRuntimeException("Only one container is allowed."); + } else + { + return assocRefs.iterator().next().getChildRef(); + } + } +} diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationReasonsUtilUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationReasonsUtilUnitTest.java new file mode 100644 index 0000000000..ac0dac5d03 --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationReasonsUtilUnitTest.java @@ -0,0 +1,128 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2018 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.script.slingshot; + +import static org.alfresco.model.ContentModel.ASSOC_CHILDREN; +import static org.alfresco.model.ContentModel.PROP_NAME; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil.CLASSIFICATION_REASONS_CONTAINER; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil.PROP_CLASSIFICATION_REASON_CODE; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * @author Ross Gale + * @since 2.7 + */ +public class ClassificationReasonsUtilUnitTest +{ + + @Mock + private NodeService nodeService; + + @Mock + private ChildAssociationRef childAssociationRef; + + @Mock + private ChildAssociationRef reason; + + @Mock + private Map properties; + + @InjectMocks + private ClassificationReasonsUtil classificationReasonsUtil; + + private NodeRef childNodeRef; + + @Before + public void setUp() + { + MockitoAnnotations.initMocks(this); + NodeRef rootNodeRef = new NodeRef("workspace://SpacesStore/rootNodeRef"); + NodeRef containerNodeRef = new NodeRef("workspace://SpacesStore/containerNodeRef"); + childNodeRef = new NodeRef("workspace://SpacesStore/childNodeRef"); + List assocRefs = new ArrayList<>(); + List childAssocRefs = new ArrayList<>(); + assocRefs.add(childAssociationRef); + childAssocRefs.add(reason); + when(reason.getChildRef()).thenReturn(childNodeRef); + when(nodeService.getRootNode(STORE_REF_WORKSPACE_SPACESSTORE)).thenReturn(rootNodeRef); + when(nodeService.getChildAssocs(rootNodeRef, ASSOC_CHILDREN, CLASSIFICATION_REASONS_CONTAINER)).thenReturn(assocRefs); + when(childAssociationRef.getChildRef()).thenReturn(containerNodeRef); + when(nodeService.getChildAssocs(containerNodeRef)).thenReturn(childAssocRefs); + } + + /** + * Check no modifications are made to non matching parts of the query string + */ + @Test + public void testNoChangeMadeToStringIfKeyNotFound() + { + String stringToTest = "noChangeMadeToString"; + assertEquals("Change made to string",stringToTest, classificationReasonsUtil.replaceReasonWithNodeRef(stringToTest).trim()); + } + + /** + * Check no modifications made if the plain text parameter doesn't have a stored match + */ + @Test + public void testNoChangeMadeToStringIfMatchNotFound() + { + when(nodeService.getProperties(childNodeRef)).thenReturn(properties); + when(properties.get(PROP_CLASSIFICATION_REASON_CODE)).thenReturn("not a match!"); + String stringToTest = "clf:classificationReasons:noChangeMadeToString"; + assertEquals("Change made to string", stringToTest, classificationReasonsUtil.replaceReasonWithNodeRef(stringToTest).trim()); + } + + /** + * Check the query is updated correctly when a match is found + */ + @Test + public void testChangeMadeToStringIfMatchFound() + { + when(nodeService.getProperties(childNodeRef)).thenReturn(properties); + when(properties.get(PROP_CLASSIFICATION_REASON_CODE)).thenReturn("stringToChange"); + when(properties.get(PROP_NAME)).thenReturn("newString"); + String stringToTest = "clf:classificationReasons:stringToChange"; + assertEquals("No change made to string", "clf:classificationReasons:newString", classificationReasonsUtil.replaceReasonWithNodeRef(stringToTest).trim()); + } +} diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java new file mode 100644 index 0000000000..2e914354a9 --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java @@ -0,0 +1,161 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2018 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.script.slingshot; + +import static org.alfresco.model.ContentModel.ASSOC_CHILDREN; +import static org.alfresco.model.ContentModel.PROP_NODE_UUID; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil.PROP_CLASSIFICATION_REASON_CODE; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.CLASSIFICATION_SOURCES_CONTAINER; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.PROP_CLASSIFICATION_SOURCE_NAME; +import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.SOURCES_KEY; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * @author Ross Gale + * @since 2.7 + */ +public class ClassificationSourcesUtilUnitTest +{ + + @Mock + private NodeService nodeService; + + @Mock + private ChildAssociationRef childAssociationRef; + + @Mock + private ChildAssociationRef source, secondSource; + + @Mock + private Map properties; + + @Mock + private Map secondSetOfProperties; + + @InjectMocks + private ClassificationSourcesUtil classificationSourcesUtil; + + private List childAssocRefs; + + private NodeRef childNodeRef; + + private NodeRef childNodeRef2; + + @Before + public void setUp() + { + MockitoAnnotations.initMocks(this); + NodeRef rootNodeRef = new NodeRef("workspace://SpacesStore/rootNodeRef"); + NodeRef containerNodeRef = new NodeRef("workspace://SpacesStore/containerNodeRef"); + childNodeRef = new NodeRef("workspace://SpacesStore/childNodeRef"); + childNodeRef2 = new NodeRef("workspace://SpacesStore/childNodeRef2"); + List assocRefs = new ArrayList<>(); + childAssocRefs = new ArrayList<>(); + assocRefs.add(childAssociationRef); + childAssocRefs.add(source); + when(source.getChildRef()).thenReturn(childNodeRef); + when(nodeService.getRootNode(STORE_REF_WORKSPACE_SPACESSTORE)).thenReturn(rootNodeRef); + when(nodeService.getChildAssocs(rootNodeRef, ASSOC_CHILDREN, CLASSIFICATION_SOURCES_CONTAINER)).thenReturn(assocRefs); + when(childAssociationRef.getChildRef()).thenReturn(containerNodeRef); + when(nodeService.getChildAssocs(containerNodeRef)).thenReturn(childAssocRefs); + } + + /** + * Check no modifications are made to non matching parts of the query string + */ + @Test + public void testNoChangeMadeToStringIfKeyNotFound() + { + String stringToTest = "noChangeMadeToString"; + assertEquals("Change made to string",stringToTest, classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest)); + } + + /** + * Check no modifications made if the plain text parameter doesn't have a stored match + */ + @Test + public void testNoChangeMadeToStringIfMatchNotFound() + { + when(nodeService.getProperties(childNodeRef)).thenReturn(properties); + when(properties.get(PROP_CLASSIFICATION_REASON_CODE)).thenReturn("not a match!"); + String stringToTest = SOURCES_KEY + "noChangeMadeToString"; + assertEquals("Change made to string", stringToTest, classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest)); + } + + /** + * Check the query is updated correctly when a match is found + */ + @Test + public void testChangeMadeToStringIfMatchFound() + { + when(nodeService.getProperties(childNodeRef)).thenReturn(properties); + when(properties.get(PROP_CLASSIFICATION_SOURCE_NAME)).thenReturn("stringToChange"); + when(properties.get(PROP_NODE_UUID)).thenReturn("newString"); + String stringToTest = SOURCES_KEY + "\"stringToChange\""; + assertEquals("No change made to string", "(cs:appliedSources:\"newString\")", classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest)); + } + + /** + * Check the query is updated correctly when multiple matches are found + * + * This is required as the source name isn't unique to the container. + */ + @Test + public void testChangeMadeToStringIfMultipleMatchesFound() + { + childAssocRefs.add(secondSource); + when(secondSource.getChildRef()).thenReturn(childNodeRef2); + when(nodeService.getProperties(childNodeRef)).thenReturn(properties); + when(nodeService.getProperties(childNodeRef2)).thenReturn(secondSetOfProperties); + when(properties.get(PROP_CLASSIFICATION_SOURCE_NAME)).thenReturn("stringToChange"); + when(properties.get(PROP_NODE_UUID)).thenReturn("newString"); + when(secondSetOfProperties.get(PROP_CLASSIFICATION_SOURCE_NAME)).thenReturn("stringToChange"); + when(secondSetOfProperties.get(PROP_NODE_UUID)).thenReturn("secondNewString"); + String stringToTest = SOURCES_KEY + "\"stringToChange\""; + String actual = classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest); + assertTrue(actual.contains("cs:appliedSources:\"newString\"")); + assertTrue(actual.contains("cs:appliedSources:\"secondNewString\"")); + } +} \ No newline at end of file From e9d42bfeef7768b548d81ec8ddaee478f45c246e Mon Sep 17 00:00:00 2001 From: Ross Gale Date: Wed, 9 May 2018 14:29:12 +0100 Subject: [PATCH 03/34] search fields added --- .../rm-webscript-context.xml | 5 - .../slingshot/ClassificationSourcesUtil.java | 120 ------------- .../script/slingshot/RMSearchGet.java | 16 -- .../ClassificationSourcesUtilUnitTest.java | 161 ------------------ 4 files changed, 302 deletions(-) delete mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtil.java delete mode 100644 rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml index f95804c684..c922181ba7 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml @@ -468,7 +468,6 @@ - @@ -479,10 +478,6 @@ - - - . - * #L% - */ -package org.alfresco.module.org_alfresco_module_rm.script.slingshot; - - -import static org.alfresco.model.ContentModel.PROP_NODE_UUID; -import static org.alfresco.service.namespace.QName.createQName; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.namespace.QName; - -/** - * Method to replace the plain text classification source name with all possible nodeRefs during record search - * @author Ross Gale - * @since 2.7 - */ -public class ClassificationSourcesUtil extends SearchUtil -{ - - - public static final String CS_URI = "http://www.alfresco.org/model/classificationsources/1.0"; - public static final QName CLASSIFICATION_SOURCES_CONTAINER = createQName(CS_URI, "classificationSourcesContainer"); - public static final QName PROP_CLASSIFICATION_SOURCE_NAME = createQName(CS_URI, "classificationSourceName"); - public static final String SOURCES_KEY = "cs:appliedSources:"; - public static final String START = "start"; - public static final String END = "end"; - - /** - * Replace plain text source name with all matching nodeRefs - * - * @param searchQuery String e.g. clf:classificationReasons:"Other source" - * @return String e.g. (cs:appliedSources:5cc6d344-fa94-4370-9c81-d947b7e8f2ac OR cs:appliedSources:47afd476-358f-4007-a35e-8f83adb06523) - */ - public String replaceSourceNameWithNodeRef(String searchQuery) - { - Pattern pattern = Pattern.compile("cs:appliedSources:\"[^\"]*\""); - Matcher matcher = pattern.matcher(searchQuery); - StringBuilder builder = new StringBuilder(searchQuery); - Map> index = new HashMap<>(); - int count = 0; - //create a map of where the strings to replace are - while(matcher.find()) - { - index.put(count, new HashMap<>()); - index.get(count).put(START,matcher.start()); - index.get(count).put(END, matcher.end()); - count++; - } - //Go through the string in reverse and replace the plain text reference with nodeIds - for(int i = index.size(); i > 0; i--) - { - Map element = index.get(i-1); - int start = element.get(START); - int end = element.get(END); - builder.replace(start, end, replaceSingleInstance(searchQuery.substring(start, end))); - } - - return builder.toString(); - } - - private String replaceSingleInstance(String str) - { - StringBuilder stringBuilder = new StringBuilder(); - if (str.contains(SOURCES_KEY)) - { - boolean multipleResults = false; - stringBuilder.append('('); - for (String sourceId : retrieveAllNodeIds(getRootContainer(CLASSIFICATION_SOURCES_CONTAINER))) - { - NodeRef reasonNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceId); - Map properties = nodeService.getProperties(reasonNodeRef); - if (str.equals(SOURCES_KEY + "\"" + properties.get(PROP_CLASSIFICATION_SOURCE_NAME).toString() + "\"")) - { - if (multipleResults) - { - stringBuilder.append(" OR "); - } - stringBuilder.append(SOURCES_KEY + "\"" + properties.get(PROP_NODE_UUID).toString() + "\""); - //Sources create a node each time even if all the details are the same this will allow multiple nodeIds to be added for a single string - multipleResults = true; - } - } - } - stringBuilder.append(')'); - return stringBuilder.toString(); - } - - -} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java index 1755209997..ca66efefee 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java @@ -28,7 +28,6 @@ package org.alfresco.module.org_alfresco_module_rm.script.slingshot; import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil.REASONS_KEY; -import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.SOURCES_KEY; import java.io.Serializable; import java.io.UnsupportedEncodingException; @@ -109,9 +108,6 @@ public class RMSearchGet extends DeclarativeWebScript /** Utility class for classification reasons (enterprise only) */ private ClassificationReasonsUtil classificationReasonsUtil; - /** Utility class for classification sources (enterprise only) */ - private ClassificationSourcesUtil classificationSourcesUtil; - /** * @param recordsManagementSearchService records management search service */ @@ -173,11 +169,6 @@ public class RMSearchGet extends DeclarativeWebScript this.classificationReasonsUtil = classificationReasonsUtil; } - public void setClassificationSourcesUtil(ClassificationSourcesUtil classificationSourcesUtil) - { - this.classificationSourcesUtil = classificationSourcesUtil; - } - /** * @param personService person service */ @@ -223,13 +214,6 @@ public class RMSearchGet extends DeclarativeWebScript query = classificationReasonsUtil.replaceReasonWithNodeRef(query); } - //replace any plain test other source titles with appropriate node ref - if(query.contains(SOURCES_KEY)) - { - query = classificationSourcesUtil.replaceSourceNameWithNodeRef(query); - } - - // Convert into a rm search parameter object RecordsManagementSearchParameters searchParameters = SavedSearchDetailsCompatibility.createSearchParameters(filters, new String[]{",", "/"}, sortby, namespaceService); diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java deleted file mode 100644 index 2e914354a9..0000000000 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/ClassificationSourcesUtilUnitTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * #%L - * Alfresco Records Management Module - * %% - * Copyright (C) 2005 - 2018 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.script.slingshot; - -import static org.alfresco.model.ContentModel.ASSOC_CHILDREN; -import static org.alfresco.model.ContentModel.PROP_NODE_UUID; -import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil.PROP_CLASSIFICATION_REASON_CODE; -import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.CLASSIFICATION_SOURCES_CONTAINER; -import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.PROP_CLASSIFICATION_SOURCE_NAME; -import static org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationSourcesUtil.SOURCES_KEY; -import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.QName; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * @author Ross Gale - * @since 2.7 - */ -public class ClassificationSourcesUtilUnitTest -{ - - @Mock - private NodeService nodeService; - - @Mock - private ChildAssociationRef childAssociationRef; - - @Mock - private ChildAssociationRef source, secondSource; - - @Mock - private Map properties; - - @Mock - private Map secondSetOfProperties; - - @InjectMocks - private ClassificationSourcesUtil classificationSourcesUtil; - - private List childAssocRefs; - - private NodeRef childNodeRef; - - private NodeRef childNodeRef2; - - @Before - public void setUp() - { - MockitoAnnotations.initMocks(this); - NodeRef rootNodeRef = new NodeRef("workspace://SpacesStore/rootNodeRef"); - NodeRef containerNodeRef = new NodeRef("workspace://SpacesStore/containerNodeRef"); - childNodeRef = new NodeRef("workspace://SpacesStore/childNodeRef"); - childNodeRef2 = new NodeRef("workspace://SpacesStore/childNodeRef2"); - List assocRefs = new ArrayList<>(); - childAssocRefs = new ArrayList<>(); - assocRefs.add(childAssociationRef); - childAssocRefs.add(source); - when(source.getChildRef()).thenReturn(childNodeRef); - when(nodeService.getRootNode(STORE_REF_WORKSPACE_SPACESSTORE)).thenReturn(rootNodeRef); - when(nodeService.getChildAssocs(rootNodeRef, ASSOC_CHILDREN, CLASSIFICATION_SOURCES_CONTAINER)).thenReturn(assocRefs); - when(childAssociationRef.getChildRef()).thenReturn(containerNodeRef); - when(nodeService.getChildAssocs(containerNodeRef)).thenReturn(childAssocRefs); - } - - /** - * Check no modifications are made to non matching parts of the query string - */ - @Test - public void testNoChangeMadeToStringIfKeyNotFound() - { - String stringToTest = "noChangeMadeToString"; - assertEquals("Change made to string",stringToTest, classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest)); - } - - /** - * Check no modifications made if the plain text parameter doesn't have a stored match - */ - @Test - public void testNoChangeMadeToStringIfMatchNotFound() - { - when(nodeService.getProperties(childNodeRef)).thenReturn(properties); - when(properties.get(PROP_CLASSIFICATION_REASON_CODE)).thenReturn("not a match!"); - String stringToTest = SOURCES_KEY + "noChangeMadeToString"; - assertEquals("Change made to string", stringToTest, classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest)); - } - - /** - * Check the query is updated correctly when a match is found - */ - @Test - public void testChangeMadeToStringIfMatchFound() - { - when(nodeService.getProperties(childNodeRef)).thenReturn(properties); - when(properties.get(PROP_CLASSIFICATION_SOURCE_NAME)).thenReturn("stringToChange"); - when(properties.get(PROP_NODE_UUID)).thenReturn("newString"); - String stringToTest = SOURCES_KEY + "\"stringToChange\""; - assertEquals("No change made to string", "(cs:appliedSources:\"newString\")", classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest)); - } - - /** - * Check the query is updated correctly when multiple matches are found - * - * This is required as the source name isn't unique to the container. - */ - @Test - public void testChangeMadeToStringIfMultipleMatchesFound() - { - childAssocRefs.add(secondSource); - when(secondSource.getChildRef()).thenReturn(childNodeRef2); - when(nodeService.getProperties(childNodeRef)).thenReturn(properties); - when(nodeService.getProperties(childNodeRef2)).thenReturn(secondSetOfProperties); - when(properties.get(PROP_CLASSIFICATION_SOURCE_NAME)).thenReturn("stringToChange"); - when(properties.get(PROP_NODE_UUID)).thenReturn("newString"); - when(secondSetOfProperties.get(PROP_CLASSIFICATION_SOURCE_NAME)).thenReturn("stringToChange"); - when(secondSetOfProperties.get(PROP_NODE_UUID)).thenReturn("secondNewString"); - String stringToTest = SOURCES_KEY + "\"stringToChange\""; - String actual = classificationSourcesUtil.replaceSourceNameWithNodeRef(stringToTest); - assertTrue(actual.contains("cs:appliedSources:\"newString\"")); - assertTrue(actual.contains("cs:appliedSources:\"secondNewString\"")); - } -} \ No newline at end of file From 75574d140e2a921cd00e6156419b30a33ab1f36c Mon Sep 17 00:00:00 2001 From: Ross Gale Date: Wed, 9 May 2018 15:52:01 +0100 Subject: [PATCH 04/34] RM-6302 code review comments addressed --- .../jscript/app/JSONConversionComponent.java | 5 +++-- .../org_alfresco_module_rm/model/RecordsManagementModel.java | 1 - .../script/DispositionAbstractBase.java | 2 ++ .../script/DispositionActionDefinitionPost.java | 4 ++-- .../script/DispositionActionDefinitionPut.java | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/jscript/app/JSONConversionComponent.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/jscript/app/JSONConversionComponent.java index bae437569b..da2a7234a3 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/jscript/app/JSONConversionComponent.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/jscript/app/JSONConversionComponent.java @@ -482,8 +482,9 @@ public class JSONConversionComponent extends org.alfresco.repo.jscript.app.JS { if(!details.isEventComplete()) { - ((HashMap) rmNodeValues.get("properties")).put("combineDispositionStepConditions", nodeService.getProperty(dispositionService.getNextDispositionAction(nodeRef).getDispositionActionDefinition().getNodeRef(), PROP_COMBINE_DISPOSITION_STEP_CONDITIONS)); - ((HashMap) rmNodeValues.get("properties")).put("incompleteDispositionEvent", details.getEventName()); + HashMap properties = ((HashMap) rmNodeValues.get("properties")); + properties.put("combineDispositionStepConditions", nodeService.getProperty(dispositionService.getNextDispositionAction(nodeRef).getDispositionActionDefinition().getNodeRef(), PROP_COMBINE_DISPOSITION_STEP_CONDITIONS)); + properties.put("incompleteDispositionEvent", details.getEventName()); break; } } 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 3c02c90627..f7211b7d33 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 @@ -240,7 +240,6 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel QName PROP_RS_DISPOSITION_ACTION_AS_OF = QName.createQName(RM_URI, "recordSearchDispositionActionAsOf"); QName PROP_RS_DISPOSITION_EVENTS_ELIGIBLE = QName.createQName(RM_URI, "recordSearchDispositionEventsEligible"); QName PROP_RS_DISPOSITION_EVENTS = QName.createQName(RM_URI, "recordSearchDispositionEvents"); - QName PROP_DISPOSITION_EVENTS = QName.createQName(RM_URI, "dispositionEvents"); QName PROP_RS_VITAL_RECORD_REVIEW_PERIOD = QName.createQName(RM_URI, "recordSearchVitalRecordReviewPeriod"); QName PROP_RS_VITAL_RECORD_REVIEW_PERIOD_EXPRESSION = QName.createQName(RM_URI, "recordSearchVitalRecordReviewPeriodExpression"); QName PROP_RS_DISPOSITION_PERIOD = QName.createQName(RM_URI, "recordSearchDispositionPeriod"); diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionAbstractBase.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionAbstractBase.java index be367e060e..a07f4f7b0f 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionAbstractBase.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionAbstractBase.java @@ -51,6 +51,8 @@ import org.springframework.extensions.webscripts.WebScriptRequest; */ public class DispositionAbstractBase extends AbstractRmWebScript { + + public final static String COMBINE_DISPOSITION_STEP_CONDITIONS = "combineDispositionStepConditions"; /** * Parses the request and providing it's valid returns the DispositionSchedule object. * diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPost.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPost.java index 19357a8680..1fcfcb06b9 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPost.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPost.java @@ -133,10 +133,10 @@ public class DispositionActionDefinitionPost extends DispositionAbstractBase json.getBoolean("eligibleOnFirstCompleteEvent") ? "or" : "and"); } - if (json.has("combineDispositionStepConditions")) + if (json.has(COMBINE_DISPOSITION_STEP_CONDITIONS)) { props.put(RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS, - json.getBoolean("combineDispositionStepConditions")); + json.getBoolean(COMBINE_DISPOSITION_STEP_CONDITIONS)); } if (json.has("location")) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPut.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPut.java index 510118f047..8d826d6a1a 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPut.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/DispositionActionDefinitionPut.java @@ -131,10 +131,10 @@ public class DispositionActionDefinitionPut extends DispositionAbstractBase json.getBoolean("eligibleOnFirstCompleteEvent") ? "or" : "and"); } - if (json.has("combineDispositionStepConditions")) + if (json.has(COMBINE_DISPOSITION_STEP_CONDITIONS)) { props.put(RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS, - json.getBoolean("combineDispositionStepConditions")); + json.getBoolean(COMBINE_DISPOSITION_STEP_CONDITIONS)); } if (json.has("location")) From 1b5653bb86b9a9c9f6b13e819d386740a3a46475 Mon Sep 17 00:00:00 2001 From: cagache Date: Fri, 11 May 2018 16:54:54 +0300 Subject: [PATCH 05/34] RM-6311 added API test to check that rm search results are ordered by security marks --- .../java/org/alfresco/rest/v0/SearchAPI.java | 17 +++++++++--- .../rm/community/base/BaseRMRestTest.java | 26 +++++++++---------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java index 2bad85cbd5..f462f06cdf 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java @@ -91,6 +91,7 @@ public class SearchAPI extends BaseAPI * @param site * @param query * @param filters + * @param sortby * @return search results (see API reference for more details), null for any errors */ public JSONObject rmSearch( @@ -98,11 +99,16 @@ public class SearchAPI extends BaseAPI String password, String site, String query, - String filters) + String filters, + String sortby) { List searchParameters = new ArrayList(); searchParameters.add(new BasicNameValuePair("query", query)); searchParameters.add(new BasicNameValuePair("filters", filters)); + if (sortby != null) + { + searchParameters.add(new BasicNameValuePair("sortby", sortby)); + } String requestURL = MessageFormat.format( RM_SEARCH_ENDPOINT, @@ -114,20 +120,23 @@ public class SearchAPI extends BaseAPI } /** - * Search as a user for records on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS + * Search as a user for records on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS and sorted + * by sortby *
* If more fine-grained control of search parameters is required, use rmSearch() directly. * @param username * @param password * @param query + * @param sortby * @return list of record names */ public List searchForRecordsAsUser( String username, String password, - String query) + String query, + String sortby) { - return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS)); + return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS, sortby)); } /** diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index 25fe4d9954..d8f20e0224 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -673,10 +673,10 @@ public class BaseRMRestTest extends RestTest * * @param user * @param term + * @param sortby * @return - * @throws Exception */ - public List searchForRMContentAsUser(UserModel user, String term, String expectedResult) throws Exception + public List searchForRMContentAsUser(UserModel user, String term, String sortby) { List results = new ArrayList<>(); // wait for solr indexing @@ -684,16 +684,6 @@ public class BaseRMRestTest extends RestTest int waitInMilliSeconds = 6000; while (counter < 3) { - results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term); - if ((results != null && !results.isEmpty() && results.contains(expectedResult))) - { - break; - } else - { - counter++; - } - // double wait time to not overdo solr search - waitInMilliSeconds = (waitInMilliSeconds * 2); synchronized (this) { try @@ -703,7 +693,17 @@ public class BaseRMRestTest extends RestTest { } } - + + results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term, sortby); + if ((results != null && !results.isEmpty())) + { + break; + } else + { + counter++; + } + // double wait time to not overdo solr search + waitInMilliSeconds = (waitInMilliSeconds * 2); } return results; } From d06c4a36d1aaab49b7a8c469aa0ef661c0b22c1b Mon Sep 17 00:00:00 2001 From: cagache Date: Fri, 11 May 2018 17:26:09 +0300 Subject: [PATCH 06/34] RM-6311 wait for the expected records to be in the search results list --- .../org/alfresco/rest/rm/community/base/BaseRMRestTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index d8f20e0224..8610d4460d 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -674,9 +674,10 @@ public class BaseRMRestTest extends RestTest * @param user * @param term * @param sortby + * @param expectedResults * @return */ - public List searchForRMContentAsUser(UserModel user, String term, String sortby) + public List searchForRMContentAsUser(UserModel user, String term, String sortby, List expectedResults) { List results = new ArrayList<>(); // wait for solr indexing @@ -695,7 +696,7 @@ public class BaseRMRestTest extends RestTest } results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term, sortby); - if ((results != null && !results.isEmpty())) + if ((results != null && !results.isEmpty()) && results.containsAll(expectedResults)) { break; } else From 899301d7cd1f2ea73df35bf7a202687960ec114b Mon Sep 17 00:00:00 2001 From: cagache Date: Mon, 14 May 2018 11:07:06 +0300 Subject: [PATCH 07/34] code review changes --- .../alfresco/rest/rm/community/base/BaseRMRestTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index 8610d4460d..5de8128200 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -658,7 +658,8 @@ public class BaseRMRestTest extends RestTest names.add(childNode.onModel().getName()); }); break; - } else + } + else { counter++; } @@ -696,10 +697,11 @@ public class BaseRMRestTest extends RestTest } results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term, sortby); - if ((results != null && !results.isEmpty()) && results.containsAll(expectedResults)) + if (!results.isEmpty() && results.containsAll(expectedResults)) { break; - } else + } + else { counter++; } From 17fa36314e80066a9d0e7b595430091d345648af Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Mon, 14 May 2018 13:49:38 +0100 Subject: [PATCH 08/34] [maven-release-plugin] prepare release V2.7.b --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index b6ef6d47be..d1eb212bdb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.1-SNAPSHOT + 2.7.b Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - V2.7.0 + V2.7.b diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 9537d46a7d..33186d28df 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 630c15608d..ee0fd6cbc6 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-community/pom.xml b/rm-community/pom.xml index af2b7ee9ec..733389b2fa 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 8de405183e..cc9896923f 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index bb55ff6dd1..b2761ab1cd 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 2.7.b From 03210fc70970f16f2801c0b71f4be32aef15746e Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Mon, 14 May 2018 13:49:40 +0100 Subject: [PATCH 09/34] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index d1eb212bdb..ccc7d886e7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.b + -SNAPSHOT Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - V2.7.b + V2.7.0 diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 33186d28df..2bd7f13c68 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + -SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index ee0fd6cbc6..56b56b5943 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.b + -SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index 733389b2fa..dc0bf74551 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + -SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index cc9896923f..a69b3a1dc6 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.b + -SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index b2761ab1cd..59c2c7a206 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.b + -SNAPSHOT From 894adf7add8a28b32871212c1eac4f51a22e36b1 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 14 May 2018 14:02:34 +0100 Subject: [PATCH 10/34] Revert "[maven-release-plugin] prepare for next development iteration" This reverts commit 03210fc70970f16f2801c0b71f4be32aef15746e. --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index ccc7d886e7..d1eb212bdb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - -SNAPSHOT + 2.7.b Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - V2.7.0 + V2.7.b diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 2bd7f13c68..33186d28df 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - -SNAPSHOT + 2.7.b diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 56b56b5943..ee0fd6cbc6 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - -SNAPSHOT + 2.7.b diff --git a/rm-community/pom.xml b/rm-community/pom.xml index dc0bf74551..733389b2fa 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - -SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index a69b3a1dc6..cc9896923f 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - -SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index 59c2c7a206..b2761ab1cd 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - -SNAPSHOT + 2.7.b From 663ffd38c269c12c3dcafd678542a7c5345ca337 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 14 May 2018 14:02:36 +0100 Subject: [PATCH 11/34] Revert "[maven-release-plugin] prepare release V2.7.b" This reverts commit 17fa36314e80066a9d0e7b595430091d345648af. --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index d1eb212bdb..b6ef6d47be 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.b + 2.7.1-SNAPSHOT Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - V2.7.b + V2.7.0 diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 33186d28df..9537d46a7d 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index ee0fd6cbc6..630c15608d 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index 733389b2fa..af2b7ee9ec 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index cc9896923f..8de405183e 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index b2761ab1cd..bb55ff6dd1 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.b + 2.7.1-SNAPSHOT From 2575dc64adb43d31893ebc9b910c7961654e1b33 Mon Sep 17 00:00:00 2001 From: Ross Gale Date: Tue, 15 May 2018 10:12:03 +0100 Subject: [PATCH 12/34] RM-6318 code review changes --- .../script/slingshot/SearchUtil.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java index e088a559eb..84c5b9a61d 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/SearchUtil.java @@ -43,6 +43,7 @@ import org.alfresco.service.namespace.QName; /** * Parent class for records search utilities + * * @author Ross Gale * @since 2.7 */ @@ -55,6 +56,7 @@ public class SearchUtil /** * Setter for node service + * * @param nodeService Node service */ public void setNodeService(NodeService nodeService) @@ -64,6 +66,7 @@ public class SearchUtil /** * Use a container node ref and return the nodeIds of the contents + * * @param nodeRef container * @return list of nodeIds */ @@ -84,13 +87,15 @@ public class SearchUtil NodeRef rootNodeRef = nodeService.getRootNode(STORE_REF_WORKSPACE_SPACESSTORE); List assocRefs = nodeService.getChildAssocs(rootNodeRef, ASSOC_CHILDREN, container); - if (assocRefs.size() == 0) + if (assocRefs.isEmpty()) { return nodeService.createNode(rootNodeRef, ASSOC_CHILDREN, container, TYPE_CONTAINER).getChildRef(); - } else if (assocRefs.size() != 1) + } + else if (assocRefs.size() != 1) { throw new AlfrescoRuntimeException("Only one container is allowed."); - } else + } + else { return assocRefs.iterator().next().getChildRef(); } From 57201319d1d5be10be0f899ea231fe40ea349aa5 Mon Sep 17 00:00:00 2001 From: Roxana Lucanu-Ghetu Date: Wed, 16 May 2018 11:03:32 +0300 Subject: [PATCH 13/34] RM-6320 Added Declassification Review properties in records search --- .../model/recordsModel.xml | 13 ++++++ .../disposition/DispositionActionImpl.java | 40 +++++++++++++++++++ .../model/RecordsManagementModel.java | 2 + 3 files changed, 55 insertions(+) diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml index dc0e5277b3..a8ef0ea7bf 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml @@ -1132,6 +1132,19 @@ false
+ + d:date + true + + + d:text + true + + true + false + false + + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java index 2e5a12664f..9d59693d28 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java @@ -35,11 +35,13 @@ import java.util.List; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction; import org.alfresco.module.org_alfresco_module_rm.event.EventCompletionDetails; import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.script.slingshot.RMSearchGet; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -328,6 +330,11 @@ public class DispositionActionImpl implements DispositionAction, props.put(PROP_EVENT_EXECUTION_COMPLETED_BY, completedByValue); services.getNodeService().setProperties(eventNodeRef, props); + if (eventName.equals("declassification_review")) + { + setDeclassificationReview(eventNodeRef, completedAtValue, completedByValue); + } + // Check to see if the events eligible property needs to be updated updateEventEligible(); @@ -518,4 +525,37 @@ public class DispositionActionImpl implements DispositionAction, return eligible; } + + /** + * Sets declassification review authority and date on records and record folder + * + * @param eventNodeRef Declassification review event node ref + * @param completedAtValue Declassification review authority + * @param completedByValue Declassification review date + */ + private void setDeclassificationReview(NodeRef eventNodeRef, Date completedAtValue, String completedByValue) + { + NodeRef nextDispositionActionNodeRef = services.getNodeService().getPrimaryParent(eventNodeRef).getParentRef(); + NodeRef nodeRef = services.getNodeService().getPrimaryParent(nextDispositionActionNodeRef).getParentRef(); + + Map nodeProps = services.getNodeService().getProperties(nodeRef); + nodeProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT, completedAtValue); + nodeProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY, completedByValue); + services.getNodeService().setProperties(nodeRef, nodeProps); + + // check if the node is a record folder then set the declassification review on the records also + if (services.getNodeService().getType(nodeRef).equals(RecordsManagementModel.TYPE_RECORD_FOLDER)) + { + // get all the records inside the record folder + List records = services.getNodeService().getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef child : records) + { + NodeRef recordNodeRef = child.getChildRef(); + Map recordProps = services.getNodeService().getProperties(recordNodeRef); + recordProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT, completedAtValue); + recordProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY, completedByValue); + services.getNodeService().setProperties(recordNodeRef, recordProps); + } + } + } } 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 f7211b7d33..e7f23fb9c9 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 @@ -247,6 +247,8 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel QName PROP_RS_HAS_DISPOITION_SCHEDULE = QName.createQName(RM_URI, "recordSearchHasDispositionSchedule"); QName PROP_RS_DISPOITION_INSTRUCTIONS = QName.createQName(RM_URI, "recordSearchDispositionInstructions"); QName PROP_RS_DISPOITION_AUTHORITY = QName.createQName(RM_URI, "recordSearchDispositionAuthority"); + QName PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT = QName.createQName(RM_URI, "recordSearchDeclassificationReviewCompletedAt"); + QName PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY = QName.createQName(RM_URI, "recordSearchDeclassificationReviewCompletedBy"); /** @depreacted as of 2.2, because disposable items can now be in multiple holds */ @Deprecated QName PROP_RS_HOLD_REASON = QName.createQName(RM_URI, "recordSearchHoldReason"); From ee96ccd8572ba89b298d4bd2590eb4e562fbc454 Mon Sep 17 00:00:00 2001 From: jcule Date: Wed, 16 May 2018 11:55:14 +0100 Subject: [PATCH 14/34] RM-6302: Add Edi tFunctionality To Disposition Schedule: automation tests --- .../org/alfresco/rest/core/v0/BaseAPI.java | 2 +- .../alfresco/rest/v0/RecordCategoriesAPI.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java index e3a37ff998..66c1cdf37d 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java @@ -662,7 +662,7 @@ public abstract class BaseAPI RETENTION_GHOST, RETENTION_ELIGIBLE_FIRST_EVENT, RETENTION_EVENTS, - + COMBINE_DISPOSITION_STEP_CONDITIONS } /** diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java index 34ff344f92..57f2368f56 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java @@ -35,6 +35,7 @@ import java.util.Map; import org.alfresco.rest.core.v0.BaseAPI; import org.apache.http.HttpResponse; import org.json.JSONObject; +import org.json.JSONArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -51,6 +52,8 @@ public class RecordCategoriesAPI extends BaseAPI private static final Logger LOGGER = LoggerFactory.getLogger(RecordCategoriesAPI.class); private static final String RM_ACTIONS_API = "{0}rma/actions/ExecutionQueue"; private static final String DISPOSITION_ACTIONS_API = "{0}node/{1}/dispositionschedule/dispositionactiondefinitions"; + private static final String DISPOSITION_SCHEDULE_API = "{0}node/{1}/dispositionschedule"; + /** * Creates a retention schedule for the category given as parameter @@ -71,6 +74,21 @@ public class RecordCategoriesAPI extends BaseAPI return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); } + /** + * Get the disposition schedule nodeRef + * + * @param user + * @param password + * @param categoryName + * @return the disposition schedule nodeRef + */ + public String getDispositionScheduleNodeRef(String user, String password, String categoryName) + { + String catNodeRef = NODE_PREFIX + getItemNodeRef(user, password, "/" + categoryName); + JSONObject dispositionSchedule = doGetRequest(user, password, MessageFormat.format(DISPOSITION_SCHEDULE_API, "{0}", catNodeRef)); + return dispositionSchedule.getJSONObject("data").getString("nodeRef").replace(getNodeRefSpacesStore(), ""); + } + /** * Sets retention schedule authority and instructions, also if it is applied to records or folders * @@ -109,6 +127,34 @@ public class RecordCategoriesAPI extends BaseAPI addPropertyToRequest(requestParams, "ghostOnDestroy", properties, RETENTION_SCHEDULE.RETENTION_GHOST); addPropertyToRequest(requestParams, "periodProperty", properties, RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY); addPropertyToRequest(requestParams, "events", properties, RETENTION_SCHEDULE.RETENTION_EVENTS); + addPropertyToRequest(requestParams, "combineDispositionStepConditions", properties, RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS); + addPropertyToRequest(requestParams, "eligibleOnFirstCompleteEvent", properties, RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT); + + return doPostJsonRequest(user, password, SC_OK, requestParams, MessageFormat.format(DISPOSITION_ACTIONS_API, "{0}", catNodeRef)); + } + + /** + * Creates a retention schedule for a given category with added event + + * @param user + * @param password + * @param categoryName + * @param properties + * @param events + * @return The HTTP Response. + */ + public HttpResponse addDispositionScheduleSteps(String user, String password, String categoryName, Map properties, String events) + { + String catNodeRef = NODE_PREFIX + getItemNodeRef(user, password, "/" + categoryName); + + JSONObject requestParams = new JSONObject(); + addPropertyToRequest(requestParams, "name", properties, RETENTION_SCHEDULE.NAME); + addPropertyToRequest(requestParams, "description", properties, RETENTION_SCHEDULE.DESCRIPTION); + addPropertyToRequest(requestParams, "period", properties, RETENTION_SCHEDULE.RETENTION_PERIOD); + addPropertyToRequest(requestParams, "ghostOnDestroy", properties, RETENTION_SCHEDULE.RETENTION_GHOST); + addPropertyToRequest(requestParams, "periodProperty", properties, RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY); + requestParams.append("events", events); + addPropertyToRequest(requestParams, "combineDispositionStepConditions", properties, RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS); addPropertyToRequest(requestParams, "eligibleOnFirstCompleteEvent", properties, RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT); return doPostJsonRequest(user, password, SC_OK, requestParams, MessageFormat.format(DISPOSITION_ACTIONS_API, "{0}", catNodeRef)); From 6ce336d32e0ea4c3d57bc203ac4d7400510a76ab Mon Sep 17 00:00:00 2001 From: Roxana Lucanu-Ghetu Date: Wed, 16 May 2018 15:35:43 +0300 Subject: [PATCH 15/34] RM-6320 Code review changes. --- .../model/recordsModel.xml | 4 ++-- .../disposition/DispositionActionImpl.java | 20 ++++++++++--------- .../model/RecordsManagementModel.java | 4 ++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml index a8ef0ea7bf..d23a9f7b37 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml @@ -1132,11 +1132,11 @@ false
- + d:date true - + d:text true diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java index 9d59693d28..c8d474cac8 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionActionImpl.java @@ -330,6 +330,7 @@ public class DispositionActionImpl implements DispositionAction, props.put(PROP_EVENT_EXECUTION_COMPLETED_BY, completedByValue); services.getNodeService().setProperties(eventNodeRef, props); + // check a specific event from rmEventConfigBootstrap.json if (eventName.equals("declassification_review")) { setDeclassificationReview(eventNodeRef, completedAtValue, completedByValue); @@ -537,11 +538,7 @@ public class DispositionActionImpl implements DispositionAction, { NodeRef nextDispositionActionNodeRef = services.getNodeService().getPrimaryParent(eventNodeRef).getParentRef(); NodeRef nodeRef = services.getNodeService().getPrimaryParent(nextDispositionActionNodeRef).getParentRef(); - - Map nodeProps = services.getNodeService().getProperties(nodeRef); - nodeProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT, completedAtValue); - nodeProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY, completedByValue); - services.getNodeService().setProperties(nodeRef, nodeProps); + setPropsOnContent(nodeRef, completedAtValue, completedByValue); // check if the node is a record folder then set the declassification review on the records also if (services.getNodeService().getType(nodeRef).equals(RecordsManagementModel.TYPE_RECORD_FOLDER)) @@ -551,11 +548,16 @@ public class DispositionActionImpl implements DispositionAction, for (ChildAssociationRef child : records) { NodeRef recordNodeRef = child.getChildRef(); - Map recordProps = services.getNodeService().getProperties(recordNodeRef); - recordProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT, completedAtValue); - recordProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY, completedByValue); - services.getNodeService().setProperties(recordNodeRef, recordProps); + setPropsOnContent(recordNodeRef, completedAtValue, completedByValue); } } } + + private void setPropsOnContent(NodeRef nodeRef, Date completedAtValue, String completedByValue) + { + Map nodeProps = services.getNodeService().getProperties(nodeRef); + nodeProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT, completedAtValue); + nodeProps.put(PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY, completedByValue); + services.getNodeService().setProperties(nodeRef, nodeProps); + } } 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 e7f23fb9c9..0b77311cf4 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 @@ -247,8 +247,8 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel QName PROP_RS_HAS_DISPOITION_SCHEDULE = QName.createQName(RM_URI, "recordSearchHasDispositionSchedule"); QName PROP_RS_DISPOITION_INSTRUCTIONS = QName.createQName(RM_URI, "recordSearchDispositionInstructions"); QName PROP_RS_DISPOITION_AUTHORITY = QName.createQName(RM_URI, "recordSearchDispositionAuthority"); - QName PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT = QName.createQName(RM_URI, "recordSearchDeclassificationReviewCompletedAt"); - QName PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY = QName.createQName(RM_URI, "recordSearchDeclassificationReviewCompletedBy"); + QName PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_AT = QName.createQName(RM_URI, "declassificationReviewCompletedAt"); + QName PROP_RS_DECLASSIFICATION_REVIEW_COMPLETED_BY = QName.createQName(RM_URI, "declassificationReviewCompletedBy"); /** @depreacted as of 2.2, because disposable items can now be in multiple holds */ @Deprecated QName PROP_RS_HOLD_REASON = QName.createQName(RM_URI, "recordSearchHoldReason"); From 2dc13476b2d5184c59f25fe350446ca6211db982 Mon Sep 17 00:00:00 2001 From: jcule Date: Wed, 16 May 2018 18:22:28 +0100 Subject: [PATCH 16/34] RM-6302: Add Edi tFunctionality To Disposition Schedule: automation tests --- .../alfresco/rest/v0/RecordCategoriesAPI.java | 34 +++---------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java index 57f2368f56..6a3caed2cc 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordCategoriesAPI.java @@ -35,7 +35,6 @@ import java.util.Map; import org.alfresco.rest.core.v0.BaseAPI; import org.apache.http.HttpResponse; import org.json.JSONObject; -import org.json.JSONArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -126,34 +125,11 @@ public class RecordCategoriesAPI extends BaseAPI addPropertyToRequest(requestParams, "period", properties, RETENTION_SCHEDULE.RETENTION_PERIOD); addPropertyToRequest(requestParams, "ghostOnDestroy", properties, RETENTION_SCHEDULE.RETENTION_GHOST); addPropertyToRequest(requestParams, "periodProperty", properties, RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY); - addPropertyToRequest(requestParams, "events", properties, RETENTION_SCHEDULE.RETENTION_EVENTS); - addPropertyToRequest(requestParams, "combineDispositionStepConditions", properties, RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS); - addPropertyToRequest(requestParams, "eligibleOnFirstCompleteEvent", properties, RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT); - - return doPostJsonRequest(user, password, SC_OK, requestParams, MessageFormat.format(DISPOSITION_ACTIONS_API, "{0}", catNodeRef)); - } - - /** - * Creates a retention schedule for a given category with added event - - * @param user - * @param password - * @param categoryName - * @param properties - * @param events - * @return The HTTP Response. - */ - public HttpResponse addDispositionScheduleSteps(String user, String password, String categoryName, Map properties, String events) - { - String catNodeRef = NODE_PREFIX + getItemNodeRef(user, password, "/" + categoryName); - - JSONObject requestParams = new JSONObject(); - addPropertyToRequest(requestParams, "name", properties, RETENTION_SCHEDULE.NAME); - addPropertyToRequest(requestParams, "description", properties, RETENTION_SCHEDULE.DESCRIPTION); - addPropertyToRequest(requestParams, "period", properties, RETENTION_SCHEDULE.RETENTION_PERIOD); - addPropertyToRequest(requestParams, "ghostOnDestroy", properties, RETENTION_SCHEDULE.RETENTION_GHOST); - addPropertyToRequest(requestParams, "periodProperty", properties, RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY); - requestParams.append("events", events); + String events = getPropertyValue(properties, RETENTION_SCHEDULE.RETENTION_EVENTS); + if(!events.equals("")) + { + requestParams.append("events", events); + } addPropertyToRequest(requestParams, "combineDispositionStepConditions", properties, RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS); addPropertyToRequest(requestParams, "eligibleOnFirstCompleteEvent", properties, RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT); From 61ef40ab07ec4c3fd6ff5c98c6ebc95319369855 Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Thu, 17 May 2018 11:49:13 +0100 Subject: [PATCH 17/34] [maven-release-plugin] prepare release V2.7.b --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index e91a141ffe..d1eb212bdb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 3.0.0-SNAPSHOT + 2.7.b Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - HEAD + V2.7.b diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 1033c353a4..33186d28df 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 3.0.0-SNAPSHOT + 2.7.b diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 36080c3d8e..ee0fd6cbc6 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 3.0.0-SNAPSHOT + 2.7.b diff --git a/rm-community/pom.xml b/rm-community/pom.xml index 9e3e1d0779..733389b2fa 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 3.0.0-SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 0f2cb1c749..cc9896923f 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 3.0.0-SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index cded13c0aa..b2761ab1cd 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 3.0.0-SNAPSHOT + 2.7.b From 61e7a1553f87d5d28b59bfb08b8392dc2f036109 Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Thu, 17 May 2018 11:49:15 +0100 Subject: [PATCH 18/34] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index d1eb212bdb..9c1f9499ae 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.b + 2.7.1-SNAPSHOT Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - V2.7.b + HEAD diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 33186d28df..9537d46a7d 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index ee0fd6cbc6..630c15608d 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index 733389b2fa..af2b7ee9ec 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index cc9896923f..8de405183e 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index b2761ab1cd..bb55ff6dd1 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.b + 2.7.1-SNAPSHOT From fcc63ab10db653500b9fe30fbefe57f3db9ff2a5 Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Thu, 17 May 2018 13:53:55 +0100 Subject: [PATCH 19/34] [maven-release-plugin] prepare release V2.7.b --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 9c1f9499ae..d1eb212bdb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.1-SNAPSHOT + 2.7.b Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - HEAD + V2.7.b diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 9537d46a7d..33186d28df 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 630c15608d..ee0fd6cbc6 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-community/pom.xml b/rm-community/pom.xml index af2b7ee9ec..733389b2fa 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 8de405183e..cc9896923f 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 2.7.b diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index bb55ff6dd1..b2761ab1cd 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 2.7.b From 613265383dc106c06c747e00e3bab073490e050f Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Thu, 17 May 2018 13:53:57 +0100 Subject: [PATCH 20/34] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index d1eb212bdb..9c1f9499ae 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.b + 2.7.1-SNAPSHOT Alfresco Records Management @@ -24,7 +24,7 @@ scm:git:https://git.alfresco.com/records-management/records-management.git scm:git:https://git.alfresco.com/records-management/records-management.git https://git.alfresco.com/records-management/records-management - V2.7.b + HEAD diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 33186d28df..9537d46a7d 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index ee0fd6cbc6..630c15608d 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index 733389b2fa..af2b7ee9ec 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index cc9896923f..8de405183e 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.b + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index b2761ab1cd..bb55ff6dd1 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.b + 2.7.1-SNAPSHOT From 271883b1c726bf3ec8544cb11b83a998a578512a Mon Sep 17 00:00:00 2001 From: Tom Page Date: Fri, 18 May 2018 06:51:02 +0100 Subject: [PATCH 21/34] Update version to V2.7.0.1-SNAPSHOT. --- pom.xml | 2 +- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index e91a141ffe..23d477d21e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 3.0.0-SNAPSHOT + 2.7.0.1-SNAPSHOT Alfresco Records Management diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 1033c353a4..496465be48 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 3.0.0-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 36080c3d8e..ce2e06b574 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 3.0.0-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index 9e3e1d0779..ff1f35ec79 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 3.0.0-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 0f2cb1c749..1c15e72cf8 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 3.0.0-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index cded13c0aa..ddf33cf85c 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 3.0.0-SNAPSHOT + 2.7.0.1-SNAPSHOT From 2408e4144ac2eaf10d6cd8fb8a478d5d0017d8c1 Mon Sep 17 00:00:00 2001 From: cagache Date: Fri, 18 May 2018 17:45:38 +0300 Subject: [PATCH 22/34] RM-6320 Automated tests for Declassification review for records and record folders --- .../org/alfresco/rest/core/v0/BaseAPI.java | 31 +++++ .../FilePlanComponentFields.java | 2 + .../rest/v0/RMRolesAndActionsAPI.java | 54 +++++++- .../java/org/alfresco/rest/v0/SearchAPI.java | 23 ++++ .../service/DispositionScheduleService.java | 124 ++++++++++++++++++ .../rm/community/base/BaseRMRestTest.java | 2 +- 6 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java index 66c1cdf37d..e87c7a21b2 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java @@ -674,6 +674,8 @@ public abstract class BaseAPI CUT_OFF("cutoff"), UNDO_CUT_OFF("undoCutoff"), TRANSFER("transfer"), + COMPLETE_EVENT("completeEvent"), + UNDO_EVENT("undoEvent"), DESTROY("destroy"); String action; @@ -688,6 +690,35 @@ public abstract class BaseAPI } } + public enum RM_EVENTS + { + ABOLISHED("abolished", "Abolished"), + ALL_ALLOWANCES_GRANTED_ARE_TERMINATED("all_allowances_granted_are_terminated", "All Allowances Granted are Terminated"), + CASE_CLOSED("case_closed", "Case Closed"), + DECLASSIFICATION_REVIEW("declassification_review", "Declassification Review"), + OBSOLETE("obsolete", "Obsolete"), + NO_LONGER_NEEDED("no_longer_needed", "No Longer Needed"), + STUDY_COMPLETE("study_complete", "Study Complete"); + String eventName; + String eventDisplayLabel; + + RM_EVENTS(String eventName, String eventDisplayLabel) + { + this.eventName = eventName; + this.eventDisplayLabel = eventDisplayLabel; + } + + public String getEventName() + { + return eventName; + } + + public String getEventDisplayLabel() + { + return eventDisplayLabel; + } + } + public enum PermissionType { SET_READ, diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/fileplancomponents/FilePlanComponentFields.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/fileplancomponents/FilePlanComponentFields.java index 2fbbf3cc15..4732c28a17 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/fileplancomponents/FilePlanComponentFields.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/fileplancomponents/FilePlanComponentFields.java @@ -58,6 +58,8 @@ public class FilePlanComponentFields public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_ACTION_NAME = "rma:recordSearchDispositionActionName"; public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_EVENTS_ELIGIBLE = "rma:recordSearchDispositionEventsEligible"; public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_INSTRUCTIONS = "rma:recordSearchDispositionInstructions"; + public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_BY = "rma:declassificationReviewCompletedBy"; + public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_AT = "rma:declassificationReviewCompletedAt"; /** File plan properties */ diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java index 61de24b76c..c222dd1fb2 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java @@ -325,9 +325,9 @@ public class RMRolesAndActionsAPI extends BaseAPI /** * Perform an action on the record folder * - * @param user the user closing the folder + * @param user the user executing the action * @param password the user's password - * @param contentName the record folder name + * @param contentName the content name * @param date the date to be updated * @return The HTTP response. */ @@ -349,6 +349,56 @@ public class RMRolesAndActionsAPI extends BaseAPI return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); } + /** + * Complete an event on the record/record folder + * + * @param user the user executing the action + * @param password the user's password + * @param contentName the content name + * @param event the event to be completed + * @param date the date to be updated + * @return The HTTP response. + */ + public HttpResponse completeEvent(String user, String password, String contentName, RM_EVENTS event, ZonedDateTime date) + { + String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); + JSONObject requestParams = new JSONObject(); + requestParams.put("name", RM_ACTIONS.COMPLETE_EVENT.getAction()); + requestParams.put("nodeRef", recNodeRef); + date = (date != null) ? date : ZonedDateTime.now(); + String formattedDate = date.format(DateTimeFormatter.ISO_INSTANT); + requestParams.put("params", new JSONObject() + .put("eventName", event.getEventName()) + .put("eventCompletedBy", user) + .put("eventCompletedAt", new JSONObject() + .put("iso8601", formattedDate) + ) + ); + + return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); + } + + /** + * Undo an event on the record/record folder + * + * @param user the user executing the action + * @param password the user's password + * @param contentName the content name + * @param event the event to be completed + * @return The HTTP response. + */ + public HttpResponse undoEvent(String user, String password, String contentName, RM_EVENTS event) + { + String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); + JSONObject requestParams = new JSONObject(); + requestParams.put("name", RM_ACTIONS.UNDO_EVENT.getAction()); + requestParams.put("nodeRef", recNodeRef); + requestParams.put("params", new JSONObject() + .put("eventName", event.getEventName())); + + return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); + } + /** * Deletes every item in the given container * diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java index f462f06cdf..62c0ba697f 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java @@ -66,6 +66,9 @@ public class SearchAPI extends BaseAPI /** RM document search filters */ private static final String RM_DEFAULT_RECORD_FILTERS = "records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false"; + /** RM all content search filters */ + private static final String RM_DEFAULT_CONTENT_FILTERS = + "records/true,undeclared/true,vital/false,folders/true,categories/true,frozen/false,cutoff/false"; /** * Perform search request on search endpoint as a user. @@ -139,6 +142,26 @@ public class SearchAPI extends BaseAPI return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS, sortby)); } + /** + * Search as a user for content on site "rm" matching query, using SearchAPI.RM_DEFAULT_CONTENT_FILTERS and sorted + * by sortby + *
+ * If more fine-grained control of search parameters is required, use rmSearch() directly. + * @param username + * @param password + * @param query + * @param sortby + * @return list of record names + */ + public List searchForRmContentAsUser( + String username, + String password, + String query, + String sortby) + { + return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_CONTENT_FILTERS, sortby)); + } + /** * Generic faceted search. * @param username diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java new file mode 100644 index 0000000000..c414e16b2c --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java @@ -0,0 +1,124 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.v0.service; + + +import java.util.HashMap; + +import org.alfresco.rest.core.v0.BaseAPI; +import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory; +import org.alfresco.rest.v0.RecordCategoriesAPI; +import org.alfresco.utility.data.DataUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Service for different disposition schedule actions + * + * @author jcule + * @since 2.7.0.1 + */ +@Service +public class DispositionScheduleService extends BaseAPI +{ + @Autowired + private RecordCategoriesAPI recordCategoriesAPI; + + @Autowired + private DataUser dataUser; + + /** + * Helper method for adding a cut off after period step + * + * @param categoryName the category in whose schedule the step will be added + * @param period + * @return + */ + public void addCutOffAfterPeriodStep(String categoryName, String period) + { + HashMap cutOffStep = new HashMap<>(); + cutOffStep.put(RETENTION_SCHEDULE.NAME, "cutoff"); + cutOffStep.put(RETENTION_SCHEDULE.RETENTION_PERIOD, period); + cutOffStep.put(RETENTION_SCHEDULE.DESCRIPTION, "Cut off after a period step"); + recordCategoriesAPI.addDispositionScheduleSteps(dataUser.getAdminUser().getUsername(), + dataUser.getAdminUser().getPassword(), categoryName, cutOffStep); + } + + /** + * Helper method for adding a cut off after an event occurs step + * + * @param categoryName the category in whose schedule the step will be added + * @param events + */ + public void addCutOffAfterEventStep(String categoryName, String events) + { + HashMap cutOffStep = new HashMap<>(); + cutOffStep.put(RETENTION_SCHEDULE.NAME, "cutoff"); + cutOffStep.put(RETENTION_SCHEDULE.RETENTION_EVENTS, events); + cutOffStep.put(RETENTION_SCHEDULE.DESCRIPTION, "Cut off after event step"); + + recordCategoriesAPI.addDispositionScheduleSteps(dataUser.getAdminUser().getUsername(), + dataUser.getAdminUser().getPassword(), categoryName, cutOffStep); + } + + /** + * Helper method for accession step properties + * + * @param timeOrEvent + * @param events + * @param period + * @param periodProperty + * @param combineConditions + * @return + */ + public void addAccessionStep(String categoryName, Boolean timeOrEvent, String events, String period, String + periodProperty, Boolean combineConditions) + { + HashMap accessionStep = new HashMap<>(); + accessionStep.put(RETENTION_SCHEDULE.NAME, "accession"); + accessionStep.put(RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS, Boolean.toString(combineConditions)); + accessionStep.put(RETENTION_SCHEDULE.RETENTION_PERIOD, period); + accessionStep.put(RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY, periodProperty); + if (!timeOrEvent) + { + accessionStep.put(RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT, Boolean.toString(timeOrEvent)); + } + accessionStep.put(RETENTION_SCHEDULE.RETENTION_EVENTS, events); + accessionStep.put(RETENTION_SCHEDULE.DESCRIPTION, + "Accession step with time and event conditions."); + recordCategoriesAPI.addDispositionScheduleSteps(dataUser.getAdminUser().getUsername(), + dataUser.getAdminUser().getPassword(), categoryName, accessionStep); + } + + /** + * Helper method to create retention schedule with general fields for the given category as admin + * and apply it to the records + * + * @param categoryName + * @param appliedToRecords + */ + public void createCategoryRetentionSchedule(String categoryName, Boolean appliedToRecords) + { + recordCategoriesAPI.createRetentionSchedule(dataUser.getAdminUser().getUsername(), + dataUser.getAdminUser().getPassword(), categoryName); + String retentionScheduleNodeRef = recordCategoriesAPI.getDispositionScheduleNodeRef( + dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(), categoryName); + + HashMap retentionScheduleGeneralFields = new HashMap<>(); + retentionScheduleGeneralFields.put(RETENTION_SCHEDULE.RETENTION_AUTHORITY, "Authority"); + retentionScheduleGeneralFields.put(RETENTION_SCHEDULE.RETENTION_INSTRUCTIONS, "Instructions"); + recordCategoriesAPI.setRetentionScheduleGeneralFields(dataUser.getAdminUser().getUsername(), + dataUser.getAdminUser().getPassword(), retentionScheduleNodeRef, retentionScheduleGeneralFields, + appliedToRecords); + + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index 5de8128200..29b06b488f 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -696,7 +696,7 @@ public class BaseRMRestTest extends RestTest } } - results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term, sortby); + results = searchApi.searchForRmContentAsUser(user.getUsername(), user.getPassword(), term, sortby); if (!results.isEmpty() && results.containsAll(expectedResults)) { break; From 8d1179907cbd4e5daf545446ba34cc80ec5913c9 Mon Sep 17 00:00:00 2001 From: cagache Date: Mon, 21 May 2018 11:08:50 +0300 Subject: [PATCH 23/34] fix license --- .../service/DispositionScheduleService.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java index c414e16b2c..a541c0d571 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java @@ -4,9 +4,24 @@ * %% * Copyright (C) 2005 - 2018 Alfresco Software Limited * %% - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. + * 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.v0.service; From a77cfe9ac5ca65fac3ccdc2c489725aeebadbf6e Mon Sep 17 00:00:00 2001 From: cagache Date: Mon, 21 May 2018 11:20:24 +0300 Subject: [PATCH 24/34] javadoc updates --- .../main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java | 2 +- .../alfresco/rest/v0/service/DispositionScheduleService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java index c222dd1fb2..abaf11debd 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java @@ -384,7 +384,7 @@ public class RMRolesAndActionsAPI extends BaseAPI * @param user the user executing the action * @param password the user's password * @param contentName the content name - * @param event the event to be completed + * @param event the event to be undone * @return The HTTP response. */ public HttpResponse undoEvent(String user, String password, String contentName, RM_EVENTS event) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java index a541c0d571..e5265f69ac 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/DispositionScheduleService.java @@ -86,7 +86,7 @@ public class DispositionScheduleService extends BaseAPI } /** - * Helper method for accession step properties + * Helper method for adding an accession step * * @param timeOrEvent * @param events From 86320dbdd2476b26a94939c6ff5d76792b12361c Mon Sep 17 00:00:00 2001 From: cagache Date: Mon, 21 May 2018 11:58:17 +0300 Subject: [PATCH 25/34] reverted version changes --- pom.xml | 2 +- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 9c1f9499ae..23d477d21e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.1-SNAPSHOT + 2.7.0.1-SNAPSHOT Alfresco Records Management diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 9537d46a7d..496465be48 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 630c15608d..ce2e06b574 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.1-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index af2b7ee9ec..ff1f35ec79 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 8de405183e..1c15e72cf8 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 2.7.0.1-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index bb55ff6dd1..ddf33cf85c 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 2.7.0.1-SNAPSHOT From 89fefe174713f282647c69d044dcffbd6c0cf5b1 Mon Sep 17 00:00:00 2001 From: jcule Date: Mon, 21 May 2018 13:38:21 +0100 Subject: [PATCH 26/34] RM-6318: Search for "derived by" and classification reasons: Automate AC --- .../main/java/org/alfresco/rest/v0/SearchAPI.java | 15 +++++++-------- .../rest/rm/community/base/BaseRMRestTest.java | 10 ++++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java index f462f06cdf..aec0b129ba 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java @@ -65,8 +65,7 @@ public class SearchAPI extends BaseAPI /** RM document search filters */ private static final String RM_DEFAULT_RECORD_FILTERS = - "records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false"; - + "records/true,undeclared/true,vital/false,folders/{0},categories/{1},frozen/false,cutoff/false"; /** * Perform search request on search endpoint as a user. *

@@ -120,7 +119,7 @@ public class SearchAPI extends BaseAPI } /** - * Search as a user for records on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS and sorted + * Search as a user for nodes on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS and sorted * by sortby *
* If more fine-grained control of search parameters is required, use rmSearch() directly. @@ -131,12 +130,12 @@ public class SearchAPI extends BaseAPI * @return list of record names */ public List searchForRecordsAsUser( - String username, - String password, - String query, - String sortby) + String username, String password, + String query, String sortby, + Boolean includeCategories, Boolean includeFolders) { - return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS, sortby)); + String searchFilterParamaters = MessageFormat.format(RM_DEFAULT_RECORD_FILTERS, Boolean.toString(includeFolders), Boolean.toString(includeCategories)); + return getItemNames(rmSearch(username, password, "rm", query, searchFilterParamaters, sortby)); } /** diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index 5de8128200..ee4ae09a62 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -678,7 +678,8 @@ public class BaseRMRestTest extends RestTest * @param expectedResults * @return */ - public List searchForRMContentAsUser(UserModel user, String term, String sortby, List expectedResults) + public List searchForRMContentAsUser(UserModel user, String term, String sortby, Boolean includeFolders, + Boolean includeCategories, List expectedResults) { List results = new ArrayList<>(); // wait for solr indexing @@ -691,12 +692,13 @@ public class BaseRMRestTest extends RestTest try { this.wait(waitInMilliSeconds); - } catch (InterruptedException e) + } + catch (InterruptedException e) { } } - - results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term, sortby); + results = searchApi.searchForRecordsAsUser(user.getUsername(), user.getPassword(), term, sortby, + includeFolders, includeCategories); if (!results.isEmpty() && results.containsAll(expectedResults)) { break; From 26a346ee8f4bbed2ec974816d2543fc77a762050 Mon Sep 17 00:00:00 2001 From: cagache Date: Mon, 21 May 2018 15:50:56 +0300 Subject: [PATCH 27/34] code review changes --- .../org/alfresco/rest/core/v0/BaseAPI.java | 29 ------------------- .../org/alfresco/rest/core/v0/RMEvents.java | 23 +++++++++++++++ .../rest/v0/RMRolesAndActionsAPI.java | 14 +++++---- .../java/org/alfresco/rest/v0/SearchAPI.java | 8 ++--- 4 files changed, 35 insertions(+), 39 deletions(-) create mode 100644 rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java index e87c7a21b2..935dcc151c 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java @@ -690,35 +690,6 @@ public abstract class BaseAPI } } - public enum RM_EVENTS - { - ABOLISHED("abolished", "Abolished"), - ALL_ALLOWANCES_GRANTED_ARE_TERMINATED("all_allowances_granted_are_terminated", "All Allowances Granted are Terminated"), - CASE_CLOSED("case_closed", "Case Closed"), - DECLASSIFICATION_REVIEW("declassification_review", "Declassification Review"), - OBSOLETE("obsolete", "Obsolete"), - NO_LONGER_NEEDED("no_longer_needed", "No Longer Needed"), - STUDY_COMPLETE("study_complete", "Study Complete"); - String eventName; - String eventDisplayLabel; - - RM_EVENTS(String eventName, String eventDisplayLabel) - { - this.eventName = eventName; - this.eventDisplayLabel = eventDisplayLabel; - } - - public String getEventName() - { - return eventName; - } - - public String getEventDisplayLabel() - { - return eventDisplayLabel; - } - } - public enum PermissionType { SET_READ, diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java new file mode 100644 index 0000000000..bf1d724f65 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java @@ -0,0 +1,23 @@ +package org.alfresco.rest.core.v0; + +public enum RMEvents +{ + ABOLISHED("abolished"), + ALL_ALLOWANCES_GRANTED_ARE_TERMINATED("all_allowances_granted_are_terminated"), + CASE_CLOSED("case_closed"), + DECLASSIFICATION_REVIEW("declassification_review"), + OBSOLETE("obsolete"), + NO_LONGER_NEEDED("no_longer_needed"), + STUDY_COMPLETE("study_complete"); + private String eventName; + + RMEvents(String eventName) + { + this.eventName = eventName; + } + + public String getEventName() + { + return eventName; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java index abaf11debd..122ab88bef 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java @@ -35,6 +35,7 @@ import static org.testng.AssertJUnit.fail; import java.io.IOException; import java.text.MessageFormat; +import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; @@ -46,6 +47,7 @@ import org.alfresco.dataprep.AlfrescoHttpClientFactory; import org.alfresco.dataprep.ContentService; import org.alfresco.dataprep.UserService; import org.alfresco.rest.core.v0.BaseAPI; +import org.alfresco.rest.core.v0.RMEvents; import org.apache.chemistry.opencmis.client.api.CmisObject; import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpResponse; @@ -354,19 +356,19 @@ public class RMRolesAndActionsAPI extends BaseAPI * * @param user the user executing the action * @param password the user's password - * @param contentName the content name + * @param nodeName the node name * @param event the event to be completed * @param date the date to be updated * @return The HTTP response. */ - public HttpResponse completeEvent(String user, String password, String contentName, RM_EVENTS event, ZonedDateTime date) + public HttpResponse completeEvent(String user, String password, String nodeName, RMEvents event, Instant date) { - String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); + String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, nodeName); JSONObject requestParams = new JSONObject(); requestParams.put("name", RM_ACTIONS.COMPLETE_EVENT.getAction()); requestParams.put("nodeRef", recNodeRef); - date = (date != null) ? date : ZonedDateTime.now(); - String formattedDate = date.format(DateTimeFormatter.ISO_INSTANT); + date = (date != null) ? date : Instant.now(); + String formattedDate = DateTimeFormatter.ISO_INSTANT.format(date); requestParams.put("params", new JSONObject() .put("eventName", event.getEventName()) .put("eventCompletedBy", user) @@ -387,7 +389,7 @@ public class RMRolesAndActionsAPI extends BaseAPI * @param event the event to be undone * @return The HTTP response. */ - public HttpResponse undoEvent(String user, String password, String contentName, RM_EVENTS event) + public HttpResponse undoEvent(String user, String password, String contentName, RMEvents event) { String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); JSONObject requestParams = new JSONObject(); diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java index 62c0ba697f..2e91ee2928 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java @@ -66,8 +66,8 @@ public class SearchAPI extends BaseAPI /** RM document search filters */ private static final String RM_DEFAULT_RECORD_FILTERS = "records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false"; - /** RM all content search filters */ - private static final String RM_DEFAULT_CONTENT_FILTERS = + /** RM all nodes search filters */ + private static final String RM_DEFAULT_NODES_FILTERS = "records/true,undeclared/true,vital/false,folders/true,categories/true,frozen/false,cutoff/false"; /** @@ -143,7 +143,7 @@ public class SearchAPI extends BaseAPI } /** - * Search as a user for content on site "rm" matching query, using SearchAPI.RM_DEFAULT_CONTENT_FILTERS and sorted + * Search as a user for content on site "rm" matching query, using SearchAPI.RM_DEFAULT_NODES_FILTERS and sorted * by sortby *
* If more fine-grained control of search parameters is required, use rmSearch() directly. @@ -159,7 +159,7 @@ public class SearchAPI extends BaseAPI String query, String sortby) { - return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_CONTENT_FILTERS, sortby)); + return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_NODES_FILTERS, sortby)); } /** From 8b43c08ecfd19758387f15b6324ae67b0090d16a Mon Sep 17 00:00:00 2001 From: cagache Date: Mon, 21 May 2018 16:03:34 +0300 Subject: [PATCH 28/34] added license --- .../org/alfresco/rest/core/v0/RMEvents.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java index bf1d724f65..a63fa5b903 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/RMEvents.java @@ -1,3 +1,29 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2018 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.core.v0; public enum RMEvents From c1a84b90dc28b508bfd827f1e825c96c2d7e9a1a Mon Sep 17 00:00:00 2001 From: cagache Date: Tue, 22 May 2018 09:50:52 +0300 Subject: [PATCH 29/34] changed version from 2.7.0.1 to 2.7.1 --- pom.xml | 2 +- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 23d477d21e..9c1f9499ae 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.0.1-SNAPSHOT + 2.7.1-SNAPSHOT Alfresco Records Management diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 496465be48..9537d46a7d 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.0.1-SNAPSHOT + 2.7.1-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index ce2e06b574..630c15608d 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.0.1-SNAPSHOT + 2.7.1-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index ff1f35ec79..af2b7ee9ec 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.0.1-SNAPSHOT + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 1c15e72cf8..8de405183e 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.0.1-SNAPSHOT + 2.7.1-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index ddf33cf85c..bb55ff6dd1 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.0.1-SNAPSHOT + 2.7.1-SNAPSHOT From 917dccc66f456e0d11876c2268c3b725161b6fa3 Mon Sep 17 00:00:00 2001 From: cagache Date: Tue, 22 May 2018 10:15:34 +0300 Subject: [PATCH 30/34] changed version from 2.7.1 to 3.0.0 --- pom.xml | 2 +- rm-automation/pom.xml | 2 +- rm-automation/rm-automation-community-rest-api/pom.xml | 2 +- rm-community/pom.xml | 2 +- rm-community/rm-community-repo/pom.xml | 2 +- rm-community/rm-community-rest-api-explorer/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 9c1f9499ae..e91a141ffe 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.alfresco alfresco-rm pom - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT Alfresco Records Management diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 9537d46a7d..1033c353a4 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 630c15608d..36080c3d8e 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm-automation - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT diff --git a/rm-community/pom.xml b/rm-community/pom.xml index af2b7ee9ec..9e3e1d0779 100644 --- a/rm-community/pom.xml +++ b/rm-community/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-rm - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT diff --git a/rm-community/rm-community-repo/pom.xml b/rm-community/rm-community-repo/pom.xml index 8de405183e..0f2cb1c749 100644 --- a/rm-community/rm-community-repo/pom.xml +++ b/rm-community/rm-community-repo/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT diff --git a/rm-community/rm-community-rest-api-explorer/pom.xml b/rm-community/rm-community-rest-api-explorer/pom.xml index bb55ff6dd1..cded13c0aa 100644 --- a/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-rm-community - 2.7.1-SNAPSHOT + 3.0.0-SNAPSHOT From 7ec45fc0d37908ce510693781ff13be1548a53f0 Mon Sep 17 00:00:00 2001 From: David Webster Date: Tue, 22 May 2018 12:01:28 +0100 Subject: [PATCH 31/34] Copy version records notes from old architectural map --- rm-community/documentation/README.md | 2 +- .../documentation/versionRecords/README.md | 20 ++++++++++++++++++ .../versionRecords/RecordedVersions.png | Bin 0 -> 66207 bytes 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 rm-community/documentation/versionRecords/README.md create mode 100644 rm-community/documentation/versionRecords/RecordedVersions.png diff --git a/rm-community/documentation/README.md b/rm-community/documentation/README.md index b4b7911330..8d2a411bec 100644 --- a/rm-community/documentation/README.md +++ b/rm-community/documentation/README.md @@ -11,7 +11,7 @@ * Easy Access Records * Physical Records * Record Import and Export - * Version Records + * [Version Records](./versionRecords) * Retention * [Destruction](./destruction) * Retention Schedules and Events diff --git a/rm-community/documentation/versionRecords/README.md b/rm-community/documentation/versionRecords/README.md new file mode 100644 index 0000000000..405827ed13 --- /dev/null +++ b/rm-community/documentation/versionRecords/README.md @@ -0,0 +1,20 @@ +## Version Records ![](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square) + +### Notes: + +NodesService varies depending on store. Version Service has a different service that hydrates effectively fake nodes (which contain url, version details, associations, aspects, as denormalised meta data) back into a full node + +Recorded Versions take content out of version store and create a record by version store implementation extension. + +Declaring record as version - standard use case is auto declaring or via records. Head version is extracted to a record, rather than a new version being created + +Records are linked by association + +Disposition events can be triggered automatically from versioning events. + +### Diagram: + +![Version Records Primer](./RecordedVersions.png) + + + diff --git a/rm-community/documentation/versionRecords/RecordedVersions.png b/rm-community/documentation/versionRecords/RecordedVersions.png new file mode 100644 index 0000000000000000000000000000000000000000..7ac208b9e243e29f3f87c06643cf46990c9372df GIT binary patch literal 66207 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

V=QH|GV@P>Ps#mJo!&Ipr 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 literal 0 HcmV?d00001 From 360c6a45b4b0774bdf14ce31845dd68a14175a9a Mon Sep 17 00:00:00 2001 From: David Webster Date: Tue, 22 May 2018 12:08:18 +0100 Subject: [PATCH 32/34] Add build flow from old architectural map --- rm-community/documentation/README.md | 2 + rm-community/documentation/build/README.md | 6 ++ .../documentation/build/resource/build.png | Bin 0 -> 53910 bytes .../documentation/build/resource/build.puml | 66 ++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 rm-community/documentation/build/README.md create mode 100644 rm-community/documentation/build/resource/build.png create mode 100644 rm-community/documentation/build/resource/build.puml diff --git a/rm-community/documentation/README.md b/rm-community/documentation/README.md index 8d2a411bec..634c4b4900 100644 --- a/rm-community/documentation/README.md +++ b/rm-community/documentation/README.md @@ -27,3 +27,5 @@ * Governance Rules * Core Module Services * [RM Patch Service](./PatchService.md) +* Build and Release + * [Build](./build) diff --git a/rm-community/documentation/build/README.md b/rm-community/documentation/build/README.md new file mode 100644 index 0000000000..8a50c3219a --- /dev/null +++ b/rm-community/documentation/build/README.md @@ -0,0 +1,6 @@ +## GS Build ![](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square) + +Build location: https://bamboo.alfresco.com/bamboo/browse/RM (not externally accessible.) + +Build Flow: +![build](./resource/build.png) \ No newline at end of file diff --git a/rm-community/documentation/build/resource/build.png b/rm-community/documentation/build/resource/build.png new file mode 100644 index 0000000000000000000000000000000000000000..902e37424b19d7b82cddeaadb7185229246cbbf2 GIT binary patch literal 53910 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

AtwRxk(x|S8^Z5SCnwS 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 CaW1d` literal 0 HcmV?d00001 diff --git a/rm-community/documentation/build/resource/build.puml b/rm-community/documentation/build/resource/build.puml new file mode 100644 index 0000000000..7c56bef154 --- /dev/null +++ b/rm-community/documentation/build/resource/build.puml @@ -0,0 +1,66 @@ +@startuml + +Title: Governance Services Build Pipeline (RM HEAD) + +'build plans: +'Ent UI: Automated UI Tests Enterprise +'Com API: Automation Community REST API +'Ent API: Automation Enterprise REST API +'Community +'Com UI: Community Automated UI Tests +'Enterprise +'Ent L1: Enterprise Level 1 Automated UI Tests +'Ent L2: Level 2 Automated UI Tests Enterprise +'RM Benchmark Driver + + +start + +if(Trigger) then (commit to path) + if (rm-community/*) + :Community; + fork + :Ent L1; + fork again + :Enterprise; + fork + :Ent L2; + fork again + :Ent UI; + end fork + end fork + elseif (rm-enterprise/*) + :Enterprise; + fork + :Ent L2; + fork again + :Ent UI; + end fork + elseif (rm-automation/*) + fork + :Ent L1; + fork again + :Ent L2; + fork again + :Ent UI; + end fork + stop + elseif (rm-community-rest-api/*) + :Com API; + stop + elseif (rm-enterprise-rest-api/*) + :Ent API; + stop + elseif (rm-benchmark-driver/*) + :Benchmark; + stop + else + end + endif +else (Time: 1am) + :Community UI; + stop +endif +:Release Step; +end +@enduml \ No newline at end of file From b075bf9e621fd287c8ae4b47766b77f29a2e0bce Mon Sep 17 00:00:00 2001 From: jcule Date: Tue, 22 May 2018 20:13:42 +0100 Subject: [PATCH 33/34] RM-6318: Search for "derived by" and classification reasons: Automate AC --- .../org/alfresco/rest/rm/community/base/BaseRMRestTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index ee4ae09a62..3523521852 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -678,8 +678,8 @@ public class BaseRMRestTest extends RestTest * @param expectedResults * @return */ - public List searchForRMContentAsUser(UserModel user, String term, String sortby, Boolean includeFolders, - Boolean includeCategories, List expectedResults) + public List searchForRMContentAsUser(UserModel user, String term, String sortby, boolean includeFolders, + boolean includeCategories, List expectedResults) { List results = new ArrayList<>(); // wait for solr indexing From 8612a58a734e2eb40c324830d0fdcfefd77a4774 Mon Sep 17 00:00:00 2001 From: jcule Date: Wed, 23 May 2018 16:35:56 +0100 Subject: [PATCH 34/34] RM-6318: Search for "derived by" and classification reasons: Automate AC -fixed failing tests --- .../java/org/alfresco/rest/v0/SearchAPI.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java index 7dbf469de5..3dc1f1edfd 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java @@ -135,30 +135,10 @@ public class SearchAPI extends BaseAPI String query, String sortby, boolean includeCategories, boolean includeFolders) { - String searchFilterParamaters = MessageFormat.format(RM_DEFAULT_NODES_FILTERS, Boolean.toString(includeFolders), Boolean.toString(includeCategories)); + String searchFilterParamaters = MessageFormat.format(RM_DEFAULT_NODES_FILTERS, Boolean.toString(includeFolders), Boolean.toString(includeCategories)); return getItemNames(rmSearch(username, password, "rm", query, searchFilterParamaters, sortby)); } - /** - * Search as a user for content on site "rm" matching query, using SearchAPI.RM_DEFAULT_NODES_FILTERS and sorted - * by sortby - *
- * If more fine-grained control of search parameters is required, use rmSearch() directly. - * @param username - * @param password - * @param query - * @param sortby - * @return list of record names - */ - public List searchForRmContentAsUser( - String username, - String password, - String query, - String sortby) - { - return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_NODES_FILTERS, sortby)); - } - /** * Generic faceted search. * @param username