RM-4689 (Can delete all RM site content through Repository browser)

Manually backported following changes:

RM-4293
734c1b2a82

RM-4326
a4aac053a8
c6ca74ab26
This commit is contained in:
Tuna Aksoy
2017-06-12 16:17:24 +01:00
parent 1db145c228
commit 1712bac995
18 changed files with 831 additions and 111 deletions

3
.gitignore vendored
View File

@@ -38,3 +38,6 @@ test-output
/rm-enterprise/rm-automation-enterprise/root /rm-enterprise/rm-automation-enterprise/root
rm-automation/src/test/resources/webdriver.properties rm-automation/src/test/resources/webdriver.properties
/rm-community/rm-community-rest-api-explorer/overlays
/rm-enterprise/rm-enterprise-rest-api-explorer/overlays

View File

@@ -94,4 +94,35 @@
</property> </property>
</bean> </bean>
<bean id="rmDeleteTransferContainerCapability"
parent="declarativeCapability">
<property name="name" value="DeleteTransferContainer"/>
<property name="kinds">
<list>
<value>TRANSFER_CONTAINER</value>
</list>
</property>
<property name="conditions">
<map>
<entry key="capabilityCondition.filling" value="true"/>
</map>
</property>
<property name="private" value="true"/>
</bean>
<bean id="rmDeleteHoldContainerCapability"
parent="declarativeCapability">
<property name="name" value="DeleteHoldContainer"/>
<property name="kinds">
<list>
<value>HOLD_CONTAINER</value>
</list>
</property>
<property name="conditions">
<map>
<entry key="capabilityCondition.filling" value="true"/>
</map>
</property>
<property name="private" value="true"/>
</bean>
</beans> </beans>

View File

@@ -25,6 +25,8 @@
<ref bean="rmDeleteUnfiledRecordsContainerFolderCapability"/> <ref bean="rmDeleteUnfiledRecordsContainerFolderCapability"/>
<ref bean="rmDeleteHoldCapability"/> <ref bean="rmDeleteHoldCapability"/>
<ref bean="rmUnlinkFromRecordFolderCapability"/> <ref bean="rmUnlinkFromRecordFolderCapability"/>
<ref bean="rmDeleteTransferContainerCapability"/>
<ref bean="rmDeleteHoldContainerCapability"/>
</list> </list>
</property> </property>
</bean> </bean>

View File

@@ -76,6 +76,9 @@
<property name="filePlanService" ref="FilePlanService" /> <property name="filePlanService" ref="FilePlanService" />
<property name="recordFolderService" ref="RecordFolderService" /> <property name="recordFolderService" ref="RecordFolderService" />
<property name="filePlanRoleService" ref="FilePlanRoleService" /> <property name="filePlanRoleService" ref="FilePlanRoleService" />
<property name="unfilerRecordContainerType" ref="rma.unfiledRecordsContainer"/>
<property name="transferContainerType" ref="rma.transferContainer"/>
<property name="holdContainerType" ref="rma.holdContainer"/>
</bean> </bean>
<bean id="rma.holdContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.HoldContainerType" parent="rm.baseBehaviour"> <bean id="rma.holdContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.HoldContainerType" parent="rm.baseBehaviour">
@@ -84,6 +87,14 @@
<bean id="rma.transferContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferContainerType" parent="rm.baseBehaviour"> <bean id="rma.transferContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferContainerType" parent="rm.baseBehaviour">
</bean> </bean>
<bean id="rma.transfer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferType"
parent="rm.baseBehaviour"/>
<bean id="rma.unfiledRecordsContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.UnfiledRecordContainerType" parent="rm.baseBehaviour">
</bean>
<bean id="rma.unfiledRecordFolder" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.UnfiledRecordFolderType" parent="rm.baseBehaviour"/>
<bean id="rma.recordCategory" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.RecordCategoryType" parent="rm.baseBehaviour"> <bean id="rma.recordCategory" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.RecordCategoryType" parent="rm.baseBehaviour">
<property name="vitalRecordService" ref="VitalRecordService" /> <property name="vitalRecordService" ref="VitalRecordService" />
<property name="filePlanPermissionService" ref="FilePlanPermissionService" /> <property name="filePlanPermissionService" ref="FilePlanPermissionService" />
@@ -105,6 +116,7 @@
<property name="recordsManagementSearchService" ref="RecordsManagementSearchService" /> <property name="recordsManagementSearchService" ref="RecordsManagementSearchService" />
<property name="capabilityService" ref="CapabilityService" /> <property name="capabilityService" ref="CapabilityService" />
<property name="authorityService" ref="AuthorityService" /> <property name="authorityService" ref="AuthorityService" />
<property name="filePlanType" ref="rma.filePlan"/>
</bean> </bean>
<!-- rma model aspects --> <!-- rma model aspects -->

