Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)

121851 jvonka: (Quick) Shared Links API - update resource name to "/shared-links"
   - also add REST impl layer
   - TODO review impl (+ add tests)
   RA-775, RA-773, RA-750, RA-708, RA-776


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@126428 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-05-10 10:53:03 +00:00
parent 06f639f03d
commit c03accdbea
4 changed files with 373 additions and 168 deletions

View File

@@ -481,6 +481,28 @@
</property> </property>
</bean> </bean>
<!-- TODO - experimental (review) -->
<bean id="quickShareLinks" class="org.alfresco.rest.api.impl.QuickShareLinksImpl">
<property name="quickShareService" ref="QuickShareService"/>
<property name="nodes" ref="nodes"/>
<property name="nodeService" ref="NodeService"/>
<property name="enabled" value="${system.quickshare.enabled}" />
</bean>
<bean id="QuickShareLinks" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.rest.api.QuickShareLinks</value>
</property>
<property name="target">
<ref bean="quickShareLinks" />
</property>
<property name="interceptorNames">
<list>
<idref bean="legacyExceptionInterceptor" />
</list>
</property>
</bean>
<bean id="favourites" class="org.alfresco.rest.api.impl.FavouritesImpl"> <bean id="favourites" class="org.alfresco.rest.api.impl.FavouritesImpl">
<property name="people" ref="People" /> <property name="people" ref="People" />
<property name="sites" ref="Sites" /> <property name="sites" ref="Sites" />
@@ -702,9 +724,7 @@
<!-- TODO - experimental (review) --> <!-- TODO - experimental (review) -->
<bean class="org.alfresco.rest.api.quicksharelinks.QuickShareLinkEntityResource"> <bean class="org.alfresco.rest.api.quicksharelinks.QuickShareLinkEntityResource">
<property name="quickShareService" ref="QuickShareService" /> <property name="quickShareLinks" ref="QuickShareLinks" />
<property name="nodes" ref="Nodes" />
<property name="nodeService" ref="NodeService" />
</bean> </bean>
<bean class="org.alfresco.rest.api.people.PersonFavouritesRelation"> <bean class="org.alfresco.rest.api.people.PersonFavouritesRelation">

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2005-2016 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.rest.api;
import org.alfresco.rest.api.model.QuickShareLink;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import java.util.List;
/**
* Centralises access to quick share services and maps between representations.
*
* @author janv
*
* @since publicapi1.0
*/
public interface QuickShareLinks
{
/**
* Returns limited metadata regarding the shared (content) link.
*
* Note: does *not* require authenticated access for (public) shared link.
*/
QuickShareLink readById(String sharedId, Parameters parameters);
/**
* Download content via shared link.
*
* Note: does *not* require authenticated access for (public) shared link.
*
* @param sharedId
* @param parameters {@link Parameters}
* @return
* @throws EntityNotFoundException
*/
BinaryResource readProperty(String sharedId, final Parameters parameters) throws EntityNotFoundException;
/**
* Delete the shared link.
*
* Once deleted, the shared link will no longer exist hence get/download will no longer work (ie. return 404).
* If the link is later re-created then a new unique shared id will be generated.
*
* Requires authenticated access.
*
* @param sharedId String id of the quick share
*/
void delete(String sharedId, Parameters parameters);
/**
* Create quick share.
*
* Requires authenticated access.
*
* @param nodeIds
* @param parameters
* @return
*/
List<QuickShareLink> create(List<QuickShareLink> nodeIds, Parameters parameters);
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright (C) 2005-2016 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.rest.api.impl;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.QuickShareLinks;
import org.alfresco.rest.api.model.ContentInfo;
import org.alfresco.rest.api.model.QuickShareLink;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.Parameters;
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.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Centralises access to quick share services and maps between representations.
*
* @author janv
*
* @since publicapi1.0
*/
public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
{
private static final Log logger = LogFactory.getLog(QuickShareLinksImpl.class);
private final static String DISABLED = "QuickShare is disabled system-wide";
private boolean enabled = true;
private QuickShareService quickShareService;
private Nodes nodes;
private NodeService nodeService;
public void setQuickShareService(QuickShareService quickShareService)
{
this.quickShareService = quickShareService;
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
@Override
public void afterPropertiesSet()
{
ParameterCheck.mandatory("quickShareService", this.quickShareService);
ParameterCheck.mandatory("nodes", this.nodes);
ParameterCheck.mandatory("nodeService", this.nodeService);
}
/**
* Returns limited metadata regarding the shared (content) link.
*
* Note: does *not* require authenticated access for (public) shared link.
*/
public QuickShareLink readById(String sharedId, Parameters parameters)
{
if (! enabled)
{
throw new PermissionDeniedException(DISABLED);
}
return getQuickShareInfo(sharedId);
}
/**
* Download content via shared link.
*
* Note: does *not* require authenticated access for (public) shared link.
*
* @param sharedId
* @param parameters {@link Parameters}
* @return
* @throws EntityNotFoundException
*/
public BinaryResource readProperty(String sharedId, final Parameters parameters) throws EntityNotFoundException
{
if (! enabled)
{
throw new PermissionDeniedException(DISABLED);
}
try
{
Pair<String, NodeRef> pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
final NodeRef nodeRef = pair.getSecond();
return TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork<BinaryResource>()
{
public BinaryResource doWork() throws Exception
{
// belt-and-braces (similar to QuickShareContentGet)
if (! nodeService.hasAspect(nodeRef, QuickShareModel.ASPECT_QSHARE))
{
throw new InvalidNodeRefException(nodeRef);
}
return nodes.getContent(nodeRef.getId(), parameters);
}
}, networkTenantDomain);
}
catch (InvalidSharedIdException ex)
{
logger.warn("Unable to find: "+sharedId);
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
catch (InvalidNodeRefException inre){
logger.warn("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
}
/**
* Delete the shared link.
*
* Once deleted, the shared link will no longer exist hence get/download will no longer work (ie. return 404).
* If the link is later re-created then a new unique shared id will be generated.
*
* Requires authenticated access.
*
* @param sharedId String id of the quick share
*/
public void delete(String sharedId, Parameters parameters)
{
if (! enabled)
{
throw new PermissionDeniedException(DISABLED);
}
try
{
quickShareService.unshareContent(sharedId);
}
catch (InvalidSharedIdException ex)
{
logger.warn("Unable to find: "+sharedId);
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
catch (InvalidNodeRefException inre){
logger.warn("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
}
/**
* Create quick share.
*
* Requires authenticated access.
*
* @param nodeIds
* @param parameters
* @return
*/
public List<QuickShareLink> create(List<QuickShareLink> nodeIds, Parameters parameters)
{
List<QuickShareLink> result = new ArrayList<>(nodeIds.size());
for (QuickShareLink qs : nodeIds)
{
String nodeId = qs.getNodeId();
QuickShareDTO qsDto = quickShareService.shareContent(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId));
// TODO should we skip errors (eg. broken share) ?
result.add(getQuickShareInfo(qsDto.getId()));
}
return result;
}
private QuickShareLink getQuickShareInfo(String sharedId)
{
try
{
Map<String, Object> map = (Map<String, Object>)quickShareService.getMetaData(sharedId).get("item");
String nodeId = new NodeRef((String)map.get("nodeRef")).getId();
ContentInfo contentInfo = new ContentInfo((String)map.get("mimetype"), null, (Long)map.get("size"), null);
// note: we do not return modifier user id (to be consistent with v0 internal - limited disclosure)
UserInfo modifier = new UserInfo(null,(String)map.get("modifierFirstName"), (String)map.get("modifierLastName"));
// TODO other "properties" (if needed) - eg. cm:title, cm:lastThumbnailModificationData, ... thumbnail info ...
QuickShareLink qs = new QuickShareLink(sharedId, nodeId);
qs.setName((String)map.get("name"));
qs.setContent(contentInfo);
qs.setModifiedAt((Date)map.get("modified"));
qs.setModifiedByUser(modifier);
return qs;
}
catch (InvalidSharedIdException ex)
{
logger.warn("Unable to find: "+sharedId);
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
catch (InvalidNodeRefException inre){
logger.warn("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
}
}

View File

@@ -18,111 +18,62 @@
*/ */
package org.alfresco.rest.api.quicksharelinks; package org.alfresco.rest.api.quicksharelinks;
import org.alfresco.model.QuickShareModel; import org.alfresco.rest.api.QuickShareLinks;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.ContentInfo;
import org.alfresco.rest.api.model.QuickShareLink; import org.alfresco.rest.api.model.QuickShareLink;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.BinaryProperties; import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiNoAuth; import org.alfresco.rest.framework.WebApiNoAuth;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
import org.alfresco.rest.framework.resource.content.BinaryResource; import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.Parameters;
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.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* An implementation of an Entity Resource for a QuickShareLink (name TBC !!) * An implementation of an Entity Resource for Shared Links.
* *
* @author janv * @author janv
*/ */
@EntityResource(name="quicksharelinks", title = "QuickShareLinks") @EntityResource(name="shared-links", title = "Shared Links")
public class QuickShareLinkEntityResource implements EntityResourceAction.ReadById<QuickShareLink>, public class QuickShareLinkEntityResource implements EntityResourceAction.ReadById<QuickShareLink>,
BinaryResourceAction.Read, EntityResourceAction.Delete, BinaryResourceAction.Read, EntityResourceAction.Delete,
EntityResourceAction.Create<QuickShareLink>, InitializingBean EntityResourceAction.Create<QuickShareLink>, InitializingBean
{ {
// TODO move impl into QuickShare REST service (especially if & when we need to span more than one resource) .... private QuickShareLinks quickShareLinks;
private static final Log logger = LogFactory.getLog(QuickShareLinkEntityResource.class); public void setQuickShareLinks(QuickShareLinks quickShareLinks)
private final static String DISABLED = "QuickShare is disabled system-wide";
private boolean enabled = true;
private QuickShareService quickShareService;
private Nodes nodes;
private NodeService nodeService;
public void setQuickShareService(QuickShareService quickShareService)
{ {
this.quickShareService = quickShareService; this.quickShareLinks = quickShareLinks;
} }
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
@Override @Override
public void afterPropertiesSet() public void afterPropertiesSet()
{ {
ParameterCheck.mandatory("quickShareService", this.quickShareService); ParameterCheck.mandatory("quickShareLinks", this.quickShareLinks);
ParameterCheck.mandatory("nodes", this.nodes);
ParameterCheck.mandatory("nodeService", this.nodeService);
} }
/** /**
* Returns limited metadata regarding the sharedId. * Returns limited metadata regarding the shared (content) link.
* *
* Note: does not require authenticated access ! * Note: does *not* require authenticated access for (public) shared link.
*/ */
@Override @Override
@WebApiDescription(title="Returns quick share information for given sharedId.") @WebApiDescription(title="Get shared link info", description = "Return limited metadata for shared link")
@WebApiNoAuth @WebApiNoAuth
public QuickShareLink readById(String sharedId, Parameters parameters) public QuickShareLink readById(String sharedId, Parameters parameters)
{ {
if (! enabled) return quickShareLinks.readById(sharedId, parameters);
{
throw new PermissionDeniedException(DISABLED);
}
return getQuickShareInfo(sharedId);
} }
/** /**
* Download content via sharedId. * Download content via shared link.
* *
* Note: does not require authenticated access ! * Note: does *not* require authenticated access for (public) shared link.
* *
* @param sharedId * @param sharedId
* @param parameters {@link Parameters} * @param parameters {@link Parameters}
@@ -130,77 +81,29 @@ public class QuickShareLinkEntityResource implements EntityResourceAction.ReadBy
* @throws EntityNotFoundException * @throws EntityNotFoundException
*/ */
@Override @Override
@WebApiDescription(title = "Download content", description = "Download content") @WebApiDescription(title = "Download shared link content", description = "Download content for shared link")
@WebApiNoAuth @WebApiNoAuth
@BinaryProperties({"content"}) @BinaryProperties({"content"})
public BinaryResource readProperty(String sharedId, final Parameters parameters) throws EntityNotFoundException public BinaryResource readProperty(String sharedId, final Parameters parameters) throws EntityNotFoundException
{ {
if (! enabled) return quickShareLinks.readProperty(sharedId, parameters);
{
throw new PermissionDeniedException(DISABLED);
}
try
{
Pair<String, NodeRef> pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
final NodeRef nodeRef = pair.getSecond();
return TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork<BinaryResource>()
{
public BinaryResource doWork() throws Exception
{
// belt-and-braces (similar to QuickSjareContentGet)
if (! nodeService.hasAspect(nodeRef, QuickShareModel.ASPECT_QSHARE))
{
throw new InvalidNodeRefException(nodeRef);
}
return nodes.getContent(nodeRef.getId(), parameters);
}
}, networkTenantDomain);
}
catch (InvalidSharedIdException ex)
{
logger.warn("Unable to find: "+sharedId);
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
catch (InvalidNodeRefException inre){
logger.warn("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
} }
/** /**
* Delete the specified quick share. * Delete the shared link.
*
* Once deleted, the shared link will no longer exist hence get/download will no longer work (ie. return 404).
* If the link is later re-created then a new unique shared id will be generated.
* *
* Requires authenticated access. * Requires authenticated access.
* *
* @param sharedId String id of the quick share * @param sharedId String id of the quick share
*/ */
@Override @Override
@WebApiDescription(title = "Delete quick share", description="Delete the quick share reference") @WebApiDescription(title = "Delete shared link", description="Delete the shared link")
public void delete(String sharedId, Parameters parameters) public void delete(String sharedId, Parameters parameters)
{ {
if (! enabled) quickShareLinks.delete(sharedId, parameters);
{
throw new PermissionDeniedException(DISABLED);
}
try
{
quickShareService.unshareContent(sharedId);
}
catch (InvalidSharedIdException ex)
{
logger.warn("Unable to find: "+sharedId);
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
catch (InvalidNodeRefException inre){
logger.warn("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
} }
/** /**
@@ -213,54 +116,9 @@ public class QuickShareLinkEntityResource implements EntityResourceAction.ReadBy
* @return * @return
*/ */
@Override @Override
@WebApiDescription(title="Create quick share") @WebApiDescription(title="Create shared link", description="Create a new unique system-generated shared (link) id")
public List<QuickShareLink> create(List<QuickShareLink> nodeIds, Parameters parameters) public List<QuickShareLink> create(List<QuickShareLink> nodeIds, Parameters parameters)
{ {
List<QuickShareLink> result = new ArrayList<>(nodeIds.size()); return quickShareLinks.create(nodeIds, parameters);
for (QuickShareLink qs : nodeIds)
{
String nodeId = qs.getNodeId();
QuickShareDTO qsDto = quickShareService.shareContent(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId));
// TODO should we skip errors (eg. broken share) ?
result.add(getQuickShareInfo(qsDto.getId()));
}
return result;
}
private QuickShareLink getQuickShareInfo(String sharedId)
{
try
{
Map<String, Object> map = (Map<String, Object>)quickShareService.getMetaData(sharedId).get("item");
String nodeId = new NodeRef((String)map.get("nodeRef")).getId();
ContentInfo contentInfo = new ContentInfo((String)map.get("mimetype"), null, (Long)map.get("size"), null);
// note: we do not return modifier user id (to be consistent with v0 internal - limited disclosure)
UserInfo modifier = new UserInfo(null,(String)map.get("modifierFirstName"), (String)map.get("modifierLastName"));
// TODO other "properties" (if needed) - eg. cm:title, cm:lastThumbnailModificationData, ... thumbnail info ...
QuickShareLink qs = new QuickShareLink(sharedId, nodeId);
qs.setName((String)map.get("name"));
qs.setContent(contentInfo);
qs.setModifiedAt((Date)map.get("modified"));
qs.setModifiedByUser(modifier);
return qs;
}
catch (InvalidSharedIdException ex)
{
logger.warn("Unable to find: "+sharedId);
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
catch (InvalidNodeRefException inre){
logger.warn("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new EntityNotFoundException("Unable to find: "+sharedId);
}
} }
} }