diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml
index c18a6f948b..6a2055e1c2 100644
--- a/config/alfresco/public-rest-context.xml
+++ b/config/alfresco/public-rest-context.xml
@@ -487,9 +487,7 @@
-
-
-
+
diff --git a/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java b/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java
index 46b37e6268..2fb1b1a57e 100644
--- a/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java
+++ b/source/java/org/alfresco/rest/api/impl/QuickShareLinksImpl.java
@@ -37,15 +37,19 @@ import org.alfresco.rest.framework.core.exceptions.NotFoundException;
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.ServiceRegistry;
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.ContentData;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
@@ -53,6 +57,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.I18NUtil;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -73,11 +78,19 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
private final static String DISABLED = "QuickShare is disabled system-wide";
private boolean enabled = true;
+ private ServiceRegistry sr;
private QuickShareService quickShareService;
private Nodes nodes;
private NodeService nodeService;
private PersonService personService;
private AuthorityService authorityService;
+ private MimetypeService mimeTypeService;
+
+ public void setServiceRegistry(ServiceRegistry sr)
+ {
+ this.sr = sr;
+ }
+
public void setQuickShareService(QuickShareService quickShareService)
{
@@ -89,21 +102,6 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
this.nodes = nodes;
}
- public void setNodeService(NodeService nodeService)
- {
- this.nodeService = nodeService;
- }
-
- public void setPersonService(PersonService personService)
- {
- this.personService = personService;
- }
-
- public void setAuthorityService(AuthorityService authorityService)
- {
- this.authorityService = authorityService;
- }
-
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
@@ -112,11 +110,14 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
@Override
public void afterPropertiesSet()
{
+ ParameterCheck.mandatory("sr", this.sr);
ParameterCheck.mandatory("quickShareService", this.quickShareService);
ParameterCheck.mandatory("nodes", this.nodes);
- ParameterCheck.mandatory("nodeService", this.nodeService);
- ParameterCheck.mandatory("personService", this.personService);
- ParameterCheck.mandatory("authorityService", this.authorityService);
+
+ this.nodeService = sr.getNodeService();
+ this.personService = sr.getPersonService();
+ this.authorityService = sr.getAuthorityService();
+ this.mimeTypeService = sr.getMimetypeService();
}
/**
@@ -133,11 +134,13 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
Pair pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
+ final boolean noAuth = (AuthenticationUtil.getRunAsUser() == null);
+
return TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork()
{
public QuickShareLink doWork() throws Exception
{
- return getQuickShareInfo(sharedId);
+ return getQuickShareInfo(sharedId, noAuth);
}
}, networkTenantDomain);
}
@@ -255,6 +258,8 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
List result = new ArrayList<>(nodeIds.size());
+ boolean noAuth = (AuthenticationUtil.getRunAsUser() == null);
+
for (QuickShareLink qs : nodeIds)
{
String nodeId = qs.getNodeId();
@@ -268,15 +273,28 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
try
{
- // Note: this throws AccessDeniedException (=> 403) via QuickShareService (when NodeService tries to getAspects)
- QuickShareDTO qsDto = quickShareService.shareContent(nodeRef);
+ // Note: will throw InvalidNodeRefException (=> 404) if node does not exist
+ String sharedId = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
+ if (sharedId != null)
+ {
+ throw new InvalidArgumentException("sharedId already exists: "+nodeId+" ["+sharedId+"]");
+ }
- result.add(getQuickShareInfo(qsDto.getId()));
+ // Note: will throw AccessDeniedException (=> 403) via QuickShareService (when NodeService tries to getAspects)
+ // Note: since we already check node exists above, we can assume that InvalidNodeRefException (=> 404) here means not content (see type check)
+ try
+ {
+ QuickShareDTO qsDto = quickShareService.shareContent(nodeRef);
+ result.add(getQuickShareInfo(qsDto.getId(), noAuth));
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ throw new InvalidArgumentException("Unable to create shared link to non-file content: " + nodeId);
+ }
}
catch (AccessDeniedException ade)
{
- logger.warn("Unable to create shared link: [" + nodeRef + "]");
- throw new PermissionDeniedException("Unable to create shared link: " + nodeId);
+ throw new PermissionDeniedException("Unable to create shared link to node that does not exist: " + nodeId);
}
catch (InvalidNodeRefException inre)
{
@@ -319,7 +337,7 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
}
}
- private QuickShareLink getQuickShareInfo(String sharedId)
+ private QuickShareLink getQuickShareInfo(String sharedId, boolean noAuth)
{
checkValidShareId(sharedId);
@@ -329,10 +347,12 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
NodeRef nodeRef = new NodeRef((String) map.get("nodeRef"));
- ContentInfo contentInfo = new ContentInfo((String) map.get("mimetype"), null, (Long) map.get("size"), null);
+ Map nodeProps = nodeService.getProperties(nodeRef);
+ ContentData cd = (ContentData)nodeProps.get(ContentModel.PROP_CONTENT);
- // note: if not authenticated then we do not currently return userids (to be consistent with v0 internal - limited disclosure)
- boolean noAuth = (AuthenticationUtil.isRunAsUserTheSystemUser()); // TODO review - for now assume "System" implies unauthenticated access
+ String mimeType = cd.getMimetype();
+ String mimeTypeName = mimeTypeService.getDisplaysByMimetype().get(mimeType);
+ ContentInfo contentInfo = new ContentInfo(mimeType, mimeTypeName, cd.getSize(), cd.getEncoding());
//
// modifiedByUser
@@ -340,19 +360,21 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
UserInfo modifiedByUser = null;
if (noAuth)
{
+ // note: if not authenticated then we do not currently return userids (to be consistent with v0 internal - limited disclosure)
modifiedByUser = new UserInfo(null, (String) map.get("modifierFirstName"), (String) map.get("modifierLastName"));
}
else
{
- String modifiedByUserId = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIER);
+ String modifiedByUserId = (String)nodeProps.get(ContentModel.PROP_MODIFIER);
modifiedByUser = new UserInfo(modifiedByUserId, (String) map.get("modifierFirstName"), (String) map.get("modifierLastName"));
}
//
// sharedByUser
+ // TODO review - should we return for authenticated users only ?? (not exposed by V0 but needed for "find")
//
UserInfo sharedByUser = null;
- String sharedByUserId = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
+ String sharedByUserId = (String)nodeProps.get(QuickShareModel.PROP_QSHARE_SHAREDBY);
if (sharedByUserId != null)
{
NodeRef pRef = personService.getPerson(sharedByUserId);
@@ -361,9 +383,9 @@ public class QuickShareLinksImpl implements QuickShareLinks, InitializingBean
PersonService.PersonInfo pInfo = personService.getPerson(pRef);
if (pInfo != null)
{
- // TODO review - limit to authenticated users only ?? (not exposed by V0 but needed for "find")
if (noAuth)
{
+ // note: if not authenticated then we do not currently return userids (to be consistent with v0 internal - limited disclosure)
sharedByUser = new UserInfo(null, pInfo.getFirstName(), pInfo.getLastName());
}
else
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 1d7ea16eb9..dd6f1f9ff5 100644
--- a/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java
+++ b/source/test-java/org/alfresco/rest/api/tests/SharedLinkApiTest.java
@@ -212,16 +212,34 @@ public class SharedLinkApiTest extends AbstractBaseApiTest
assertEquals(d1Id, resp.getNodeId());
assertEquals(docName1, resp.getName());
+ // hmm
+ assertEquals(MimetypeMap.MIMETYPE_BINARY, resp.getContent().getMimeType());
+ assertEquals("Binary File (Octet Stream)", resp.getContent().getMimeTypeName());
+
+ assertEquals(new Long(contentText.length()), resp.getContent().getSizeInBytes());
+ assertEquals("UTF-8", resp.getContent().getEncoding());
+
assertEquals(docModifiedAt.getTime(), resp.getModifiedAt().getTime()); // not changed
assertEquals(docModifiedBy, resp.getModifiedByUser().getId()); // not changed (ie. not user2)
+ assertEquals(docModifiedBy+" "+docModifiedBy, resp.getModifiedByUser().getDisplayName());
assertEquals(user2, resp.getSharedByUser().getId());
+ assertEquals(user2+" "+user2, resp.getSharedByUser().getDisplayName());
- // try to create again (same user) - should return previous shared id
- response = post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 201);
+ // -ve test - try to create again (same user) - already exists
+ post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 400);
+
+
+ // auth access to get shared link info
+ response = getSingle(QuickShareLinkEntityResource.class, user1, sharedId, null, 200);
resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class);
assertEquals(sharedId, resp.getSharedId());
+ assertEquals(d1Id, resp.getNodeId());
+ assertEquals(docName1, resp.getName());
+
+ assertEquals(user1, resp.getModifiedByUser().getId()); // returned if authenticated
+ assertEquals(user2, resp.getSharedByUser().getId()); // returned if authenticated
// unauth access to get shared link info
@@ -248,37 +266,23 @@ public class SharedLinkApiTest extends AbstractBaseApiTest
// TODO unauth access to get shared-link rendition content
- // As user 2 ...
+ // -ve delete tests
+ {
+ // -ve test - user1 cannot delete shared link
+ delete(URL_SHARED_LINKS, user1, sharedId, 403);
- // try to create again (different user, that has read permission) - should return previous shared id
- response = post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 201);
- resp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), QuickShareLink.class);
-
- assertEquals(sharedId, resp.getSharedId());
-
- assertEquals(user1, resp.getModifiedByUser().getId());
- assertEquals(user2, resp.getSharedByUser().getId());
-
-
- // As user 1 ...
-
- // -ve test - user1 cannot delete shared link
- delete(URL_SHARED_LINKS, user1, sharedId, 403);
-
- // As user 2 ...
-
- // delete shared link
- delete(URL_SHARED_LINKS, user2, sharedId, 204);
-
- response = getSingle(NodesEntityResource.class, user2, d1Id, null, 200);
- nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class);
-
- assertEquals(docModifiedAt.getTime(), nodeResp.getModifiedAt().getTime()); // not changed
- assertEquals(docModifiedBy, nodeResp.getModifiedByUser().getId()); // not changed (ie. not user2)
+ // -ve test - delete - cannot delete non-existent link
+ delete(URL_SHARED_LINKS, user1, "dummy", 404);
+ }
// -ve create tests
{
+ // As user 1 ...
+
+ // -ve test - try to create again (different user, that has read permission) - already exists
+ post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 400);
+
// -ve - create - missing nodeId
body = new HashMap<>();
post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 400);
@@ -292,7 +296,7 @@ public class SharedLinkApiTest extends AbstractBaseApiTest
String f1Id = createFolder(user1, myFolderNodeId, "f1 " + RUNID).getId();
body = new HashMap<>();
body.put("nodeId", f1Id);
- post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 404);
+ post(URL_SHARED_LINKS, user1, toJsonAsStringNonNull(body), 400);
// -ve test - cannot create if user does not have permission to read
body = new HashMap<>();
@@ -300,6 +304,21 @@ public class SharedLinkApiTest extends AbstractBaseApiTest
post(URL_SHARED_LINKS, user2, toJsonAsStringNonNull(body), 403);
}
+
+ // delete shared link
+ delete(URL_SHARED_LINKS, user2, sharedId, 204);
+
+ // -ve test - delete - cannot delete non-existent link
+ delete(URL_SHARED_LINKS, user1, sharedId, 404);
+
+
+ response = getSingle(NodesEntityResource.class, user2, d1Id, null, 200);
+ nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class);
+
+ assertEquals(docModifiedAt.getTime(), nodeResp.getModifiedAt().getTime()); // not changed
+ assertEquals(docModifiedBy, nodeResp.getModifiedByUser().getId()); // not changed (ie. not user2)
+
+
// -ve get tests
{
// try to get link that has been deleted (see above)
@@ -311,16 +330,6 @@ public class SharedLinkApiTest extends AbstractBaseApiTest
getSingle(QuickShareLinkEntityResource.class, null, "dummy/content", null, 404);
}
- // -ve delete tests
- {
- // -ve test - delete - cannot delete non-existent link
- delete(URL_SHARED_LINKS, user1, sharedId, 404);
-
- // -ve test - delete - cannot delete non-existent link
- delete(URL_SHARED_LINKS, user1, "dummy", 404);
- }
-
-
// TODO if and when these tests are optionally runnable via remote env then we could skip this part of the test
// (else need to verify test mechanism for enterprise admin via jmx ... etc)