View File

@@ -173,6 +173,8 @@
<property name="recordFolderService" ref="RecordFolderService" /> <property name="recordFolderService" ref="RecordFolderService" />
<property name="nodeService" ref="nodeService"/> <property name="nodeService" ref="nodeService"/>
<property name="freezeService" ref="FreezeService"/> <property name="freezeService" ref="FreezeService"/>
<property name="transferContainerType" ref="rma.transferContainer"/>
<property name="transferType" ref="rma.transfer"/>
</bean> </bean>
<bean id="RmTransferService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="RmTransferService" class="org.springframework.aop.framework.ProxyFactoryBean">
@@ -579,9 +581,9 @@
parent="baseService"> parent="baseService">
<property name="nodeService" ref="nodeService"/> <property name="nodeService" ref="nodeService"/>
<property name="filePlanService" ref="filePlanService" /> <property name="filePlanService" ref="filePlanService" />
<property name="filePlanRoleService" ref="filePlanRoleService" /> <property name="filePlanRoleService" ref="filePlanRoleService" />
<property name="authorityService" ref="authorityService"/> <property name="authorityService" ref="authorityService"/>
<property name="permissionService" ref="permissionService"/> <property name="permissionService" ref="permissionService"/>
<property name="transactionService" ref="transactionService"/> <property name="transactionService" ref="transactionService"/>
</bean> </bean>

View File

@@ -27,15 +27,20 @@
package org.alfresco.module.org_alfresco_module_rm.model; package org.alfresco.module.org_alfresco_module_rm.model;
import com.google.common.collect.Sets;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.annotation.BehaviourRegistry; import org.alfresco.repo.policy.annotation.BehaviourRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
/** /**
* Convenient base class for behaviour beans. * Convenient base class for behaviour beans.
@@ -50,6 +55,12 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
/** Logger */ /** Logger */
protected static final Log LOGGER = LogFactory.getLog(BaseBehaviourBean.class); protected static final Log LOGGER = LogFactory.getLog(BaseBehaviourBean.class);
/**
* I18N
*/
protected static final String UNIQUE_CHILD_TYPE_ERROR = "rm.action.unique.child.type-error-message";
protected static final String MULTIPLE_CHILDREN_TYPE_ERROR = "rm.action.multiple.children.type-error-message";
/** behaviour filter */ /** behaviour filter */
protected BehaviourFilter behaviourFilter; protected BehaviourFilter behaviourFilter;
@@ -87,4 +98,52 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
return behaviours.get(name); return behaviours.get(name);
} }
/**
* Helper method that checks if the newly created child association complies with the RM rules
*
* @param parent the parent node
* @param childType the child node
* @param acceptedUniqueChildType a list of node types that are accepted as children of the provided parent only once
* @param acceptedMultipleChildType a list of node types that are accepted as children of the provided parent multiple times
* @throws IntegrityException if the child association doesn't comply with the RM rules
*/
protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List<QName> acceptedUniqueChildType, List<QName> acceptedMultipleChildType) throws IntegrityException
{
QName childType = getInternalNodeService().getType(child);
if (acceptedUniqueChildType.contains(childType))
{
// check the user is not trying to create multiple children of a type that is only accepted once
if (nodeService.getChildAssocs(parent, Sets.newHashSet(childType))
.size() > 1)
{
throw new IntegrityException(I18NUtil.getMessage(UNIQUE_CHILD_TYPE_ERROR), null);
}
}
else if (!acceptedMultipleChildType.contains(childType))
{
throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, childType), null);
}
}
/**
* Helper method that checks if the newly created child association is between the sub-types of accepted types.
*
* @param child the child node
* @param acceptedMultipleChildType a list of node types that are accepted as children of the provided parent multiple times
* @throws IntegrityException if the child association isn't between the sub-types of accepted types
*/
protected void validateNewChildAssociationSubTypesIncluded(NodeRef child, List<QName> acceptedMultipleChildType)
throws IntegrityException
{
QName childType = getInternalNodeService().getType(child);
for (QName type : acceptedMultipleChildType)
{
if (instanceOf(childType, type))
{
return;
}
}
//no match was found in sub-types of permitted types list
throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, childType), null);
}
} }

View File

