From 25141be82116efa4b8edc91d4f57aa88f36f83e6 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Wed, 11 May 2016 10:49:29 +0000 Subject: [PATCH] Merged HEAD (5.2) to 5.2.N (5.2.1) 126368 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 119796 jvonka: FileFolder API - NodeApiTest - add tests (+ve & -ve) for create folder RA-635 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126713 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/rest/api/impl/NodesImpl.java | 12 +- .../org/alfresco/rest/api/model/Document.java | 9 +- .../org/alfresco/rest/api/model/Folder.java | 8 +- .../org/alfresco/rest/api/model/Node.java | 42 ++++-- .../alfresco/rest/api/tests/NodeApiTest.java | 126 +++++++++++++++--- 5 files changed, 158 insertions(+), 39 deletions(-) diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index bdf508b4fa..8f293a1781 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -72,6 +72,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; @@ -952,7 +953,16 @@ public class NodesImpl implements Nodes props.put(ContentModel.PROP_NAME, nodeName); QName assocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName)); - NodeRef nodeRef = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef(); + + NodeRef nodeRef; + try + { + nodeRef = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef(); + } + catch (DuplicateChildNodeNameException dcne) + { + throw new ConstraintViolatedException(dcne.getMessage()); + } List aspectNames = nodeInfo.getAspectNames(); if (aspectNames != null) diff --git a/source/java/org/alfresco/rest/api/model/Document.java b/source/java/org/alfresco/rest/api/model/Document.java index 8ce426e6b9..71293df173 100644 --- a/source/java/org/alfresco/rest/api/model/Document.java +++ b/source/java/org/alfresco/rest/api/model/Document.java @@ -29,6 +29,7 @@ import java.io.Serializable; import java.math.BigInteger; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonInclude; import org.alfresco.model.ContentModel; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ContentData; @@ -42,15 +43,11 @@ import org.alfresco.service.namespace.QName; * @author janv * */ +@JsonInclude(JsonInclude.Include.NON_NULL) public class Document extends Node { private ContentInfo contentInfo; - // instance init block - { - this.isFolder = Boolean.FALSE; - } - public Document() { super(); } @@ -67,6 +64,8 @@ public class Document extends Node String mimeTypeName = sr.getMimetypeService().getDisplaysByMimetype().get(mimeType); this.contentInfo = new ContentInfo(mimeType, mimeTypeName, cd.getSize(), cd.getEncoding()); } + + this.isFolder = false; } public ContentInfo getContent() diff --git a/source/java/org/alfresco/rest/api/model/Folder.java b/source/java/org/alfresco/rest/api/model/Folder.java index fbb2fe8897..812be977d2 100644 --- a/source/java/org/alfresco/rest/api/model/Folder.java +++ b/source/java/org/alfresco/rest/api/model/Folder.java @@ -29,6 +29,7 @@ package org.alfresco.rest.api.model; import java.io.Serializable; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonInclude; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -39,13 +40,9 @@ import org.alfresco.service.namespace.QName; * @author steveglover * @author janv */ +@JsonInclude(JsonInclude.Include.NON_NULL) public class Folder extends Node { - // instance init block - { - this.isFolder = Boolean.TRUE; - } - public Folder() { super(); @@ -54,6 +51,7 @@ public class Folder extends Node public Folder(NodeRef nodeRef, NodeRef parentNodeRef, Map nodeProps, Map mapUserInfo, ServiceRegistry sr) { super(nodeRef, parentNodeRef, nodeProps, mapUserInfo, sr); + this.isFolder = true; } @Override diff --git a/source/java/org/alfresco/rest/api/model/Node.java b/source/java/org/alfresco/rest/api/model/Node.java index 2196a7a119..81e5b46e22 100644 --- a/source/java/org/alfresco/rest/api/model/Node.java +++ b/source/java/org/alfresco/rest/api/model/Node.java @@ -31,11 +31,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonInclude; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.rest.framework.resource.UniqueId; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.NoSuchPersonException; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.QName; @@ -49,6 +50,7 @@ import org.apache.chemistry.opencmis.commons.data.PropertyData; * @author Gethin James * @author janv */ +@JsonInclude(JsonInclude.Include.NON_NULL) public class Node implements Comparable { protected NodeRef nodeRef; @@ -142,15 +144,29 @@ public class Node implements Comparable return userInfo; } - @UniqueId - public NodeRef getNodeRef() - { - return nodeRef; + private String getNodeRefAsString(NodeRef nRef) { + return (nRef != null ? nRef.getId() : null); } - public void setNodeRef(NodeRef nodeRef) + private NodeRef getStringAsNodeRef(String nRefString) { + if(! NodeRef.isNodeRef(nRefString)) + { + return new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nRefString); + } + else + { + return new NodeRef(nRefString); + } + } + + public String getId() { - this.nodeRef = nodeRef; + return getNodeRefAsString(this.nodeRef); + } + + public void setId(String id) + { + this.nodeRef = getStringAsNodeRef(id); } public Date getCreatedAt() @@ -222,14 +238,14 @@ public class Node implements Comparable this.aspectNames = aspectNames; } - public NodeRef getParentId() + public String getParentId() { - return parentNodeRef; + return getNodeRefAsString(parentNodeRef); } - public void setParentId(NodeRef parentNodeRef) + public void setParentId(String parentId) { - this.parentNodeRef = parentNodeRef; + this.parentNodeRef = getStringAsNodeRef(parentId); } public Boolean getIsFolder() @@ -265,13 +281,13 @@ public class Node implements Comparable } Node node = (Node)other; - return EqualsHelper.nullSafeEquals(getNodeRef(), node.getNodeRef()); + return EqualsHelper.nullSafeEquals(getId(), node.getId()); } @Override public int compareTo(Node node) { - return getNodeRef().toString().compareTo(node.getNodeRef().toString()); + return getId().toString().compareTo(node.getId().toString()); } @Override diff --git a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java index 05a6e4f019..0e2e5cd721 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + import org.alfresco.model.ContentModel; import org.alfresco.model.ForumModel; import org.alfresco.repo.content.MimetypeMap; @@ -56,10 +57,13 @@ import org.alfresco.rest.api.tests.util.MultiPartBuilder.MultiPartRequest; import org.alfresco.rest.api.tests.util.RestApiUtil; import org.alfresco.rest.framework.jacksonextensions.JacksonHelper; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.site.SiteVisibility; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.annotate.JsonSerialize; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -67,15 +71,18 @@ import org.springframework.util.ResourceUtils; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.Serializable; import java.net.URL; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.UUID; /** * API tests for: @@ -304,7 +311,7 @@ public class NodeApiTest extends AbstractBaseApiTest Document node = (Document) nodes.get(2); assertEquals(content1, node.getName()); assertEquals("cm:content", node.getNodeType()); - assertEquals(contentNodeRef.getId(), node.getNodeRef().getId()); + assertEquals(contentNodeRef.getId(), node.getId()); UserInfo createdByUser = node.getCreatedByUser(); assertEquals(user1, createdByUser.getUserName()); assertEquals(user1 + " " + user1, createdByUser.getDisplayName()); @@ -426,14 +433,14 @@ public class NodeApiTest extends AbstractBaseApiTest AuthenticationUtil.setFullyAuthenticatedUser(user1); HttpResponse response = getSingle(NodesEntityResource.class, user1, Nodes.PATH_MY, null, 200); Node node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class); - NodeRef myFilesNodeRef = node.getNodeRef(); - assertNotNull(myFilesNodeRef); + String myFilesNodeId = node.getId(); + assertNotNull(myFilesNodeId); assertEquals(user1, node.getName()); assertTrue(node.getIsFolder()); // /Company Home/User Homes/user/folder_A String folderA = "folder" + System.currentTimeMillis() + "_A"; - NodeRef folderA_Ref = repoService.createFolder(myFilesNodeRef, folderA); + NodeRef folderA_Ref = repoService.createFolder(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, myFilesNodeId), folderA); // /Company Home/User Homes/user/folder_A/folder_B String folderB = "folder" + System.currentTimeMillis() + "_B"; @@ -483,7 +490,7 @@ public class NodeApiTest extends AbstractBaseApiTest HttpResponse response = getSingle(NodesEntityResource.class, user1, Nodes.PATH_ROOT, null, 200); Node node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class); assertEquals("Company Home", node.getName()); - assertNotNull(node.getNodeRef()); + assertNotNull(node.getId()); assertNull(node.getPath()); // unknown alias @@ -491,23 +498,23 @@ public class NodeApiTest extends AbstractBaseApiTest response = getSingle(NodesEntityResource.class, user1, Nodes.PATH_MY, null, 200); node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class); - NodeRef myFilesNodeRef = node.getNodeRef(); - assertNotNull(myFilesNodeRef); + String myFilesNodeId = node.getId(); + assertNotNull(myFilesNodeId); assertEquals(user1, node.getName()); assertTrue(node.getIsFolder()); assertNull(node.getPath()); // note: path can be optionally "select"'ed - see separate test response = getSingle(NodesEntityResource.class, user1, Nodes.PATH_SHARED, null, 200); node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class); - NodeRef sharedFilesNodeRef = node.getNodeRef(); - assertNotNull(sharedFilesNodeRef); + String sharedFilesNodeId = node.getId(); + assertNotNull(sharedFilesNodeId); assertEquals("Shared", node.getName()); assertTrue(node.getIsFolder()); assertNull(node.getPath()); //Delete user1's home AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); - repoService.getNodeService().deleteNode(myFilesNodeRef); + repoService.getNodeService().deleteNode(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, myFilesNodeId)); AuthenticationUtil.setFullyAuthenticatedUser(user1); getSingle(NodesEntityResource.class, user1, Nodes.PATH_MY, null, 404); // Not found @@ -544,7 +551,7 @@ public class NodeApiTest extends AbstractBaseApiTest assertEquals(MimetypeMap.MIMETYPE_PDF, contentInfo.getMimeType()); // Retrieve the uploaded file - response = getSingle(NodesEntityResource.class, user1, document.getNodeRef().getId(), null, 200); + response = getSingle(NodesEntityResource.class, user1, document.getId(), null, 200); document = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class); assertEquals(fileName, document.getName()); contentInfo = document.getContent(); @@ -573,7 +580,7 @@ public class NodeApiTest extends AbstractBaseApiTest reqBody = MultiPartBuilder.create() .setFileData(new FileData(fileName2, file2, MimetypeMap.MIMETYPE_TEXT_PLAIN)) .build(); - post(getChildrenUrl(user1Home.getNodeRef()), user2, new String(reqBody.getBody()), null, reqBody.getContentType(), 403); + post(getChildrenUrl(user1Home.getId()), user2, new String(reqBody.getBody()), null, reqBody.getContentType(), 403); response = getAll(getChildrenUrl(Nodes.PATH_MY), user1, paging, 200); pagingResult = parsePaging(response.getJsonResponse()); @@ -581,7 +588,7 @@ public class NodeApiTest extends AbstractBaseApiTest assertEquals("Access Denied. The file shouldn't have been uploaded.", numOfNodes + 1, pagingResult.getCount().intValue()); // User1 tries to upload a file into a document rather than a folder! - post(getChildrenUrl(document.getNodeRef()), user1, new String(reqBody.getBody()), null, reqBody.getContentType(), 400); + post(getChildrenUrl(document.getId()), user1, new String(reqBody.getBody()), null, reqBody.getContentType(), 400); // Try to upload a file without defining the required formData reqBody = MultiPartBuilder.create().build(); @@ -622,7 +629,7 @@ public class NodeApiTest extends AbstractBaseApiTest assertEquals(MimetypeMap.MIMETYPE_TEXT_PLAIN, contentInfo.getMimeType()); // Retrieve the uploaded file - response = getSingle(NodesEntityResource.class, userOneN1.getId(), document.getNodeRef().getId(), null, 200); + response = getSingle(NodesEntityResource.class, userOneN1.getId(), document.getId(), null, 200); document = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class); assertEquals(fileName, document.getName()); contentInfo = document.getContent(); @@ -659,7 +666,7 @@ public class NodeApiTest extends AbstractBaseApiTest } /** - * Tests delete. + * Tests delete (folder or file). *

DELETE:

* {@literal :/alfresco/api/-default-/public/alfresco/versions/1/nodes/} */ @@ -699,6 +706,87 @@ public class NodeApiTest extends AbstractBaseApiTest delete("nodes", user1, chNodeRef.getId(), 403); } + /** + * Tests create folder. + *

POST:

+ * {@literal :/alfresco/api/-default-/public/alfresco/versions/1/nodes//children} + */ + @Test + public void testCreateFolder() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(user1); + + NodeRef personNodeRef = personService.getPerson(user1); + NodeRef myFilesNodeRef = repositoryHelper.getUserHome(personNodeRef); + + String postUrl = "nodes/"+myFilesNodeRef.getId()+"/children"; + + Folder f1 = new Folder(); + f1.setName("f1"); + f1.setNodeType("cm:folder"); + + // create folder + HttpResponse response = post(postUrl, user1, toJsonAsStringNonNull(f1), 201); + + Folder f1Created = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Folder.class); + assertNotNull(f1Created.getId()); + assertEquals("f1",f1Created.getName()); + assertEquals("cm:folder",f1Created.getNodeType()); + assertEquals(true, f1Created.getIsFolder()); + assertNotNull(f1Created.getCreatedAt()); + assertEquals(user1,f1Created.getCreatedByUser().getUserName()); + assertNotNull(f1Created.getModifiedAt()); + assertEquals(user1,f1Created.getModifiedByUser().getUserName()); + assertEquals(myFilesNodeRef.getId(), f1Created.getParentId()); + assertTrue(f1Created.getAspectNames().contains("cm:auditable")); + assertNull(f1Created.getProperties()); + assertNull(f1Created.getPath()); + assertNull(f1Created.getIsLink()); + + // create folder with properties + Map props = new HashMap<>(); + props.put("cm:title","my folder title"); + props.put("cm:description","my folder description"); + + Folder f2 = new Folder(); + f2.setName("f2"); + f2.setNodeType("cm:folder"); + f2.setProperties(props); + + response = post(postUrl, user1, toJsonAsStringNonNull(f2), 201); + Folder f2Created = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Folder.class); + assertNotNull(f2Created.getId()); + + assertTrue(f2Created.getAspectNames().contains("cm:auditable")); + assertTrue(f2Created.getAspectNames().contains("cm:titled")); + assertEquals(f2Created.getProperties().get("cm:title"),"my folder title"); + assertEquals(f2Created.getProperties().get("cm:description"),"my folder description"); + + // -ve test - name is mandatory + Folder invalid = new Folder(); + invalid.setNodeType("cm:folder"); + post(postUrl, user1, toJsonAsStringNonNull(invalid), 400); + + // -ve test - node type is mandatory + invalid = new Folder(); + invalid.setName("my folder"); + post(postUrl, user1, toJsonAsStringNonNull(invalid), 400); + + // -ve test - invalid (eg. not a folder) parent id + Folder f3 = new Folder(); + f3.setName("f3"); + f3.setNodeType("cm:folder"); + post("nodes/"+personNodeRef.getId()+"/children", user1, toJsonAsStringNonNull(f3), 400); + + // -ve test - unknown parent folder node id + post("nodes/"+UUID.randomUUID().toString()+"/children", user1, toJsonAsStringNonNull(f3), 404); + + // -ve test - duplicate name + post(postUrl, user1, toJsonAsStringNonNull(f1), 409); + } + + // TODO add test for file/folder links - creating, getting, listing, deleting + private String getChildrenUrl(NodeRef parentNodeRef) { return getChildrenUrl(parentNodeRef.getId()); @@ -724,4 +812,12 @@ public class NodeApiTest extends AbstractBaseApiTest { return "public"; } + + // TODO move into RestApiUtil (and statically init the OM) + private String toJsonAsStringNonNull(Object obj) throws IOException + { + ObjectMapper om = new ObjectMapper(); + om.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); + return om.writeValueAsString(obj); + } }