diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-condition-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-condition-context.xml index 135a49616a..9115c500ac 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-condition-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-condition-context.xml @@ -60,9 +60,9 @@ class="org.alfresco.module.org_alfresco_module_rm.capability.declarative.condition.TransferredCapabilityCondition"> - + class="org.alfresco.module.org_alfresco_module_rm.capability.declarative.condition.MovableRecordFolderCapabilityCondition"> + + + RECORD_FOLDER + + @@ -129,7 +134,7 @@ - + diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 25f6fae4fd..6682d0a617 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -388,10 +388,10 @@ - + - @@ -1090,8 +1090,8 @@ - - + + @@ -1552,20 +1552,20 @@ diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/declarative/condition/MovableCapabilityCondition.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/declarative/condition/MovableRecordFolderCapabilityCondition.java similarity index 89% rename from rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/declarative/condition/MovableCapabilityCondition.java rename to rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/declarative/condition/MovableRecordFolderCapabilityCondition.java index 90cae8d7d9..41c0f4aba2 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/declarative/condition/MovableCapabilityCondition.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/declarative/condition/MovableRecordFolderCapabilityCondition.java @@ -36,7 +36,7 @@ import org.alfresco.service.cmr.repository.NodeRef; * @since 2.4.1 * */ -public class MovableCapabilityCondition extends AbstractCapabilityCondition +public class MovableRecordFolderCapabilityCondition extends AbstractCapabilityCondition { /** @@ -47,6 +47,6 @@ public class MovableCapabilityCondition extends AbstractCapabilityCondition { if (nodeService.hasAspect(nodeRef, ASPECT_GHOSTED) && dispositionService.isDisposableItemCutoff(nodeRef)) return true; - return !dispositionService.isDisposableItemCutoff(nodeRef); + return !(dispositionService.isDisposableItemCutoff(nodeRef) || recordFolderService.isRecordFolderClosed(nodeRef)); } } 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 d274d78e8f..a862d6f892 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 @@ -27,6 +27,12 @@ package org.alfresco.module.org_alfresco_module_rm.record; + +import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.FIRST_EVENT; +import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTION_COMMIT; +import static org.alfresco.repo.policy.annotation.BehaviourKind.ASSOCIATION; +import static org.apache.commons.lang.StringUtils.isNotBlank; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -67,10 +73,9 @@ import org.alfresco.module.org_alfresco_module_rm.role.Role; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionModel; import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService; +import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.node.NodeServicePolicies; -import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.ClassPolicyDelegate; -import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; @@ -82,16 +87,13 @@ import org.alfresco.repo.security.permissions.impl.ExtendedPermissionService; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.security.AccessPermission; @@ -126,9 +128,8 @@ public class RecordServiceImpl extends BaseBehaviourBean RecordsManagementModel, RecordsManagementCustomModel, NodeServicePolicies.OnCreateChildAssociationPolicy, - NodeServicePolicies.OnAddAspectPolicy, - NodeServicePolicies.OnRemoveAspectPolicy, - NodeServicePolicies.OnUpdatePropertiesPolicy + NodeServicePolicies.OnUpdatePropertiesPolicy, + ContentServicePolicies.OnContentUpdatePolicy { /** Logger */ private static final Logger LOGGER = LoggerFactory.getLogger(RecordServiceImpl.class); @@ -141,7 +142,6 @@ public class RecordServiceImpl extends BaseBehaviourBean /** transation data key */ private static final String KEY_IGNORE_ON_UPDATE = "ignoreOnUpdate"; - private static final String KEY_PENDING_FILLING = "pendingFilling"; public static final String KEY_NEW_RECORDS = "newRecords"; /** I18N */ @@ -257,12 +257,6 @@ public class RecordServiceImpl extends BaseBehaviourBean private ClassPolicyDelegate beforeFileRecord; private ClassPolicyDelegate onFileRecord; - /** Behaviours */ - private JavaBehaviour onCreateChildAssociation = new JavaBehaviour( - this, - "onCreateChildAssociation", - NotificationFrequency.FIRST_EVENT); - /** * @param identifierService identifier service */ @@ -396,8 +390,8 @@ public class RecordServiceImpl extends BaseBehaviourBean */ public void setRecordsManagementContainerType(RecordsManagementContainerType recordsManagementContainerType) { - this.recordsManagementContainerType = recordsManagementContainerType; - } + this.recordsManagementContainerType = recordsManagementContainerType; + } /** * @param recordableVersionService recordable version service @@ -415,13 +409,6 @@ public class RecordServiceImpl extends BaseBehaviourBean // bind policies beforeFileRecord = policyComponent.registerClassPolicy(BeforeFileRecord.class); onFileRecord = policyComponent.registerClassPolicy(OnFileRecord.class); - - // bind behaviours - policyComponent.bindAssociationBehaviour( - NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME, - TYPE_RECORD_FOLDER, - ContentModel.ASSOC_CONTAINS, - onCreateChildAssociation); } /** @@ -430,88 +417,10 @@ public class RecordServiceImpl extends BaseBehaviourBean @Override @Behaviour ( - kind = BehaviourKind.CLASS, - type = "sys:noContent" + kind = ASSOCIATION, + type = "rma:recordFolder", + notificationFrequency = FIRST_EVENT ) - public void onRemoveAspect(NodeRef nodeRef, QName aspect) - { - - if (nodeService.hasAspect(nodeRef, ASPECT_RECORD)) - { - ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - - // Only switch name back to the format of "name (identifierId)" if content size is non-zero, else leave it as the original name to avoid CIFS shuffling issues. - if (contentData != null && contentData.getSize() > 0) - { - switchNames(nodeRef); - } - } - else - { - // check whether filling is pending aspect removal - Set pendingFilling = transactionalResourceHelper.getSet(KEY_PENDING_FILLING); - if (pendingFilling.contains(nodeRef)) - { - file(nodeRef); - } - } - } - - /** - * @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 = "sys:noContent" - ) - public void onAddAspect(NodeRef nodeRef, QName aspect) - { - switchNames(nodeRef); - } - - /** - * Helper method to switch the name of the record around. Used to support record creation via - * file protocols. - * - * @param nodeRef node reference (record) - */ - private void switchNames(NodeRef nodeRef) - { - try - { - if (nodeService.hasAspect(nodeRef, ASPECT_RECORD)) - { - String origionalName = (String)nodeService.getProperty(nodeRef, PROP_ORIGIONAL_NAME); - if (origionalName != null) - { - String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); - fileFolderService.rename(nodeRef, origionalName); - nodeService.setProperty(nodeRef, PROP_ORIGIONAL_NAME, name); - } - } - } - catch (FileExistsException e) - { - LOGGER.debug(e.getMessage()); - } - catch (InvalidNodeRefException e) - { - LOGGER.debug(e.getMessage()); - } - catch (FileNotFoundException e) - { - LOGGER.debug(e.getMessage()); - } - } - - /** - * Behaviour executed when a new item is added to a record folder. - * - * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) - */ - @Override public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, final boolean bNew) { AuthenticationUtil.runAs(new RunAsWork() @@ -519,7 +428,6 @@ public class RecordServiceImpl extends BaseBehaviourBean @Override public Void doWork() { - onCreateChildAssociation.disable(); try { NodeRef nodeRef = childAssocRef.getChildRef(); @@ -528,38 +436,29 @@ public class RecordServiceImpl extends BaseBehaviourBean !nodeService.getType(nodeRef).equals(TYPE_RECORD_FOLDER) && !nodeService.getType(nodeRef).equals(TYPE_RECORD_CATEGORY)) { - if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT)) + // store information about the 'new' record in the transaction + // @since 2.3 + // @see https://issues.alfresco.com/jira/browse/RM-1956 + if (bNew) { - // we need to postpone filling until the NO_CONTENT aspect is removed - Set pendingFilling = transactionalResourceHelper.getSet(KEY_PENDING_FILLING); - pendingFilling.add(nodeRef); + Set newRecords = transactionalResourceHelper.getSet(KEY_NEW_RECORDS); + newRecords.add(nodeRef); } else { - // store information about the 'new' record in the transaction - // @since 2.3 - // @see https://issues.alfresco.com/jira/browse/RM-1956 - if (bNew) + // if we are linking a record + NodeRef parentNodeRef = childAssocRef.getParentRef(); + if (isRecord(nodeRef) && isRecordFolder(parentNodeRef)) { - Set newRecords = transactionalResourceHelper.getSet(KEY_NEW_RECORDS); - newRecords.add(nodeRef); + // validate the link conditions + validateLinkConditions(nodeRef, parentNodeRef); } - else - { - // if we are linking a record - NodeRef parentNodeRef = childAssocRef.getParentRef(); - if (isRecord(nodeRef) && isRecordFolder(parentNodeRef)) - { - // validate the link conditions - validateLinkConditions(nodeRef, parentNodeRef); - } - } - - // create and file the content as a record - file(nodeRef); - // recalculate disposition schedule for the record when linking it - dispositionService.recalculateNextDispositionStep(nodeRef); } + + // create and file the content as a record + file(nodeRef); + // recalculate disposition schedule for the record when linking it + dispositionService.recalculateNextDispositionStep(nodeRef); } } catch (RecordLinkRuntimeException e) @@ -572,10 +471,6 @@ public class RecordServiceImpl extends BaseBehaviourBean // do nothing but log error LOGGER.warn("Unable to file pending record.", e); } - finally - { - onCreateChildAssociation.enable(); - } return null; } @@ -651,20 +546,20 @@ public class RecordServiceImpl extends BaseBehaviourBean if (beforeValue instanceof Date && afterValue instanceof Date) { // deal with date values, remove the seconds and milliseconds for the - // comparison as they are removed from the submitted for data - Calendar beforeCal = Calendar.getInstance(); - beforeCal.setTime((Date)beforeValue); - Calendar afterCal = Calendar.getInstance(); - afterCal.setTime((Date)afterValue); - beforeCal.set(Calendar.SECOND, 0); - beforeCal.set(Calendar.MILLISECOND, 0); - afterCal.set(Calendar.SECOND, 0); - afterCal.set(Calendar.MILLISECOND, 0); - propertyUnchanged = (beforeCal.compareTo(afterCal) == 0); + // comparison as they are removed from the submitted for data + Calendar beforeCal = Calendar.getInstance(); + beforeCal.setTime((Date)beforeValue); + Calendar afterCal = Calendar.getInstance(); + afterCal.setTime((Date)afterValue); + beforeCal.set(Calendar.SECOND, 0); + beforeCal.set(Calendar.MILLISECOND, 0); + afterCal.set(Calendar.SECOND, 0); + afterCal.set(Calendar.MILLISECOND, 0); + propertyUnchanged = (beforeCal.compareTo(afterCal) == 0); } else if ((afterValue instanceof Boolean) && (beforeValue == null) && (afterValue.equals(Boolean.FALSE))) { - propertyUnchanged = true; + propertyUnchanged = true; } else { @@ -891,12 +786,12 @@ public class RecordServiceImpl extends BaseBehaviourBean behaviourFilter.disableBehaviour(); try { - // move the document into the file plan - nodeService.moveNode(nodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); + // move the document into the file plan + nodeService.moveNode(nodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); } finally { - behaviourFilter.enableBehaviour(); + behaviourFilter.enableBehaviour(); } // save the information about the originating details @@ -908,6 +803,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // make the document a record makeRecord(nodeRef); + renameRecord(nodeRef); if (latestVersionRecord != null) { @@ -1093,13 +989,13 @@ public class RecordServiceImpl extends BaseBehaviourBean recordsManagementContainerType.disable(); try { - // create a copy of the original state and add it to the unfiled record container - FileInfo recordInfo = fileFolderService.copy(nodeRef, unfiledRecordFolder, null); - record = recordInfo.getNodeRef(); + // create a copy of the original state and add it to the unfiled record container + FileInfo recordInfo = fileFolderService.copy(nodeRef, unfiledRecordFolder, null); + record = recordInfo.getNodeRef(); } finally { - recordsManagementContainerType.enable(); + recordsManagementContainerType.enable(); } // if versionable, then remove without destroying version history, @@ -1116,6 +1012,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // make record makeRecord(record); + renameRecord(record); // remove added copy assocs List recordAssocs = nodeService.getTargetAssocs(record, ContentModel.ASSOC_ORIGINAL); @@ -1240,20 +1137,21 @@ public class RecordServiceImpl extends BaseBehaviourBean result = authenticationUtil.runAsSystem(new RunAsWork() { - public NodeRef doWork() throws Exception - { - // Check if the "record" aspect has been applied already. - // In case of filing a report the created node will be made - // a record within the "onCreateChildAssociation" method if - // a destination for the report has been selected. - if (!nodeService.hasAspect(record, ASPECT_RECORD)) - { - // make record - makeRecord(record); - } + public NodeRef doWork() throws Exception + { + // Check if the "record" aspect has been applied already. + // In case of filing a report the created node will be made + // a record within the "onCreateChildAssociation" method if + // a destination for the report has been selected. + if (!nodeService.hasAspect(record, ASPECT_RECORD)) + { + // make record + makeRecord(record); + renameRecord(record); + } - return record; - } + return record; + } }); } @@ -1286,28 +1184,6 @@ public class RecordServiceImpl extends BaseBehaviourBean // get the record name String name = (String)nodeService.getProperty(document, ContentModel.PROP_NAME); - // rename the record - int dotIndex = name.lastIndexOf('.'); - String prefix = name; - String postfix = ""; - if (dotIndex != -1) - { - prefix = name.substring(0, dotIndex); - postfix = name.substring(dotIndex); - } - String recordName = prefix + " (" + recordId + ")" + postfix; - behaviourFilter.disableBehaviour(); - try - { - fileFolderService.rename(document, recordName); - } - finally - { - behaviourFilter.enableBehaviour(); - } - - LOGGER.debug("Rename {} to {}", name, recordName); - // add the record aspect Map props = new HashMap(2); props.put(PROP_IDENTIFIER, recordId); @@ -1319,10 +1195,11 @@ public class RecordServiceImpl extends BaseBehaviourBean // remove the owner ownableService.setOwner(document, OwnableService.NO_OWNER); - } - catch (FileNotFoundException e) - { - throw new AlfrescoRuntimeException("Unable to make record, because rename failed.", e); + + if (TYPE_NON_ELECTRONIC_DOCUMENT.equals(nodeService.getType(document))) + { + renameRecord(document); + } } finally { @@ -1344,13 +1221,13 @@ public class RecordServiceImpl extends BaseBehaviourBean if (isRecord(nodeRef)) { - result = AuthenticationUtil.runAsSystem(new RunAsWork() - { - public Boolean doWork() throws Exception - { - return (null != nodeService.getProperty(nodeRef, PROP_DATE_FILED)); - } - }); + result = AuthenticationUtil.runAsSystem(new RunAsWork() + { + public Boolean doWork() throws Exception + { + return (null != nodeService.getProperty(nodeRef, PROP_DATE_FILED)); + } + }); } return result; @@ -1875,4 +1752,49 @@ public class RecordServiceImpl extends BaseBehaviourBean throw new RecordLinkRuntimeException("Can only unlink a record from a record folder."); } } -} + + /* + * @see org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy#onContentUpdate(org.alfresco.service.cmr.repository.NodeRef, boolean) + */ + @Override + @Behaviour + ( + kind = BehaviourKind.CLASS, + type = "rma:record", + notificationFrequency = TRANSACTION_COMMIT + ) + public void onContentUpdate(NodeRef nodeRef, boolean newContent) + { + if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN)) + { + renameRecord(nodeRef); + } + } + + private void renameRecord(NodeRef nodeRef) + { + // get the record id + String recordId = (String) nodeService.getProperty(nodeRef, PROP_IDENTIFIER); + + if (isNotBlank(recordId)) + { + // get the record name + String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + + // rename the record + int dotIndex = name.lastIndexOf('.'); + String prefix = name; + String postfix = ""; + if (dotIndex > 0) + { + prefix = name.substring(0, dotIndex); + postfix = name.substring(dotIndex); + } + String recordName = prefix + " (" + recordId + ")" + postfix; + + nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, recordName); + + LOGGER.debug("Rename " + name + " to " + recordName); + } + } +} \ No newline at end of file diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java index a7d2a22f1c..4a914961af 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java @@ -85,13 +85,13 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl /** File plan role service */ private FilePlanRoleService filePlanRoleService; - + /** authority service */ private AuthorityService authorityService; - + /** permission service */ private PermissionService permissionService; - + /** transaction service */ private TransactionService transactionService; @@ -110,7 +110,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { this.filePlanRoleService = filePlanRoleService; } - + /** * @param authorityService authority service */ @@ -118,7 +118,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { this.authorityService = authorityService; } - + /** * @param permissionService permission service */ @@ -126,7 +126,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { this.permissionService = permissionService; } - + /** * @param transactionService transaction service */ @@ -134,7 +134,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { this.transactionService = transactionService; } - + /** * Application context refresh event handler */ @@ -165,7 +165,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl } }, AuthenticationUtil.getSystemUserName()); } - + /** * Get root IPR group name */ @@ -191,15 +191,15 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl public Set getReaders(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - + Set result = Collections.EMPTY_SET; Pair iprGroups = getIPRGroups(nodeRef); if (iprGroups != null) { result = getAuthorities(iprGroups.getFirst()); } - - return result; + + return result; } /** @@ -210,20 +210,20 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl public Set getWriters(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - + Set result = Collections.EMPTY_SET; Pair iprGroups = getIPRGroups(nodeRef); if (iprGroups != null) { result = getAuthorities(iprGroups.getSecond()); } - - return result; + + return result; } - + /** * Helper to get authorities for a given group - * + * * @param group group name * @return Set immediate authorities */ @@ -233,7 +233,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl result.addAll(authorityService.getContainedAuthorities(null, group, true)); return result; } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#set(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.util.Pair) */ @@ -244,7 +244,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl set(nodeRef, readersAndWriters.getFirst(), readersAndWriters.getSecond()); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#set(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set) */ @@ -252,21 +252,21 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl public void set(NodeRef nodeRef, Set readers, Set writers) { ParameterCheck.mandatory("nodeRef", nodeRef); - + // remove existing extended security, assuming there is any remove(nodeRef); - + // find groups Pair iprGroups = createOrFindIPRGroups(readers, writers); - + // assign groups to correct fileplan roles NodeRef filePlan = filePlanService.getFilePlan(nodeRef); filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, iprGroups.getFirst()); filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, iprGroups.getSecond()); - + // assign groups to node assignIPRGroupsToNode(iprGroups, nodeRef); - + // apply the readers to any renditions of the content if (isRecord(nodeRef)) { @@ -276,14 +276,14 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl NodeRef child = assoc.getChildRef(); assignIPRGroupsToNode(iprGroups, child); } - } + } } - + /** * Get the IPR groups associated with a given node reference. *

* Return null if none found. - * + * * @param nodeRef node reference * @return Pair where first is the read group and second if the write group, null if none found */ @@ -292,7 +292,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl Pair result = null; String iprReaderGroup = null; String iprWriterGroup = null; - + // get all the set permissions Set permissions = permissionService.getAllSetPermissions(nodeRef); for (AccessPermission permission : permissions) @@ -301,36 +301,36 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl if (permission.getAuthority().startsWith(GROUP_PREFIX + READER_GROUP_PREFIX)) { iprReaderGroup = permission.getAuthority(); - } + } // look for the presence of the writer group else if (permission.getAuthority().startsWith(GROUP_PREFIX + WRITER_GROUP_PREFIX)) { iprWriterGroup = permission.getAuthority(); } } - + // assuming the are both present then return if (iprReaderGroup != null && iprWriterGroup != null) { result = new Pair(iprReaderGroup, iprWriterGroup); } - + return result; } - + /** * Given a set of readers and writers find or create the appropriate IPR groups. *

- * The IPR groups are named with hashes of the authority lists in order to reduce + * The IPR groups are named with hashes of the authority lists in order to reduce * the set of groups that require exact match. A further index is used to handle * a situation where there is a hash clash, but a difference in the authority lists. *

* When no match is found the groups are created. Once created - * + * * @param filePlan file plan * @param readers authorities with read * @param writers authorities with write - * @return Pair where first is the full name of the read group and + * @return Pair where first is the full name of the read group and * second is the full name of the write group */ private Pair createOrFindIPRGroups(Set readers, Set writers) @@ -339,10 +339,10 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl createOrFindIPRGroup(READER_GROUP_PREFIX, readers), createOrFindIPRGroup(WRITER_GROUP_PREFIX, writers)); } - + /** * Create or find an IPR group based on the provided prefix and authorities. - * + * * @param groupPrefix group prefix * @param authorities authorities * @return String full group name @@ -350,10 +350,10 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl private String createOrFindIPRGroup(String groupPrefix, Set authorities) { String group = null; - - // find group or determine what the next index is if no group exists or there is a clash + + // find group or determine what the next index is if no group exists or there is a clash Pair groupResult = findIPRGroup(groupPrefix, authorities); - + if (groupResult.getFirst() == null) { group = createIPRGroup(groupPrefix, authorities, groupResult.getSecond()); @@ -362,16 +362,16 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { group = groupResult.getFirst(); } - + return group; } - + /** * Given a group name prefix and the authorities, finds the exact match existing group. *

- * If the group does not exist then the group returned is null and the index shows the next available + * If the group does not exist then the group returned is null and the index shows the next available * group index for creation. - * + * * @param groupPrefix group name prefix * @param authorities authorities * @return Pair where first is the name of the found group, null if none found and second @@ -383,24 +383,24 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl int nextGroupIndex = 0; boolean hasMoreItems = true; int pageCount = 0; - + // determine the short name prefix String groupShortNamePrefix = getIPRGroupPrefixShortName(groupPrefix, authorities); - + // iterate over the authorities to find a match while (hasMoreItems == true) - { + { // get matching authorities - PagingResults results = authorityService.getAuthorities(AuthorityType.GROUP, - RMAuthority.ZONE_APP_RM, + PagingResults results = authorityService.getAuthorities(AuthorityType.GROUP, + RMAuthority.ZONE_APP_RM, groupShortNamePrefix, - false, - false, + false, + false, new PagingRequest(MAX_ITEMS*pageCount, MAX_ITEMS)); - + // record the total count nextGroupIndex = nextGroupIndex + results.getPage().size(); - + // see if any of the matching groups exactly match for (String group : results.getPage()) { @@ -409,35 +409,35 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { iprGroup = group; break; - } + } } - + // determine if there are any more pages to inspect hasMoreItems = results.hasMoreItems(); pageCount ++; } - + return new Pair(iprGroup, nextGroupIndex); } - + /** * Determines whether a group exactly matches a list of authorities. - * + * * @param authorities list of authorities - * @param group group + * @param group group * @return */ private boolean isIPRGroupTrueMatch(String group, Set authorities) - { + { Set contained = authorityService.getContainedAuthorities(null, group, true); return contained.equals(authorities); } - + /** * Get IPR group prefix short name. *

* 'package' scope to help testing. - * + * * @param prefix prefix * @param authorities authorities * @return String group prefix short name @@ -447,17 +447,17 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl StringBuilder builder = new StringBuilder(128) .append(prefix) .append(getAuthoritySetHashCode(authorities)); - + return builder.toString(); } - + /** * Get IPR group short name. *

* Note this excludes the "GROUP_" prefix. *

* 'package' scope to help testing. - * + * * @param prefix prefix * @param readers read authorities * @param writers write authorities @@ -468,12 +468,12 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { return getIPRGroupShortName(prefix, authorities, Integer.toString(index)); } - + /** * Get IPR group short name. *

* Note this excludes the "GROUP_" prefix. - * + * * @param prefix prefix * @param readers read authorities * @param writers write authorities @@ -485,13 +485,13 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl StringBuilder builder = new StringBuilder(128) .append(getIPRGroupPrefixShortName(prefix, authorities)) .append(index); - + return builder.toString(); } - + /** * Gets the hashcode value of a set of authorities. - * + * * @param authorities set of authorities * @return int hash code */ @@ -500,14 +500,14 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl int result = 0; if (authorities != null && !authorities.isEmpty()) { - result = StringUtils.join(authorities.toArray(), "").hashCode(); + result = StringUtils.join(authorities.toArray(), "").hashCode(); } return result; } - + /** * Creates a new IPR group. - * + * * @param groupNamePrefix group name prefix * @param children child authorities * @param index group index @@ -552,7 +552,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl /** * Assign IPR groups to a node reference with the correct permissions. - * + * * @param iprGroups iprGroups, first read and second write * @param nodeRef node reference */ @@ -561,7 +561,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl permissionService.setPermission(nodeRef, iprGroups.getFirst(), RMPermissionModel.READ_RECORDS, true); permissionService.setPermission(nodeRef, iprGroups.getSecond(), RMPermissionModel.FILING, true); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#remove(org.alfresco.service.cmr.repository.NodeRef) */ @@ -569,13 +569,13 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl public void remove(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - + Pair iprGroups = getIPRGroups(nodeRef); if (iprGroups != null) { // remove any extended security that might be present clearPermissions(nodeRef, iprGroups); - + // remove the readers from any renditions of the content if (isRecord(nodeRef)) { @@ -591,16 +591,16 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl /** * Clear the nodes IPR permissions - * + * * @param nodeRef node reference */ private void clearPermissions(NodeRef nodeRef, Pair iprGroups) { // remove group permissions from node permissionService.clearPermission(nodeRef, iprGroups.getFirst()); - permissionService.clearPermission(nodeRef, iprGroups.getSecond()); - } - + permissionService.clearPermission(nodeRef, iprGroups.getSecond()); + } + /** * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedReaders(org.alfresco.service.cmr.repository.NodeRef) */ @@ -608,7 +608,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { return getReaders(nodeRef); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedWriters(org.alfresco.service.cmr.repository.NodeRef) */ @@ -616,15 +616,15 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { return getWriters(nodeRef); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set) */ @Override @Deprecated public void addExtendedSecurity(NodeRef nodeRef, Set readers, Set writers) { - set(nodeRef, readers, writers); + set(nodeRef, readers, writers); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean) */ @@ -632,7 +632,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { set(nodeRef, readers, writers); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef) */ @@ -640,7 +640,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl { remove(nodeRef); } - + /** * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set) */ @@ -654,7 +654,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl */ @Override @Deprecated public void removeExtendedSecurity(NodeRef nodeRef, Set readers, Setwriters, boolean applyToParents) { - remove(nodeRef); + remove(nodeRef); } /** @@ -662,6 +662,6 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl */ @Override @Deprecated public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents) { - remove(nodeRef); + remove(nodeRef); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java index 79aa6738e0..0939e2ed41 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java @@ -222,15 +222,14 @@ public class TransferServiceImpl extends ServiceBaseImpl nodeRef, ASSOC_TRANSFERRED, ASSOC_TRANSFERRED); + // Set PDF indicator flag + setPDFIndicationFlag(transferNodeRef, nodeRef); } finally { transferType.enable(); } - // Set PDF indicator flag - setPDFIndicationFlag(transferNodeRef, nodeRef); - // Set the transferring indicator aspect nodeService.addAspect(nodeRef, ASPECT_TRANSFERRING, null); if (isRecordFolder(nodeRef)) diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java index 2207bd97a9..f1cb30820b 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java @@ -52,6 +52,7 @@ import org.junit.runner.RunWith; "!.*RM2190Test", "!.*RM981SystemTest", "!.*RM3993Test", + "!.*RM4163Test", "!.*RecordsManagementEventServiceImplTest", "!.*RmRestApiTest", "!.*NotificationServiceHelperSystemTest", diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4163Test.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4163Test.java new file mode 100644 index 0000000000..660f04194f --- /dev/null +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4163Test.java @@ -0,0 +1,207 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.module.org_alfresco_module_rm.test.integration.issue; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.FileToAction; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.rule.Rule; +import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.cmr.rule.RuleType; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * System test for RM-4163 + * + * @author Silviu Dinuta + * @since 2.4.1 + */ +public class RM4163Test extends BaseRMTestCase +{ + private RuleService ruleService; + private NodeRef ruleFolder; + private NodeRef nodeRefCategory1; + + @Override + protected void initServices() + { + super.initServices(); + + ruleService = (RuleService) applicationContext.getBean("RuleService"); + } + + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + @Override + protected boolean isRecordTest() + { + return true; + } + + public void testDeclareRecordsConcurently() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + // create the folder + ruleFolder = fileFolderService.create(documentLibrary, "mytestfolder", ContentModel.TYPE_FOLDER) + .getNodeRef(); + + // create record category + nodeRefCategory1 = filePlanService.createRecordCategory(filePlan, "category1"); + + //define declare as record rule and apply it to the created folder from documentLibrary + Action action = actionService.createAction(CreateRecordAction.NAME); + action.setParameterValue(CreateRecordAction.PARAM_FILE_PLAN, filePlan); + + Rule rule = new Rule(); + rule.setRuleType(RuleType.INBOUND); + rule.setTitle("declareAsRecordRule"); + rule.setAction(action); + rule.setExecuteAsynchronously(true); + ruleService.saveRule(ruleFolder, rule); + + //define filing rule and apply it to unfiled record container + Action fileAction = actionService.createAction(FileToAction.NAME); + fileAction.setParameterValue(FileToAction.PARAM_PATH, + "/category1/{node.cm:description}"); + fileAction.setParameterValue(FileToAction.PARAM_CREATE_RECORD_PATH, true); + + Rule fileRule = new Rule(); + fileRule.setRuleType(RuleType.INBOUND); + fileRule.setTitle("filingRule"); + fileRule.setAction(fileAction); + fileRule.setExecuteAsynchronously(true); + ruleService.saveRule(filePlanService.getUnfiledContainer(filePlan), fileRule); + + return null; + } + + @Override + public void test(Void result) throws Exception + { + assertFalse(ruleService.getRules(ruleFolder).isEmpty()); + } + }); + + //create 4 documents in documentLibrary + List documents = new ArrayList(4); + documents.addAll(doTestInTransaction(new Test>() + { + @Override + public List run() throws Exception + { + List documents = new ArrayList(4); + NodeRef document = createFile(documentLibrary, "document1.txt", "desc1", ContentModel.TYPE_CONTENT); + documents.add(document); + document = createFile(documentLibrary, "document2.txt", "desc2", ContentModel.TYPE_CONTENT); + documents.add(document); + document = createFile(documentLibrary, "document3.txt", "desc1", ContentModel.TYPE_CONTENT); + documents.add(document); + document = createFile(documentLibrary, "document4.txt", "desc1", ContentModel.TYPE_CONTENT); + documents.add(document); + return documents; + } + })); + + //move created documents in the folder that has Declare as Record rule + final Iterator temp = documents.iterator(); + doTestInTransaction(new Test() + { + @Override + public Void run() throws Exception + { + while (temp.hasNext()) + { + NodeRef document = temp.next(); + fileFolderService.move(document, ruleFolder, null); + } + return null; + } + }); + + //give enough time for filing all records + Thread.sleep(5000); + + //check that target category has in created record folders 4 records + Integer numberOfRecords = AuthenticationUtil.runAsSystem(new RunAsWork() + { + + @Override + public Integer doWork() throws Exception + { + List containedRecordFolders = filePlanService.getContainedRecordFolders(nodeRefCategory1); + int numberOfRecords = 0; + for(NodeRef recordFolder : containedRecordFolders) + { + numberOfRecords = numberOfRecords + fileFolderService.list(recordFolder).size(); + } + return numberOfRecords; + } + }); + assertEquals(4, numberOfRecords.intValue()); + } + + private NodeRef createFile(NodeRef parentNodeRef, String name, String descrption, QName typeQName) + { + Map properties = new HashMap(11); + properties.put(ContentModel.PROP_NAME, (Serializable) name); + properties.put(ContentModel.PROP_DESCRIPTION, (Serializable) descrption); + QName assocQName = QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName(name)); + ChildAssociationRef assocRef = nodeService.createNode( + parentNodeRef, + ContentModel.ASSOC_CONTAINS, + assocQName, + typeQName, + properties); + NodeRef nodeRef = assocRef.getChildRef(); + return nodeRef; + } +} diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4804Test.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4804Test.java new file mode 100644 index 0000000000..0005ce388f --- /dev/null +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4804Test.java @@ -0,0 +1,133 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.module.org_alfresco_module_rm.test.integration.issue; + +import java.io.InputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.TransferAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.TransferCompleteAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.extensions.webscripts.GUID; + +/** + * Integration test for RM-4804 + * + * Completed records of type pdf can be transferred + * + * @author Ramona Popa + * @since 2.6 + */ +public class RM4804Test extends BaseRMTestCase +{ + /** + * Given a category with disposition schedule applied on folder with Cut Of and Transfer, a record folder and a file PDF document + * to folder, complete the record + * When execute disposition schedule steps + * Then the Transfer step is successfully finished + */ + @org.junit.Test + public void testTransferCompletedRecordOfTypePDF() throws Exception + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef recordCategory; + NodeRef recordFolder; + NodeRef record; + + public void given() + { + // category is created + recordCategory = filePlanService.createRecordCategory(filePlan, GUID.generate()); + + // create a disposition schedule for category, applied on folder + Map dsProps = new HashMap(3); + dsProps.put(PROP_DISPOSITION_AUTHORITY, CommonRMTestUtils.DEFAULT_DISPOSITION_AUTHORITY); + dsProps.put(PROP_DISPOSITION_INSTRUCTIONS, GUID.generate()); + dsProps.put(PROP_RECORD_LEVEL_DISPOSITION, false); + + DispositionSchedule dispositionSchedule = dispositionService.createDispositionSchedule(recordCategory, dsProps); + + // cutoff immediately + Map dispositionActionCutOff = new HashMap(3); + dispositionActionCutOff.put(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME); + dispositionActionCutOff.put(PROP_DISPOSITION_DESCRIPTION, GUID.generate()); + dispositionActionCutOff.put(PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_IMMEDIATELY); + + dispositionService.addDispositionActionDefinition(dispositionSchedule, dispositionActionCutOff); + + // transfer immediately + Map dispositionActionTransfer = new HashMap(4); + dispositionActionTransfer.put(PROP_DISPOSITION_ACTION_NAME, TransferAction.NAME); + dispositionActionTransfer.put(PROP_DISPOSITION_DESCRIPTION, GUID.generate()); + dispositionActionTransfer.put(PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_IMMEDIATELY); + dispositionActionTransfer.put(PROP_DISPOSITION_LOCATION, StringUtils.EMPTY); + + dispositionService.addDispositionActionDefinition(dispositionSchedule, dispositionActionTransfer); + + // add folder under category + recordFolder = recordFolderService.createRecordFolder(recordCategory, GUID.generate()); + + // add record of type PDF under folder + Map props = new HashMap(1); + props.put(ContentModel.PROP_TITLE, GUID.generate()); + InputStream inputStream = IOUtils.toInputStream(GUID.generate()); + record = utils.createRecord(recordFolder, GUID.generate(), props, MimetypeMap.MIMETYPE_PDF, inputStream); + + // complete the record + utils.completeRecord(record); + } + + public void when() + { + // cut off and transfer record + rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, null); + NodeRef transferFolder = (NodeRef) rmActionService.executeRecordsManagementAction(recordFolder, TransferAction.NAME) + .getValue(); + rmActionService.executeRecordsManagementAction(transferFolder, TransferCompleteAction.NAME); + } + + public void then() + { + // verify record is transferred + assertTrue(nodeService.hasAspect(record, ASPECT_TRANSFERRED)); + } + }); + } +} diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/recordfolder/MoveRecordFolderTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/recordfolder/MoveRecordFolderTest.java index e0d62b9863..df34f5c96e 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/recordfolder/MoveRecordFolderTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/recordfolder/MoveRecordFolderTest.java @@ -510,6 +510,46 @@ public class MoveRecordFolderTest extends BaseRMTestCase } + /** + * Given a closed folder + * When we evaluate the move capability on it + * The access is denied + */ + public void testMoveClosedFolder() + { + final NodeRef destination = doTestInTransaction(new Test() + { + @Override + public NodeRef run() + { + // create a record category + return filePlanService.createRecordCategory(filePlan, GUID.generate()); + } + }); + + final NodeRef testFolder = doTestInTransaction(new Test() + { + @Override + public NodeRef run() + { + // create folder + NodeRef testFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate()); + + // close folder + recordFolderService.closeRecordFolder(testFolder); + + return testFolder; + } + + @Override + public void test(NodeRef testFolder) throws Exception + { + Capability moveCapability = capabilityService.getCapability("MoveRecordFolder"); + assertEquals(AccessDecisionVoter.ACCESS_DENIED, moveCapability.evaluate(testFolder, destination)); + } + }); + } + private NodeRef createRecordCategory(boolean recordLevel) { NodeRef rc = filePlanService.createRecordCategory(filePlan, GUID.generate());