@@ -27,7 +27,8 @@
package org.alfresco.module.org_alfresco_module_rm.model.rma.type; package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import org.alfresco.error.AlfrescoRuntimeException; import java.util.Arrays;
import java.util.List;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
@@ -36,6 +37,7 @@ import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
@@ -45,6 +47,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/** /**
* rma:filePlan behaviour bean * rma:filePlan behaviour bean
@@ -59,8 +62,13 @@ import org.alfresco.service.cmr.repository.NodeRef;
public class FilePlanType extends BaseBehaviourBean public class FilePlanType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy, implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnDeleteNodePolicy NodeServicePolicies.OnDeleteNodePolicy,
NodeServicePolicies.BeforeDeleteNodePolicy
{ {
private final static List<QName> ACCEPTED_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD_CONTAINER, TYPE_TRANSFER_CONTAINER, TYPE_UNFILED_RECORD_CONTAINER);
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY);
private static final String BEHAVIOUR_NAME = "onDeleteFilePlan";
/** file plan service */ /** file plan service */
private FilePlanService filePlanService; private FilePlanService filePlanService;
@@ -73,6 +81,21 @@ public class FilePlanType extends BaseBehaviourBean
/** file plan role service */ /** file plan role service */
private FilePlanRoleService filePlanRoleService; private FilePlanRoleService filePlanRoleService;
/**
* Unfiled Record Container Type behaviour bean
*/
private UnfiledRecordContainerType unfilerRecordContainerType;
/**
* Transfer Container Type behaviour bean
*/
private TransferContainerType transferContainerType;
/**
* Hold Container Type behaviour bean
*/
private HoldContainerType holdContainerType;
/** /**
* @return File plan service * @return File plan service
*/ */
@@ -137,6 +160,46 @@ public class FilePlanType extends BaseBehaviourBean
this.filePlanRoleService = filePlanRoleService; this.filePlanRoleService = filePlanRoleService;
} }
/**
* @param unfilerRecordContainerType - unfiled record container type behaviour bean
*/
public void setUnfilerRecordContainerType(UnfiledRecordContainerType unfilerRecordContainerType)
{
this.unfilerRecordContainerType = unfilerRecordContainerType;
}
/**
* @param transferContainerType - transfer container type behaviour bean
*/
public void setTransferContainerType(TransferContainerType transferContainerType)
{
this.transferContainerType = transferContainerType;
}
/**
* @param holdContainerType - hold container type behaviour bean
*/
public void setHoldContainerType(HoldContainerType holdContainerType)
{
this.holdContainerType = holdContainerType;
}
/**
* Disable the behaviours for this transaction
*/
public void disable()
{
getBehaviour(BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*/
public void enable()
{
getBehaviour(BEHAVIOUR_NAME).enable();
}
/** /**
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/ */
@@ -147,20 +210,17 @@ public class FilePlanType extends BaseBehaviourBean
@Override @Override
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
{ {
// ensure we are not trying to put content in the file plan root node // We need to automatically cast the created folder to category if it is a plain folder
NodeRef nodeRef = childAssocRef.getChildRef(); // This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes.
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT)) // Some modules use hidden files to store information (see RM-3283)
if (nodeService.getType(childAssocRef.getChildRef())
.equals(ContentModel.TYPE_FOLDER))
{ {
throw new AlfrescoRuntimeException("Operation failed, because you can't place content in the root of the file plan."); nodeService.setType(childAssocRef.getChildRef(), TYPE_RECORD_CATEGORY);
}
// ensure we are not trying to put a record folder in the root of the file plan
NodeRef parent = childAssocRef.getParentRef();
if (getFilePlanService().isFilePlan(parent) && getRecordFolderService().isRecordFolder(nodeRef))
{
throw new AlfrescoRuntimeException("Operation failed, because you can not place a record folder in the root of the file plan.");
} }
// check the created child is of an accepted type
validateNewChildAssociation(childAssocRef.getParentRef(), childAssocRef.getChildRef(), ACCEPTED_UNIQUE_CHILD_TYPES, ACCEPTED_NON_UNIQUE_CHILD_TYPES);
} }
/** /**
@@ -182,8 +242,8 @@ public class FilePlanType extends BaseBehaviourBean
{ {
// ensure rules are not inherited // ensure rules are not inherited
nodeService.addAspect(filePlan, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null); nodeService.addAspect(filePlan, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null);
// set the identifier // set the identifier
if (nodeService.getProperty(filePlan, PROP_IDENTIFIER) == null) if (nodeService.getProperty(filePlan, PROP_IDENTIFIER) == null)
{ {
String id = getIdentifierService().generateIdentifier(filePlan); String id = getIdentifierService().generateIdentifier(filePlan);
@@ -201,15 +261,40 @@ public class FilePlanType extends BaseBehaviourBean
/** /**
* @see org.alfresco.repo.node.NodeServicePolicies.OnDeleteNodePolicy#onDeleteNode(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) * @see org.alfresco.repo.node.NodeServicePolicies.OnDeleteNodePolicy#onDeleteNode(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/ */
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
@Override @Override
@Behaviour(kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.FIRST_EVENT,
name = BEHAVIOUR_NAME)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean archived) public void onDeleteNode(ChildAssociationRef childAssocRef, boolean archived)
{
unfilerRecordContainerType.enable();
transferContainerType.enable();
holdContainerType.enable();
throw new IntegrityException("Operation failed. Deletion of File Plan is not allowed.", null);
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
@Behaviour(kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.FIRST_EVENT)
public void beforeDeleteNode(NodeRef nodeRef)
{
unfilerRecordContainerType.disable();
transferContainerType.disable();
holdContainerType.disable();
}
@Behaviour(kind = BehaviourKind.CLASS,
policy = "alf:onDeleteNode",
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT)
public void onDeleteNodeOnCommit(ChildAssociationRef childAssocRef, boolean archived)
{ {
// tear down the file plan roles // tear down the file plan roles
getFilePlanRoleService().tearDownFilePlanRoles(childAssocRef.getChildRef()); getFilePlanRoleService().tearDownFilePlanRoles(childAssocRef.getChildRef());
unfilerRecordContainerType.enable();
transferContainerType.enable();
holdContainerType.enable();
} }
} }

