diff --git a/source/java/org/alfresco/rest/api/QuickShareLinks.java b/source/java/org/alfresco/rest/api/QuickShareLinks.java
index cb885fb5ac..d2e45e23ef 100644
--- a/source/java/org/alfresco/rest/api/QuickShareLinks.java
+++ b/source/java/org/alfresco/rest/api/QuickShareLinks.java
@@ -102,4 +102,6 @@ public interface QuickShareLinks
* API Constants - query parameters, etc
*/
String PARAM_SHAREDBY = "sharedByUser";
+
+ String PARAM_SELECT_ISLINK = "allowableOperations";
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java b/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java
index 62ea6712a3..3937965e0f 100644
--- a/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java
+++ b/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java
@@ -25,6 +25,7 @@ import org.alfresco.repo.quickshare.QuickShareServiceImpl.QuickShareEmailRequest
import org.alfresco.repo.search.QueryParameterDefImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.api.Nodes;
@@ -67,6 +68,7 @@ import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
@@ -76,10 +78,13 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.I18NUtil;
+import org.springframework.extensions.webscripts.WebScriptException;
+import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -114,6 +119,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
private SearchService searchService;
private DictionaryService dictionaryService;
private NamespaceService namespaceService;
+ private SiteService siteService;
public void setServiceRegistry(ServiceRegistry sr)
{
@@ -155,6 +161,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
this.searchService = sr.getSearchService();
this.dictionaryService = sr.getDictionaryService();
this.namespaceService = sr.getNamespaceService();
+ this.siteService = sr.getSiteService();
}
/**
@@ -162,7 +169,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
*
* Note: does *not* require authenticated access for (public) shared link.
*/
- public QuickShareLink readById(final String sharedId, Parameters parameters)
+ public QuickShareLink readById(final String sharedId, final Parameters parameters)
{
checkEnabled();
@@ -177,7 +184,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
{
public QuickShareLink doWork() throws Exception
{
- return getQuickShareInfo(sharedId, noAuth);
+ return getQuickShareInfo(sharedId, noAuth, parameters.getSelectedProperties());
}
}, networkTenantDomain);
}
@@ -264,14 +271,9 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
try
{
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
- String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
- // TODO site check - see ACE-XXX
- //String siteName = getSiteName(nodeRef);
-
- String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
-
- if ((!currentUser.equals(sharedBy)) && (!authorityService.isAdminAuthority(currentUser)))
+ String sharedByUserId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
+ if (! canDeleteSharedLink(nodeRef, sharedByUserId))
{
throw new PermissionDeniedException("Can't perform unshare action: " + sharedId);
}
@@ -307,6 +309,8 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
boolean noAuth = (AuthenticationUtil.getRunAsUser() == null);
+ List selectParam = parameters.getSelectedProperties();
+
for (QuickShareLink qs : nodeIds)
{
String nodeId = qs.getNodeId();
@@ -332,7 +336,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
try
{
QuickShareDTO qsDto = quickShareService.shareContent(nodeRef);
- result.add(getQuickShareInfo(qsDto.getId(), noAuth));
+ result.add(getQuickShareInfo(qsDto.getId(), noAuth, selectParam));
}
catch (InvalidNodeRefException inre)
{
@@ -434,17 +438,18 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
sp.setSkipCount(pagingRequest.getSkipCount());
sp.setMaxItems(pagingRequest.getMaxItems());
- // TODO is perf ok with Solr 4 paging/sorting ? (otherwise make this optional via orderBy and leave default sort as undefined)
sp.addSort("@" + ContentModel.PROP_MODIFIED, false);
ResultSet results = searchService.query(sp);
List qsLinks = new ArrayList<>(results.length());
+ List selectParam = parameters.getSelectedProperties();
+
for (ResultSetRow row : results)
{
NodeRef nodeRef = row.getNodeRef();
- qsLinks.add(getQuickShareInfo(nodeRef, false));
+ qsLinks.add(getQuickShareInfo(nodeRef, false, selectParam));
}
results.close();
@@ -452,23 +457,23 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
return CollectionWithPagingInfo.asPaged(paging, qsLinks, results.hasMore(), new Long(results.getNumberFound()).intValue());
}
- private QuickShareLink getQuickShareInfo(String sharedId, boolean noAuth)
+ private QuickShareLink getQuickShareInfo(String sharedId, boolean noAuth, List selectParam)
{
checkValidShareId(sharedId);
Map map = (Map) quickShareService.getMetaData(sharedId).get("item");
NodeRef nodeRef = new NodeRef((String) map.get("nodeRef"));
- return getQuickShareInfo(nodeRef, map, noAuth);
+ return getQuickShareInfo(nodeRef, map, noAuth, selectParam);
}
- private QuickShareLink getQuickShareInfo(NodeRef nodeRef, boolean noAuth)
+ private QuickShareLink getQuickShareInfo(NodeRef nodeRef, boolean noAuth, List selectParam)
{
Map map = (Map) quickShareService.getMetaData(nodeRef).get("item");
- return getQuickShareInfo(nodeRef, map , noAuth);
+ return getQuickShareInfo(nodeRef, map , noAuth, selectParam);
}
- private QuickShareLink getQuickShareInfo(NodeRef nodeRef, Map map, boolean noAuth)
+ private QuickShareLink getQuickShareInfo(NodeRef nodeRef, Map map, boolean noAuth, List selectParam)
{
String sharedId = (String)map.get("sharedId");
@@ -489,17 +494,24 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
UserInfo modifiedByUser = Node.lookupUserInfo((String)nodeProps.get(ContentModel.PROP_MODIFIER), mapUserInfo, personService, displayNameOnly);
// TODO review - should we return sharedByUser for authenticated users only ?? (not exposed by V0 but needed for "find")
- UserInfo sharedByUser = Node.lookupUserInfo((String)nodeProps.get(QuickShareModel.PROP_QSHARE_SHAREDBY), mapUserInfo, personService, displayNameOnly);
+ String sharedByUserId = (String)nodeProps.get(QuickShareModel.PROP_QSHARE_SHAREDBY);
+ UserInfo sharedByUser = Node.lookupUserInfo(sharedByUserId, mapUserInfo, personService, displayNameOnly);
- // TODO other "properties" (if needed) - eg. cm:title, cm:lastThumbnailModificationData, ... thumbnail info ...
-
- QuickShareLink qs = new QuickShareLink(sharedId, nodeRef.getId());
+ QuickShareLink qs = new QuickShareLink(sharedId, (noAuth ? null : nodeRef.getId()));
qs.setName((String) map.get("name"));
qs.setContent(contentInfo);
qs.setModifiedAt((Date) map.get("modified"));
qs.setModifiedByUser(modifiedByUser);
qs.setSharedByUser(sharedByUser);
+ if ((! noAuth) && selectParam.contains(PARAM_SELECT_ISLINK))
+ {
+ if (canDeleteSharedLink(nodeRef, sharedByUserId))
+ {
+ qs.setAllowableOperations(Collections.singletonList("delete"));
+ }
+ }
+
return qs;
}
catch (InvalidSharedIdException ex)
@@ -514,6 +526,54 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
}
}
+ // TODO push down to QuickShareService and also update v0 webscript (UnshareContentDelete)
+ private boolean canDeleteSharedLink(NodeRef nodeRef, String sharedByUserId)
+ {
+ boolean canDeleteSharedLink = false;
+
+ String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
+ String siteName = getSiteName(nodeRef);
+
+ if (siteName != null)
+ {
+ // node belongs to a site - current user must be a manager or collaborator (irrespective of whether they shared the link or not)
+ String role = siteService.getMembersRole(siteName, currentUser);
+ if (role.equals(SiteModel.SITE_MANAGER) || role.equals(SiteModel.SITE_COLLABORATOR))
+ {
+ canDeleteSharedLink = true;
+ }
+ }
+ else if ((currentUser.equals(sharedByUserId)) || (authorityService.isAdminAuthority(currentUser)))
+ {
+ // node does not belongs to a site - current user must be the person who shared the link or an admin
+ canDeleteSharedLink = true;
+ }
+
+ return canDeleteSharedLink;
+ }
+
+ private String getSiteName(NodeRef nodeRef)
+ {
+ NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
+ while (parent != null && !nodeService.getType(parent).equals(SiteModel.TYPE_SITE))
+ {
+ // check that we can read parent name
+ String parentName = (String) nodeService.getProperty(parent, ContentModel.PROP_NAME);
+
+ if (nodeService.getPrimaryParent(nodeRef) != null)
+ {
+ parent = nodeService.getPrimaryParent(parent).getParentRef();
+ }
+ }
+
+ if (parent == null)
+ {
+ return null;
+ }
+
+ return nodeService.getProperty(parent, ContentModel.PROP_NAME).toString();
+ }
+
private void checkEnabled()
{
if (!enabled)
diff --git a/source/java/org/alfresco/rest/api/model/QuickShareLink.java b/source/java/org/alfresco/rest/api/model/QuickShareLink.java
index 5e823a3cdb..0555ffc6be 100644
--- a/source/java/org/alfresco/rest/api/model/QuickShareLink.java
+++ b/source/java/org/alfresco/rest/api/model/QuickShareLink.java
@@ -19,6 +19,7 @@
package org.alfresco.rest.api.model;
import java.util.Date;
+import java.util.List;
/**
* Representation of quick share link
@@ -45,10 +46,13 @@ public class QuickShareLink
private String name;
private ContentInfo content;
- protected Date modifiedAt;
- protected UserInfo modifiedByUser;
+ private Date modifiedAt;
+ private UserInfo modifiedByUser;
+
+ private UserInfo sharedByUser;
+
+ private List allowableOperations;
- protected UserInfo sharedByUser;
public QuickShareLink()
{
@@ -126,6 +130,16 @@ public class QuickShareLink
this.sharedByUser = sharedByUser;
}
+ public List getAllowableOperations()
+ {
+ return allowableOperations;
+ }
+
+ public void setAllowableOperations(List allowableOperations)
+ {
+ this.allowableOperations = allowableOperations;
+ }
+
// eg. for debug logging etc
@Override
public String toString()
@@ -138,6 +152,7 @@ public class QuickShareLink
sb.append(", modifiedByUser=").append(getModifiedByUser());
sb.append(", sharedByUser=").append(getSharedByUser());
sb.append(", content=").append(getContent());
+ sb.append(", allowableOperations=").append(getAllowableOperations());
sb.append("]");
return sb.toString();
}
diff --git a/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java b/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java
index 138d6d18b7..c229f1ae49 100644
--- a/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java
+++ b/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java
@@ -21,7 +21,6 @@ package org.alfresco.rest.api.tests;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
-import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.People;
import org.alfresco.rest.api.QuickShareLinks;
import org.alfresco.rest.api.impl.QuickShareLinksImpl;
@@ -41,6 +40,7 @@ import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -182,29 +182,54 @@ public class SharedLinkApiTest extends AbstractBaseApiTest
post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 409);
- // auth access to get shared link info
- response = getSingle(QuickShareLinkEntityResource.class, user1, sharedId, null, 200);
+ // auth access to get shared link info - as user1
+ Map params = Collections.singletonMap("select", "allowableOperations");
+ response = getSingle(QuickShareLinkEntityResource.class, user1, sharedId, params, 200);
resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class);
assertEquals(sharedId, resp.getId());
- assertEquals(d1Id, resp.getNodeId());
assertEquals(docName1, resp.getName());
+ assertEquals(d1Id, resp.getNodeId());
assertEquals(user1, resp.getModifiedByUser().getId()); // returned if authenticated
assertEquals(user2, resp.getSharedByUser().getId()); // returned if authenticated
+ assertNull(resp.getAllowableOperations());
- // unauth access to get shared link info
- response = getSingle(QuickShareLinkEntityResource.class, null, sharedId, null, 200);
+ // auth access to get shared link info - as user2
+ params = Collections.singletonMap("select", "allowableOperations");
+ response = getSingle(QuickShareLinkEntityResource.class, user2, sharedId, params, 200);
resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class);
assertEquals(sharedId, resp.getId());
- assertEquals(d1Id, resp.getNodeId());
assertEquals(docName1, resp.getName());
+ assertEquals(d1Id, resp.getNodeId());
- assertNull(resp.getModifiedByUser().getId());
+ assertEquals(user1, resp.getModifiedByUser().getId()); // returned if authenticated
+ assertEquals(user2, resp.getSharedByUser().getId()); // returned if authenticated
+
+ assertEquals(1, resp.getAllowableOperations().size());
+ assertEquals("delete", resp.getAllowableOperations().get(0));
+
+ // allowable operations not selected
+ response = getSingle(QuickShareLinkEntityResource.class, user2, sharedId, null, 200);
+ resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class);
+ assertNull(resp.getAllowableOperations());
+
+
+ // unauth access to get shared link info
+ params = Collections.singletonMap("select", "allowableOperations"); // note: this will be ignore for unauth access
+ response = getSingle(QuickShareLinkEntityResource.class, null, sharedId, params, 200);
+ resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class);
+
+ assertEquals(sharedId, resp.getId());
+ assertEquals(docName1, resp.getName());
+ assertNull(resp.getNodeId()); // nodeId not returned
+ assertNull(resp.getAllowableOperations()); // select is ignored
+
+ assertNull(resp.getModifiedByUser().getId()); // userId not returned
assertEquals(user1+" "+user1, resp.getModifiedByUser().getDisplayName());
- assertNull(resp.getSharedByUser().getId());
+ assertNull(resp.getSharedByUser().getId()); // userId not returned
assertEquals(user2+" "+user2, resp.getSharedByUser().getDisplayName());