diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml index d1dda0a2e9..c80360da50 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml @@ -16,6 +16,9 @@ + + + {http://www.alfresco.org/model/content/1.0}content diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties index 3b4c93b3d4..e2d43aa52b 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties @@ -48,9 +48,10 @@ isRecordType.description=Records have a specified record type # # Declare As Record create-record.title=Declare as Record -create-record.description=Declares file as a record +create-record.description=Declares file as a record and optionally files it create-record.file-plan.display-label=File Plan create-record.hide-record.display-label=Hide Record +create-record.path.display-label=Destination Record Folder Path # Declare As Version Record declare-as-version-record.title=Declare Version as Record declare-as-version-record.description=Declares this version of the file as a record diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java index 2869b9c755..bd60827fcc 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java @@ -27,16 +27,27 @@ package org.alfresco.module.org_alfresco_module_rm.action.dm; +import java.util.Arrays; import java.util.List; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.action.AuditableActionExecuterAbstractBase; +import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.record.RecordService; +import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; + +import org.springframework.util.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Creates a new record from an existing content object. @@ -48,16 +59,53 @@ import org.alfresco.service.cmr.repository.NodeRef; public class CreateRecordAction extends AuditableActionExecuterAbstractBase implements RecordsManagementModel { + /** Logger */ + private static final Log LOGGER = LogFactory.getLog(CreateRecordAction.class); + /** Action name */ public static final String NAME = "create-record"; /** Parameter names */ public static final String PARAM_FILE_PLAN = "file-plan"; public static final String PARAM_HIDE_RECORD = "hide-record"; + public static final String PARAM_PATH = "path"; + + /** Node service */ + private NodeService nodeService; + + /** File plan service */ + private FilePlanService filePlanService; + + /** Authentication util */ + private AuthenticationUtil authenticationUtil; /** Record service */ private RecordService recordService; + /** + * @param nodeService node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param filePlanService file plan service + */ + public void setFilePlanService(FilePlanService filePlanService) + { + this.filePlanService = filePlanService; + } + + /** + * @param authenticationUtil authentication util + */ + public void setAuthenticationUtil(AuthenticationUtil authenticationUtil) + { + this.authenticationUtil = authenticationUtil; + } + /** * @param recordService record service */ @@ -74,6 +122,14 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase { NodeRef filePlan = (NodeRef) action.getParameterValue(PARAM_FILE_PLAN); + // resolve destination record folder if path supplied + NodeRef destinationRecordFolder = null; + String pathParameter = (String) action.getParameterValue(PARAM_PATH); + if (pathParameter != null && !pathParameter.isEmpty()) + { + destinationRecordFolder = resolvePath(filePlan, pathParameter); + } + // indicate whether the record should be hidden or not (default not) boolean hideRecord = false; Boolean hideRecordValue = ((Boolean) action.getParameterValue(PARAM_HIDE_RECORD)); @@ -85,7 +141,12 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase synchronized (this) { // create record from existing document - recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord); + recordService.createRecord(filePlan, actionedUponNodeRef, destinationRecordFolder, !hideRecord); + + if (destinationRecordFolder != null) + { + recordService.file(actionedUponNodeRef); + } } } @@ -97,6 +158,102 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase { // NOTE: commented out for now so that it doesn't appear in the UI ... enable later when multi-file plan support is added //params.add(new ParameterDefinitionImpl(PARAM_FILE_PLAN, DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_FILE_PLAN))); + params.add(new ParameterDefinitionImpl(PARAM_PATH, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_PATH))); params.add(new ParameterDefinitionImpl(PARAM_HIDE_RECORD, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_HIDE_RECORD))); } + + /** + * Helper method to get the target record folder node reference from the action path parameter + * + * @param filePlan The filePlan containing the path + * @param pathParameter The path + * @return The NodeRef of the resolved path + */ + private NodeRef resolvePath(NodeRef filePlan, final String pathParameter) + { + NodeRef destinationFolder; + + if (filePlan == null) + { + filePlan = getDefaultFilePlan(); + } + + final String[] pathElementsArray = StringUtils.tokenizeToStringArray(pathParameter, "/", false, true); + if ((pathElementsArray != null) && (pathElementsArray.length > 0)) + { + destinationFolder = resolvePath(filePlan, Arrays.asList(pathElementsArray)); + + // destination must be a record folder + QName nodeType = nodeService.getType(destinationFolder); + if (!nodeType.equals(RecordsManagementModel.TYPE_RECORD_FOLDER)) + { + throw new AlfrescoRuntimeException("Unable to execute " + NAME + " action, because the destination path is not a record folder."); + } + } + else + { + throw new AlfrescoRuntimeException("Unable to execute " + NAME + " action, because the destination path could not be found."); + } + return destinationFolder; + } + + /** + * Helper method to recursively get the next path element node reference from the action path parameter + * + * @param parent The parent of the path elements + * @param pathElements The path elements still to be resolved + * @return The NodeRef of the resolved path element + */ + private NodeRef resolvePath(NodeRef parent, List pathElements) + { + NodeRef nodeRef; + String childName = pathElements.get(0); + + nodeRef = nodeService.getChildByName(parent, ContentModel.ASSOC_CONTAINS, childName); + + if (nodeRef == null) + { + throw new AlfrescoRuntimeException("Unable to execute " + NAME + " action, because the destination path could not be resolved."); + } + else + { + QName nodeType = nodeService.getType(nodeRef); + if (nodeType.equals(RecordsManagementModel.TYPE_HOLD_CONTAINER) || + nodeType.equals(RecordsManagementModel.TYPE_TRANSFER_CONTAINER) || + nodeType.equals(RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER)) + { + throw new AlfrescoRuntimeException("Unable to execute " + NAME + " action, because the destination path is invalid."); + } + } + if (pathElements.size() > 1) + { + nodeRef = resolvePath(nodeRef, pathElements.subList(1, pathElements.size())); + } + return nodeRef; + } + + /** + * Helper method to get the default RM filePlan + * + * @return The NodeRef of the default RM filePlan + */ + private NodeRef getDefaultFilePlan() + { + NodeRef filePlan = authenticationUtil.runAsSystem(new org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork() + { + @Override + public NodeRef doWork() + { + return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID); + } + }); + + // if the file plan is still null, raise an exception + if (filePlan == null) + { + LOGGER.debug("Unable to execute " + NAME + " action, because the fileplan path could not be determined. Make sure at least one file plan has been created."); + throw new AlfrescoRuntimeException("Unable to execute " + NAME + " action, because the fileplan path could not be determined."); + } + return filePlan; + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index fd1209762d..d5a249f107 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -159,6 +159,31 @@ public interface RecordService */ boolean isDeclared(NodeRef nodeRef); + /** + * Creates a new record from an existing node and files it into the specified location. + *

+ * Note that the node reference of the record will be the same as the original + * document. + * + * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. + * @param nodeRef The node from which the record will be created + * @param locationNodeRef The container in which the record will be created + * @param isLinked indicates if the newly created record is linked to it's original location or not. + */ + void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final NodeRef locationNodeRef, final boolean isLinked); + + /** + * Creates a new record from an existing node and files it into the specified location. + *

+ * Note that the node reference of the record will be the same as the original + * document. + * + * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. + * @param nodeRef The node from which the record will be created + * @param locationNodeRef The container in which the record will be created + */ + void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final NodeRef locationNodeRef); + /** * Creates a new unfiled record from an existing node. *

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 fc0c2615d2..031caf5a9c 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 @@ -812,7 +812,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#getRecordMetaDataAspects(org.alfresco.service.cmr.repository.NodeRef) + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#getRecordMetadataAspects(org.alfresco.service.cmr.repository.NodeRef) */ @Override public Set getRecordMetadataAspects(NodeRef nodeRef) @@ -861,8 +861,27 @@ public class RecordServiceImpl extends BaseBehaviourBean */ @Override public void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final boolean isLinked) + { + createRecord(filePlan, nodeRef, null, isLinked); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecord(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final NodeRef destinationNodeRef) + { + createRecord(filePlan, nodeRef, destinationNodeRef, true); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecord(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, boolean) + */ + @Override + public void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final NodeRef destinationNodeRef, final boolean isLinked) { // filePlan can be null. In this case the default RM site will be used. + // locationNodeRef can be null. In this case the unfiled record container will be used ParameterCheck.mandatory("nodeRef", nodeRef); ParameterCheck.mandatory("isLinked", isLinked); @@ -882,11 +901,33 @@ public class RecordServiceImpl extends BaseBehaviourBean ruleService.disableRuleType("outbound"); try { - // get the new record container for the file plan - NodeRef newRecordContainer = filePlanService.getUnfiledContainer(checkedFilePlan); + NodeRef newRecordContainer = destinationNodeRef; + // if optional location not specified, use the unfiledContainer if (newRecordContainer == null) { - throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found."); + // get the new record container for the file plan + newRecordContainer = filePlanService.getUnfiledContainer(checkedFilePlan); + if (newRecordContainer == null) + { + throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found."); + } + + } + // if optional location supplied, check that it is a valid record folder + else + { + QName nodeType = nodeService.getType(newRecordContainer); + if(!(nodeType.equals(RecordsManagementModel.TYPE_RECORD_FOLDER) || + nodeType.equals(RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER))) + { + throw new AlfrescoRuntimeException("Unable to create record, because container is not a valid type for new record."); + } + + Boolean isClosed = (Boolean) nodeService.getProperty(newRecordContainer, PROP_IS_CLOSED); + if (isClosed != null && isClosed) + { + throw new AlfrescoRuntimeException("Unable to create record, because container is closed."); + } } // get the documents readers and writers @@ -1202,7 +1243,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createNewRecord(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map, org.alfresco.service.cmr.repository.ContentReader) + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecordFromContent(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map, org.alfresco.service.cmr.repository.ContentReader) */ @Override public NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map properties, ContentReader reader) @@ -1322,7 +1363,7 @@ public class RecordServiceImpl extends BaseBehaviourBean } /** - * @see org.alfresco.module.org_alfresco_module_rm.disposableitem.RecordService#isFiled(org.alfresco.service.cmr.repository.NodeRef) + * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isFiled(org.alfresco.service.cmr.repository.NodeRef) */ @Override public boolean isFiled(final NodeRef nodeRef) diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/CreateRecordActionTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/CreateRecordActionTest.java index 0afe5d76f5..16450b107d 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/CreateRecordActionTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/CreateRecordActionTest.java @@ -31,6 +31,7 @@ import org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AccessStatus; /** @@ -52,6 +53,13 @@ public class CreateRecordActionTest extends BaseRMTestCase return true; } + /** + * Test create record action + * + * Given a collaboration site document + * When the create record action is executed for that document + * Then a record is created for it + */ public void testCreateRecordAction() { doTestInTransaction(new Test() @@ -75,8 +83,45 @@ public class CreateRecordActionTest extends BaseRMTestCase assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS)); - }; + } }, dmCollaborator); } + + /** + * Test create record action with optional location + * + * Given a collaboration site document + * When the create record action with optional record location is executed for that document + * Then a record is created for it and filed in the specified location + */ + public void testCreateRecordActionWithLocation() + { + doTestInTransaction(new Test() + { + public Void run() + { + assertFalse(recordService.isRecord(dmDocument1)); + + Action action = actionService.createAction(CreateRecordAction.NAME); + action.setParameterValue(CreateRecordAction.PARAM_HIDE_RECORD, false); + action.setParameterValue(CreateRecordAction.PARAM_FILE_PLAN, filePlan); + action.setParameterValue(CreateRecordAction.PARAM_PATH, "rmContainer/rmFolder"); + actionService.executeAction(action, dmDocument1); + + return null; + } + + public void test(Void result) throws Exception + { + assertTrue(recordService.isRecord(dmDocument1)); + assertTrue(recordService.isFiled(dmDocument1)); + + // is the record folder the primary parent of the filed record + NodeRef parent = nodeService.getPrimaryParent(dmDocument1).getParentRef(); + assertEquals(rmFolder, parent); + } + }, + ADMIN_USER); + } } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java index 4eeb564b49..a47d89dc5f 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java @@ -123,6 +123,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase /** test data */ protected String NAME_DM_DOCUMENT = "collabDocument.txt"; + protected String NAME_DM_DOCUMENT1 = "collabDocument1.txt"; /** admin user */ protected static final String ADMIN_USER = "admin"; @@ -273,7 +274,9 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase protected SiteInfo collaborationSite; protected NodeRef documentLibrary; protected NodeRef dmFolder; + protected NodeRef dmFolder1; protected NodeRef dmDocument; + protected NodeRef dmDocument1; /** collaboration site users */ protected String dmConsumer; @@ -786,6 +789,8 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase // create a folder and documents dmFolder = fileFolderService.create(documentLibrary, "collabFolder", ContentModel.TYPE_FOLDER).getNodeRef(); dmDocument = fileFolderService.create(dmFolder, NAME_DM_DOCUMENT, ContentModel.TYPE_CONTENT).getNodeRef(); + dmFolder1 = fileFolderService.create(documentLibrary, "collabFolder1", ContentModel.TYPE_FOLDER).getNodeRef(); + dmDocument1 = fileFolderService.create(dmFolder1, NAME_DM_DOCUMENT1, ContentModel.TYPE_CONTENT).getNodeRef(); dmConsumer = GUID.generate(); dmConsumerNodeRef = createPerson(dmConsumer); diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java index a2bf96b29d..c38b5cf2e1 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java @@ -45,12 +45,15 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; import org.alfresco.repo.policy.Behaviour; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.commons.collections.CollectionUtils; @@ -69,6 +72,9 @@ public class RecordServiceImplUnitTest extends BaseUnitTest { private NodeRef nonStandardFilePlanComponent; private NodeRef nonStandardFilePlan; + private NodeRef dmNodeRef; + private NodeRef unfiledRecordFolder; + private ChildAssociationRef parentAssoc; private static QName TYPE_MY_FILE_PLAN = generateQName(); private static QName ASPECT_FOR_FILE_PLAN = generateQName(); @@ -84,6 +90,9 @@ public class RecordServiceImplUnitTest extends BaseUnitTest nonStandardFilePlanComponent = generateNodeRef(TYPE_RECORD_CATEGORY); nonStandardFilePlan = generateNodeRef(TYPE_MY_FILE_PLAN); + dmNodeRef = generateNodeRef(TYPE_CONTENT); + unfiledRecordFolder = generateNodeRef(TYPE_UNFILED_RECORD_FOLDER); + parentAssoc = mock(ChildAssociationRef.class); // set-up node service when(mockedNodeService.getProperty(nonStandardFilePlanComponent, PROP_ROOT_NODEREF)).thenReturn(nonStandardFilePlan); @@ -462,4 +471,103 @@ public class RecordServiceImplUnitTest extends BaseUnitTest // verify verify(values, never()).add(nodeRef); } + + /** + * Given a file that is not yet a record + * When I create the record without specifying a location + * Then the record is created in the unfiled record folder + */ + @Test + public void createRecordIntoUnfiledRecordFolder() + { + mocksForRecordCreation(); + + // create the record + recordService.createRecord(nonStandardFilePlan, dmNodeRef); + + // verify record was created in unfiled record container + verify(mockedNodeService, times(1)).moveNode( + dmNodeRef, + unfiledRecordFolder, + ContentModel.ASSOC_CONTAINS, + parentAssoc.getQName()); + } + + /** + * Given a file that is not yet a record + * When I create the record specifying the unfiled record folder + * Then the record is created in the unfiled record folder + */ + @Test + public void createRecordIntoSpecifiedUnfiledRecordFolder() + { + mocksForRecordCreation(); + + // create the record + recordService.createRecord(nonStandardFilePlan, dmNodeRef, unfiledRecordFolder); + + // verify record was created in specified record folder + verify(mockedNodeService, times(1)).moveNode( + dmNodeRef, + unfiledRecordFolder, + ContentModel.ASSOC_CONTAINS, + parentAssoc.getQName()); + } + + /** + * Given a file that is not yet a record + * When I create the record specifying a location + * Then the record is created in the specified record folder + */ + @Test + public void createRecordIntoSpecifiedRecordFolder() + { + mocksForRecordCreation(); + + // create the record + recordService.createRecord(nonStandardFilePlan, dmNodeRef, recordFolder); + + // verify record was created in specified record folder + verify(mockedNodeService, times(1)).moveNode( + dmNodeRef, + recordFolder, + ContentModel.ASSOC_CONTAINS, + parentAssoc.getQName()); + } + + /** + * Given a file that is not yet a record + * When I create the record specifying an invalid location + * Then an exception is thrown + */ + @Test(expected=AlfrescoRuntimeException.class) + public void createRecordIntoInvalidRecordFolder() + { + mocksForRecordCreation(); + NodeRef recordCategory = generateNodeRef(TYPE_RECORD_CATEGORY); + + // create the record + recordService.createRecord(nonStandardFilePlan, dmNodeRef, recordCategory); + } + + /* Helper method to set up the mocks for record creation */ + private void mocksForRecordCreation() + { + when(mockedNodeService.getPrimaryParent(dmNodeRef)) + .thenReturn(parentAssoc); + when(parentAssoc.getQName()).thenReturn(generateQName()); + + // mocks for sanity checks on node and fileplan + when(mockedExtendedPermissionService.hasPermission(dmNodeRef, PermissionService.WRITE)).thenReturn(AccessStatus.ALLOWED); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(dmNodeRef), ContentModel.TYPE_CONTENT)).thenReturn(true); + when(mockedFilePlanService.isFilePlan(nonStandardFilePlan)).thenReturn(true); + + // mocks for policies + doNothing().when(recordService).invokeBeforeRecordDeclaration(dmNodeRef); + doNothing().when(recordService).invokeOnRecordDeclaration(dmNodeRef); + + when(mockedFilePlanService.getUnfiledContainer(nonStandardFilePlan)).thenReturn(unfiledRecordFolder); + + when(mockedVersionService.getVersionHistory(dmNodeRef)).thenReturn(null); + } } diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java index be68a337d2..b4ab37fed1 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java @@ -72,10 +72,12 @@ import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.OwnableService; import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QNamePattern; @@ -122,6 +124,8 @@ public class BaseUnitTest implements RecordsManagementModel, ContentModel @Mock(name="copyService") protected CopyService mockedCopyService; @Mock(name="fileFolderService") protected FileFolderService mockedFileFolderService; @Mock(name="modelSecurityService") protected ModelSecurityService mockedModelSecurityService; + @Mock(name="ruleService") protected RuleService mockedRuleService; + @Mock(name="versionService") protected VersionService mockedVersionService; /** rm service mocks */ @Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;