View File

@@ -26,15 +26,19 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.model.rma.type; package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import java.util.Arrays;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind; import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.extensions.surf.util.I18NUtil;
/** /**
@@ -45,9 +49,29 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/ */
@BehaviourBean(defaultType = "rma:holdContainer") @BehaviourBean(defaultType = "rma:holdContainer")
public class HoldContainerType extends BaseBehaviourBean public class HoldContainerType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateNodePolicy implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnDeleteNodePolicy
{ {
private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container"; private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container";
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD);
private static final String DELETE_BEHAVIOUR_NAME = "onDeleteHoldContainer";
/**
* Disable the behaviours for this transaction
*/
public void disable()
{
getBehaviour(DELETE_BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*/
public void enable()
{
getBehaviour(DELETE_BEHAVIOUR_NAME).enable();
}
/** /**
* On every event * On every event
@@ -59,11 +83,8 @@ public class HoldContainerType extends BaseBehaviourBean
@Behaviour(kind = BehaviourKind.ASSOCIATION) @Behaviour(kind = BehaviourKind.ASSOCIATION)
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
{ {
// check the created child is of an accepted type
NodeRef nodeRef = childAssocRef.getChildRef(); validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES);
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) { throw new AlfrescoRuntimeException(
I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); }
} }
@Override @Override
@@ -74,4 +95,12 @@ public class HoldContainerType extends BaseBehaviourBean
I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); } I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); }
} }
@Override
@Behaviour(kind = BehaviourKind.CLASS,
name = DELETE_BEHAVIOUR_NAME)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
throw new IntegrityException("Operation failed. Deletion of Hold Container is not allowed.", null);
}
} }

View File

@@ -27,6 +27,9 @@
package org.alfresco.module.org_alfresco_module_rm.model.rma.type; package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
@@ -62,6 +65,9 @@ public class RecordCategoryType extends BaseBehaviourBean
NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnMoveNodePolicy NodeServicePolicies.OnMoveNodePolicy
{ {
private final static List<QName> ACCEPTED_UNIQUE_CHILD_TYPES = new ArrayList<QName>();
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY, TYPE_RECORD_FOLDER);
/** vital record service */ /** vital record service */
protected VitalRecordService vitalRecordService; protected VitalRecordService vitalRecordService;
@@ -107,17 +113,22 @@ public class RecordCategoryType extends BaseBehaviourBean
) )
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
{ {
// ensure content is not placed directly into a record category QName childType = nodeService.getType(childAssocRef.getChildRef());
NodeRef nodeRef = childAssocRef.getChildRef();
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT)) // 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 folders to store information (see RM-3283).
if (childType.equals(ContentModel.TYPE_FOLDER))
{ {
throw new AlfrescoRuntimeException("Operation failed, because you can't place content directly into a record category."); nodeService.setType(childAssocRef.getChildRef(), TYPE_RECORD_FOLDER);
} }
validateNewChildAssociation(childAssocRef.getParentRef(), childAssocRef.getChildRef(), ACCEPTED_UNIQUE_CHILD_TYPES, ACCEPTED_NON_UNIQUE_CHILD_TYPES);
if (bNew) if (bNew)
{ {
// setup the record folder // setup the record folder
recordFolderService.setupRecordFolder(nodeRef); recordFolderService.setupRecordFolder(childAssocRef.getChildRef());
} }
} }

View File

