From 45089abfb7cfac2fb58849a67b4b0ba074e78551 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Wed, 11 May 2016 11:45:37 +0000 Subject: [PATCH] Merged HEAD (5.2) to 5.2.N (5.2.1) 126500 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 122727 jvonka: (Quick) Shared Links API - update shared links api tests for create, get & delete RA-708, RA-776, RA-750 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126844 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/public-rest-context.xml | 4 +- .../rest/api/impl/QuickShareLinksImpl.java | 84 +++++++++++------- .../rest/api/tests/SharedLinkApiTest.java | 87 ++++++++++--------- 3 files changed, 102 insertions(+), 73 deletions(-) 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)