diff --git a/README.txt b/README.txt index b46013c3f5..870cf3c876 100644 --- a/README.txt +++ b/README.txt @@ -1,27 +1,23 @@ Configuring and starting Alfresco/Share: ---------------------------------------- -- Clone the project from git +- Clone the project (e.g. git clone git@gitlab.alfresco.com:records-management/records-management.git) - Import the project as a maven project - Start the Alfresco/Share instances with the following commands: - To start the repo: - cd rm-community/rm-community-repo mvn clean install -Pstart-repo - - To start Share: - cd rm-community/rm-community-share mvn clean install -Pstart-share - NOTE: If you have the enterprise code, see rm-enterprise/README.txt for instructions on how to build/start the enterprise code. + (these commands work best if run from the specific directories, e.g. start share from + rm-enterprise/rm-enterprise-share/ or rm-community/rm-community-share/ ) Configuring a different DB other than H2 (e.g. MySQL or PostgreSQL): -------------------------------------------------------------------- -- Create a file called "local.properties" under src/main/resources in rm-community-repo (you may need to create the directory) +- Create a file called "local.properties" under src/main/resources in alfresco-rm-enterprise-repo - Add the following properties in this new file my.db.name -> The name of the database schema @@ -51,12 +47,12 @@ To run the automated UI tests, change to the rm-automation directory and run: mvn clean install -Dskip.automationtests=false -Note: due to Selenium Firefox driver changes, the highest supported Firefox version for UI tests is 43.0.4 (with Selenium 2.52.0). +Note: due to Selenium Firefox driver changes, the highest supported Firefox version for UI tests is 43.0.4 (with Selenium 2.52.0). It is possible to have multiple versions of Firefox installed onto your workstation (e.g. one for running the UI tests and the other, kept -up to date, for everyday browsing) but beware Firefox auto-updates. In this scenario the best approach is to create a non-default profile -(default profiles will be shared between your Firefox installations!) for which auto-updates are disabled and forcing the use of this -profile in your tests (-Dwebdriver.firefox.profile="ProfileName"). If your Firefox 43 install isn't in your path, you can use the +up to date, for everyday browsing) but beware Firefox auto-updates. In this scenario the best approach is to create a non-default profile +(default profiles will be shared between your Firefox installations!) for which auto-updates are disabled and forcing the use of this +profile in your tests (-Dwebdriver.firefox.profile="ProfileName"). If your Firefox 43 install isn't in your path, you can use the -Dwebdriver.firefox.profile option set to the full path of its "firefox-bin" executable. MacOS X Sierra users: if you experience by order of magnitude slower performance when connected to a WiFi network (e.g. office WiFi) @@ -90,9 +86,9 @@ To download and run RM with the Outlook Integration AMPs installed on the repo a mvn clean install -Pstart-share,outlook-integration Follow these instructions install licence and Outlook plugin: - + - http://docs.alfresco.com/outlook2.1/tasks/Outlook-license.html - - http://docs.alfresco.com/outlook2.1/tasks/Outlook-install_v2.html + - http://docs.alfresco.com/outlook2.1/tasks/Outlook-install_v2.html SNAPSHOT dependencies: @@ -115,7 +111,7 @@ This project follows the usual Alfresco Coding Standards. If you use Eclipse or Surf build errors: ------------------ -If you get: +If you get: [ERROR] Failed to execute goal on project alfresco-rm-community-share: Could not resolve dependencies for project org.alfresco:alfresco-rm-community-share:amp:2.6-SNAPSHOT: Failed to collect dependencies at org.alfresco.surf:spring-surf-api:jar:6.3 -> org.alfresco.surf:spring-surf:jar:${dependency.surf.version}: Failed to read artifact descriptor for org.alfresco.surf:spring-surf:jar:${dependency.surf.version}: Could not transfer artifact org.alfresco.surf:spring-surf:pom:${dependency.surf.version} from/to alfresco-internal (https://artifacts.alfresco.com/nexus/content/groups/private): Not authorized , ReasonPhrase:Unauthorized. -> [Help 1] then please re-run with -Ddependency.surf.version=6.3 @@ -127,3 +123,19 @@ Install lombok plugin for IDEs: To allow automation and benchmark projects to be built within an IDE the lombok 'plugin' needs to be installed. Execute lombok.jar (doubleclick it, or run java -jar lombok.jar). Follow instructions. + + +Use Solr 6 with Alfresco 5.2.x: +------------------------------- +In alfresco-global.properties (depending on the RM edition /records-management/rm-community/rm-community-repo/src/test/properties/local or /records-management/rm-enterprise/rm-enterprise-repo/src/test/properties/local) +change the value for "index.subsystem.name" from "solr4" to "solr6". +Add also the following property "solr.port=8983". + +Download the latest Alfresco Search Services from +https://nexus.alfresco.com/nexus/#nexus-search;gav~~alfresco-search-services~~~ +Currently it's 1.0.0 (alfresco-search-services-1.0.0.zip) + +Unzip it and change to the "solr" folder within it. Start the Solr server using the following command: +solr start -a "-Dcreate.alfresco.defaults=alfresco,archive" + +Start your repository \ No newline at end of file diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml index 3b05142894..73adaab087 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml @@ -389,6 +389,7 @@ + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementPolicies.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementPolicies.java index d927576591..d92158830f 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementPolicies.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementPolicies.java @@ -51,6 +51,8 @@ public interface RecordsManagementPolicies QName ON_REMOVE_REFERENCE = QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveReference"); QName BEFORE_RECORD_DECLARATION = QName.createQName(NamespaceService.ALFRESCO_URI, "beforeRecordDeclaration"); QName ON_RECORD_DECLARATION = QName.createQName(NamespaceService.ALFRESCO_URI, "onRecordDeclaration"); + QName BEFORE_RECORD_REJECTION = QName.createQName(NamespaceService.ALFRESCO_URI, "beforeRecordRejection"); + QName ON_RECORD_REJECTION = QName.createQName(NamespaceService.ALFRESCO_URI, "onRecordRejection"); /** Before records management action execution */ interface BeforeRMActionExecution extends ClassPolicy @@ -146,4 +148,22 @@ public interface RecordsManagementPolicies { void onRecordDeclaration(NodeRef nodeRef); } + + /** + * Before record rejection + * @since 2.5 + */ + interface BeforeRecordRejection extends ClassPolicy + { + void beforeRecordRejection(NodeRef nodeRef); + } + + /** + * On record rejection + * @since 2.5 + */ + interface OnRecordRejection extends ClassPolicy + { + void onRecordRejection(NodeRef nodeRef); + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java index f0be02b99a..062929f92f 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java @@ -38,6 +38,8 @@ import java.util.Set; import static org.alfresco.module.org_alfresco_module_rm.record.RecordUtils.generateRecordIdentifier; import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; +import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImpl; +import org.alfresco.module.org_alfresco_module_rm.util.TransactionalResourceHelper; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -72,13 +74,24 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase /** check mandatory properties */ private boolean checkMandatoryPropertiesEnabled = true; + /** transactional resource helper */ + private TransactionalResourceHelper transactionalResourceHelper; + /** * @param checkMandatoryPropertiesEnabled true if check mandatory properties is enabled, false otherwise */ public void setCheckMandatoryPropertiesEnabled(boolean checkMandatoryPropertiesEnabled) { - this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; - } + this.checkMandatoryPropertiesEnabled = checkMandatoryPropertiesEnabled; + } + + /** + * @param transactionalResourceHelper + */ + public void setTransactionalResourceHelper(TransactionalResourceHelper transactionalResourceHelper) + { + this.transactionalResourceHelper = transactionalResourceHelper; + } /** * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) @@ -92,8 +105,12 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase { if (!getRecordService().isDeclared(actionedUponNodeRef)) { - // make sure the record identifier is set - generateRecordIdentifier(getNodeService(), getIdentifierService(), actionedUponNodeRef); + // if the record is newly created make sure the record identifier is set before completing the record + Set newRecords = transactionalResourceHelper.getSet(RecordServiceImpl.KEY_NEW_RECORDS); + if(newRecords.contains(actionedUponNodeRef)) + { + generateRecordIdentifier(getNodeService(), getIdentifierService(), actionedUponNodeRef); + } List missingProperties = new ArrayList(5); // Aspect not already defined - check mandatory properties then add diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java index 80fb8b2a0b..37ba895c11 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java @@ -274,8 +274,6 @@ public class RecordFolderType extends AbstractDisposableItem throw new IntegrityException(I18NUtil.getMessage(MSG_CANNOT_CREATE_RECORD_FOLDER_CHILD, nodeService.getType(child)), null); } - generateRecordIdentifier(nodeService, identifierService, child); - behaviourFilter.disableBehaviour(); try { diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordsManagementContainerType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordsManagementContainerType.java index 3dc7c4ce99..a1517015ff 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordsManagementContainerType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordsManagementContainerType.java @@ -196,18 +196,6 @@ public class RecordsManagementContainerType extends BaseBehaviourBean setIdenifierProperty(child); } } - else - { - NodeRef parentRef = childAssocRef.getParentRef(); - QName parentType = nodeService.getType(parentRef); - boolean isContentSubType = dictionaryService.isSubClass(childType, ContentModel.TYPE_CONTENT); - boolean isUnfiledRecordContainer = parentType.equals(RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER); - boolean isUnfiledRecordFolder = parentType.equals(RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER); - if (isContentSubType && (isUnfiledRecordContainer || isUnfiledRecordFolder)) - { - generateRecordIdentifier(nodeService, identifierService, child); - } - } } return null; diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index 064c601f74..c286ae45ca 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -51,8 +51,10 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeFileRecord; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeRecordDeclaration; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeRecordRejection; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnFileRecord; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRecordDeclaration; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRecordRejection; import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; @@ -134,6 +136,7 @@ public class RecordServiceImpl extends BaseBehaviourBean implements RecordService, RecordsManagementModel, RecordsManagementCustomModel, + NodeServicePolicies.OnAddAspectPolicy, NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnRemoveAspectPolicy, NodeServicePolicies.OnUpdatePropertiesPolicy, @@ -266,6 +269,8 @@ public class RecordServiceImpl extends BaseBehaviourBean private ClassPolicyDelegate onFileRecord; private ClassPolicyDelegate beforeRecordDeclarationDelegate; private ClassPolicyDelegate onRecordDeclarationDelegate; + private ClassPolicyDelegate beforeRecordRejectionDelegate; + private ClassPolicyDelegate onRecordRejectionDelegate; /** * @param identifierService identifier service @@ -421,6 +426,34 @@ public class RecordServiceImpl extends BaseBehaviourBean onFileRecord = policyComponent.registerClassPolicy(OnFileRecord.class); beforeRecordDeclarationDelegate = policyComponent.registerClassPolicy(BeforeRecordDeclaration.class); onRecordDeclarationDelegate = policyComponent.registerClassPolicy(OnRecordDeclaration.class); + beforeRecordRejectionDelegate = policyComponent.registerClassPolicy(BeforeRecordRejection.class); + onRecordRejectionDelegate = policyComponent.registerClassPolicy(OnRecordRejection.class); + } + + /** + * @see org.alfresco.repo.node.NodeServicePolicies.OnAddAspectPolicy#onAddAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) + */ + @Override + @Behaviour + ( + kind = BehaviourKind.CLASS, + type = "rma:record", + notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT + ) + public void onAddAspect(NodeRef nodeRef, QName aspect) + { + authenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() throws Exception + { + if (nodeService.exists(nodeRef) && nodeService.hasAspect(nodeRef, ASPECT_RECORD)) + { + generateRecordIdentifier(nodeService, identifierService, nodeRef); + } + return null; + } + }); } /** @@ -1404,6 +1437,9 @@ public class RecordServiceImpl extends BaseBehaviourBean // Save the id of the currently logged in user final String userId = AuthenticationUtil.getFullyAuthenticatedUser(); + // invoke policy + invokeBeforeRecordRejection(nodeRef); + // do the work of rejecting the record as the system user AuthenticationUtil.runAsSystem(new RunAsWork() { @@ -1520,6 +1556,9 @@ public class RecordServiceImpl extends BaseBehaviourBean } } }); + + // invoke policy + invokeOnRecordRejection(nodeRef); } /** @@ -1916,4 +1955,32 @@ public class RecordServiceImpl extends BaseBehaviourBean OnRecordDeclaration policy = onRecordDeclarationDelegate.get(qnames); policy.onRecordDeclaration(nodeRef); } + + /** + * Invoke invokeBeforeRecordRejection policy + * + * @param nodeRef node reference + */ + protected void invokeBeforeRecordRejection(NodeRef nodeRef) + { + // get qnames to invoke against + Set qnames = PoliciesUtil.getTypeAndAspectQNames(nodeService, nodeRef); + // execute policy for node type and aspects + BeforeRecordRejection policy = beforeRecordRejectionDelegate.get(qnames); + policy.beforeRecordRejection(nodeRef); + } + + /** + * Invoke invokeOnRecordRejection policy + * + * @param nodeRef node reference + */ + protected void invokeOnRecordRejection(NodeRef nodeRef) + { + // get qnames to invoke against + Set qnames = PoliciesUtil.getTypeAndAspectQNames(nodeService, nodeRef); + // execute policy for node type and aspects + OnRecordRejection policy = onRecordRejectionDelegate.get(qnames); + policy.onRecordRejection(nodeRef); + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/FilePlanComponentsApiUtils.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/FilePlanComponentsApiUtils.java index 5f5193f283..802683146e 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/FilePlanComponentsApiUtils.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/FilePlanComponentsApiUtils.java @@ -79,6 +79,7 @@ import org.alfresco.rm.rest.api.RMSites; import org.alfresco.rm.rest.api.model.RMNode; import org.alfresco.rm.rest.api.model.RMSite; import org.alfresco.rm.rest.api.model.TransferContainer; +import org.alfresco.rm.rest.api.model.UploadInfo; import org.alfresco.service.cmr.activities.ActivityInfo; import org.alfresco.service.cmr.activities.ActivityPoster; import org.alfresco.service.cmr.attributes.DuplicateAttributeException; @@ -672,32 +673,50 @@ public class FilePlanComponentsApiUtils /** * Upload a record * - * @param parentNodeRef the parent of the record - * @param name the name of the record - * @param type the type of the record (if null the record's type will be cm:content) - * @param properties properties to set (can be null) - * @param stream the stream to write + * @param parentNodeRef the parent of the record + * @param uploadInfo the infos of the uploaded record + * @param parameters the object to get the parameters passed into the request * @return the new record */ - public NodeRef uploadRecord(NodeRef parentNodeRef, String name, String type, Map properties, InputStream stream) + public NodeRef uploadRecord(NodeRef parentNodeRef, UploadInfo uploadInfo, Parameters parameters) { - checkNotBlank(RMNode.PARAM_NAME, name); + mandatory("parentNodeRef", parentNodeRef); + mandatory("uploadInfo", uploadInfo); + mandatory("parameters", parameters); + + String nodeName = uploadInfo.getFileName(); + String nodeType = uploadInfo.getNodeType(); + InputStream stream = uploadInfo.getContent().getInputStream(); mandatory("stream", stream); + checkNotBlank(RMNode.PARAM_NAME, nodeName); // Create the node - QName typeQName = StringUtils.isBlank(type) ? ContentModel.TYPE_CONTENT : nodes.createQName(type); - if(!dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT)) + QName typeQName = StringUtils.isBlank(nodeType) ? ContentModel.TYPE_CONTENT : nodes.createQName(nodeType); + if (!dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT)) { throw new InvalidArgumentException("Can only upload type of cm:content: " + typeQName); } - NodeRef newNodeRef = fileFolderService.create(parentNodeRef, name, typeQName).getNodeRef(); + + // Existing file/folder name handling + boolean autoRename = Boolean.valueOf(parameters.getParameter(RMNode.PARAM_AUTO_RENAME)); + if (autoRename) + { + NodeRef existingNode = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, nodeName); + if (existingNode != null) + { + // File already exists, find a unique name + nodeName = findUniqueName(parentNodeRef, nodeName); + } + } + + NodeRef newNodeRef = fileFolderService.create(parentNodeRef, nodeName, typeQName).getNodeRef(); // Write content - writeContent(newNodeRef, name, stream, true); + writeContent(newNodeRef, nodeName, stream, true); // Set the provided properties if any - Map qnameProperties = mapToNodeProperties(properties); - if(qnameProperties != null) + Map qnameProperties = mapToNodeProperties(uploadInfo.getProperties()); + if (qnameProperties != null) { nodeService.addProperties(newNodeRef, qnameProperties); } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/recordfolders/RecordFolderChildrenRelation.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/recordfolders/RecordFolderChildrenRelation.java index 1b4fd75877..a943a9dcae 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/recordfolders/RecordFolderChildrenRelation.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/recordfolders/RecordFolderChildrenRelation.java @@ -207,8 +207,7 @@ public class RecordFolderChildrenRelation implements RelationshipResourceAction. { public NodeRef execute() { - return apiUtils.uploadRecord(parentNodeRef, uploadInfo.getFileName(), uploadInfo.getNodeType(), uploadInfo.getProperties(), - uploadInfo.getContent().getInputStream()); + return apiUtils.uploadRecord(parentNodeRef, uploadInfo, parameters); } }; NodeRef newNode = transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true); diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledcontainers/UnfiledContainerChildrenRelation.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledcontainers/UnfiledContainerChildrenRelation.java index 0408de262a..e9409a29e1 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledcontainers/UnfiledContainerChildrenRelation.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledcontainers/UnfiledContainerChildrenRelation.java @@ -223,7 +223,7 @@ public class UnfiledContainerChildrenRelation implements RelationshipResourceAct { public NodeRef execute() { - return apiUtils.uploadRecord(parentNodeRef, uploadInfo.getFileName(), uploadInfo.getNodeType(), uploadInfo.getProperties(), uploadInfo.getContent().getInputStream()); + return apiUtils.uploadRecord(parentNodeRef, uploadInfo, parameters); } }; NodeRef newNode = transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true); diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledrecordfolders/UnfiledRecordFolderChildrenRelation.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledrecordfolders/UnfiledRecordFolderChildrenRelation.java index 9fff8274af..b519666980 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledrecordfolders/UnfiledRecordFolderChildrenRelation.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/unfiledrecordfolders/UnfiledRecordFolderChildrenRelation.java @@ -232,7 +232,7 @@ public class UnfiledRecordFolderChildrenRelation implements RelationshipResource public Pair execute() { final NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(unfiledRecordFolderId, RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER, uploadInfo.getRelativePath()); - NodeRef newNode = apiUtils.uploadRecord(parentNodeRef, uploadInfo.getFileName(), uploadInfo.getNodeType(), uploadInfo.getProperties(), uploadInfo.getContent().getInputStream()); + NodeRef newNode = apiUtils.uploadRecord(parentNodeRef, uploadInfo, parameters); return new Pair(newNode, parentNodeRef); } }; diff --git a/rm-community/rm-community-repo/src/test/properties/local/alfresco-global.properties b/rm-community/rm-community-repo/src/test/properties/local/alfresco-global.properties index 0d262ecbfc..06249c5121 100644 --- a/rm-community/rm-community-repo/src/test/properties/local/alfresco-global.properties +++ b/rm-community/rm-community-repo/src/test/properties/local/alfresco-global.properties @@ -39,9 +39,6 @@ share.protocol=http # Validates and auto-recover if validation fails index.recovery.mode=AUTO -# As we run embedded, we set Lucene -# TODO: Find a better solution for indexing, as buildonly (embedded Lucene) is deprecated and going to be removed soon -index.subsystem.name=buildonly # These jobs seem to require Lucene (Unsupported Operation with Solr) so we disable them / set to future date # See https://forums.alfresco.com/en/viewtopic.php?f=52&t=41597 diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java index a644bfd400..2d10885eff 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java @@ -35,7 +35,9 @@ import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeRecordDeclaration; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeRecordRejection; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRecordDeclaration; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRecordRejection; import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; @@ -62,7 +64,10 @@ import org.alfresco.util.GUID; * @author Tuna Aksoy * @since 2.1 */ -public class RecordServiceImplTest extends BaseRMTestCase implements BeforeRecordDeclaration, OnRecordDeclaration +public class RecordServiceImplTest extends BaseRMTestCase implements BeforeRecordDeclaration, + OnRecordDeclaration, + BeforeRecordRejection, + OnRecordRejection { /** * This is a user test @@ -835,4 +840,62 @@ public class RecordServiceImplTest extends BaseRMTestCase implements BeforeRecor assertEquals(nodeRef, dmDocument); onRecordDeclaration = true; } + + /** + * RM-5180 - integration test for policies for record rejection + * @see RecordService#rejectRecord(org.alfresco.service.cmr.repository.NodeRef) + */ + private boolean beforeRecordRejection = false; + private boolean onRecordRejection = false; + + @Override + public void beforeRecordRejection(NodeRef nodeRef) + { + assertEquals(nodeRef, dmDocument); + beforeRecordRejection = true; + } + + @Override + public void onRecordRejection(NodeRef nodeRef) + { + assertEquals(nodeRef, dmDocument); + onRecordRejection = true; + } + + public void testPolicyNotificationForRecordRejection() throws Exception + { + doTestInTransaction(new Test() + { + + @Override + public Void run() + { + assertFalse(recordService.isRecord(dmDocument)); + + BehaviourDefinition beforeRecordRejectionBehaviour = policyComponent.bindClassBehaviour( + RecordsManagementPolicies.BEFORE_RECORD_REJECTION, ContentModel.TYPE_CONTENT, + new JavaBehaviour(RecordServiceImplTest.this, "beforeRecordRejection", NotificationFrequency.EVERY_EVENT)); + BehaviourDefinition onRecordRejectionBehaviour = policyComponent.bindClassBehaviour( + RecordsManagementPolicies.ON_RECORD_REJECTION, ContentModel.TYPE_CONTENT, + new JavaBehaviour(RecordServiceImplTest.this, "onRecordRejection", NotificationFrequency.EVERY_EVENT)); + + recordService.createRecord(filePlan, dmDocument); + + assertFalse(beforeRecordRejection); + assertFalse(onRecordRejection); + assertTrue(recordService.isRecord(dmDocument)); + + recordService.rejectRecord(dmDocument, "test reasons"); + + assertTrue(beforeRecordRejection); + assertTrue(onRecordRejection); + assertFalse(recordService.isRecord(dmDocument)); + + policyComponent.removeClassDefinition(beforeRecordRejectionBehaviour); + policyComponent.removeClassDefinition(onRecordRejectionBehaviour); + + return null; + } + }, dmCollaborator); + } } diff --git a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml index 37c2aa2838..d4fc3b5d81 100644 --- a/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml +++ b/rm-community/rm-community-rest-api-explorer/src/main/webapp/definitions/gs-core-api.yaml @@ -3,7 +3,7 @@ info: description: | **GS Core API** - Provides access to the core features of Governance Services. + Provides access to the core features of Alfresco Governance Services. version: '1' title: Alfresco Governance Services REST API basePath: /alfresco/api/-default-/public/gs/versions/1 @@ -186,7 +186,7 @@ paths: $ref: '#/definitions/RMSiteEntry' '400': description: | - Invalid parameter: PUT request is suported only for the RM site, or **siteBodyUpdate** invalid + Invalid parameter: PUT request is supported only for the RM site, or **siteBodyUpdate** invalid '401': description: Authentication failed '403': @@ -686,13 +686,13 @@ paths: description: | Invalid parameter: **unfiledContainerId** is not a valid format or **unfiledContainerId** is invalid '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to add children to **unfiledContainerId** + description: Current user does not have permission to add children to **unfiledContainerId** '404': - description: If **unfiledContainerId** does not exist + description: "**unfiledContainerId** does not exist" '409': - description: If new name clashes with an existing node in the current parent container + description: New name clashes with an existing node in the current parent container '422': description: Model integrity exception, including node name with invalid characters ## Unfiled record folders @@ -704,7 +704,7 @@ paths: description: | Get information for unfiled record folder id **unfiledRecordFolderId** - Besides mandatory fields the unfiled record folder's aspects and properties are returned by default. + Mandatory fields and the unfiled record folder's aspects and properties are returned by default. You can use the **include** parameter (include=allowableOperations) to return additional information. operationId: getUnfiledRecordFolder @@ -724,11 +724,11 @@ paths: description: | Invalid parameter: **unfiledRecordFolderId** is not a valid format '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to read **unfiledRecordFolderId** + description: Current user does not have permission to read **unfiledRecordFolderId** '404': - description: If **unfiledRecordFolderId** does not exist + description: "**unfiledRecordFolderId** does not exist" default: description: Unexpected error schema: @@ -780,13 +780,13 @@ paths: description: | Invalid parameter: The update request is invalid or **unfiledRecordFolderId** is not a valid format or **unfiledRecordFolderBodyUpdate** is invalid '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to update **unfiledRecordFolderId** + description: Current user does not have permission to update **unfiledRecordFolderId** '404': - description: If **unfiledRecordFolderId** does not exist + description: "**unfiledRecordFolderId** does not exist" '409': - description: If the updated name clashes with an existing unfiled record folder in the current parent category + description: Updated name clashes with an existing unfiled record folder in the current parent category '422': description: Model integrity exception, including file name with invalid characters default: @@ -811,13 +811,13 @@ paths: description: | Invalid parameter: **unfiledRecordFolderId** is not a valid format '401': - description: If authentication fails + description: Authentication failed '403': - description: If the current user does not have permission to delete **unfiledRecordFolderId** + description: Current user does not have permission to delete **unfiledRecordFolderId** '404': - description: If **unfiledRecordFolderId** does not exist + description: "**unfiledRecordFolderId** does not exist" '409': - description: If **unfiledRecordFolderId** is locked and cannot be deleted + description: "**unfiledRecordFolderId** is locked and cannot be deleted" default: description: Unexpected error schema: @@ -1085,13 +1085,13 @@ paths: description: | Invalid parameter: The update request is invalid or **recordCategoryId** is not a valid format or **recordCategoryBodyUpdate** is invalid '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to update **recordCategoryId** + description: Current user does not have permission to update **recordCategoryId** '404': - description: If **recordCategoryId** does not exist + description: "**recordCategoryId** does not exist" '409': - description: If the updated name clashes with an existing record category in the current parent category + description: Updated name clashes with an existing record category in the current parent category '422': description: Model integrity exception, including file name with invalid characters default: @@ -1116,13 +1116,13 @@ paths: description: | Invalid parameter: **recordCategoryId** is not a valid format '401': - description: If authentication fails + description: Authentication failed '403': - description: If the current user does not have permission to delete **recordCategoryId** + description: Current user does not have permission to delete **recordCategoryId** '404': - description: If **recordCategoryId** does not exist + description: "**recordCategoryId** does not exist" '409': - description: If **recordCategoryId** is locked and cannot be deleted + description: "**recordCategoryId** is locked and cannot be deleted" default: description: Unexpected error schema: @@ -1158,11 +1158,11 @@ paths: schema: $ref: '#/definitions/RecordCategoryChildPaging' '401': - description: If authentication fails + description: Authentication fails '403': - description: If current user does not have permission to read **recordCategoryId** + description: Current user does not have permission to read **recordCategoryId** '404': - description: If **recordCategoryId** does not exist + description: "**recordCategoryId** does not exist" default: description: Unexpected error schema: @@ -1294,13 +1294,13 @@ paths: description: | Invalid parameter: **recordCategoryId** is not a valid format or **nodeBodyCreate** is invalid '401': - description: If authentication fails + description: Authentication fails '403': - description: If current user does not have permission to add children to **recordCategoryId** + description: Current user does not have permission to add children to **recordCategoryId** '404': - description: If **recordCategoryId** does not exist + description: "**recordCategoryId** does not exist" '409': - description: If new name clashes with an existing node in the current parent container + description: Name clashes with an existing node in the current parent container '422': description: Model integrity exception, including node name with invalid characters ## Record folders @@ -1331,11 +1331,11 @@ paths: description: | Invalid parameter: **recordFolderId** is not a valid format '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to read **recordFolderId** + description: Current user does not have permission to read **recordFolderId** '404': - description: If **recordFolderId** does not exist + description: "**recordFolderId** does not exist" default: description: Unexpected error schema: @@ -1386,13 +1386,13 @@ paths: description: | Invalid parameter: The update request is invalid or **recordFolderId** is not a valid format or **recordFolderBodyUpdate** is invalid '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to update **recordFolderId** + description: Current user does not have permission to update **recordFolderId** '404': - description: If **recordFolderId** does not exist + description: "**recordFolderId** does not exist" '409': - description: If the updated name clashes with an existing record folder in the current parent category + description: Updated name clashes with an existing record folder in the current parent category '422': description: Model integrity exception, including file name with invalid characters default: @@ -1417,13 +1417,13 @@ paths: description: | Invalid parameter: **recordFolderId** is not a valid format '401': - description: If authentication fails + description: Authentication failed '403': - description: If the current user does not have permission to delete **recordFolderId** + description: Current user does not have permission to delete **recordFolderId** '404': - description: If **recordFolderId** does not exist + description: "**recordFolderId** does not exist" '409': - description: If **recordFolderId** is locked and cannot be deleted + description: "**recordFolderId** is locked and cannot be deleted" default: description: Unexpected error schema: @@ -1458,11 +1458,11 @@ paths: schema: $ref: '#/definitions/RecordFolderAssociationPaging' '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to read **recordFolderId** + description: Current user does not have permission to read **recordFolderId** '404': - description: If **recordFolderId** does not exist + description: "**recordFolderId** does not exist" default: description: Unexpected error schema: @@ -1587,11 +1587,11 @@ paths: description: | Invalid parameter: **recordFolderId** is not a valid format or **recordBodyCreate** is invalid '401': - description: If authentication fails + description: Authentication failed '403': - description: If current user does not have permission to add children to **recordFolderId** + description: Current user does not have permission to add children to **recordFolderId** '404': - description: If **recordFolderId** does not exist + description: "**recordFolderId** does not exist" '422': description: Model integrity exception, including node name with invalid characters ## Records @@ -1603,7 +1603,7 @@ paths: description: | Get information for record **recordId** - Besides mandatory fields the record's aspects and properties are returned by default. + Mandatory fields and the record's aspects and properties are returned by default. You can use the **include** parameter (include=allowableOperations) to return additional information. operationId: getRecord @@ -1622,11 +1622,11 @@ paths: description: | Invalid parameter: **recordId** is not a valid format '401': - description: If authentication fails + description: Authentication fails '403': - description: If current user does not have permission to read **recordId** + description: Current user does not have permission to read **recordId** '404': - description: If **recordId** does not exist + description: "**recordId** does not exist" default: description: Unexpected error schema: @@ -1677,13 +1677,13 @@ paths: description: | Invalid parameter: the update request is invalid or **recordId** is not a valid format or **recordBodyUpdate** is invalid '401': - description: If authentication + description: Authentication failed '403': - description: If current user does not have permission to update **recordId**fails + description: Current user does not have permission to update **recordId** '404': - description: If **recordId** does not exist + description: "**recordId** does not exist" '409': - description: If the updated name clashes with an existing node in the current parent folder + description: Updated name clashes with an existing node in the current parent folder '422': description: Model integrity exception, including file name with invalid characters default: @@ -1708,13 +1708,13 @@ paths: description: | Invalid parameter: **recordId** is not a valid format '401': - description: If authentication fails + description: Authentication fails '403': - description: If the current user does not have permission to delete **recordId** + description: Current user does not have permission to delete **recordId** '404': - description: If **recordId** does not exist + description: "**recordId** does not exist" '409': - description: If **recordId** is locked and cannot be deleted + description: "**recordId** is locked and cannot be deleted" default: description: Unexpected error schema: @@ -1800,47 +1800,6 @@ paths: description: Unexpected error schema: $ref: '#/definitions/Error' - '/records/{recordId}/complete': - post: - tags: - - records - summary: Complete a record - description: | - Completes the record **recordId**. - operationId: completeRecord - parameters: - - $ref: '#/parameters/recordIdParam' - - $ref: '#/parameters/recordEntryIncludeParam' - - $ref: '#/parameters/fieldsParam' - consumes: - - application/json - produces: - - application/json - responses: - '200': - description: Successful response - schema: - $ref: '#/definitions/RecordEntry' - '400': - description: | - Invalid parameter: **recordIdParam** is not a valid format or - **recordIdParam** is not a record - '401': - description: Authentication failed - '403': - description: >- - Current user does not have permission to complete record - **recordIdParam** - '404': - description: | - **recordIdParam** does not exist - '422': - description: | - Model integrity exception: the record is already completed - default: - description: Unexpected error - schema: - $ref: '#/definitions/Error' ## Files '/files/{fileId}/declare': post: @@ -1897,7 +1856,7 @@ paths: description: | Get information for transfer container **transferContainerId** - Besides mandatory fields the transfer container's aspects and properties are returned by default. + Mandatory fields and the transfer container's aspects and properties are returned by default. You can use the **include** parameter (include=allowableOperations) to return additional information. operationId: getTransferContainer