@@ -27,15 +27,20 @@
package org.alfresco.module.org_alfresco_module_rm.model.rma.type; package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import com.google.common.collect.Sets;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService; import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
@@ -54,6 +59,7 @@ import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
import org.springframework.extensions.surf.util.I18NUtil;
/** /**
* Behaviour associated with the RM Site type * Behaviour associated with the RM Site type
@@ -68,12 +74,14 @@ import org.alfresco.util.PropertyMap;
public class RmSiteType extends BaseBehaviourBean public class RmSiteType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateNodePolicy, implements NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy, NodeServicePolicies.OnUpdatePropertiesPolicy,
NodeServicePolicies.BeforeDeleteNodePolicy NodeServicePolicies.BeforeDeleteNodePolicy,
NodeServicePolicies.OnCreateChildAssociationPolicy
{ {
/** Constant values */ /** Constant values */
public static final String COMPONENT_DOCUMENT_LIBRARY = "documentLibrary"; public static final String COMPONENT_DOCUMENT_LIBRARY = "documentLibrary";
public static final String DEFAULT_SITE_NAME = "rm"; public static final String DEFAULT_SITE_NAME = "rm";
public static final QName DEFAULT_FILE_PLAN_TYPE = TYPE_FILE_PLAN; public static final QName DEFAULT_FILE_PLAN_TYPE = TYPE_FILE_PLAN;
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(ContentModel.TYPE_FOLDER);
/** Site service */ /** Site service */
protected SiteService siteService; protected SiteService siteService;
@@ -87,6 +95,8 @@ public class RmSiteType extends BaseBehaviourBean
/** Authority service */ /** Authority service */
private AuthorityService authorityService; private AuthorityService authorityService;
private FilePlanType filePlanType;
/** Map of file plan type's key'ed by corresponding site types */ /** Map of file plan type's key'ed by corresponding site types */
protected Map<QName, QName> mapFilePlanType = new HashMap<QName, QName>(3); protected Map<QName, QName> mapFilePlanType = new HashMap<QName, QName>(3);
@@ -123,6 +133,11 @@ public class RmSiteType extends BaseBehaviourBean
this.authorityService = authorityService; this.authorityService = authorityService;
} }
public void setFilePlanType(FilePlanType filePlanType)
{
this.filePlanType = filePlanType;
}
/** /**
* Registers a file plan type for a specific site type. * Registers a file plan type for a specific site type.
* *
@@ -292,7 +307,63 @@ public class RmSiteType extends BaseBehaviourBean
return null; return null;
} }
}); });
filePlanType.disable();
} }
} }
} }
/**
* Add the limitation of creating only one rma:filePlan or one dod:filePlan depending on the type of rm site.
* Also added the limitation of crating two cm:folder type under rm site.
* Other than this nothing can be created under rm site nodeRef
*
* @author Silviu Dinuta
* @since 2.6
*/
@Override
@Behaviour(kind = BehaviourKind.ASSOCIATION)
public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean isNewNode)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork()
{
final NodeRef child = childAssocRef.getChildRef();
final NodeRef parent = childAssocRef.getParentRef();
List<QName> acceptedUniqueChildTypes = new ArrayList<QName>();
SiteInfo siteInfo = siteService.getSite(parent);
acceptedUniqueChildTypes.add(getFilePlanType(siteInfo));
// check the created child is of an accepted type
validateNewChildAssociation(parent, child, acceptedUniqueChildTypes, ACCEPTED_NON_UNIQUE_CHILD_TYPES);
return null;
}
});
}
/**
* Overridden this because in this case we need to have multiple cm:folder types but not more than two of them.
* The two mentioned folders are created when rm site is created and one of them is Saved Searches and the other surf-config folder.
* After that creation of cm:folder should not be allowed under rm site node
*/
@Override
protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List<QName> acceptedUniqueChildType,
List<QName> acceptedMultipleChildType) throws IntegrityException
{
super.validateNewChildAssociation(parent, child, acceptedUniqueChildType, acceptedMultipleChildType);
// check the user is not trying to create more than 2 folders that are created by default.
if (nodeService.getChildAssocs(parent, Sets.newHashSet(ContentModel.TYPE_FOLDER)).size() > 2)
{
throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, ContentModel.TYPE_FOLDER), null);
}
}
@Behaviour(kind = BehaviourKind.CLASS,
policy = "alf:onDeleteNode",
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT)
public void onDeleteNodeOnCommit(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
filePlanType.enable();
}
} }

View File

