From ab6a5171cbd5cfe90e0131d73e5de4d7a372206f Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Tue, 18 Sep 2012 15:08:24 +0000 Subject: [PATCH] Merged BRANCHES/DEV/HEAD_QUICK_SHARE_TMP to HEAD: 41724: Merged BRANCHES/DEV/CLOUD1-BUG-FIX to BRANCHES/DEV/HEAD_QUICK_SHARE_TMP: 41211: CLOUD-593: Prevent copying of QuickShare properties on node copy. 41725: QuickShare: minor - rename unit test 41727: Refactored quickshare components to match new webscript boilerplate format in Share 41733: QuickShare: fix ShareContentGet NPE git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@41742 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../application-context-highlevel.xml | 1 + .../alfresco/quickshare-services-context.xml | 65 +++ .../quickshare/QuickShareServiceImpl.java | 472 ++++++++++++++++++ .../QuickShareServiceIntegrationTest.java | 258 ++++++++++ .../quickshare/InvalidSharedIdException.java | 39 ++ .../service/cmr/quickshare/QuickShareDTO.java | 60 +++ .../QuickShareDisabledException.java | 38 ++ .../cmr/quickshare/QuickShareService.java | 75 +++ 8 files changed, 1008 insertions(+) create mode 100644 config/alfresco/quickshare-services-context.xml create mode 100644 source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java create mode 100644 source/java/org/alfresco/repo/quickshare/QuickShareServiceIntegrationTest.java create mode 100644 source/java/org/alfresco/service/cmr/quickshare/InvalidSharedIdException.java create mode 100644 source/java/org/alfresco/service/cmr/quickshare/QuickShareDTO.java create mode 100644 source/java/org/alfresco/service/cmr/quickshare/QuickShareDisabledException.java create mode 100644 source/java/org/alfresco/service/cmr/quickshare/QuickShareService.java diff --git a/config/alfresco/application-context-highlevel.xml b/config/alfresco/application-context-highlevel.xml index ab59a407df..1db82bb854 100644 --- a/config/alfresco/application-context-highlevel.xml +++ b/config/alfresco/application-context-highlevel.xml @@ -14,6 +14,7 @@ + diff --git a/config/alfresco/quickshare-services-context.xml b/config/alfresco/quickshare-services-context.xml new file mode 100644 index 0000000000..5a76085d29 --- /dev/null +++ b/config/alfresco/quickshare-services-context.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + canDownloadAnonymously + getMetaData + getTenantNodeRefFromSharedId + + + + + + + + + + + shareContent + update + unshareContent + + + + + + + + + org.alfresco.service.cmr.quickshare.QuickShareService + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java b/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java new file mode 100644 index 0000000000..ebdd93e380 --- /dev/null +++ b/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2005-2012 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 . + */ +package org.alfresco.repo.quickshare; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.QuickShareModel; +import org.alfresco.repo.copy.CopyBehaviourCallback; +import org.alfresco.repo.copy.CopyDetails; +import org.alfresco.repo.copy.CopyServicePolicies; +import org.alfresco.repo.copy.DoNothingCopyBehaviourCallback; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; +import org.alfresco.repo.thumbnail.ThumbnailDefinition; +import org.alfresco.service.cmr.attributes.AttributeService; +import org.alfresco.service.cmr.quickshare.InvalidSharedIdException; +import org.alfresco.service.cmr.quickshare.QuickShareDTO; +import org.alfresco.service.cmr.quickshare.QuickShareDisabledException; +import org.alfresco.service.cmr.quickshare.QuickShareService; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.NoSuchPersonException; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.thumbnail.ThumbnailService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.Pair; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.safehaus.uuid.UUID; +import org.safehaus.uuid.UUIDGenerator; + +/** + * QuickShare Service implementation. + * + * In addition to the quick share service, this class also provides a BeforeDeleteNodePolicy and + * OnCopyNodePolicy for content with the QuickShare aspect. + * + * @author Alex Miller, janv + */ +public class QuickShareServiceImpl implements QuickShareService, NodeServicePolicies.BeforeDeleteNodePolicy, CopyServicePolicies.OnCopyNodePolicy +{ + private static final Log logger = LogFactory.getLog(QuickShareServiceImpl.class); + + static final String ATTR_KEY_SHAREDIDS_ROOT = ".sharedIds"; + + + private boolean enabled; + + private AttributeService attributeService; + private NodeService nodeService; + private PersonService personService; + private PolicyComponent policyComponent; + private TenantService tenantService; + private ThumbnailService thumbnailService; + + /** + * Enable or disable this service. + */ + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + /** + * Set the attribute service + */ + public void setAttributeService(AttributeService attributeService) + { + this.attributeService = attributeService; + } + + /** + * Set the node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Set the person service + */ + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + /** + * Set the policy component + */ + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + /** + * Set the tenant service + */ + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + + /** + * Set the thumbnail service + */ + public void setThumbnailService(ThumbnailService thumbnailService) + { + this.thumbnailService = thumbnailService; + } + + /** + * The initialise method. Register our policies. + */ + public void init() + { + // Register interest in the beforeDeleteNode policy - note: currently for content only !! + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), + ContentModel.TYPE_CONTENT, + new JavaBehaviour(this, "beforeDeleteNode")); + + //Register interest in the onCopyNodePolicy to block copying of quick share metadta + policyComponent.bindClassBehaviour( + CopyServicePolicies.OnCopyNodePolicy.QNAME, + QuickShareModel.ASPECT_QSHARE, + new JavaBehaviour(this, "getCopyCallback")); + } + + + @Override + public QuickShareDTO shareContent(NodeRef nodeRef) + { + checkEnabled(); + + //Check the node is the correct type + QName typeQName = nodeService.getType(nodeRef); + if (! typeQName.equals(ContentModel.TYPE_CONTENT)) + { + throw new InvalidNodeRefException(nodeRef); + } + + final String sharedId; + + // Only add the quick share aspect if it isn't already present. + // If it is retura dto built from the existing properties. + if (! nodeService.getAspects(nodeRef).contains(QuickShareModel.ASPECT_QSHARE)) + { + UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID(); + sharedId = Base64.encodeBase64URLSafeString(uuid.toByteArray()); // => 22 chars (eg. q3bEKPeDQvmJYgt4hJxOjw) + + Map props = new HashMap(2); + props.put(QuickShareModel.PROP_QSHARE_SHAREDID, sharedId); + props.put(QuickShareModel.PROP_QSHARE_SHAREDBY, AuthenticationUtil.getRunAsUser()); + + nodeService.addAspect(nodeRef, QuickShareModel.ASPECT_QSHARE, props); + + final NodeRef tenantNodeRef = tenantService.getName(nodeRef); + + TenantUtil.runAsDefaultTenant(new TenantRunAsWork() + { + public Void doWork() throws Exception + { + attributeService.setAttribute(tenantNodeRef, ATTR_KEY_SHAREDIDS_ROOT, sharedId); + return null; + } + }); + + if (logger.isInfoEnabled()) + { + logger.info("QuickShare - shared content: "+sharedId+" ["+nodeRef+"]"); + } + } + else + { + sharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID); + if (logger.isDebugEnabled()) + { + logger.debug("QuickShare - content already shared: "+sharedId+" ["+nodeRef+"]"); + } + } + + + return new QuickShareDTO(sharedId); + } + + /** + * Is this service enable? + * @throws uickShareDisabledException if it isn't. + */ + private void checkEnabled() + { + if (enabled == false) + { + throw new QuickShareDisabledException("QuickShare is disabled system-wide"); + } + } + + @SuppressWarnings("unchecked") + @Override + public Map getMetaData(NodeRef nodeRef) + { + checkEnabled(); + + Map nodeProps = getNodeProperties(nodeRef); + ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + + String modifierUserName = (String)nodeProps.get(ContentModel.PROP_MODIFIER); + Map personProps = null; + if (modifierUserName != null) + { + try + { + NodeRef personRef = personService.getPerson(modifierUserName); + if (personRef != null) + { + personProps = nodeService.getProperties(personRef); + } + } + catch (NoSuchPersonException nspe) + { + // absorb this exception - eg. System (or maybe the user has been deleted) + if (logger.isInfoEnabled()) + { + logger.info("MetaDataGet - no such person: "+modifierUserName); + } + } + } + + Map metadata = new HashMap(8); + + metadata.put("name", nodeProps.get(ContentModel.PROP_NAME)); + metadata.put("title", nodeProps.get(ContentModel.PROP_TITLE)); + + if (contentData != null) + { + metadata.put("mimetype", contentData.getMimetype()); + metadata.put("size", contentData.getSize()); + } + else + { + metadata.put("size", 0L); + } + + metadata.put("modified", nodeProps.get(ContentModel.PROP_MODIFIED)); + + if (personProps != null) + { + metadata.put("modifierFirstName", personProps.get(ContentModel.PROP_FIRSTNAME)); + metadata.put("modifierLastName", personProps.get(ContentModel.PROP_LASTNAME)); + } + + // thumbnail defs for this nodeRef + List thumbnailDefs = new ArrayList(7); + if (contentData != null) + { + // Note: thumbnail defs only appear in this list if they can produce a thumbnail for the content + // found in the content property of this node. This will be determined by looking at the mimetype of the content + // and the destination mimetype of the thumbnail. + List thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentData.getMimetype(), contentData.getSize()); + for (ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions) + { + thumbnailDefs.add(thumbnailDefinition.getName()); + } + } + metadata.put("thumbnailDefinitions", thumbnailDefs); + + // thumbnail instances for this nodeRef + List thumbnailRefs = thumbnailService.getThumbnails(nodeRef, ContentModel.PROP_CONTENT, null, null); + List thumbnailNames = new ArrayList(thumbnailRefs.size()); + for (NodeRef thumbnailRef : thumbnailRefs) + { + thumbnailNames.add((String)nodeService.getProperty(thumbnailRef, ContentModel.PROP_NAME)); + } + metadata.put("thumbnailNames", thumbnailNames); + + metadata.put("lastThumbnailModificationData", (List)nodeProps.get(ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA)); + + if (nodeProps.containsKey(QuickShareModel.PROP_QSHARE_SHAREDID)) + { + metadata.put("sharedId", nodeProps.get(QuickShareModel.PROP_QSHARE_SHAREDID)); + } + + Map model = new HashMap(1); + model.put("item", metadata); + return model; + } + + private Map getNodeProperties(NodeRef nodeRef) + { + QName typeQName = nodeService.getType(nodeRef); + if (! typeQName.equals(ContentModel.TYPE_CONTENT)) + { + throw new InvalidNodeRefException(nodeRef); + } + + Map nodeProps = nodeService.getProperties(nodeRef); + return nodeProps; + } + + @Override + public Pair getTenantNodeRefFromSharedId(final String sharedId) + { + final NodeRef nodeRef = TenantUtil.runAsDefaultTenant(new TenantRunAsWork() + { + public NodeRef doWork() throws Exception + { + return (NodeRef)attributeService.getAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId); + } + }); + + if (nodeRef == null) + { + throw new InvalidSharedIdException(sharedId); + } + + // note: relies on tenant-specific (ie. mangled) nodeRef + String tenantDomain = tenantService.getDomain(nodeRef.getStoreRef().getIdentifier()); + + return new Pair(tenantDomain, tenantService.getBaseName(nodeRef)); + } + + @Override + public Map getMetaData(String sharedId) + { + Pair pair = getTenantNodeRefFromSharedId(sharedId); + final String tenantDomain = pair.getFirst(); + final NodeRef nodeRef = pair.getSecond(); + + Map model = TenantUtil.runAsSystemTenant(new TenantRunAsWork>() + { + public Map doWork() throws Exception + { + checkQuickShareNode(nodeRef); + + return getMetaData(nodeRef); + } + }, tenantDomain); + + if (logger.isDebugEnabled()) + { + logger.debug("QuickShare - retrieved metadata: "+sharedId+" ["+nodeRef+"]["+model+"]"); + } + + return model; + } + + private void checkQuickShareNode(final NodeRef nodeRef) + { + if (! nodeService.getAspects(nodeRef).contains(QuickShareModel.ASPECT_QSHARE)) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + // behaviour - currently registered for content only !! + // note: will remove "share" even if node is only being archived (ie. moved to trash) => a subsequent restore will *not* restore the "share" + public void beforeDeleteNode(final NodeRef beforeDeleteNodeRef) + { + AuthenticationUtil.runAsSystem(new RunAsWork() + { + public Void doWork() throws Exception + { + String sharedId = (String)nodeService.getProperty(beforeDeleteNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID); + if (sharedId != null) + { + Pair pair = getTenantNodeRefFromSharedId(sharedId); + + @SuppressWarnings("unused") + final String tenantDomain = pair.getFirst(); + final NodeRef nodeRef = pair.getSecond(); + + // note: deleted nodeRef might not match, eg. for upload new version -> checkin -> delete working copy + if (nodeRef.equals(beforeDeleteNodeRef)) + { + removeSharedId(sharedId); + } + } + return null; + } + }); + } + + private void removeSharedId(final String sharedId) + { + TenantUtil.runAsDefaultTenant(new TenantRunAsWork() + { + public Void doWork() throws Exception + { + attributeService.removeAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId); + return null; + } + }); + } + + @Override + public void unshareContent(final String sharedId) + { + Pair pair = getTenantNodeRefFromSharedId(sharedId); + final String tenantDomain = pair.getFirst(); + final NodeRef nodeRef = pair.getSecond(); + + TenantUtil.runAsSystemTenant(new TenantRunAsWork() + { + public Void doWork() throws Exception + { + QName typeQName = nodeService.getType(nodeRef); + if (! typeQName.equals(ContentModel.TYPE_CONTENT)) + { + throw new InvalidNodeRefException(nodeRef); + } + + String nodeSharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID); + + if (! EqualsHelper.nullSafeEquals(nodeSharedId, sharedId)) + { + logger.warn("SharedId mismatch: expected="+sharedId+",actual="+nodeSharedId); + } + + nodeService.removeAspect(nodeRef, QuickShareModel.ASPECT_QSHARE); + + return null; + } + }, tenantDomain); + + removeSharedId(sharedId); + + if (logger.isInfoEnabled()) + { + logger.info("QuickShare - unshared content: "+sharedId+" ["+nodeRef+"]"); + } + } + + // Prevent copying of Quick share properties on node copy. + @Override + public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails) + { + return DoNothingCopyBehaviourCallback.getInstance(); + } +} diff --git a/source/java/org/alfresco/repo/quickshare/QuickShareServiceIntegrationTest.java b/source/java/org/alfresco/repo/quickshare/QuickShareServiceIntegrationTest.java new file mode 100644 index 0000000000..933ea2223b --- /dev/null +++ b/source/java/org/alfresco/repo/quickshare/QuickShareServiceIntegrationTest.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2005-2012 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 . + */ +package org.alfresco.repo.quickshare; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.Serializable; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.QuickShareModel; +import org.alfresco.repo.model.Repository; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.quickshare.InvalidSharedIdException; +import org.alfresco.service.cmr.quickshare.QuickShareDTO; +import org.alfresco.service.cmr.quickshare.QuickShareService; +import org.alfresco.service.cmr.repository.CopyService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.test.junitrules.AlfrescoPerson; +import org.alfresco.util.test.junitrules.ApplicationContextInit; +import org.alfresco.util.test.junitrules.TemporaryNodes; +import org.apache.commons.codec.binary.Base64; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.safehaus.uuid.UUID; +import org.safehaus.uuid.UUIDGenerator; +import org.springframework.context.ApplicationContext; + +/** + * Quick share service tests. + * + * @author Alex Miller + * @since Cloud/4.2 + */ +public class QuickShareServiceIntegrationTest +{ + private static final ApplicationContextInit testContext = new ApplicationContextInit(); + + private static CopyService copyService; + private static NodeService nodeService; + private static QuickShareService quickShareService; + private static Repository repository; + + private static AlfrescoPerson user1 = new AlfrescoPerson(testContext, "UserOne"); + private static AlfrescoPerson user2 = new AlfrescoPerson(testContext, "UserTwo"); + + // A rule to manage test nodes reused across all the test methods + @Rule public TemporaryNodes testNodes = new TemporaryNodes(testContext); + + @ClassRule public static RuleChain classChain = RuleChain.outerRule(testContext) + .around(user1) + .around(user2); + + private NodeRef testNode; + + private NodeRef userHome; + + @BeforeClass public static void beforeClass() throws Exception + { + findServices(); + } + + + private static void findServices() + { + ApplicationContext ctx = testContext.getApplicationContext(); + + copyService = ctx.getBean("CopyService", CopyService.class); + nodeService = ctx.getBean("NodeService", NodeService.class); + quickShareService = ctx.getBean("QuickShareService", QuickShareService.class); + repository = ctx.getBean("repositoryHelper", Repository.class); + } + + @Before public void createTestData() + { + userHome = repository.getUserHome(user1.getPersonNode()); + + testNode = testNodes.createNodeWithTextContent(userHome, + "Quick Share Test Node", + ContentModel.TYPE_CONTENT, + user1.getUsername(), + "Quick Share Test Node Content"); + } + + @Test public void getMetaDataFromNodeRefByOwner() + { + Map metadata = AuthenticationUtil.runAs(new RunAsWork>(){ + + @Override + public Map doWork() throws Exception + { + return quickShareService.getMetaData(testNode); + } + }, user1.getUsername()); + + assertNotNull(metadata); + assertTrue(metadata.size() > 0); + } + + @Test(expected=AccessDeniedException.class) + public void getMetaDataFromNodeRefByNonOwner() + { + Map metadata = AuthenticationUtil.runAs(new RunAsWork>(){ + + @Override + public Map doWork() throws Exception + { + return quickShareService.getMetaData(testNode); + } + }, user2.getUsername()); + + } + + @Test public void share() + { + share(testNode, user1.getUsername()); + + AuthenticationUtil.runAsSystem(new RunAsWork(){ + + @Override + public Void doWork() throws Exception + { + assertTrue( nodeService.getAspects(testNode).contains(QuickShareModel.ASPECT_QSHARE)); + assertNotNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); + assertEquals(user1.getUsername(), nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); + return null; + } + + }); + } + + @Test public void unshare() { + final QuickShareDTO dto = share(testNode, user1.getUsername()); + + AuthenticationUtil.runAs(new RunAsWork() + { + + @Override + public Void doWork() throws Exception + { + quickShareService.unshareContent(dto.getId()); + return null; + } + }, user1.getUsername()); + AuthenticationUtil.runAsSystem(new RunAsWork(){ + + @Override + public Void doWork() throws Exception + { + assertFalse( nodeService.getAspects(testNode).contains(QuickShareModel.ASPECT_QSHARE)); + assertNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); + assertNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); + return null; + } + + }); + } + + private QuickShareDTO share(final NodeRef nodeRef, String username) + { + return AuthenticationUtil.runAs(new RunAsWork() + { + @Override + public QuickShareDTO doWork() throws Exception + { + return quickShareService.shareContent(nodeRef); + } + }, username); + } + + @Test public void getMetadataFromShareId() + { + QuickShareDTO dto = share(testNode, user1.getUsername()); + + Map metadata = quickShareService.getMetaData(dto.getId()); + + assertNotNull(metadata); + assertTrue(metadata.size() > 0); + } + + @Test(expected=InvalidSharedIdException.class) public void getMetadataFromShareIdWithInvalidId() + { + UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID(); + String sharedId = Base64.encodeBase64URLSafeString(uuid.toByteArray()); // => 22 chars (eg. q3bEKPeDQvmJYgt4hJxOjw) + + Map metadata = quickShareService.getMetaData(sharedId); + } + + @Test public void copyNode() + { + share(testNode, user1.getUsername()); + + AuthenticationUtil.runAs(new RunAsWork() + { + + @Override + public Object doWork() throws Exception + { + + Assert.assertTrue(nodeService.hasAspect(testNode, QuickShareModel.ASPECT_QSHARE)); + Assert.assertNotNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); + Assert.assertNotNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); + + Map originalProps = nodeService.getProperties(testNode); + + NodeRef copyNodeRef = copyService.copyAndRename(testNode, userHome, ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "copy"), true); + + Map copyProps = nodeService.getProperties(copyNodeRef); + + Assert.assertFalse(nodeService.hasAspect(copyNodeRef, QuickShareModel.ASPECT_QSHARE)); + Assert.assertNull(nodeService.getProperty(copyNodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY)); + Assert.assertNull(nodeService.getProperty(copyNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID)); + + for (QName property : originalProps.keySet()) + { + if (property.equals(QuickShareModel.PROP_QSHARE_SHAREDBY) || + property.equals(QuickShareModel.PROP_QSHARE_SHAREDID)) + { + continue; + } + Assert.assertTrue("Mising property " + property, copyProps.containsKey(property)); + } + return null; + } + }, user1.getUsername()); + } +} diff --git a/source/java/org/alfresco/service/cmr/quickshare/InvalidSharedIdException.java b/source/java/org/alfresco/service/cmr/quickshare/InvalidSharedIdException.java new file mode 100644 index 0000000000..80d672214c --- /dev/null +++ b/source/java/org/alfresco/service/cmr/quickshare/InvalidSharedIdException.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2012 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 . + */ +package org.alfresco.service.cmr.quickshare; + +import org.alfresco.error.AlfrescoRuntimeException; + +/** + * Exception thrown by the QuickShareService to indicate that content for the given quick share id + * could not be found. + * + * @author Alex Miller + * @since Cloud/4.2 + */ +public class InvalidSharedIdException extends AlfrescoRuntimeException +{ + private static final long serialVersionUID = -8652843674476371259L; + + public InvalidSharedIdException(String sharedId) + { + super("Unable to find: " + sharedId); + } + +} diff --git a/source/java/org/alfresco/service/cmr/quickshare/QuickShareDTO.java b/source/java/org/alfresco/service/cmr/quickshare/QuickShareDTO.java new file mode 100644 index 0000000000..728628ff88 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/quickshare/QuickShareDTO.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2005-2012 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 . + */ +package org.alfresco.service.cmr.quickshare; + +import java.io.Serializable; + +/** + * Data transfer object for holding quick share information. + * + * @author Alex Miller + * @since Cloud/4.2 + */ +public class QuickShareDTO implements Serializable +{ + private static final long serialVersionUID = -2163618127531335360L; + + private String sharedId; + + /** + * Default constructor + * + * @param sharedId The quick share id + */ + public QuickShareDTO(String sharedId) + { + this.sharedId = sharedId; + } + + /** + * Copy constructor + */ + public QuickShareDTO(QuickShareDTO from) + { + this(from.getId()); + } + + /** + * @return The share id + */ + public String getId() + { + return this.sharedId; + } +} diff --git a/source/java/org/alfresco/service/cmr/quickshare/QuickShareDisabledException.java b/source/java/org/alfresco/service/cmr/quickshare/QuickShareDisabledException.java new file mode 100644 index 0000000000..9e0f975c44 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/quickshare/QuickShareDisabledException.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005-2012 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 . + */ +package org.alfresco.service.cmr.quickshare; + +import org.alfresco.error.AlfrescoRuntimeException; + +/** + * Exception thrown by the QUickShare service when QuickShare is disabled. + * + * @author Alex Miller + * @since Cloud/4.2 + */ +public class QuickShareDisabledException extends AlfrescoRuntimeException +{ + private static final long serialVersionUID = -640705116576240570L; + + public QuickShareDisabledException(String message) + { + super(message); + } + +} diff --git a/source/java/org/alfresco/service/cmr/quickshare/QuickShareService.java b/source/java/org/alfresco/service/cmr/quickshare/QuickShareService.java new file mode 100644 index 0000000000..b2efb74030 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/quickshare/QuickShareService.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2005-2012 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 . + */ +package org.alfresco.service.cmr.quickshare; + +import java.util.Map; + +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.Pair; + +/** + * The QuickShare service. + * + * Responsible for creating, updating and retrieving Quick share metadata, + * + * @author Alex Miller, janv + * @since Cloud/4.2 + */ +public interface QuickShareService +{ + /** + * Share content identified by nodeRef. + * + * @param nodeRef The NodeRef of the content to share + * @return QuickDTO with details of the share + */ + public QuickShareDTO shareContent(NodeRef nodeRef) throws QuickShareDisabledException, InvalidNodeRefException; + + /** + * Get QuickShare related metadata for the given node. + * + * @param nodeRef + * @return + */ + public Map getMetaData(NodeRef nodeRef) throws QuickShareDisabledException, InvalidNodeRefException; + + /** + * Get QuickShare related metadata for the given shareId. + * + * @param shareId + * @return + */ + public Map getMetaData(String shareId) throws QuickShareDisabledException, InvalidSharedIdException; + + /** + * Get the tenant domain and node reference for the the given share id. + * + * @param sharedId + * @return + */ + public Pair getTenantNodeRefFromSharedId(String sharedId) throws QuickShareDisabledException, InvalidSharedIdException; + + /** + * Unshare the content identified by sharedId + * + * @param sharedId The shared id of the content to unshare. + */ + public void unshareContent(String sharedId) throws QuickShareDisabledException, InvalidSharedIdException; +}