mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merged branch master into feature/RM-4113-Navigate-Clasification-Guide
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -100,7 +100,7 @@
|
||||
<properties>
|
||||
<alfresco.db.params>AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;MVCC=FALSE;LOCK_MODE=0;IGNORECASE=TRUE</alfresco.db.params>
|
||||
<maven.alfresco.includeDependencies>false</maven.alfresco.includeDependencies>
|
||||
<maven.build.sourceVersion>1.7</maven.build.sourceVersion>
|
||||
<maven.build.sourceVersion>1.8</maven.build.sourceVersion>
|
||||
<maven.build.testSourceVersion>1.8</maven.build.testSourceVersion>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
|
@@ -120,6 +120,7 @@
|
||||
<property name="configuredFilePermissions">
|
||||
<value>${rm.haspermissionmap.write}</value>
|
||||
</property>
|
||||
<property name="recordsManagementAuditService" ref="RecordsManagementAuditService" />
|
||||
</bean>
|
||||
<bean class="org.alfresco.util.BeanExtender">
|
||||
<property name="beanName" value="permissionServiceImpl"/>
|
||||
|
@@ -14,4 +14,7 @@ rm.audit.audit-clear=Audit Clear
|
||||
rm.audit.audit-view=Audit View
|
||||
rm.audit.trail-file-fail=We couldn't generate an audit report. Check the audit details and try again, or speak with your I.T. Dept.
|
||||
rm.audit.audit-report=Audit Report
|
||||
rm.audit.set-permission=Set Permission
|
||||
rm.audit.enable-inherit-permission=Inherited Permissions Switched On
|
||||
rm.audit.disable-inherit-permission=Inherited Permissions Switched Off
|
||||
recordable-version-config=Auto-Declare Options
|
@@ -462,6 +462,7 @@
|
||||
<property name="authorityService" ref="AuthorityService" />
|
||||
<property name="filePlanRoleService" ref="FilePlanRoleService" />
|
||||
<property name="filePlanService" ref="FilePlanService" />
|
||||
<property name="recordsManagementAuditService" ref="RecordsManagementAuditService" />
|
||||
</bean>
|
||||
|
||||
<bean id="FilePlanPermissionService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
@@ -980,6 +981,7 @@
|
||||
<![CDATA[
|
||||
org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.registerAuditEvent=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.auditEvent=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.auditOrUpdateEvent=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.clearAuditLog=RM_CAP.0.rma:filePlanComponent.DeleteAudit
|
||||
org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.getAuditTrail=RM_ALLOW
|
||||
org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.getAuditTrailFile=RM_ALLOW
|
||||
|
@@ -49,8 +49,6 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
|
||||
{
|
||||
public enum ReportFormat { HTML, JSON }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a list of audit events.
|
||||
*
|
||||
@@ -91,8 +89,8 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param eventName event name
|
||||
* @param before property values before event
|
||||
* @param after property values after event
|
||||
* @param before property values before event (this must be modifiable and may be changed by the method).
|
||||
* @param after property values after event (this must be modifiable and may be changed by the method).
|
||||
*/
|
||||
void auditEvent(NodeRef nodeRef,
|
||||
String eventName,
|
||||
@@ -104,8 +102,8 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param eventName event name
|
||||
* @param before property values before event
|
||||
* @param after property values after event
|
||||
* @param before property values before event (this must be modifiable and may be changed by the method).
|
||||
* @param after property values after event (this must be modifiable and may be changed by the method).
|
||||
* @param immediate true if event is to be audited immediately, false otherwise
|
||||
*/
|
||||
void auditEvent(NodeRef nodeRef,
|
||||
@@ -119,8 +117,8 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param eventName event name
|
||||
* @param before property values before event
|
||||
* @param after property values after event
|
||||
* @param before property values before event (this must be modifiable and may be changed by the method).
|
||||
* @param after property values after event (this must be modifiable and may be changed by the method).
|
||||
* @param immediate true if event is to be audited immediately, false otherwise
|
||||
* @param removeIfNoPropertyChanged true if event is not audited when there are no properties changed, false otherwise
|
||||
*/
|
||||
@@ -131,6 +129,21 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
|
||||
boolean immediate,
|
||||
boolean removeIfNoPropertyChanged);
|
||||
|
||||
/**
|
||||
* Supply incremental changes as part of an event. This will either create a new event or update the existing details to put any supplied properties into the map.
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param eventName event name
|
||||
* @param before additional property values before event (this must be modifiable and may be changed by the method).
|
||||
* @param after additional property values after event (this must be modifiable and may be changed by the method).
|
||||
* @param removeIfNoPropertyChanged true if event is not audited when there are no properties changed, false otherwise
|
||||
*/
|
||||
void auditOrUpdateEvent(NodeRef nodeRef,
|
||||
String eventName,
|
||||
Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after,
|
||||
boolean removeIfNoPropertyChanged);
|
||||
|
||||
/**
|
||||
* Determines whether the RM audit log is currently enabled.
|
||||
*
|
||||
@@ -153,7 +166,6 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
|
||||
*/
|
||||
void stopAuditLog(NodeRef filePlan);
|
||||
|
||||
|
||||
/**
|
||||
* Clears the RM audit.
|
||||
*
|
||||
|
@@ -294,8 +294,6 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param ignoredAuditProperties
|
||||
*/
|
||||
@@ -514,40 +512,87 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
|
||||
}
|
||||
else
|
||||
{
|
||||
Set<RMAuditNode> auditDetails = TransactionalResourceHelper.getSet(KEY_RM_AUDIT_NODE_RECORDS);
|
||||
AlfrescoTransactionSupport.bindListener(txnListener);
|
||||
|
||||
// RM-936: Eliminate multiple audit maps from being generated when events with the same name are required to be fired multiple times in the same transaction.
|
||||
// Check if auditDetails already contains an auditedNode with the same combination of nodeRef and eventName.
|
||||
boolean auditNodeAlreadyExists = false;
|
||||
for (RMAuditNode existingRMAuditNode : auditDetails)
|
||||
RMAuditNode existingEventNode = findExistingEventNode(nodeRef, eventName);
|
||||
if (existingEventNode != null)
|
||||
{
|
||||
if (existingRMAuditNode.getNodeRef().equals(nodeRef) && existingRMAuditNode.getEventName().equals(eventName))
|
||||
{
|
||||
// If there exists such an auditNode, update its 'after' properties with the latest set of properties and leave its 'before' properties unchanged so that it
|
||||
// retains the original set of properties. The first 'before' and last 'after' will be diff'ed when comes to building the auditMap later when the transaction
|
||||
// commits.
|
||||
existingRMAuditNode.setNodePropertiesAfter(after);
|
||||
auditNodeAlreadyExists = true;
|
||||
break;
|
||||
}
|
||||
// If there exists such an auditNode, update its 'after' properties with the latest set of properties and leave its 'before' properties unchanged so that it
|
||||
// retains the original set of properties. The first 'before' and last 'after' will be diff'ed when comes to building the auditMap later when the transaction
|
||||
// commits.
|
||||
existingEventNode.setNodePropertiesAfter(after);
|
||||
}
|
||||
|
||||
if (!auditNodeAlreadyExists)
|
||||
else
|
||||
{
|
||||
// Create a new auditNode if it doesn't already exist
|
||||
RMAuditNode auditedNode = new RMAuditNode();
|
||||
auditedNode.setNodeRef(nodeRef);
|
||||
auditedNode.setEventName(eventName);
|
||||
auditedNode.setNodePropertiesBefore(before);
|
||||
auditedNode.setNodePropertiesAfter(after);
|
||||
auditedNode.setRemoveIfNoPropertyChanged(removeIfNoPropertyChanged);
|
||||
|
||||
auditDetails.add(auditedNode);
|
||||
createAuditEventInTransaction(nodeRef, eventName, before, after, removeIfNoPropertyChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void auditOrUpdateEvent(NodeRef nodeRef, String eventName, Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after, boolean removeIfNoPropertyChanged)
|
||||
{
|
||||
RMAuditNode existingEventNode = findExistingEventNode(nodeRef, eventName);
|
||||
if (existingEventNode != null)
|
||||
{
|
||||
// Update the existing event to include all the new properties.
|
||||
existingEventNode.getNodePropertiesBefore().putAll(before);
|
||||
existingEventNode.getNodePropertiesAfter().putAll(after);
|
||||
}
|
||||
else
|
||||
{
|
||||
createAuditEventInTransaction(nodeRef, eventName, before, after, removeIfNoPropertyChanged);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new audit event for this transaction.
|
||||
*
|
||||
* @param nodeRef The node the audit message is about.
|
||||
* @param eventName The event.
|
||||
* @param before The before property map to use.
|
||||
* @param after The after property map to use.
|
||||
* @param removeIfNoPropertyChanged Whether to remove the event if no properties have changed.
|
||||
*/
|
||||
private void createAuditEventInTransaction(NodeRef nodeRef, String eventName, Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after, boolean removeIfNoPropertyChanged)
|
||||
{
|
||||
// Create a new auditNode.
|
||||
RMAuditNode auditedNode = new RMAuditNode();
|
||||
auditedNode.setNodeRef(nodeRef);
|
||||
auditedNode.setEventName(eventName);
|
||||
auditedNode.setNodePropertiesBefore(before);
|
||||
auditedNode.setNodePropertiesAfter(after);
|
||||
auditedNode.setRemoveIfNoPropertyChanged(removeIfNoPropertyChanged);
|
||||
|
||||
// Add it to the transaction.
|
||||
Set<RMAuditNode> auditDetails = TransactionalResourceHelper.getSet(KEY_RM_AUDIT_NODE_RECORDS);
|
||||
auditDetails.add(auditedNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an audit node if it already exists for the transaction.
|
||||
*
|
||||
* @param nodeRef The node the event is against.
|
||||
* @param eventName The name of the event.
|
||||
* @return The pre-existing event node, or null if none exists.
|
||||
*/
|
||||
private RMAuditNode findExistingEventNode(NodeRef nodeRef, String eventName)
|
||||
{
|
||||
AlfrescoTransactionSupport.bindListener(txnListener);
|
||||
Set<RMAuditNode> auditDetails = TransactionalResourceHelper.getSet(KEY_RM_AUDIT_NODE_RECORDS);
|
||||
for (RMAuditNode existingRMAuditNode : auditDetails)
|
||||
{
|
||||
if (existingRMAuditNode.getNodeRef().equals(nodeRef) && existingRMAuditNode.getEventName().equals(eventName))
|
||||
{
|
||||
return existingRMAuditNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to build audit map
|
||||
*
|
||||
|
@@ -234,6 +234,11 @@ public class RecordsManagementSearchBehaviour implements RecordsManagementModel
|
||||
TYPE_RECORD_FOLDER,
|
||||
new JavaBehaviour(this, "recordFolderCreate", NotificationFrequency.TRANSACTION_COMMIT));
|
||||
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onSetNodeType"),
|
||||
TYPE_RECORD_FOLDER,
|
||||
new JavaBehaviour(this, "convertedToOrFromRecordFolder", NotificationFrequency.TRANSACTION_COMMIT));
|
||||
|
||||
// Vital Records Review Details Rollup
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"),
|
||||
@@ -428,6 +433,30 @@ public class RecordsManagementSearchBehaviour implements RecordsManagementModel
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* On update type to or from record folder behaviour implementation
|
||||
* @param nodeRef the updated node
|
||||
* @param oldType the type the node had before update
|
||||
* @param newType the type the node has after update
|
||||
*/
|
||||
public void convertedToOrFromRecordFolder(final NodeRef nodeRef, final QName oldType, final QName newType)
|
||||
{
|
||||
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// If the node has been updated to a record folder
|
||||
if (newType.equals(TYPE_RECORD_FOLDER) && nodeService.exists(nodeRef))
|
||||
{
|
||||
applySearchAspect(nodeRef);
|
||||
setupDispositionScheduleProperties(nodeRef);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Helper method to setup the disposition schedule properties
|
||||
*
|
||||
|
@@ -65,7 +65,7 @@ import org.springframework.extensions.surf.util.I18NUtil;
|
||||
public class RecordComponentIdentifierAspect extends BaseBehaviourBean
|
||||
implements NodeServicePolicies.OnUpdatePropertiesPolicy,
|
||||
NodeServicePolicies.BeforeDeleteNodePolicy,
|
||||
NodeServicePolicies.OnCreateNodePolicy,
|
||||
NodeServicePolicies.OnAddAspectPolicy,
|
||||
CopyServicePolicies.OnCopyCompletePolicy
|
||||
{
|
||||
/** I18N */
|
||||
@@ -258,7 +258,7 @@ public class RecordComponentIdentifierAspect extends BaseBehaviourBean
|
||||
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
|
||||
)
|
||||
@Override
|
||||
public void onCreateNode(final ChildAssociationRef childAssocRef)
|
||||
public void onAddAspect(final NodeRef nodeRef, final QName aspectTypeQName)
|
||||
{
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Object>()
|
||||
{
|
||||
@@ -268,10 +268,9 @@ public class RecordComponentIdentifierAspect extends BaseBehaviourBean
|
||||
* When creating a new record the identifier is writable to allow the upload in multiple steps.
|
||||
* On transaction commit make the identifier read only (remove the editable aspect).
|
||||
*/
|
||||
NodeRef newNode = childAssocRef.getChildRef();
|
||||
if(nodeService.exists(newNode))
|
||||
if(nodeService.exists(nodeRef) && nodeService.hasAspect(nodeRef, aspectTypeQName))
|
||||
{
|
||||
nodeService.setProperty(newNode, RecordsManagementModel.PROP_ID_IS_TEMPORARILY_EDITABLE, false);
|
||||
nodeService.setProperty(nodeRef, RecordsManagementModel.PROP_ID_IS_TEMPORARILY_EDITABLE, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -137,7 +137,7 @@ public class RecordsManagementContainerType extends BaseBehaviourBean
|
||||
final NodeRef child = childAssocRef.getChildRef();
|
||||
if (nodeService.exists(child))
|
||||
{
|
||||
QName childType = nodeService.getType(child);
|
||||
QName childType = convertNodeToFileplanComponent(childAssocRef);
|
||||
|
||||
// We only care about "folder" or sub-types that are not hidden.
|
||||
// Some modules use hidden files to store information (see RM-3283)
|
||||
@@ -205,4 +205,39 @@ public class RecordsManagementContainerType extends BaseBehaviourBean
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converted the child node to a fileplan component
|
||||
* The conversion is needed here to be able to generate the identifier
|
||||
* If there is no conversion rule for the created type nothing happens and the current type is returned
|
||||
*
|
||||
* @param childAssocRef reference to the new association
|
||||
* @return the new type of the child node
|
||||
*/
|
||||
protected QName convertNodeToFileplanComponent(final ChildAssociationRef childAssocRef)
|
||||
{
|
||||
NodeRef child = childAssocRef.getChildRef();
|
||||
QName childType = nodeService.getType(child);
|
||||
QName parentType = nodeService.getType(childAssocRef.getParentRef());
|
||||
|
||||
if(childType.equals(ContentModel.TYPE_FOLDER))
|
||||
{
|
||||
if(parentType.equals(TYPE_FILE_PLAN))
|
||||
{
|
||||
nodeService.setType(child, TYPE_RECORD_CATEGORY);
|
||||
return TYPE_RECORD_CATEGORY;
|
||||
}
|
||||
if(parentType.equals(TYPE_RECORD_CATEGORY))
|
||||
{
|
||||
nodeService.setType(child, TYPE_RECORD_FOLDER);
|
||||
return TYPE_RECORD_FOLDER;
|
||||
}
|
||||
if(parentType.equals(TYPE_UNFILED_RECORD_CONTAINER) || parentType.equals(TYPE_UNFILED_RECORD_FOLDER))
|
||||
{
|
||||
nodeService.setType(child, TYPE_UNFILED_RECORD_FOLDER);
|
||||
return TYPE_UNFILED_RECORD_FOLDER;
|
||||
}
|
||||
}
|
||||
return childType;
|
||||
}
|
||||
}
|
||||
|
@@ -76,6 +76,15 @@ public class UnfiledRecordContainerType extends BaseBehaviourBean
|
||||
@Behaviour(kind = BehaviourKind.ASSOCIATION)
|
||||
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
|
||||
{
|
||||
// We need to automatically cast the created folder to record folder if it is a plain folder
|
||||
// This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes.
|
||||
// Some modules use hidden folder subtypes to store information (see RM-3283).
|
||||
QName childType = nodeService.getType(childAssocRef.getChildRef());
|
||||
if (childType.equals(ContentModel.TYPE_FOLDER))
|
||||
{
|
||||
nodeService.setType(childAssocRef.getChildRef(), TYPE_UNFILED_RECORD_FOLDER);
|
||||
}
|
||||
|
||||
// check the created child is of an accepted type
|
||||
validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES);
|
||||
}
|
||||
|
@@ -55,6 +55,15 @@ public class UnfiledRecordFolderType extends BaseBehaviourBean
|
||||
@Behaviour(kind = BehaviourKind.ASSOCIATION)
|
||||
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
|
||||
{
|
||||
// We need to automatically cast the created folder to record folder if it is a plain folder
|
||||
// This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes.
|
||||
// Some modules use hidden folder subtypes to store information (see RM-3283).
|
||||
QName childType = nodeService.getType(childAssocRef.getChildRef());
|
||||
if (childType.equals(ContentModel.TYPE_FOLDER))
|
||||
{
|
||||
nodeService.setType(childAssocRef.getChildRef(), TYPE_UNFILED_RECORD_FOLDER);
|
||||
}
|
||||
|
||||
// check the created child is of an accepted type
|
||||
validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES);
|
||||
}
|
||||
|
@@ -27,6 +27,9 @@
|
||||
|
||||
package org.alfresco.module.org_alfresco_module_rm.security;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority.EXTENDED_READER;
|
||||
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority.EXTENDED_WRITER;
|
||||
import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTION_COMMIT;
|
||||
import static org.alfresco.repo.policy.annotation.BehaviourKind.CLASS;
|
||||
import static org.alfresco.repo.security.authentication.AuthenticationUtil.getSystemUserName;
|
||||
@@ -34,10 +37,15 @@ import static org.alfresco.service.cmr.security.OwnableService.NO_OWNER;
|
||||
import static org.alfresco.util.ParameterCheck.mandatory;
|
||||
import static org.apache.commons.lang.BooleanUtils.isTrue;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.audit.event.AuditEvent;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
|
||||
@@ -48,6 +56,7 @@ import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.policy.annotation.Behaviour;
|
||||
import org.alfresco.repo.policy.annotation.BehaviourBean;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
@@ -73,6 +82,12 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
RMPermissionModel,
|
||||
NodeServicePolicies.OnMoveNodePolicy
|
||||
{
|
||||
/** An audit key for the set permission event. */
|
||||
private static final String AUDIT_SET_PERMISSION = "set-permission";
|
||||
|
||||
/** An namespace to use when constructing QNames to use for auditing changes to permissions. */
|
||||
private static final String AUDIT_NAMESPACE = "audit://permissions/";
|
||||
|
||||
/** Permission service */
|
||||
private PermissionService permissionService;
|
||||
|
||||
@@ -91,6 +106,9 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
/** File plan service */
|
||||
private FilePlanService filePlanService;
|
||||
|
||||
/** The RM audit service. */
|
||||
private RecordsManagementAuditService recordsManagementAuditService;
|
||||
|
||||
/** Logger */
|
||||
private static final Log LOGGER = LogFactory.getLog(FilePlanPermissionServiceImpl.class);
|
||||
|
||||
@@ -111,6 +129,16 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
NodeServicePolicies.OnMoveNodePolicy.QNAME,
|
||||
TYPE_RECORD_CATEGORY,
|
||||
new JavaBehaviour(this, "onMoveNode", TRANSACTION_COMMIT));
|
||||
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
recordsManagementAuditService.registerAuditEvent(new AuditEvent(AUDIT_SET_PERMISSION, "rm.audit.set-permission"));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,6 +255,16 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
this.filePlanService = filePlanService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the RM audit service.
|
||||
*
|
||||
* @param recordsManagementAuditService The RM audit service.
|
||||
*/
|
||||
public void setRecordsManagementAuditService(RecordsManagementAuditService recordsManagementAuditService)
|
||||
{
|
||||
this.recordsManagementAuditService = recordsManagementAuditService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService#setupRecordCategoryPermissions(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@@ -340,6 +378,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
|
||||
final boolean hasUserPermission = authenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Boolean>()
|
||||
{
|
||||
@Override
|
||||
public Boolean doWork()
|
||||
{
|
||||
return getPermissionService().hasPermission(nodeRef, RMPermissionModel.FILING) == AccessStatus.ALLOWED;
|
||||
@@ -350,6 +389,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
{
|
||||
authenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork()
|
||||
{
|
||||
getPermissionService().setPermission(nodeRef, user, RMPermissionModel.FILING, true);
|
||||
@@ -365,6 +405,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
* @param parent parent node reference
|
||||
* @param nodeRef child node reference
|
||||
*/
|
||||
@Override
|
||||
public void setupPermissions(final NodeRef parent, final NodeRef nodeRef)
|
||||
{
|
||||
mandatory("parent", parent);
|
||||
@@ -374,6 +415,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
{
|
||||
authenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object doWork()
|
||||
{
|
||||
// set inheritance
|
||||
@@ -480,6 +522,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
|
||||
authenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object doWork()
|
||||
{
|
||||
if (nodeService.exists(record) && nodeService.hasAspect(record, aspectTypeQName))
|
||||
@@ -506,6 +549,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
|
||||
authenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork()
|
||||
{
|
||||
NodeRef record = sourceAssocRef.getChildRef();
|
||||
@@ -547,6 +591,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#setPermission(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void setPermission(final NodeRef nodeRef, final String authority, final String permission)
|
||||
{
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
@@ -555,12 +600,18 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
|
||||
authenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork()
|
||||
{
|
||||
if (canPerformPermissionAction(nodeRef))
|
||||
{
|
||||
QName auditProperty = constructAuditEventName(authority, permission);
|
||||
Map<QName, Serializable> oldPermission = getCurrentPermissionForAuthority(nodeRef, authority, permission, auditProperty);
|
||||
// Set the permission on the node
|
||||
getPermissionService().setPermission(nodeRef, authority, permission, true);
|
||||
// Add an entry in the audit log.
|
||||
recordsManagementAuditService.auditOrUpdateEvent(nodeRef, AUDIT_SET_PERMISSION, oldPermission,
|
||||
new HashMap<>(singletonMap(auditProperty, (Serializable) true)), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -575,9 +626,31 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current permission on a node for an authority.
|
||||
*
|
||||
* @param nodeRef The node.
|
||||
* @param authority The authority.
|
||||
* @param auditProperty The QName used as the key in the returned map.
|
||||
* @return A map from the audit property to true or false depending on whether the user currently has permission.
|
||||
*/
|
||||
private Map<QName, Serializable> getCurrentPermissionForAuthority(NodeRef nodeRef, String authority, String permission, QName auditProperty)
|
||||
{
|
||||
Set<AccessPermission> allSetPermissions = getPermissionService().getAllSetPermissions(nodeRef);
|
||||
for (AccessPermission setPermission : allSetPermissions)
|
||||
{
|
||||
if (setPermission.getAuthority().equals(authority) && setPermission.getPermission().equals(permission))
|
||||
{
|
||||
return new HashMap<>(singletonMap(auditProperty, (Serializable) true));
|
||||
}
|
||||
}
|
||||
return new HashMap<>(singletonMap(auditProperty, (Serializable) false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#deletePermission(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void deletePermission(final NodeRef nodeRef, final String authority, final String permission)
|
||||
{
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
@@ -586,12 +659,18 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
|
||||
authenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork()
|
||||
{
|
||||
if (canPerformPermissionAction(nodeRef))
|
||||
{
|
||||
QName auditProperty = constructAuditEventName(authority, permission);
|
||||
Map<QName, Serializable> oldPermission = getCurrentPermissionForAuthority(nodeRef, authority, permission, auditProperty);
|
||||
// Delete permission on this node
|
||||
getPermissionService().deletePermission(nodeRef, authority, permission);
|
||||
// Add an entry in the audit log.
|
||||
recordsManagementAuditService.auditOrUpdateEvent(nodeRef, AUDIT_SET_PERMISSION, oldPermission,
|
||||
new HashMap<>(singletonMap(auditProperty, (Serializable) false)), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -606,6 +685,19 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a QName so that the authority and permission are visible in the log.
|
||||
*
|
||||
* @param authority The authority whose permission is being changed.
|
||||
* @param permission The name of the permission being changed.
|
||||
* @return A QName such that the local name will make sense to the end user.
|
||||
*/
|
||||
private QName constructAuditEventName(String authority, String permission)
|
||||
{
|
||||
QName auditProperty = QName.createQName(AUDIT_NAMESPACE, permission + " " + authority);
|
||||
return auditProperty;
|
||||
}
|
||||
|
||||
private boolean canPerformPermissionAction(NodeRef nodeRef)
|
||||
{
|
||||
return isFilePlanContainer(nodeRef) || isRecordFolder(nodeRef) || isRecord(nodeRef) || isTransfer(nodeRef) || isHold(nodeRef);
|
||||
|
@@ -36,12 +36,15 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.audit.event.AuditEvent;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
|
||||
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.role.FilePlanRoleService;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.permissions.AccessControlEntry;
|
||||
import org.alfresco.repo.security.permissions.AccessControlList;
|
||||
import org.alfresco.repo.security.permissions.processor.PermissionPostProcessor;
|
||||
@@ -67,6 +70,11 @@ import org.springframework.context.ApplicationEvent;
|
||||
*/
|
||||
public class ExtendedPermissionServiceImpl extends PermissionServiceImpl implements ExtendedPermissionService
|
||||
{
|
||||
/** An audit key for the enable permission inheritance event. */
|
||||
private static final String AUDIT_ENABLE_INHERIT_PERMISSION = "enable-inherit-permission";
|
||||
/** An audit key for the disable permission inheritance event. */
|
||||
private static final String AUDIT_DISABLE_INHERIT_PERMISSION = "disable-inherit-permission";
|
||||
|
||||
/** Writers simple cache */
|
||||
protected SimpleCache<Serializable, Set<String>> writersCache;
|
||||
|
||||
@@ -90,6 +98,26 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl impleme
|
||||
/** Permission processor registry */
|
||||
private PermissionProcessorRegistry permissionProcessorRegistry;
|
||||
|
||||
/** The RM audit service. */
|
||||
private RecordsManagementAuditService recordsManagementAuditService;
|
||||
|
||||
/** {@inheritDoc} Register the audit events. */
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
recordsManagementAuditService.registerAuditEvent(new AuditEvent(AUDIT_ENABLE_INHERIT_PERMISSION, "rm.audit.enable-inherit-permission"));
|
||||
recordsManagementAuditService.registerAuditEvent(new AuditEvent(AUDIT_DISABLE_INHERIT_PERMISSION, "rm.audit.disable-inherit-permission"));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file plan service
|
||||
*
|
||||
@@ -120,6 +148,16 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl impleme
|
||||
this.permissionProcessorRegistry = permissionProcessorRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the RM audit service.
|
||||
*
|
||||
* @param recordsManagementAuditService The RM audit service.
|
||||
*/
|
||||
public void setRecordsManagementAuditService(RecordsManagementAuditService recordsManagementAuditService)
|
||||
{
|
||||
this.recordsManagementAuditService = recordsManagementAuditService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.security.permissions.impl.PermissionServiceImpl#setAnyDenyDenies(boolean)
|
||||
*/
|
||||
@@ -300,6 +338,7 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl impleme
|
||||
* @param aclId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getReadersDenied(Long aclId)
|
||||
{
|
||||
AccessControlList acl = aclDaoComponent.getAccessControlList(aclId);
|
||||
@@ -335,6 +374,7 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl impleme
|
||||
/**
|
||||
* @see org.alfresco.repo.security.permissions.impl.ExtendedPermissionService#getWriters(java.lang.Long)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getWriters(Long aclId)
|
||||
{
|
||||
AccessControlList acl = aclDaoComponent.getAccessControlList(aclId);
|
||||
@@ -378,7 +418,12 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl impleme
|
||||
{
|
||||
setPermission(nodeRef, adminRole, RMPermissionModel.FILING, true);
|
||||
}
|
||||
super.setInheritParentPermissions(nodeRef, inheritParentPermissions);
|
||||
if (inheritParentPermissions != super.getInheritParentPermissions(nodeRef))
|
||||
{
|
||||
super.setInheritParentPermissions(nodeRef, inheritParentPermissions);
|
||||
String auditEvent = (inheritParentPermissions ? AUDIT_ENABLE_INHERIT_PERMISSION : AUDIT_DISABLE_INHERIT_PERMISSION);
|
||||
recordsManagementAuditService.auditEvent(nodeRef, auditEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -28,6 +28,7 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.issue;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.springframework.extensions.webscripts.GUID;
|
||||
|
||||
/**
|
||||
@@ -49,13 +50,30 @@ public class RM4619Test extends BaseRMTestCase
|
||||
*/
|
||||
public void testConvertFolderToCategory() throws Exception
|
||||
{
|
||||
/*
|
||||
* Create a folder in the unfiled record container and check it is immediately converted
|
||||
*/
|
||||
final NodeRef recordCategory = doTestInTransaction(new Test<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef run() throws Exception
|
||||
{
|
||||
FileInfo info = fileFolderService.create(filePlan, GUID.generate(), TYPE_FOLDER);
|
||||
assertEquals(TYPE_RECORD_CATEGORY, info.getType());
|
||||
assertNotNull(info.getProperties().get(PROP_IDENTIFIER));
|
||||
return info.getNodeRef();
|
||||
}
|
||||
}, ADMIN_USER);
|
||||
|
||||
/*
|
||||
* Check that when the transaction ends the identifier is no longer editable
|
||||
*/
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
FileInfo info = fileFolderService.create(filePlan, GUID.generate(), TYPE_FOLDER);
|
||||
assertEquals(info.getType(), TYPE_RECORD_CATEGORY);
|
||||
assertFalse((Boolean)nodeService.getProperty(recordCategory, PROP_ID_IS_TEMPORARILY_EDITABLE));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -69,13 +87,101 @@ public class RM4619Test extends BaseRMTestCase
|
||||
*/
|
||||
public void testConvertFolderToRecordFolder() throws Exception
|
||||
{
|
||||
/*
|
||||
* Create a folder in a record category and check it is immediately converted
|
||||
*/
|
||||
final NodeRef recordFolder = doTestInTransaction(new Test<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef run() throws Exception
|
||||
{
|
||||
FileInfo info = fileFolderService.create(rmContainer, GUID.generate(), TYPE_FOLDER);
|
||||
assertEquals(TYPE_RECORD_FOLDER, info.getType());
|
||||
assertNotNull(info.getProperties().get(PROP_IDENTIFIER));
|
||||
return info.getNodeRef();
|
||||
}
|
||||
}, ADMIN_USER);
|
||||
|
||||
/*
|
||||
* Check that when the transaction ends the identifier is no longer editable
|
||||
* And the record folder has the ASPECT_RM_SEARCH aspect
|
||||
*/
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
FileInfo info = fileFolderService.create(rmContainer, GUID.generate(), TYPE_FOLDER);
|
||||
assertEquals(info.getType(), TYPE_RECORD_FOLDER);
|
||||
assertFalse((Boolean)nodeService.getProperty(recordFolder, PROP_ID_IS_TEMPORARILY_EDITABLE));
|
||||
assertTrue(nodeService.hasAspect(recordFolder, ASPECT_RM_SEARCH));
|
||||
return null;
|
||||
}
|
||||
|
||||
}, ADMIN_USER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the RM site is created
|
||||
* When we create a regular folder in the unfiled record container
|
||||
* Then the folder is immediately converted to a unfiled record folder
|
||||
*
|
||||
* And when we create another regular folder in that unfiled record folder
|
||||
* Then the folder is also immediately converted to a unfiled record folder
|
||||
*/
|
||||
public void testConvertFolderToUnfiledRecordFolder() throws Exception
|
||||
{
|
||||
/*
|
||||
* Create a folder in the unfiled record container and check it is immediately converted
|
||||
*/
|
||||
final NodeRef folder1 = doTestInTransaction(new Test<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef run() throws Exception
|
||||
{
|
||||
FileInfo folder = fileFolderService.create(unfiledContainer, GUID.generate(), TYPE_FOLDER);
|
||||
assertEquals(TYPE_UNFILED_RECORD_FOLDER, folder.getType());
|
||||
assertNotNull(folder.getProperties().get(PROP_IDENTIFIER));
|
||||
return folder.getNodeRef();
|
||||
}
|
||||
}, ADMIN_USER);
|
||||
|
||||
/*
|
||||
* Check that when the transaction ends the identified is no longer editable
|
||||
*/
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
assertFalse((Boolean)nodeService.getProperty(folder1, PROP_ID_IS_TEMPORARILY_EDITABLE));
|
||||
return null;
|
||||
}
|
||||
|
||||
}, ADMIN_USER);
|
||||
|
||||
/*
|
||||
* Create a folder in the unfiled record folder and check it is immediately converted
|
||||
*/
|
||||
final NodeRef folder2 = doTestInTransaction(new Test<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef run() throws Exception
|
||||
{
|
||||
FileInfo folder = fileFolderService.create(folder1, GUID.generate(), TYPE_FOLDER);
|
||||
assertEquals(TYPE_UNFILED_RECORD_FOLDER, folder.getType());
|
||||
assertNotNull(folder.getProperties().get(PROP_IDENTIFIER));
|
||||
return folder.getNodeRef();
|
||||
}
|
||||
}, ADMIN_USER);
|
||||
|
||||
/*
|
||||
* Check that when the transaction ends the identified is no longer editable
|
||||
*/
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
assertFalse((Boolean)nodeService.getProperty(folder2, PROP_ID_IS_TEMPORARILY_EDITABLE));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -37,6 +38,7 @@ import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
|
||||
import org.alfresco.module.org_alfresco_module_rm.test.util.TestModel;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
|
||||
@@ -50,29 +52,117 @@ public class RecordsManagementContainerTypeUnitTest extends BaseUnitTest
|
||||
/** test object */
|
||||
private @InjectMocks RecordsManagementContainerType recordManagementContainerType;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
super.before();
|
||||
|
||||
when(mockedDictionaryService.isSubClass(ContentModel.TYPE_FOLDER, ContentModel.TYPE_FOLDER)).thenReturn(true);
|
||||
when(mockedDictionaryService.isSubClass(ContentModel.TYPE_FOLDER, ContentModel.TYPE_SYSTEM_FOLDER)).thenReturn(false);
|
||||
|
||||
when(mockedDictionaryService.isSubClass(TestModel.NOT_RM_FOLDER_TYPE, ContentModel.TYPE_FOLDER)).thenReturn(true);
|
||||
when(mockedDictionaryService.isSubClass(TestModel.NOT_RM_FOLDER_TYPE, ContentModel.TYPE_SYSTEM_FOLDER)).thenReturn(false);
|
||||
|
||||
when(mockedDictionaryService.isSubClass(TYPE_RECORD_CATEGORY, ContentModel.TYPE_FOLDER)).thenReturn(true);
|
||||
when(mockedDictionaryService.isSubClass(TYPE_RECORD_CATEGORY, ContentModel.TYPE_SYSTEM_FOLDER)).thenReturn(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Having the Unfilled Record container and a folder having the aspect ASPECT_HIDDEN
|
||||
* Having the Unfilled Record container and a non RM folder subtype node
|
||||
* When adding a child association between the folder and the container
|
||||
* Then the new folder should not be altered
|
||||
*
|
||||
* Outlook creates a hidden folder subtype to store attachments and we don't want to change the type of those folders
|
||||
*/
|
||||
@Test
|
||||
public void testAddHiddenFolderToRMContainer()
|
||||
public void testAddNonRMFolderSubtypeToRMContainer()
|
||||
{
|
||||
/* Having a RM container and a folder with ASPECT_HIDDEN applied */
|
||||
/* Having a RM container and a non RM folder subtype node */
|
||||
NodeRef rmContainer = generateRMContainer();
|
||||
NodeRef rmFolder = generateFolderNode(true);
|
||||
NodeRef folder = generateNonRmFolderSubtypeNode();
|
||||
|
||||
/*
|
||||
* When adding a child association between the folder and the container
|
||||
*/
|
||||
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, rmContainer, ContentModel.ASSOC_CONTAINS, rmFolder);
|
||||
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, rmContainer, ContentModel.ASSOC_CONTAINS, folder);
|
||||
recordManagementContainerType.onCreateChildAssociation(childAssoc, true);
|
||||
|
||||
/* The type should not be changed and no aspects should be added */
|
||||
verify(mockedNodeService, never()).setType(any(), any());
|
||||
verify(mockedNodeService, never()).addAspect(any(), any(), any());
|
||||
}
|
||||
|
||||
/**
|
||||
* Having the fileplan and a non RM folder node
|
||||
* When adding a child association between the fileplan and the folder
|
||||
* Then the new folder should be converted to a record category
|
||||
*/
|
||||
@Test
|
||||
public void testAddFolderInFilePlan()
|
||||
{
|
||||
NodeRef fileplan = generateNodeRef();
|
||||
when(mockedNodeService.getType(fileplan)).thenReturn(TYPE_FILE_PLAN);
|
||||
NodeRef folder = generateNonRmFolderNode();
|
||||
|
||||
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, fileplan, ContentModel.ASSOC_CONTAINS, folder);
|
||||
recordManagementContainerType.onCreateChildAssociation(childAssoc, true);
|
||||
|
||||
verify(mockedNodeService).setType(folder, TYPE_RECORD_CATEGORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Having a record category and a non RM folder node
|
||||
* When adding a child association between the record category and the folder
|
||||
* Then the new folder should be converted to a record folder
|
||||
*/
|
||||
@Test
|
||||
public void testAddFolderInRecordCategory()
|
||||
{
|
||||
NodeRef category = generateNodeRef();
|
||||
when(mockedNodeService.getType(category)).thenReturn(TYPE_RECORD_CATEGORY);
|
||||
NodeRef folder = generateNonRmFolderNode();
|
||||
|
||||
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, category, ContentModel.ASSOC_CONTAINS, folder);
|
||||
recordManagementContainerType.onCreateChildAssociation(childAssoc, true);
|
||||
|
||||
verify(mockedNodeService).setType(folder, TYPE_RECORD_FOLDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Having an unfiled record container and a non RM folder node
|
||||
* When adding a child association between the container and the folder
|
||||
* Then the new folder should be converted to a unfiled record folder
|
||||
*/
|
||||
@Test
|
||||
public void testAddFolderInUnfiledRecordContainer()
|
||||
{
|
||||
NodeRef unfiledRecordContainer = generateNodeRef();
|
||||
when(mockedNodeService.getType(unfiledRecordContainer)).thenReturn(TYPE_UNFILED_RECORD_CONTAINER);
|
||||
NodeRef folder = generateNonRmFolderNode();
|
||||
|
||||
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, unfiledRecordContainer, ContentModel.ASSOC_CONTAINS, folder);
|
||||
recordManagementContainerType.onCreateChildAssociation(childAssoc, true);
|
||||
|
||||
verify(mockedNodeService).setType(folder, TYPE_UNFILED_RECORD_FOLDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Having an unfiled record folder and a non RM folder node
|
||||
* When adding a child association between the unfiled record folder and the regular folder
|
||||
* Then the new folder should be converted to a unfiled record folder
|
||||
*/
|
||||
@Test
|
||||
public void testAddFolderInUnfiledRecordFolder()
|
||||
{
|
||||
NodeRef unfiledRecordFolder = generateNodeRef();
|
||||
when(mockedNodeService.getType(unfiledRecordFolder)).thenReturn(TYPE_UNFILED_RECORD_FOLDER);
|
||||
NodeRef folder = generateNonRmFolderNode();
|
||||
|
||||
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, unfiledRecordFolder, ContentModel.ASSOC_CONTAINS, folder);
|
||||
recordManagementContainerType.onCreateChildAssociation(childAssoc, true);
|
||||
|
||||
verify(mockedNodeService).setType(folder, TYPE_UNFILED_RECORD_FOLDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a record management container
|
||||
* @return reference to the generated container
|
||||
@@ -81,39 +171,33 @@ public class RecordsManagementContainerTypeUnitTest extends BaseUnitTest
|
||||
{
|
||||
NodeRef rmContainer = generateNodeRef();
|
||||
when(mockedNodeService.getType(rmContainer)).thenReturn(RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER);
|
||||
when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER, TYPE_FILE_PLAN)).thenReturn(false);
|
||||
return rmContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a folder node
|
||||
* @param hasHiddenAspect does the folder node have the aspect ASPECT_HIDDEN
|
||||
* Generates a non RM folder subtype node
|
||||
* @return reference to the created folder
|
||||
*/
|
||||
private NodeRef generateFolderNode(boolean hasHiddenAspect)
|
||||
private NodeRef generateNonRmFolderSubtypeNode()
|
||||
{
|
||||
NodeRef rmFolder = generateNodeRef();
|
||||
when(mockedDictionaryService.isSubClass(ContentModel.TYPE_FOLDER, ContentModel.TYPE_FOLDER)).thenReturn(true);
|
||||
when(mockedDictionaryService.isSubClass(ContentModel.TYPE_FOLDER, ContentModel.TYPE_SYSTEM_FOLDER)).thenReturn(false);
|
||||
when(mockedNodeService.getType(rmFolder)).thenReturn(ContentModel.TYPE_FOLDER);
|
||||
when(mockedNodeService.exists(rmFolder)).thenReturn(true);
|
||||
when(mockedNodeService.hasAspect(rmFolder, ContentModel.ASPECT_HIDDEN)).thenReturn(hasHiddenAspect);
|
||||
when(mockedNodeService.hasAspect(rmFolder, ASPECT_FILE_PLAN_COMPONENT)).thenReturn(false);
|
||||
return rmFolder;
|
||||
NodeRef nonRmFolder = generateNodeRef();
|
||||
|
||||
when(mockedNodeService.getType(nonRmFolder)).thenReturn(TestModel.NOT_RM_FOLDER_TYPE);
|
||||
when(mockedNodeService.exists(nonRmFolder)).thenReturn(true);
|
||||
when(mockedNodeService.hasAspect(nonRmFolder, ASPECT_FILE_PLAN_COMPONENT)).thenReturn(false);
|
||||
return nonRmFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a folder node
|
||||
* Generates a non RM folder node
|
||||
* @return reference to the created folder
|
||||
*/
|
||||
private NodeRef generateNonRmFolderNode()
|
||||
{
|
||||
NodeRef nonRmFolder = generateNodeRef();
|
||||
when(mockedDictionaryService.isSubClass(TestModel.NOT_RM_FOLDER_TYPE, ContentModel.TYPE_FOLDER)).thenReturn(true);
|
||||
when(mockedNodeService.getType(nonRmFolder)).thenReturn(TestModel.NOT_RM_FOLDER_TYPE);
|
||||
when(mockedNodeService.exists(nonRmFolder)).thenReturn(true);
|
||||
when(mockedNodeService.hasAspect(nonRmFolder, ContentModel.ASPECT_HIDDEN)).thenReturn(false);
|
||||
when(mockedNodeService.hasAspect(nonRmFolder, ASPECT_FILE_PLAN_COMPONENT)).thenReturn(false);
|
||||
return nonRmFolder;
|
||||
NodeRef regularFolder = generateNodeRef();
|
||||
when(mockedNodeService.getType(regularFolder)).thenReturn(ContentModel.TYPE_FOLDER);
|
||||
when(mockedNodeService.exists(regularFolder)).thenReturn(true);
|
||||
when(mockedNodeService.hasAspect(regularFolder, ASPECT_FILE_PLAN_COMPONENT)).thenReturn(false);
|
||||
return regularFolder;
|
||||
}
|
||||
}
|
||||
|
@@ -12,8 +12,8 @@
|
||||
|
||||
<properties>
|
||||
<alfresco.api.explorer.version>1.4</alfresco.api.explorer.version>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
Reference in New Issue
Block a user