@@ -30,6 +30,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind; import org.alfresco.repo.policy.annotation.BehaviourKind;
@@ -45,31 +46,61 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/ */
@BehaviourBean(defaultType = "rma:transferContainer") @BehaviourBean(defaultType = "rma:transferContainer")
public class TransferContainerType extends BaseBehaviourBean public class TransferContainerType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateNodePolicy implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnDeleteNodePolicy
{ {
private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container"; private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container";
private final static String MSG_ERROR_ADD_CHILD_TO_TRANSFER_CONTAINER = "rm.action.create.transfer.container.child-error-message";
private static final String BEHAVIOUR_NAME = "onCreateChildAssocsForTransferContainer";
private static final String DELETE_BEHAVIOUR_NAME = "onDeleteTransferContainer";
/** /**
* On every event * Disable the behaviours for this transaction
*/
public void disable()
{
getBehaviour(BEHAVIOUR_NAME).disable();
getBehaviour(DELETE_BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*/
public void enable()
{
getBehaviour(BEHAVIOUR_NAME).enable();
getBehaviour(DELETE_BEHAVIOUR_NAME).enable();
}
/**
* Prevent creating a node inside transfer container, this will be possible only through internal services in a controlled manner.
* *
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, * boolean)
* boolean)
*/ */
@Override @Override
@Behaviour(kind = BehaviourKind.ASSOCIATION) @Behaviour(kind = BehaviourKind.ASSOCIATION,
name = BEHAVIOUR_NAME)
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
{ {
// ensure not content to be added in Holdsfolder throw new IntegrityException(I18NUtil.getMessage(MSG_ERROR_ADD_CHILD_TO_TRANSFER_CONTAINER), null);
NodeRef nodeRef = childAssocRef.getChildRef();
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) { throw new AlfrescoRuntimeException(
I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); }
} }
@Override @Override
public void onCreateNode(ChildAssociationRef childAssocRef) public void onCreateNode(ChildAssociationRef childAssocRef)
{ {
NodeRef nodeRef = childAssocRef.getChildRef(); NodeRef nodeRef = childAssocRef.getChildRef();
if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) { throw new AlfrescoRuntimeException( if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true)
I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); } {
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER));
}
}
@Override
@Behaviour(kind = BehaviourKind.CLASS,
name = DELETE_BEHAVIOUR_NAME)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
throw new IntegrityException("Operation failed. Deletion of Transfer Container is not allowed.", null);
} }
} }

View File

@@ -0,0 +1,79 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* rma:transfer behaviour bean
*
* @author Silviu Dinuta
* @since 2.6
*/
@BehaviourBean(defaultType = "rma:transfer")
public class TransferType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy
{
private final static String MSG_ERROR_ADD_CHILD_TO_TRANSFER = "rm.action.create.transfer.child-error-message";
private static final String CREATE_CHILD_BEHAVIOUR_NAME = "onCreateChildAssocsForTransferType";
/**
* Disable the behaviours for this transaction
*/
public void disable()
{
getBehaviour(CREATE_CHILD_BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*/
public void enable()
{
getBehaviour(CREATE_CHILD_BEHAVIOUR_NAME).enable();
}
/**
* Prevent creating a node inside transfer folder, this will be possible only through internal services in a controlled manner.
*/
@Override
@Behaviour(kind = BehaviourKind.ASSOCIATION,
name = CREATE_CHILD_BEHAVIOUR_NAME)
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
{
throw new IntegrityException(I18NUtil.getMessage(MSG_ERROR_ADD_CHILD_TO_TRANSFER), null);
}
}

View File

@@ -0,0 +1,97 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import java.util.Arrays;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.namespace.QName;
/**
* rma:unfiledRecordContainer behaviour bean
*
* @author Silviu Dinuta
* @since 2.6
*/
@BehaviourBean(defaultType = "rma:unfiledRecordContainer")
public class UnfiledRecordContainerType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnDeleteNodePolicy
{
private static final String BEHAVIOUR_NAME = "onDeleteUnfiledRecordContainer";
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_UNFILED_RECORD_FOLDER, ContentModel.TYPE_CONTENT, TYPE_NON_ELECTRONIC_DOCUMENT);
/**
* Disable the behaviours for this transaction
*/
public void disable()
{
getBehaviour(BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*/
public void enable()
{
getBehaviour(BEHAVIOUR_NAME).enable();
}
@Override
@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);
}
@Override
@Behaviour(kind = BehaviourKind.CLASS,
name = BEHAVIOUR_NAME)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
throw new IntegrityException("Operation failed. Deletion of Unfiled Record Container is not allowed.", null);
}
}

View File

@@ -0,0 +1,70 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import java.util.Arrays;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.namespace.QName;
/**
* rma:unfiledRecordFolder behaviour bean
*
* @author Silviu Dinuta
* @since 2.6
*/
@BehaviourBean(defaultType = "rma:unfiledRecordFolder")
public class UnfiledRecordFolderType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy
{
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_UNFILED_RECORD_FOLDER, ContentModel.TYPE_CONTENT, TYPE_NON_ELECTRONIC_DOCUMENT);
@Override
@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);
}
}

View File

