mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
<import resource="classpath:alfresco/comment-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/discussions-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/links-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/quickshare-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/rating-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/remote-credentials-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/oauth1-credentials-store-services-context.xml"/>
|
||||
|
65
config/alfresco/quickshare-services-context.xml
Normal file
65
config/alfresco/quickshare-services-context.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Transaction Interceptors for the Calendar Service -->
|
||||
<bean id="quickShareServiceReadTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
|
||||
<property name="advice">
|
||||
<ref bean="retryingReadTxnAdvice"/>
|
||||
</property>
|
||||
<property name="mappedNames">
|
||||
<list>
|
||||
<value>canDownloadAnonymously</value>
|
||||
<value>getMetaData</value>
|
||||
<value>getTenantNodeRefFromSharedId</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="quickShareServiceWriteTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
|
||||
<property name="advice">
|
||||
<ref bean="retryingWriteTxnAdvice"/>
|
||||
</property>
|
||||
<property name="mappedNames">
|
||||
<list>
|
||||
<value>shareContent</value>
|
||||
<value>update</value>
|
||||
<value>unshareContent</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Calendar Service -->
|
||||
<bean id="QuickShareService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<value>org.alfresco.service.cmr.quickshare.QuickShareService</value>
|
||||
</property>
|
||||
<property name="target">
|
||||
<ref bean="quickShareService" />
|
||||
</property>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<idref bean="quickShareServiceReadTxnAdvisor" />
|
||||
<idref bean="quickShareServiceWriteTxnAdvisor" />
|
||||
<idref bean="checkTxnAdvisor" />
|
||||
<idref bean="AuditMethodInterceptor" />
|
||||
<idref bean="exceptionTranslator" />
|
||||
<idref bean="CalendarService_security" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Calendar Service base bean -->
|
||||
<bean id="quickShareService" class="org.alfresco.repo.quickshare.QuickShareServiceImpl" init-method="init">
|
||||
<property name="attributeService" ref="AttributeService"/>
|
||||
<property name="enabled" value="${system.quickshare.enabled}" />
|
||||
<property name="nodeService" ref="NodeService"/>
|
||||
<property name="personService" ref="PersonService"/>
|
||||
<property name="policyComponent" ref="policyComponent"/>
|
||||
<property name="tenantService" ref="tenantService"/>
|
||||
<property name="thumbnailService" ref="ThumbnailService"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<QName,Serializable> props = new HashMap<QName,Serializable>(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<Void>()
|
||||
{
|
||||
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<String, Object> getMetaData(NodeRef nodeRef)
|
||||
{
|
||||
checkEnabled();
|
||||
|
||||
Map<QName, Serializable> nodeProps = getNodeProperties(nodeRef);
|
||||
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
|
||||
String modifierUserName = (String)nodeProps.get(ContentModel.PROP_MODIFIER);
|
||||
Map<QName, Serializable> 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<String, Object> metadata = new HashMap<String, Object>(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<String> thumbnailDefs = new ArrayList<String>(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<ThumbnailDefinition> 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<NodeRef> thumbnailRefs = thumbnailService.getThumbnails(nodeRef, ContentModel.PROP_CONTENT, null, null);
|
||||
List<String> thumbnailNames = new ArrayList<String>(thumbnailRefs.size());
|
||||
for (NodeRef thumbnailRef : thumbnailRefs)
|
||||
{
|
||||
thumbnailNames.add((String)nodeService.getProperty(thumbnailRef, ContentModel.PROP_NAME));
|
||||
}
|
||||
metadata.put("thumbnailNames", thumbnailNames);
|
||||
|
||||
metadata.put("lastThumbnailModificationData", (List<String>)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<String, Object> model = new HashMap<String, Object>(1);
|
||||
model.put("item", metadata);
|
||||
return model;
|
||||
}
|
||||
|
||||
private Map<QName, Serializable> getNodeProperties(NodeRef nodeRef)
|
||||
{
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
if (! typeQName.equals(ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
throw new InvalidNodeRefException(nodeRef);
|
||||
}
|
||||
|
||||
Map<QName, Serializable> nodeProps = nodeService.getProperties(nodeRef);
|
||||
return nodeProps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<String, NodeRef> getTenantNodeRefFromSharedId(final String sharedId)
|
||||
{
|
||||
final NodeRef nodeRef = TenantUtil.runAsDefaultTenant(new TenantRunAsWork<NodeRef>()
|
||||
{
|
||||
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<String, NodeRef>(tenantDomain, tenantService.getBaseName(nodeRef));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getMetaData(String sharedId)
|
||||
{
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
Map<String, Object> model = TenantUtil.runAsSystemTenant(new TenantRunAsWork<Map<String, Object>>()
|
||||
{
|
||||
public Map<String, Object> 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<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
String sharedId = (String)nodeService.getProperty(beforeDeleteNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
|
||||
if (sharedId != null)
|
||||
{
|
||||
Pair<String, NodeRef> 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<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
attributeService.removeAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unshareContent(final String sharedId)
|
||||
{
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
TenantUtil.runAsSystemTenant(new TenantRunAsWork<Void>()
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<String, Object> metadata = AuthenticationUtil.runAs(new RunAsWork<Map<String,Object>>(){
|
||||
|
||||
@Override
|
||||
public Map<String, Object> doWork() throws Exception
|
||||
{
|
||||
return quickShareService.getMetaData(testNode);
|
||||
}
|
||||
}, user1.getUsername());
|
||||
|
||||
assertNotNull(metadata);
|
||||
assertTrue(metadata.size() > 0);
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void getMetaDataFromNodeRefByNonOwner()
|
||||
{
|
||||
Map<String, Object> metadata = AuthenticationUtil.runAs(new RunAsWork<Map<String,Object>>(){
|
||||
|
||||
@Override
|
||||
public Map<String, Object> doWork() throws Exception
|
||||
{
|
||||
return quickShareService.getMetaData(testNode);
|
||||
}
|
||||
}, user2.getUsername());
|
||||
|
||||
}
|
||||
|
||||
@Test public void share()
|
||||
{
|
||||
share(testNode, user1.getUsername());
|
||||
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>(){
|
||||
|
||||
@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<Void>()
|
||||
{
|
||||
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
quickShareService.unshareContent(dto.getId());
|
||||
return null;
|
||||
}
|
||||
}, user1.getUsername());
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>(){
|
||||
|
||||
@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<QuickShareDTO>()
|
||||
{
|
||||
@Override
|
||||
public QuickShareDTO doWork() throws Exception
|
||||
{
|
||||
return quickShareService.shareContent(nodeRef);
|
||||
}
|
||||
}, username);
|
||||
}
|
||||
|
||||
@Test public void getMetadataFromShareId()
|
||||
{
|
||||
QuickShareDTO dto = share(testNode, user1.getUsername());
|
||||
|
||||
Map<String, Object> 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<String, Object> metadata = quickShareService.getMetaData(sharedId);
|
||||
}
|
||||
|
||||
@Test public void copyNode()
|
||||
{
|
||||
share(testNode, user1.getUsername());
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
|
||||
@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<QName, Serializable> originalProps = nodeService.getProperties(testNode);
|
||||
|
||||
NodeRef copyNodeRef = copyService.copyAndRename(testNode, userHome, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "copy"), true);
|
||||
|
||||
Map<QName, Serializable> 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());
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<String, Object> getMetaData(NodeRef nodeRef) throws QuickShareDisabledException, InvalidNodeRefException;
|
||||
|
||||
/**
|
||||
* Get QuickShare related metadata for the given shareId.
|
||||
*
|
||||
* @param shareId
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> getMetaData(String shareId) throws QuickShareDisabledException, InvalidSharedIdException;
|
||||
|
||||
/**
|
||||
* Get the tenant domain and node reference for the the given share id.
|
||||
*
|
||||
* @param sharedId
|
||||
* @return
|
||||
*/
|
||||
public Pair<String, NodeRef> 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;
|
||||
}
|
Reference in New Issue
Block a user