mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM-1440: Edit Non Record Metadata capability is required to file a record
* can now file an electronic record with only CreateRecord capability * tidied up some of the policy code as I went * integration test * non-electronic records to follow git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@73961 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -61,7 +61,7 @@ public class ChangeOrDeleteReferencesCapability extends DeclarativeCapability
|
||||
else
|
||||
{
|
||||
if (checkConditions(source) &&
|
||||
checkPermissions(source))
|
||||
checkPermissions(source))
|
||||
{
|
||||
return AccessDecisionVoter.ACCESS_GRANTED;
|
||||
}
|
||||
|
@@ -67,19 +67,18 @@ public class CreateCapability extends DeclarativeCapability
|
||||
@Override
|
||||
public int evaluate(NodeRef nodeRef)
|
||||
{
|
||||
return evaluate(nodeRef, null, null, null);
|
||||
return evaluate(nodeRef, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate capability.
|
||||
*
|
||||
* @param destination
|
||||
* @param linkee
|
||||
* @param type
|
||||
* @param assocType
|
||||
* @param destination destination node reference
|
||||
* @param linkee linkee node reference, can be null
|
||||
* @param assocType association type, can be null
|
||||
* @return
|
||||
*/
|
||||
public int evaluate(NodeRef destination, NodeRef linkee, QName type, QName assocType)
|
||||
public int evaluate(NodeRef destination, NodeRef linkee, QName assocType)
|
||||
{
|
||||
if (linkee != null)
|
||||
{
|
||||
@@ -95,8 +94,9 @@ public class CreateCapability extends DeclarativeCapability
|
||||
{
|
||||
if (linkee == null)
|
||||
{
|
||||
if (recordService.isRecord(destination) && !recordService.isDeclared(destination) &&
|
||||
permissionService.hasPermission(destination, RMPermissionModel.FILE_RECORDS) == AccessStatus.ALLOWED)
|
||||
if (recordService.isRecord(destination) &&
|
||||
!recordService.isDeclared(destination) &&
|
||||
permissionService.hasPermission(destination, RMPermissionModel.FILE_RECORDS) == AccessStatus.ALLOWED)
|
||||
{
|
||||
return AccessDecisionVoter.ACCESS_GRANTED;
|
||||
}
|
||||
|
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.capability.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCompositeCapability;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Update properties capability.
|
||||
*
|
||||
* @author andyh
|
||||
*/
|
||||
public class UpdatePropertiesCapability extends DeclarativeCompositeCapability
|
||||
{
|
||||
/**
|
||||
* Evaluate capability, taking into account the protected properties.
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param properties updated properties, if no null
|
||||
*/
|
||||
public int evaluate(NodeRef nodeRef, Map<QName, Serializable> properties)
|
||||
{
|
||||
// if ((properties != null) && (voter.includesProtectedPropertyChange(nodeRef, properties)))
|
||||
// {
|
||||
// return AccessDecisionVoter.ACCESS_DENIED;
|
||||
// }
|
||||
|
||||
return evaluate(nodeRef);
|
||||
}
|
||||
}
|
@@ -30,11 +30,14 @@ import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* RM security configuration definition.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @since 2.1
|
||||
*/
|
||||
public class ConfigAttributeDefinition
|
||||
{
|
||||
/** allowable RM security configurations */
|
||||
public static final String RM = "RM";
|
||||
public static final String RM_ALLOW = "RM_ALLOW";
|
||||
public static final String RM_DENY = "RM_DENY";
|
||||
@@ -42,18 +45,30 @@ public class ConfigAttributeDefinition
|
||||
public static final String RM_ABSTAIN = "RM_ABSTAIN";
|
||||
public static final String RM_QUERY = "RM_QUERY";
|
||||
|
||||
/** security type */
|
||||
private String typeString;
|
||||
|
||||
/** policy name */
|
||||
private String policyName;
|
||||
|
||||
/** simple permission reference */
|
||||
private SimplePermissionReference required;
|
||||
|
||||
/** parameter position map */
|
||||
private Map<Integer, Integer> parameters = new HashMap<Integer, Integer>(2, 1.0f);
|
||||
|
||||
/** is parent */
|
||||
private boolean parent = false;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param attr configuration attribute instance
|
||||
* @param namespacePrefixResolver namespace prefix resolver
|
||||
*/
|
||||
public ConfigAttributeDefinition(ConfigAttribute attr, NamespacePrefixResolver namespacePrefixResolver)
|
||||
{
|
||||
// tokenize configuration string
|
||||
StringTokenizer st = new StringTokenizer(attr.getAttribute(), ".", false);
|
||||
if (st.countTokens() < 1)
|
||||
{
|
||||
@@ -61,8 +76,13 @@ public class ConfigAttributeDefinition
|
||||
}
|
||||
typeString = st.nextToken();
|
||||
|
||||
if (!(typeString.equals(RM) || typeString.equals(RM_ALLOW) || typeString.equals(RM_CAP) || typeString.equals(RM_DENY) || typeString.equals(RM_QUERY) || typeString
|
||||
.equals(RM_ABSTAIN)))
|
||||
// check that the configuration is valid
|
||||
if (!(typeString.equals(RM) ||
|
||||
typeString.equals(RM_ALLOW) ||
|
||||
typeString.equals(RM_CAP) ||
|
||||
typeString.equals(RM_DENY) ||
|
||||
typeString.equals(RM_QUERY) ||
|
||||
typeString.equals(RM_ABSTAIN)))
|
||||
{
|
||||
throw new ACLEntryVoterException("Invalid type: must be ACL_NODE, ACL_PARENT or ACL_ALLOW");
|
||||
}
|
||||
|
@@ -31,18 +31,25 @@ public class CreatePolicy extends AbstractBasePolicy
|
||||
Class[] params,
|
||||
ConfigAttributeDefinition cad)
|
||||
{
|
||||
|
||||
NodeRef destination = getTestNode(invocation, params, cad.getParameters().get(0), cad.isParent());
|
||||
QName type = getType(invocation, params, cad.getParameters().get(1), cad.isParent());
|
||||
// linkee is not null for creating secondary child assocs
|
||||
NodeRef linkee = getTestNode(invocation, params, cad.getParameters().get(1), cad.isParent());
|
||||
NodeRef linkee = null;
|
||||
QName assocType = null;
|
||||
if(cad.getParameters().size() > 2)
|
||||
|
||||
// get the destination node
|
||||
NodeRef destination = getTestNode(invocation, params, cad.getParameters().get(0), cad.isParent());
|
||||
|
||||
if (cad.getParameters().size() > 1)
|
||||
{
|
||||
assocType = getType(invocation, params, cad.getParameters().get(2), cad.isParent());
|
||||
// get the linkee when present
|
||||
linkee = getTestNode(invocation, params, cad.getParameters().get(1), cad.isParent());
|
||||
|
||||
// get the assoc type
|
||||
if(cad.getParameters().size() > 2)
|
||||
{
|
||||
assocType = getType(invocation, params, cad.getParameters().get(2), cad.isParent());
|
||||
}
|
||||
}
|
||||
|
||||
return ((CreateCapability)capabilityService.getCapability("Create")).evaluate(destination, linkee, type, assocType);
|
||||
return ((CreateCapability)capabilityService.getCapability("Create")).evaluate(destination, linkee, assocType);
|
||||
}
|
||||
|
||||
}
|
@@ -18,13 +18,7 @@
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.capability.policy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.impl.UpdatePropertiesCapability;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
public class UpdatePropertiesPolicy extends AbstractBasePolicy
|
||||
@@ -35,29 +29,8 @@ public class UpdatePropertiesPolicy extends AbstractBasePolicy
|
||||
Class[] params,
|
||||
ConfigAttributeDefinition cad)
|
||||
{
|
||||
NodeRef updatee = getTestNode(invocation, params, cad.getParameters().get(0), cad.isParent());
|
||||
Map<QName, Serializable> properties;
|
||||
if (QName.class.isAssignableFrom(params[cad.getParameters().get(1)]))
|
||||
{
|
||||
// single update/delete
|
||||
// We have a specific property
|
||||
QName propertyQName = getQName(invocation, params, cad.getParameters().get(1));
|
||||
properties = new HashMap<QName, Serializable>(1, 1.0f);
|
||||
if (cad.getParameters().size() > 2)
|
||||
{
|
||||
properties.put(propertyQName, getProperty(invocation, params, cad.getParameters().get(2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
properties.put(propertyQName, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
properties = getProperties(invocation, params, cad.getParameters().get(1));
|
||||
}
|
||||
|
||||
return ((UpdatePropertiesCapability)capabilityService.getCapability("UpdateProperties")).evaluate(updatee, properties);
|
||||
NodeRef nodeRef = getTestNode(invocation, params, cad.getParameters().get(0), cad.isParent());
|
||||
return capabilityService.getCapability("UpdateProperties").evaluate(nodeRef);
|
||||
}
|
||||
|
||||
}
|
@@ -56,6 +56,14 @@ public interface RecordService
|
||||
* Disables the property editable check.
|
||||
*/
|
||||
void disablePropertyEditableCheck();
|
||||
|
||||
/**
|
||||
* Disables the property editable check for a given node in this transaction only.
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @since 2.2
|
||||
*/
|
||||
void disablePropertyEditableCheck(NodeRef nodeRef);
|
||||
|
||||
/**
|
||||
* Enables the property editable check. By default this is always enabled.
|
||||
@@ -138,12 +146,13 @@ public interface RecordService
|
||||
* Creates a new document in the unfiled records container if the given node reference is a file plan
|
||||
* node reference otherwise the node reference will be used as the destination for the new record.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param name
|
||||
* @param type
|
||||
* @param properties
|
||||
* @param parent parent node reference
|
||||
* @param name name of the new record
|
||||
* @param type content type, cm:content if null
|
||||
* @param properties properties
|
||||
* @param reader content reader
|
||||
*/
|
||||
NodeRef createRecord(NodeRef nodeRef, String name, QName type, Map<QName, Serializable> properties, ContentReader reader);
|
||||
NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map<QName, Serializable> properties, ContentReader reader);
|
||||
|
||||
/**
|
||||
* Indicates whether the record is filed or not
|
||||
|
@@ -109,6 +109,9 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(RecordServiceImpl.class);
|
||||
|
||||
/** transation data key */
|
||||
private static final String IGNORE_ON_UPDATE = "ignoreOnUpdate";
|
||||
|
||||
/** I18N */
|
||||
private static final String MSG_NODE_HAS_ASPECT = "rm.service.node-has-aspect";
|
||||
@@ -335,8 +338,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
onDeleteDeclaredRecordLink);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.node.NodeServicePolicies.OnRemoveAspectPolicy#onRemoveAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
@@ -510,6 +511,15 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
getBehaviour("onUpdateProperties").disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#disablePropertyEditableCheck(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public void disablePropertyEditableCheck(NodeRef nodeRef)
|
||||
{
|
||||
Set<NodeRef> ignoreOnUpdate = TransactionalResourceHelper.getSet(IGNORE_ON_UPDATE);
|
||||
ignoreOnUpdate.add(nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#enablePropertyEditableCheck()
|
||||
@@ -537,7 +547,8 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
if (AuthenticationUtil.getFullyAuthenticatedUser() != null &&
|
||||
!AuthenticationUtil.isRunAsUserTheSystemUser() &&
|
||||
nodeService.exists(nodeRef) &&
|
||||
isRecord(nodeRef))
|
||||
isRecord(nodeRef) &&
|
||||
!TransactionalResourceHelper.getSet(IGNORE_ON_UPDATE).contains(nodeRef))
|
||||
{
|
||||
for (Map.Entry<QName, Serializable> entry : after.entrySet())
|
||||
{
|
||||
@@ -560,9 +571,10 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
// otherwise
|
||||
propertyUnchanged = EqualsHelper.nullSafeEquals(beforeValue, afterValue);
|
||||
}
|
||||
|
||||
|
||||
if (!propertyUnchanged &&
|
||||
!isPropertyEditable(nodeRef, property))
|
||||
!(ContentModel.PROP_CONTENT.equals(property) && beforeValue == null) &&
|
||||
!isPropertyEditable(nodeRef, property))
|
||||
{
|
||||
// the user can't edit the record property
|
||||
throw new ModelAccessDeniedException(
|
||||
@@ -814,19 +826,21 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecord(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map, org.alfresco.service.cmr.repository.ContentReader)
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createNewRecord(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map, org.alfresco.service.cmr.repository.ContentReader)
|
||||
*/
|
||||
@Override
|
||||
public NodeRef createRecord(NodeRef nodeRef, String name, QName type, Map<QName, Serializable> properties, ContentReader reader)
|
||||
public NodeRef createRecordFromContent(NodeRef parent, String name, QName type, Map<QName, Serializable> properties, ContentReader reader)
|
||||
{
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
ParameterCheck.mandatory("nodeRef", parent);
|
||||
ParameterCheck.mandatory("name", name);
|
||||
|
||||
NodeRef destination = nodeRef;
|
||||
if (isFilePlan(nodeRef))
|
||||
|
||||
NodeRef record = null;
|
||||
NodeRef destination = parent;
|
||||
|
||||
if (isFilePlan(parent))
|
||||
{
|
||||
// get the unfiled record container for the file plan
|
||||
destination = filePlanService.getUnfiledContainer(nodeRef);
|
||||
destination = filePlanService.getUnfiledContainer(parent);
|
||||
if (destination == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unable to create record, because unfiled container could not be found.");
|
||||
@@ -838,24 +852,35 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
{
|
||||
type = ContentModel.TYPE_CONTENT;
|
||||
}
|
||||
// TODO ensure that the type is a sub-type of cm:content
|
||||
|
||||
// create the new record
|
||||
NodeRef record = fileFolderService.create(destination, name, type).getNodeRef();
|
||||
|
||||
// set the properties
|
||||
if (properties != null)
|
||||
else if (!dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
nodeService.addProperties(record, properties);
|
||||
throw new AlfrescoRuntimeException("Record can only be created from a sub-type of cm:content.");
|
||||
}
|
||||
|
||||
// set the content
|
||||
if (reader != null)
|
||||
|
||||
disablePropertyEditableCheck();
|
||||
try
|
||||
{
|
||||
ContentWriter writer = fileFolderService.getWriter(record);
|
||||
writer.setEncoding(reader.getEncoding());
|
||||
writer.setMimetype(reader.getMimetype());
|
||||
writer.putContent(reader);
|
||||
// create the new record
|
||||
record = fileFolderService.create(destination, name, type).getNodeRef();
|
||||
|
||||
// set the properties
|
||||
if (properties != null)
|
||||
{
|
||||
nodeService.addProperties(record, properties);
|
||||
}
|
||||
|
||||
// set the content
|
||||
if (reader != null)
|
||||
{
|
||||
ContentWriter writer = fileFolderService.getWriter(record);
|
||||
writer.setEncoding(reader.getEncoding());
|
||||
writer.setMimetype(reader.getMimetype());
|
||||
writer.putContent(reader);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
enablePropertyEditableCheck();
|
||||
}
|
||||
|
||||
// Check if the "record" aspect has been applied already.
|
||||
@@ -882,6 +907,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
ParameterCheck.mandatory("document", document);
|
||||
|
||||
ruleService.disableRules();
|
||||
disablePropertyEditableCheck();
|
||||
try
|
||||
{
|
||||
// get the record id
|
||||
@@ -921,6 +947,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
|
||||
finally
|
||||
{
|
||||
ruleService.enableRules();
|
||||
enablePropertyEditableCheck();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -116,10 +116,10 @@ public class ReportServiceImpl extends ServiceBaseImpl
|
||||
ParameterCheck.mandatory("nodeRef", nodeRef);
|
||||
ParameterCheck.mandatory("report", report);
|
||||
|
||||
return recordService.createRecord(nodeRef,
|
||||
report.getReportName(),
|
||||
report.getReportType(),
|
||||
report.getReportProperties(),
|
||||
report.getReportContent());
|
||||
return recordService.createRecordFromContent(nodeRef,
|
||||
report.getReportName(),
|
||||
report.getReportType(),
|
||||
report.getReportProperties(),
|
||||
report.getReportContent());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.alfresco.repo.model.filefolder;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class ExtendedFileFolderServiceImpl extends FileFolderServiceImpl
|
||||
{
|
||||
protected RecordService recordService;
|
||||
|
||||
public void setRecordService(RecordService recordService)
|
||||
{
|
||||
this.recordService = recordService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName) throws FileExistsException
|
||||
{
|
||||
FileInfo result = null;
|
||||
|
||||
recordService.disablePropertyEditableCheck();
|
||||
try
|
||||
{
|
||||
result = super.create(parentNodeRef, name, typeQName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
recordService.enablePropertyEditableCheck();
|
||||
recordService.disablePropertyEditableCheck(result.getNodeRef());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName, QName assocQName) throws FileExistsException
|
||||
{
|
||||
FileInfo result = null;
|
||||
|
||||
recordService.disablePropertyEditableCheck();
|
||||
try
|
||||
{
|
||||
result = super.create(parentNodeRef, name, typeQName, assocQName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
recordService.enablePropertyEditableCheck();
|
||||
recordService.disablePropertyEditableCheck(result.getNodeRef());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user