@@ -32,7 +32,6 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction;
@@ -41,6 +40,8 @@ import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService; import org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferContainerType;
import org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferType;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
@@ -87,6 +88,10 @@ public class TransferServiceImpl extends ServiceBaseImpl
/** Freeze Service */ /** Freeze Service */
protected FreezeService freezeService; protected FreezeService freezeService;
protected TransferContainerType transferContainerType;
protected TransferType transferType;
/** /**
* @param filePlanService file plan service * @param filePlanService file plan service
*/ */
@@ -127,6 +132,16 @@ public class TransferServiceImpl extends ServiceBaseImpl
this.freezeService = freezeService; this.freezeService = freezeService;
} }
public void setTransferContainerType(TransferContainerType transferContainerType)
{
this.transferContainerType = transferContainerType;
}
public void setTransferType(TransferType transferType)
{
this.transferType = transferType;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#transfer(NodeRef, boolean) * @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#transfer(NodeRef, boolean)
*/ */
@@ -164,11 +179,19 @@ public class TransferServiceImpl extends ServiceBaseImpl
} }
NodeRef transferContainer = filePlanService.getTransferContainer(root); NodeRef transferContainer = filePlanService.getTransferContainer(root);
transferNodeRef = nodeService.createNode(transferContainer,
ContentModel.ASSOC_CONTAINS, transferContainerType.disable();
QName.createQName(RM_URI, transferName), try
TYPE_TRANSFER, {
transferProps).getChildRef(); transferNodeRef = nodeService.createNode(transferContainer, ContentModel.ASSOC_CONTAINS,
QName.createQName(RM_URI, transferName), TYPE_TRANSFER, transferProps)
.getChildRef();
}
finally
{
transferContainerType.enable();
}
// Bind the hold node reference to the transaction // Bind the hold node reference to the transaction
AlfrescoTransactionSupport.bindResource(KEY_TRANSFER_NODEREF, transferNodeRef); AlfrescoTransactionSupport.bindResource(KEY_TRANSFER_NODEREF, transferNodeRef);
@@ -188,13 +211,17 @@ public class TransferServiceImpl extends ServiceBaseImpl
} }
// Link the record to the trasnfer object // Link the record to the trasnfer object
nodeService.addChild(transferNodeRef, transferType.disable();
nodeRef, try
ASSOC_TRANSFERRED, {
ASSOC_TRANSFERRED); nodeService.addChild(transferNodeRef, nodeRef, ASSOC_TRANSFERRED, ASSOC_TRANSFERRED);
// Set PDF indicator flag
// Set PDF indicator flag setPDFIndicationFlag(transferNodeRef, nodeRef);
setPDFIndicationFlag(transferNodeRef, nodeRef); }
finally
{
transferType.enable();
}
// Set the transferring indicator aspect // Set the transferring indicator aspect
nodeService.addAspect(nodeRef, ASPECT_TRANSFERRING, null); nodeService.addAspect(nodeRef, ASPECT_TRANSFERRING, null);
@@ -253,12 +280,12 @@ public class TransferServiceImpl extends ServiceBaseImpl
{ {
throw new AlfrescoRuntimeException("Could not complete a transfer that contains held folders"); throw new AlfrescoRuntimeException("Could not complete a transfer that contains held folders");
} }
if(freezeService.hasFrozenChildren(assoc.getChildRef())) if(freezeService.hasFrozenChildren(assoc.getChildRef()))
{ {
throw new AlfrescoRuntimeException("Cound not complete a transfer that contains folders with held children"); throw new AlfrescoRuntimeException("Cound not complete a transfer that contains folders with held children");
} }
markComplete(assoc.getChildRef(), accessionIndicator, transferLocation); markComplete(assoc.getChildRef(), accessionIndicator, transferLocation);
} }

View File

@@ -25,16 +25,15 @@
* #L% * #L%
* *
*/ */
package org.alfresco.module.org_alfresco_module_rm.test.integration.issue; package org.alfresco.module.org_alfresco_module_rm.test.integration.issue;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.springframework.extensions.surf.util.I18NUtil;
/** /**
* Unit test for RM-3341 .. can copy to hold and transfer folder * Unit test for RM-3341 .. can copy to hold and transfer folder
@@ -43,9 +42,6 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/ */
public class RM3341Test extends BaseRMTestCase public class RM3341Test extends BaseRMTestCase
{ {
private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container";
public void testCopyingContentsInHoldandTransfer() throws Exception public void testCopyingContentsInHoldandTransfer() throws Exception
{ {
doTestInTransaction(new Test<Void>() doTestInTransaction(new Test<Void>()
@@ -59,9 +55,9 @@ public class RM3341Test extends BaseRMTestCase
assertNotNull(transferContainer); assertNotNull(transferContainer);
assertEquals(AccessStatus.ALLOWED, assertEquals(AccessStatus.ALLOWED,
permissionService.hasPermission(holdContainer, RMPermissionModel.FILING)); permissionService.hasPermission(holdContainer, RMPermissionModel.FILING));
assertEquals(AccessStatus.ALLOWED, assertEquals(AccessStatus.ALLOWED,
permissionService.hasPermission(transferContainer, RMPermissionModel.FILING)); permissionService.hasPermission(transferContainer, RMPermissionModel.FILING));
return null; return null;
} }
@@ -79,13 +75,12 @@ public class RM3341Test extends BaseRMTestCase
try try
{ {
FileInfo copyInfo = fileFolderService.create(holdContainer, "test file", ContentModel.TYPE_CONTENT); fileFolderService.create(holdContainer, "test file", ContentModel.TYPE_CONTENT);
fail("This should have thrown an exception"); fail("This should have thrown an exception");
} }
catch (AlfrescoRuntimeException e) catch (IntegrityException e)
{ {
// ("Content can't be added to a record container. Use record folders to file content.") // ("Content can't be added to a hold container. Use record folders to file content.")
assertEquals(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER), e.getMsgId());
} }
return null; return null;
} }
@@ -109,10 +104,9 @@ public class RM3341Test extends BaseRMTestCase
fail("This should have thrown an exception"); fail("This should have thrown an exception");
} }
catch (AlfrescoRuntimeException e) catch (IntegrityException e)
{ {
// ("Content can't be added to a record container. Use record folders to file content.") // ("Content can't be added to a transfer container. Use record folders to file content.")
assertEquals(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER), e.getMsgId());
} }
return null; return null;
} }

