mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM-4586 (Record can be declared a record) / RM-4587 (Folder in collaboration site can be declared a record)
This commit is contained in:
@@ -16,16 +16,13 @@
|
||||
<!-- TODO rename -->
|
||||
<bean id="create-record" parent="action-executer" class="org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction">
|
||||
<property name="recordService" ref="RecordService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="filePlanService" ref="FilePlanService" />
|
||||
<property name="dictionaryService" ref="DictionaryService" />
|
||||
<property name="applicableTypes">
|
||||
<list>
|
||||
<value>{http://www.alfresco.org/model/content/1.0}content</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Declare as Record Version action -->
|
||||
<bean id="declare-as-version-record" parent="action-executer" class="org.alfresco.module.org_alfresco_module_rm.action.dm.DeclareAsVersionRecordAction">
|
||||
<property name="recordableVersionService" ref="RecordableVersionService" />
|
||||
|
@@ -29,24 +29,14 @@ package org.alfresco.module.org_alfresco_module_rm.action.dm;
|
||||
|
||||
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.repo.action.ParameterDefinitionImpl;
|
||||
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.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Creates a new record from an existing content object.
|
||||
@@ -58,9 +48,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
public class CreateRecordAction extends AuditableActionExecuterAbstractBase
|
||||
implements RecordsManagementModel
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(CreateRecordAction.class);
|
||||
|
||||
/** Action name */
|
||||
public static final String NAME = "create-record";
|
||||
|
||||
@@ -68,23 +55,9 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase
|
||||
public static final String PARAM_FILE_PLAN = "file-plan";
|
||||
public static final String PARAM_HIDE_RECORD = "hide-record";
|
||||
|
||||
/** Sync Model URI */
|
||||
static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0";
|
||||
/** Synced aspect */
|
||||
static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced");
|
||||
|
||||
/** Record service */
|
||||
private RecordService recordService;
|
||||
|
||||
/** Node service */
|
||||
private NodeService nodeService;
|
||||
|
||||
/** File plan service */
|
||||
private FilePlanService filePlanService;
|
||||
|
||||
/** Dictionary service */
|
||||
private DictionaryService dictionaryService;
|
||||
|
||||
/**
|
||||
* @param recordService record service
|
||||
*/
|
||||
@@ -93,138 +66,26 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase
|
||||
this.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 dictionaryService dictionary service
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
NodeRef filePlan = (NodeRef) action.getParameterValue(PARAM_FILE_PLAN);
|
||||
|
||||
if (!nodeService.exists(actionedUponNodeRef))
|
||||
// indicate whether the record should be hidden or not (default not)
|
||||
boolean hideRecord = false;
|
||||
Boolean hideRecordValue = ((Boolean) action.getParameterValue(PARAM_HIDE_RECORD));
|
||||
if (hideRecordValue != null)
|
||||
{
|
||||
// do not create record if the actioned upon node does not exist!
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " does not exist.");
|
||||
}
|
||||
hideRecord = hideRecordValue.booleanValue();
|
||||
}
|
||||
else if (!dictionaryService.isSubClass(nodeService.getType(actionedUponNodeRef), ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
// TODO eventually we should support other types .. either as record folders or as composite records
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " is not a supported type.");
|
||||
}
|
||||
}
|
||||
else if (nodeService.hasAspect(actionedUponNodeRef, ASPECT_RECORD))
|
||||
{
|
||||
// Do not create record if the actioned upon node is already a record!
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " is already a record.");
|
||||
}
|
||||
}
|
||||
else if (nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY))
|
||||
{
|
||||
// We can not create records from working copies
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can node create record, because " + actionedUponNodeRef.toString() + " is a working copy.");
|
||||
}
|
||||
|
||||
}
|
||||
else if (nodeService.hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS))
|
||||
synchronized (this)
|
||||
{
|
||||
// can not create a record from a previously rejected one
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " has previously been rejected.");
|
||||
}
|
||||
}
|
||||
else if (nodeService.hasAspect(actionedUponNodeRef, ASPECT_SYNCED))
|
||||
{
|
||||
// can't declare the record if the node is sync'ed
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can't declare as record, because " + actionedUponNodeRef.toString() + " is synched content.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeRef filePlan = (NodeRef)action.getParameterValue(PARAM_FILE_PLAN);
|
||||
if (filePlan == null)
|
||||
{
|
||||
// TODO .. eventually make the file plan parameter required
|
||||
|
||||
filePlan = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef doWork()
|
||||
{
|
||||
return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
|
||||
}
|
||||
}, AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// if the file plan is still null, raise an exception
|
||||
if (filePlan == null)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can not create record, because the default file plan can not be determined. Make sure at least one file plan has been created.");
|
||||
}
|
||||
throw new AlfrescoRuntimeException("Can not create record, because the default file plan can not be determined.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify that the provided file plan is actually a file plan
|
||||
if (!filePlanService.isFilePlan(filePlan))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Can not create record, because the provided file plan node reference is not a file plan.");
|
||||
}
|
||||
throw new AlfrescoRuntimeException("Can not create record, because the provided file plan node reference is not a file plan.");
|
||||
}
|
||||
}
|
||||
|
||||
// indicate whether the record should be hidden or not (default not)
|
||||
boolean hideRecord = false;
|
||||
Boolean hideRecordValue = ((Boolean)action.getParameterValue(PARAM_HIDE_RECORD));
|
||||
if (hideRecordValue != null)
|
||||
{
|
||||
hideRecord = hideRecordValue.booleanValue();
|
||||
}
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
// create record from existing document
|
||||
recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord);
|
||||
}
|
||||
// create record from existing document
|
||||
recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,5 +99,4 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase
|
||||
//params.add(new ParameterDefinitionImpl(PARAM_FILE_PLAN, DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_FILE_PLAN)));
|
||||
params.add(new ParameterDefinitionImpl(PARAM_HIDE_RECORD, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_HIDE_RECORD)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -165,7 +165,7 @@ public interface RecordService
|
||||
* 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
|
||||
* @param filePlan The filePlan in which the record should be placed. filePlan can be <code>null</code> in this case the default RM site will be used.
|
||||
* @param nodeRef The node from which the record will be created
|
||||
* @param isLinked indicates if the newly created record is linked to it's original location or not.
|
||||
*/
|
||||
|
@@ -135,6 +135,13 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(RecordServiceImpl.class);
|
||||
|
||||
|
||||
/** Sync Model URI */
|
||||
private static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0";
|
||||
|
||||
/** Synced aspect */
|
||||
private static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced");
|
||||
|
||||
/** transation data key */
|
||||
private static final String KEY_IGNORE_ON_UPDATE = "ignoreOnUpdate";
|
||||
private static final String KEY_PENDING_FILLING = "pendingFilling";
|
||||
@@ -238,10 +245,10 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
|
||||
/** records management container type */
|
||||
private RecordsManagementContainerType recordsManagementContainerType;
|
||||
|
||||
|
||||
/** recordable version service */
|
||||
private RecordableVersionService recordableVersionService;
|
||||
|
||||
|
||||
/** list of available record meta-data aspects and the file plan types the are applicable to */
|
||||
private Map<QName, Set<QName>> recordMetaDataAspects;
|
||||
|
||||
@@ -390,7 +397,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
this.recordsManagementContainerType = recordsManagementContainerType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param recordableVersionService recordable version service
|
||||
*/
|
||||
@@ -398,7 +405,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
this.recordableVersionService = recordableVersionService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Init method
|
||||
*/
|
||||
@@ -854,19 +861,12 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
@Override
|
||||
public void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final boolean isLinked)
|
||||
{
|
||||
ParameterCheck.mandatory("filePlan", filePlan);
|
||||
// filePlan can be null. In this case the default RM site will be used.
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
ParameterCheck.mandatory("isLinked", isLinked);
|
||||
|
||||
// first we do a sanity check to ensure that the user has at least write permissions on the document
|
||||
if (extendedPermissionService.hasPermission(nodeRef, PermissionService.WRITE) != AccessStatus.ALLOWED)
|
||||
{
|
||||
throw new AccessDeniedException("Can not create record from document, because the user " +
|
||||
AuthenticationUtil.getRunAsUser() +
|
||||
" does not have Write permissions on the doucment " +
|
||||
nodeRef.toString());
|
||||
}
|
||||
|
||||
recordCreationSanityCheckOnNode(nodeRef);
|
||||
recordCreationSanityCheckOnFilePlan(filePlan);
|
||||
|
||||
// do the work of creating the record as the system user
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
@@ -961,6 +961,158 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check the given file plan before trying to determine the unfiled records container.
|
||||
*
|
||||
* @param filePlan The reference of the file plan node
|
||||
*/
|
||||
private void recordCreationSanityCheckOnFilePlan(NodeRef filePlan)
|
||||
{
|
||||
if (filePlan == null)
|
||||
{
|
||||
// TODO .. eventually make the file plan parameter required
|
||||
|
||||
filePlan = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef doWork()
|
||||
{
|
||||
return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
|
||||
}
|
||||
}, AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// if the file plan is still null, raise an exception
|
||||
if (filePlan == null)
|
||||
{
|
||||
String msg = "Can not create record, because the default file plan can not be determined. Make sure at least one file plan has been created.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify that the provided file plan is actually a file plan
|
||||
if (!filePlanService.isFilePlan(filePlan))
|
||||
{
|
||||
String msg = "Can not create record, because the provided file plan node reference is not a file plan.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check the given node before trying to declare it as record
|
||||
*
|
||||
* @param nodeRef The reference of the node which will be declared as record
|
||||
*/
|
||||
private void recordCreationSanityCheckOnNode(NodeRef nodeRef)
|
||||
{
|
||||
// first we do a sanity check to ensure that the user has at least write permissions on the document
|
||||
if (extendedPermissionService.hasPermission(nodeRef, PermissionService.WRITE) != AccessStatus.ALLOWED)
|
||||
{
|
||||
String msg = "Can not create record from document, because the user " +
|
||||
AuthenticationUtil.getRunAsUser() +
|
||||
" does not have Write permissions on the doucment " +
|
||||
nodeRef.toString();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AccessDeniedException(msg);
|
||||
}
|
||||
|
||||
// do not create record if the node does not exist!
|
||||
if (!nodeService.exists(nodeRef))
|
||||
{
|
||||
String msg = "Can not create record, because " + nodeRef.toString() + " does not exist.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
|
||||
// TODO eventually we should support other types .. either as record folders or as composite records
|
||||
if (!dictionaryService.isSubClass(nodeService.getType(nodeRef), ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
String msg = "Can not create record, because " + nodeRef.toString() + " is not a supported type.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
|
||||
// Do not create record if the node is already a record!
|
||||
if (nodeService.hasAspect(nodeRef, ASPECT_RECORD))
|
||||
{
|
||||
String msg = "Can not create record, because " + nodeRef.toString() + " is already a record.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
|
||||
// We can not create records from working copies
|
||||
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY))
|
||||
{
|
||||
String msg = "Can node create record, because " + nodeRef.toString() + " is a working copy.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
|
||||
// can not create a record from a previously rejected one
|
||||
if (nodeService.hasAspect(nodeRef, ASPECT_RECORD_REJECTION_DETAILS))
|
||||
{
|
||||
String msg = "Can not create record, because " + nodeRef.toString() + " has previously been rejected.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
|
||||
// can't declare the record if the node is sync'ed
|
||||
if (nodeService.hasAspect(nodeRef, ASPECT_SYNCED))
|
||||
{
|
||||
String msg = "Can't declare as record, because " + nodeRef.toString() + " is synched content.";
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
throw new AlfrescoRuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecordFromCopy(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@@ -999,7 +1151,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
recordsManagementContainerType.enable();
|
||||
}
|
||||
|
||||
|
||||
// if versionable, then remove without destroying version history,
|
||||
// because it is being shared with the originating document
|
||||
behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE);
|
||||
@@ -1011,7 +1163,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE);
|
||||
}
|
||||
|
||||
|
||||
// make record
|
||||
makeRecord(record);
|
||||
|
||||
@@ -1060,8 +1212,8 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
private NodeRef getLatestVersionRecord(NodeRef nodeRef)
|
||||
{
|
||||
NodeRef versionRecord = null;
|
||||
|
||||
|
||||
|
||||
|
||||
recordableVersionService.createSnapshotVersion(nodeRef);
|
||||
// wire record up to previous record
|
||||
VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
|
||||
@@ -1739,7 +1891,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
record,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name));
|
||||
|
||||
|
||||
// recalculate disposition schedule for the record when linking it
|
||||
dispositionService.recalculateNextDispositionStep(record);
|
||||
}
|
||||
@@ -1758,10 +1910,10 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
private void validateLinkConditions(NodeRef record, NodeRef recordFolder)
|
||||
{
|
||||
// ensure that the linking record folders have compatible disposition schedules
|
||||
|
||||
|
||||
// get the origin disposition schedule for the record, not the calculated one
|
||||
DispositionSchedule recordDispositionSchedule = dispositionService.getOriginDispositionSchedule(record);
|
||||
|
||||
|
||||
if (recordDispositionSchedule != null)
|
||||
{
|
||||
DispositionSchedule recordFolderDispositionSchedule = dispositionService.getDispositionSchedule(recordFolder);
|
||||
@@ -1798,7 +1950,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
|
||||
// remove the link
|
||||
nodeService.removeChild(recordFolder, record);
|
||||
|
||||
|
||||
// recalculate disposition schedule for record after unlinking it
|
||||
dispositionService.recalculateNextDispositionStep(record);
|
||||
}
|
||||
@@ -1807,5 +1959,5 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
// can only unlink a record from a record folder
|
||||
throw new RecordLinkRuntimeException("Can only unlink a record from a record folder.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user