mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-15 15:02:20 +00:00
SHA-1892 : Error appears when Consumer or Contributor is trying to create a link on a document
- After creating the link for a node, add the marker aspect (LINKED) to the original node as System user. - Added test for case - Added a new test for DocumentLinkServiceImplTest for updated fucntionality git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@132612 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -39,6 +39,7 @@ import org.alfresco.repo.policy.BehaviourFilter;
|
|||||||
import org.alfresco.repo.policy.JavaBehaviour;
|
import org.alfresco.repo.policy.JavaBehaviour;
|
||||||
import org.alfresco.repo.policy.PolicyComponent;
|
import org.alfresco.repo.policy.PolicyComponent;
|
||||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||||
import org.alfresco.repo.site.SiteModel;
|
import org.alfresco.repo.site.SiteModel;
|
||||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||||
@@ -60,8 +61,8 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import org.springframework.extensions.surf.util.I18NUtil;
|
import org.springframework.extensions.surf.util.I18NUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the document link service
|
* Implementation of the document link service In addition to the document link
|
||||||
* In addition to the document link service, this class also provides a BeforeDeleteNodePolicy
|
* service, this class also provides a BeforeDeleteNodePolicy
|
||||||
*
|
*
|
||||||
* @author Ana Bozianu
|
* @author Ana Bozianu
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
@@ -80,7 +81,7 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
|
|
||||||
/** Shallow search for nodes with a name pattern */
|
/** Shallow search for nodes with a name pattern */
|
||||||
private static final String XPATH_QUERY_NODE_NAME_MATCH = "./*[like(@cm:name, $cm:name, false)]";
|
private static final String XPATH_QUERY_NODE_NAME_MATCH = "./*[like(@cm:name, $cm:name, false)]";
|
||||||
|
|
||||||
/** Shallow search for links with a destination pattern */
|
/** Shallow search for links with a destination pattern */
|
||||||
private static final String XPATH_QUERY_LINK_DEST_MATCH = ".//*[like(@cm:destination, $cm:destination, false)]";
|
private static final String XPATH_QUERY_LINK_DEST_MATCH = ".//*[like(@cm:destination, $cm:destination, false)]";
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
|
|
||||||
/* I18N labels */
|
/* I18N labels */
|
||||||
private static final String LINK_TO_LABEL = "doclink_service.link_to_label";
|
private static final String LINK_TO_LABEL = "doclink_service.link_to_label";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The initialise method. Register our policies.
|
* The initialise method. Register our policies.
|
||||||
*/
|
*/
|
||||||
@@ -124,13 +125,13 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NodeRef createDocumentLink(NodeRef source, NodeRef destination)
|
public NodeRef createDocumentLink(final NodeRef source, NodeRef destination)
|
||||||
{
|
{
|
||||||
if(logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Creating document link. source: " + source + ", destination: " + destination);
|
logger.debug("Creating document link. source: " + source + ", destination: " + destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate input */
|
/* Validate input */
|
||||||
PropertyCheck.mandatory(this, "source", source);
|
PropertyCheck.mandatory(this, "source", source);
|
||||||
PropertyCheck.mandatory(this, "destination", destination);
|
PropertyCheck.mandatory(this, "destination", destination);
|
||||||
@@ -172,9 +173,9 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
ChildAssociationRef childRef = null;
|
ChildAssociationRef childRef = null;
|
||||||
QName sourceType = nodeService.getType(source);
|
QName sourceType = nodeService.getType(source);
|
||||||
|
|
||||||
if( checkOutCheckInService.isWorkingCopy(source) || nodeService.hasAspect(source, ContentModel.ASPECT_LOCKABLE))
|
if (checkOutCheckInService.isWorkingCopy(source) || nodeService.hasAspect(source, ContentModel.ASPECT_LOCKABLE))
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException( "Cannot perform operation since the node (id:" + source.getId() + ") is locked.");
|
throw new IllegalArgumentException("Cannot perform operation since the node (id:" + source.getId() + ") is locked.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dictionaryService.isSubClass(sourceType, ContentModel.TYPE_CONTENT))
|
if (dictionaryService.isSubClass(sourceType, ContentModel.TYPE_CONTENT))
|
||||||
@@ -183,7 +184,8 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
childRef = nodeService.createNode(destination, ContentModel.ASSOC_CONTAINS, assocQName, ApplicationModel.TYPE_FILELINK, props);
|
childRef = nodeService.createNode(destination, ContentModel.ASSOC_CONTAINS, assocQName, ApplicationModel.TYPE_FILELINK, props);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!dictionaryService.isSubClass(sourceType, SiteModel.TYPE_SITE) && dictionaryService.isSubClass(nodeService.getType(source), ContentModel.TYPE_FOLDER))
|
else if (!dictionaryService.isSubClass(sourceType, SiteModel.TYPE_SITE)
|
||||||
|
&& dictionaryService.isSubClass(nodeService.getType(source), ContentModel.TYPE_FOLDER))
|
||||||
{
|
{
|
||||||
// create Folder link node
|
// create Folder link node
|
||||||
childRef = nodeService.createNode(destination, ContentModel.ASSOC_CONTAINS, assocQName, ApplicationModel.TYPE_FOLDERLINK, props);
|
childRef = nodeService.createNode(destination, ContentModel.ASSOC_CONTAINS, assocQName, ApplicationModel.TYPE_FOLDERLINK, props);
|
||||||
@@ -193,16 +195,24 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
throw new IllegalArgumentException("unsupported source node type : " + nodeService.getType(source));
|
throw new IllegalArgumentException("unsupported source node type : " + nodeService.getType(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
//add linked aspect to the sourceNode
|
// add linked aspect to the sourceNode - run as System
|
||||||
behaviourFilter.disableBehaviour(source, ContentModel.ASPECT_AUDITABLE);
|
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||||
try
|
|
||||||
{
|
{
|
||||||
nodeService.addAspect(source, ApplicationModel.ASPECT_LINKED, null);
|
public Void doWork() throws Exception
|
||||||
}
|
{
|
||||||
finally
|
behaviourFilter.disableBehaviour(source, ContentModel.ASPECT_AUDITABLE);
|
||||||
{
|
try
|
||||||
behaviourFilter.enableBehaviour(source, ContentModel.ASPECT_AUDITABLE);
|
{
|
||||||
}
|
nodeService.addAspect(source, ApplicationModel.ASPECT_LINKED, null);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
behaviourFilter.enableBehaviour(source, ContentModel.ASPECT_AUDITABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
|
|
||||||
return childRef.getChildRef();
|
return childRef.getChildRef();
|
||||||
}
|
}
|
||||||
@@ -246,13 +256,13 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
|
|
||||||
return (NodeRef) nodeService.getProperty(linkNodeRef, ContentModel.PROP_LINK_DESTINATION);
|
return (NodeRef) nodeService.getProperty(linkNodeRef, ContentModel.PROP_LINK_DESTINATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<NodeRef> getNodeLinks(NodeRef nodeRef)
|
public List<NodeRef> getNodeLinks(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
/* Validate input */
|
/* Validate input */
|
||||||
PropertyCheck.mandatory(this, "nodeRef", nodeRef);
|
PropertyCheck.mandatory(this, "nodeRef", nodeRef);
|
||||||
|
|
||||||
/* Get all links of the given nodeRef */
|
/* Get all links of the given nodeRef */
|
||||||
QueryParameterDefinition[] params = new QueryParameterDefinition[1];
|
QueryParameterDefinition[] params = new QueryParameterDefinition[1];
|
||||||
params[0] = new QueryParameterDefImpl(ContentModel.PROP_LINK_DESTINATION, dictionaryService.getDataType(DataTypeDefinition.NODE_REF), true, nodeRef.toString());
|
params[0] = new QueryParameterDefImpl(ContentModel.PROP_LINK_DESTINATION, dictionaryService.getDataType(DataTypeDefinition.NODE_REF), true, nodeRef.toString());
|
||||||
@@ -260,12 +270,12 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
List<NodeRef> nodeLinks = new ArrayList<NodeRef>();
|
List<NodeRef> nodeLinks = new ArrayList<NodeRef>();
|
||||||
List<NodeRef> nodeRefs;
|
List<NodeRef> nodeRefs;
|
||||||
/* Search for links in all stores */
|
/* Search for links in all stores */
|
||||||
for(StoreRef store : nodeService.getStores())
|
for (StoreRef store : nodeService.getStores())
|
||||||
{
|
{
|
||||||
/* Get the root node */
|
/* Get the root node */
|
||||||
NodeRef rootNodeRef = nodeService.getRootNode(store);
|
NodeRef rootNodeRef = nodeService.getRootNode(store);
|
||||||
|
|
||||||
/* Execute the query, retrieve links to the document*/
|
/* Execute the query, retrieve links to the document */
|
||||||
nodeRefs = searchService.selectNodes(rootNodeRef, XPATH_QUERY_LINK_DEST_MATCH, params, namespaceService, true);
|
nodeRefs = searchService.selectNodes(rootNodeRef, XPATH_QUERY_LINK_DEST_MATCH, params, namespaceService, true);
|
||||||
nodeLinks.addAll(nodeRefs);
|
nodeLinks.addAll(nodeRefs);
|
||||||
}
|
}
|
||||||
@@ -337,25 +347,31 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
|
|
||||||
public void beforeDeleteLinkNode(NodeRef linkNodeRef)
|
public void beforeDeleteLinkNode(NodeRef linkNodeRef)
|
||||||
{
|
{
|
||||||
// NodeRef linkNodeRef = childAssocRef.getChildRef();
|
final NodeRef nodeRef = getLinkDestination(linkNodeRef);
|
||||||
NodeRef nodeRef = getLinkDestination(linkNodeRef);
|
|
||||||
|
|
||||||
List<NodeRef> nodeRefLinks = getNodeLinks(nodeRef);
|
List<NodeRef> nodeRefLinks = getNodeLinks(nodeRef);
|
||||||
|
|
||||||
if (nodeRefLinks.size() == 1 && nodeRefLinks.contains(linkNodeRef))
|
if (nodeRefLinks.size() == 1 && nodeRefLinks.contains(linkNodeRef))
|
||||||
{
|
{
|
||||||
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||||
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_LOCKABLE);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
// remove linked aspect to the sourceNode
|
public Void doWork() throws Exception
|
||||||
nodeService.removeAspect(nodeRef, ApplicationModel.ASPECT_LINKED);
|
{
|
||||||
}
|
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||||
finally
|
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_LOCKABLE);
|
||||||
{
|
try
|
||||||
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
{
|
||||||
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_LOCKABLE);
|
nodeService.removeAspect(nodeRef, ApplicationModel.ASPECT_LINKED);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||||
|
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_LOCKABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,4 +409,4 @@ public class DocumentLinkServiceImpl implements DocumentLinkService, NodeService
|
|||||||
{
|
{
|
||||||
this.behaviourFilter = behaviourFilter;
|
this.behaviourFilter = behaviourFilter;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -39,6 +39,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.repo.security.permissions.AccessDeniedException;
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||||
import org.alfresco.service.cmr.model.FileFolderService;
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
import org.alfresco.service.cmr.repository.DeleteLinksStatusReport;
|
import org.alfresco.service.cmr.repository.DeleteLinksStatusReport;
|
||||||
import org.alfresco.service.cmr.repository.DocumentLinkService;
|
import org.alfresco.service.cmr.repository.DocumentLinkService;
|
||||||
@@ -79,8 +80,10 @@ public class DocumentLinkServiceImplTest extends TestCase
|
|||||||
private SiteService siteService;
|
private SiteService siteService;
|
||||||
private FileFolderService fileFolderService;
|
private FileFolderService fileFolderService;
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
|
private CheckOutCheckInService cociService;
|
||||||
|
|
||||||
// nodes the test user has read/write permission to
|
// nodes the test user has read/write permission to
|
||||||
|
private NodeRef site1;
|
||||||
private NodeRef site1File1;
|
private NodeRef site1File1;
|
||||||
private NodeRef site1File2; // do not create links of this file
|
private NodeRef site1File2; // do not create links of this file
|
||||||
private NodeRef site1Folder1;
|
private NodeRef site1Folder1;
|
||||||
@@ -108,6 +111,7 @@ public class DocumentLinkServiceImplTest extends TestCase
|
|||||||
siteService = serviceRegistry.getSiteService();
|
siteService = serviceRegistry.getSiteService();
|
||||||
fileFolderService = serviceRegistry.getFileFolderService();
|
fileFolderService = serviceRegistry.getFileFolderService();
|
||||||
nodeService = serviceRegistry.getNodeService();
|
nodeService = serviceRegistry.getNodeService();
|
||||||
|
cociService = serviceRegistry.getCheckOutCheckInService();
|
||||||
|
|
||||||
// Start the transaction
|
// Start the transaction
|
||||||
txn = transactionService.getUserTransaction();
|
txn = transactionService.getUserTransaction();
|
||||||
@@ -125,7 +129,7 @@ public class DocumentLinkServiceImplTest extends TestCase
|
|||||||
* Create the working test root 1 to which the user has read/write
|
* Create the working test root 1 to which the user has read/write
|
||||||
* permission
|
* permission
|
||||||
*/
|
*/
|
||||||
NodeRef site1 = siteService.createSite("site1", GUID.generate(), "myTitle", "myDescription", SiteVisibility.PUBLIC).getNodeRef();
|
site1 = siteService.createSite("site1", GUID.generate(), "myTitle", "myDescription", SiteVisibility.PUBLIC).getNodeRef();
|
||||||
permissionService.setPermission(site1, TEST_USER, PermissionService.ALL_PERMISSIONS, true);
|
permissionService.setPermission(site1, TEST_USER, PermissionService.ALL_PERMISSIONS, true);
|
||||||
site1Folder1 = fileFolderService.create(site1, site1Folder1Name, ContentModel.TYPE_FOLDER).getNodeRef();
|
site1Folder1 = fileFolderService.create(site1, site1Folder1Name, ContentModel.TYPE_FOLDER).getNodeRef();
|
||||||
site1File1 = fileFolderService.create(site1Folder1, site1File1Name, ContentModel.TYPE_CONTENT).getNodeRef();
|
site1File1 = fileFolderService.create(site1Folder1, site1File1Name, ContentModel.TYPE_CONTENT).getNodeRef();
|
||||||
@@ -336,4 +340,57 @@ public class DocumentLinkServiceImplTest extends TestCase
|
|||||||
assertEquals(ex.getClass(), AccessDeniedException.class);
|
assertEquals(ex.getClass(), AccessDeniedException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the creation of a Site link, an locked node or a checked out node
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void testCreateLinksNotAllowed() throws Exception
|
||||||
|
{
|
||||||
|
NodeRef invalidLinkNodeRef;
|
||||||
|
|
||||||
|
// Create link for Site
|
||||||
|
try
|
||||||
|
{
|
||||||
|
invalidLinkNodeRef = documentLinkService.createDocumentLink(site1, site2Folder1);
|
||||||
|
fail("unsupported source node type : " + nodeService.getType(site1));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeRef firstLinkNodeRef = documentLinkService.createDocumentLink(site1File1, site1Folder1);
|
||||||
|
assertEquals(true, nodeService.hasAspect(site1File1, ApplicationModel.ASPECT_LINKED));
|
||||||
|
|
||||||
|
// Create link for working copy
|
||||||
|
NodeRef workingCopyNodeRef = cociService.checkout(site1File1);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
invalidLinkNodeRef = documentLinkService.createDocumentLink(workingCopyNodeRef, site1Folder1);
|
||||||
|
fail("Cannot perform operation since the node (id:" + workingCopyNodeRef.getId() + ") is locked.");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create link for locked node (original)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
invalidLinkNodeRef = documentLinkService.createDocumentLink(site1File1, site1Folder1);
|
||||||
|
fail("Cannot perform operation since the node (id:" + site1File1.getId() + ") is locked.");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even the node is locked, user can delete previous created links
|
||||||
|
nodeService.deleteNode(firstLinkNodeRef);
|
||||||
|
assertEquals(false, nodeService.hasAspect(site1File1, ApplicationModel.ASPECT_LINKED));
|
||||||
|
|
||||||
|
cociService.cancelCheckout(workingCopyNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user