View File

@@ -0,0 +1,125 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*
*/
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.repo.node.integrity.IntegrityException;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Test for RM-4293
*
* @author Silviu Dinuta
* @since 2.6
*/
public class RM4293Test extends BaseRMTestCase
{
public void testDeleteSpecialContainers() throws Exception
{
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
NodeRef holdContainer = filePlanService.getHoldContainer(filePlan);
assertNotNull(holdContainer);
try
{
fileFolderService.delete(holdContainer);
fail("This should have thrown an exception");
}
catch (IntegrityException e)
{
// ("Hold Container can't be deleted.")
}
return null;
}
});
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
NodeRef transferContainer = filePlanService.getTransferContainer(filePlan);
assertNotNull(transferContainer);
try
{
fileFolderService.delete(transferContainer);
fail("This should have thrown an exception");
}
catch (IntegrityException e)
{
// ("Transfer Container can't be deleted.")
}
return null;
}
});
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
NodeRef unfiledRecordContainer = filePlanService.getUnfiledContainer(filePlan);
assertNotNull(unfiledRecordContainer);
try
{
fileFolderService.delete(unfiledRecordContainer);
fail("This should have thrown an exception");
}
catch (IntegrityException e)
{
// ("Unfiled Record Container can't be deleted.")
}
return null;
}
});
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
try
{
fileFolderService.delete(filePlan);
fail("This should have thrown an exception");
}
catch (IntegrityException e)
{
// ("FilePlan can't be deleted.")
}
return null;
}
});
}
}

View File

@@ -26,11 +26,16 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.model.rma.type; package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
import org.alfresco.error.AlfrescoRuntimeException; import static org.mockito.Mockito.mock;
import org.alfresco.model.ContentModel; import static org.mockito.Mockito.when;
import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.junit.Test; import org.junit.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
@@ -42,40 +47,27 @@ import org.mockito.InjectMocks;
*/ */
public class TransferContainerTypeUnitTest extends BaseUnitTest public class TransferContainerTypeUnitTest extends BaseUnitTest
{ {
/** test object */ /**
private @InjectMocks TransferContainerType transferContainerType; * test object
*/
private @InjectMocks
TransferContainerType transferContainerType;
/** /**
* Having the Unfilled Record container and a folder having the aspect ASPECT_HIDDEN When adding a child association * Given that we try to add to transfer container,
* between the folder and the container Then the folder type shouldn't be renamed * Then IntegrityException is thrown.
*/ */
@Test(expected = AlfrescoRuntimeException.class) @Test(expected = IntegrityException.class)
public void testAddContentToTransferContainerTest() public void testAddToTransferContainerTest()
{ {
NodeRef transferContainer = generateNodeRef(TYPE_TRANSFER_CONTAINER, true);
NodeRef transferContainer = createTransferContainer(); QName type = AlfMock.generateQName();
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type);
/*
* When adding a child association between the folder and the container
*/
NodeRef record = generateNodeRef(ContentModel.TYPE_CONTENT);
ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.TYPE_CONTENT, transferContainer,
ContentModel.TYPE_CONTENT, record);
transferContainerType.onCreateChildAssociation(childAssoc, true);
ChildAssociationRef mockedChildAssoc = mock(ChildAssociationRef.class);
when(mockedChildAssoc.getChildRef()).thenReturn(nodeRef);
when(mockedChildAssoc.getParentRef()).thenReturn(transferContainer);
transferContainerType.onCreateChildAssociation(mockedChildAssoc, true);
} }
/**
* Generates a record management container
*
* @return reference to the generated container
*/
private NodeRef createTransferContainer()
{
NodeRef holdContainer = generateNodeRef(TYPE_TRANSFER, true);
return holdContainer;
}
} }