diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index d6acd0a396..eded636f15 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -1610,9 +1610,28 @@ public class NodesImpl implements Nodes { assocTypeQName = getAssocType(nodeInfo.getAssociation().getAssocType()); } + + Boolean versionMajor = null; + String str = parameters.getParameter(PARAM_VERSION_MAJOR); + if (str != null) + { + versionMajor = new Boolean(str); + } + String versionComment = parameters.getParameter(PARAM_VERSION_COMMENT); // Create the node - NodeRef nodeRef = createNodeImpl(parentNodeRef, nodeName, nodeTypeQName, props, assocTypeQName); + NodeRef nodeRef; + + if (isContent) + { + // create empty file node - note: currently will be set to default encoding only (UTF-8) + nodeRef = createNewFile(parentNodeRef, nodeName, nodeTypeQName, null, props, assocTypeQName, parameters, versionMajor, versionComment); + } + else + { + // create non-content node + nodeRef = createNodeImpl(parentNodeRef, nodeName, nodeTypeQName, props, assocTypeQName); + } List aspectNames = nodeInfo.getAspectNames(); if (aspectNames != null) @@ -1629,13 +1648,7 @@ public class NodesImpl implements Nodes nodeService.addAspect(nodeRef, aspectQName, null); } } - - if (isContent) - { - // add empty file - note: currently will be set to default encoding only (UTF-8) - writeContent(nodeRef, nodeName, new ByteArrayInputStream("".getBytes()), false); - } - + // eg. to create mandatory assoc(s) if (nodeInfo.getTargets() != null) @@ -2449,9 +2462,9 @@ public class NodesImpl implements Nodes String fileName = null; Content content = null; boolean autoRename = false; - QName nodeTypeQName = null; + QName nodeTypeQName = ContentModel.TYPE_CONTENT; boolean overwrite = false; // If a fileName clashes for a versionable file - Boolean majorVersion = null; + Boolean versionMajor = null; String versionComment = null; String relativePath = null; String renditionNames = null; @@ -2496,7 +2509,7 @@ public class NodesImpl implements Nodes break; case "majorversion": - majorVersion = Boolean.valueOf(field.getValue()); + versionMajor = Boolean.valueOf(field.getValue()); break; case "comment": @@ -2571,7 +2584,7 @@ public class NodesImpl implements Nodes { // overwrite existing (versionable) file BasicContentInfo contentInfo = new ContentInfoImpl(content.getMimetype(), content.getEncoding(), -1, null); - return updateExistingFile(parentNodeRef, existingFile, fileName, contentInfo, content.getInputStream(), parameters, majorVersion, versionComment); + return updateExistingFile(parentNodeRef, existingFile, fileName, contentInfo, content.getInputStream(), parameters, versionMajor, versionComment); } else { @@ -2579,9 +2592,18 @@ public class NodesImpl implements Nodes throw new ConstraintViolatedException(fileName + " already exists."); } } + + // Note: pending REPO-159, we currently auto-enable versioning on new upload (but not when creating empty file) + if (versionMajor == null) + { + versionMajor = true; + } // Create a new file. - final Node fileNode = createNewFile(parentNodeRef, fileName, nodeTypeQName, content, properties, assocTypeQName, parameters, majorVersion, versionComment); + NodeRef nodeRef = createNewFile(parentNodeRef, fileName, nodeTypeQName, content, properties, assocTypeQName, parameters, versionMajor, versionComment); + + // Create the response + final Node fileNode = getFolderOrDocumentFullInfo(nodeRef, parentNodeRef, nodeTypeQName, parameters); // RA-1052 try @@ -2633,40 +2655,44 @@ public class NodesImpl implements Nodes } } - private Node createNewFile(NodeRef parentNodeRef, String fileName, QName nodeType, Content content, Map props, QName assocTypeQName, Parameters params, - Boolean versionMajor, String versionComment) + private NodeRef createNewFile(NodeRef parentNodeRef, String fileName, QName nodeType, Content content, Map props, QName assocTypeQName, Parameters params, + Boolean versionMajor, String versionComment) { - if (nodeType == null) - { - nodeType = ContentModel.TYPE_CONTENT; - } - NodeRef nodeRef = createNodeImpl(parentNodeRef, fileName, nodeType, props, assocTypeQName); - - // Write content - writeContent(nodeRef, fileName, content.getInputStream(), true); - - behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE); - try + + if (content == null) { - // by default, first version is major, unless specified otherwise - VersionType versionType = VersionType.MAJOR; - if ((versionMajor != null) && (! versionMajor)) + // Write "empty" content + writeContent(nodeRef, fileName, new ByteArrayInputStream("".getBytes()), false); + } + else + { + // Write content + writeContent(nodeRef, fileName, content.getInputStream(), true); + } + + if ((versionMajor != null) || (versionComment != null)) + { + behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE); + try { - versionType = VersionType.MINOR; + // by default, first version is major, unless specified otherwise + VersionType versionType = VersionType.MAJOR; + if ((versionMajor != null) && (!versionMajor)) + { + versionType = VersionType.MINOR; + } + + createVersion(nodeRef, false, versionType, versionComment); + + extractMetadata(nodeRef); + } finally + { + behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE); } - - createVersion(nodeRef, false, versionType, versionComment); - - extractMetadata(nodeRef); - } - finally - { - behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE); } - // Create the response - return getFolderOrDocumentFullInfo(nodeRef, parentNodeRef, nodeType, params); + return nodeRef; } private String getStringOrNull(String value) diff --git a/source/test-java/org/alfresco/rest/DeletedNodesTest.java b/source/test-java/org/alfresco/rest/DeletedNodesTest.java index ae1e0c59f5..fdfa70cf93 100644 --- a/source/test-java/org/alfresco/rest/DeletedNodesTest.java +++ b/source/test-java/org/alfresco/rest/DeletedNodesTest.java @@ -86,12 +86,13 @@ public class DeletedNodesTest extends AbstractSingleNetworkSiteTest String folder1 = "folder-testCreateAndDelete-" + now.getTime() + "_1"; Folder createdFolder = createFolder(tDocLibNodeId, folder1, null); assertNotNull(createdFolder); + String f1Id = createdFolder.getId(); //Create a folder outside a site Folder createdFolderNonSite = createFolder(Nodes.PATH_MY, folder1, null); assertNotNull(createdFolderNonSite); - Document document = createEmptyTextFile(createdFolder, "d1.txt"); + Document document = createEmptyTextFile(f1Id, "d1.txt"); PublicApiClient.Paging paging = getPaging(0, 100); @@ -176,16 +177,17 @@ public class DeletedNodesTest extends AbstractSingleNetworkSiteTest String folder1 = "folder" + now.getTime() + "_1"; Folder createdFolder = createFolder(tDocLibNodeId, folder1, null); assertNotNull(createdFolder); + String f1Id = createdFolder.getId(); //Create a folder outside a site Folder createdFolderNonSite = createFolder(Nodes.PATH_MY, folder1, null); assertNotNull(createdFolderNonSite); - Document document = createEmptyTextFile(createdFolder, "restoreme.txt"); + Document document = createEmptyTextFile(f1Id, "restoreme.txt"); deleteNode(document.getId()); //Create another document with the same name - Document documentSameName = createEmptyTextFile(createdFolder, "restoreme.txt"); + Document documentSameName = createEmptyTextFile(f1Id, "restoreme.txt"); //Can't restore a node of the same name post(URL_DELETED_NODES+"/"+document.getId()+"/restore", null, null, Status.STATUS_CONFLICT); diff --git a/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java b/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java index 2f19008dda..7b4cae86e6 100644 --- a/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java @@ -742,7 +742,12 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi return RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class); } - protected Document createEmptyTextFile(Folder parentFolder, String docName) throws Exception + protected Document createEmptyTextFile(String parentFolderId, String docName) throws Exception + { + return createEmptyTextFile(parentFolderId, docName, null, 201); + } + + protected Document createEmptyTextFile(String parentFolderId, String docName, Map params, int expectedStatus) throws Exception { Document d1 = new Document(); d1.setName(docName); @@ -752,17 +757,17 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi d1.setContent(ci); // create empty file - HttpResponse response = post(getNodeChildrenUrl(parentFolder.getId()), toJsonAsStringNonNull(d1), 201); + HttpResponse response = post(getNodeChildrenUrl(parentFolderId), toJsonAsStringNonNull(d1), params, null, "alfresco", expectedStatus); return RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class); } - protected Document updateTextFile(String contentId, String textContent, Map parameters) throws IOException, Exception + protected Document updateTextFile(String contentId, String textContent, Map params) throws IOException, Exception { ByteArrayInputStream inputStream = new ByteArrayInputStream(textContent.getBytes()); File txtFile = TempFileProvider.createTempFile(inputStream, getClass().getSimpleName(), ".txt"); BinaryPayload payload = new BinaryPayload(txtFile); - HttpResponse response = putBinary(getNodeContentUrl(contentId), payload, null, parameters, 200); + HttpResponse response = putBinary(getNodeContentUrl(contentId), payload, null, params, 200); return RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class); } diff --git a/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java b/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java index 5fb6348d59..34860cfb43 100644 --- a/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java @@ -69,9 +69,10 @@ public class ActivitiesPostingTest extends AbstractSingleNetworkSiteTest String folder1 = "folder" + System.currentTimeMillis() + "_1"; Folder createdFolder = createFolder(tDocLibNodeId, folder1, null); assertNotNull(createdFolder); + String f1Id = createdFolder.getId(); String docName = "d1.txt"; - Document documentResp = createEmptyTextFile(createdFolder, docName); + Document documentResp = createEmptyTextFile(f1Id, docName); //Update the file Document dUpdate = new Document(); @@ -141,12 +142,14 @@ public class ActivitiesPostingTest extends AbstractSingleNetworkSiteTest List activities = getMyActivities(); String folder1 = "nonSitefolder" + System.currentTimeMillis() + "_1"; + //Create a folder outside a site Folder createdFolder = createFolder(Nodes.PATH_MY, folder1, null); assertNotNull(createdFolder); + String f1Id = createdFolder.getId(); String docName = "nonsite_d1.txt"; - Document documentResp = createEmptyTextFile(createdFolder, docName); + Document documentResp = createEmptyTextFile(f1Id, docName); assertNotNull(documentResp); //Update the file 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 14ef36d352..0926f91d76 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -2872,6 +2872,74 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest f1.setNodeType("app:glossary"); f1.expected(folderResp); + + { + // test versioning for metadata-only updates + + Map params = new HashMap<>(); + params.put("majorVersion", "true"); + params.put("comment", "Initial empty file :-)"); + + String fileName = "My File"; + Node nodeResp = createEmptyTextFile(f0Id, fileName, params, 201); + assertEquals("1.0", nodeResp.getProperties().get("cm:versionLabel")); + + props = new HashMap<>(); + props.put("cm:title", "my file title"); + dUpdate = new Document(); + dUpdate.setProperties(props); + + response = put(URL_NODES, dId, toJsonAsStringNonNull(dUpdate), null, 200); + nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + assertEquals("1.0", nodeResp.getProperties().get("cm:versionLabel")); + + // turn-off auto-version on metadata-only updates (OOTB this is now false by default, as per MNT-12226) + props = new HashMap<>(); + props.put("cm:autoVersionOnUpdateProps", true); + dUpdate = new Document(); + dUpdate.setProperties(props); + + response = put(URL_NODES, dId, toJsonAsStringNonNull(dUpdate), null, 200); + nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + assertEquals("1.1", nodeResp.getProperties().get("cm:versionLabel")); + + props = new HashMap<>(); + props.put("cm:title","my file title 2"); + dUpdate = new Document(); + dUpdate.setProperties(props); + + response = put(URL_NODES, dId, toJsonAsStringNonNull(dUpdate), null, 200); + nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + assertEquals("1.2", nodeResp.getProperties().get("cm:versionLabel")); + + props = new HashMap<>(); + props.put("cm:title","my file title 3"); + dUpdate = new Document(); + dUpdate.setProperties(props); + + response = put(URL_NODES, dId, toJsonAsStringNonNull(dUpdate), null, 200); + nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + assertEquals("1.3", nodeResp.getProperties().get("cm:versionLabel")); + + // turn-off auto-version on metadata-only updates + props = new HashMap<>(); + props.put("cm:autoVersionOnUpdateProps", false); + dUpdate = new Document(); + dUpdate.setProperties(props); + + response = put(URL_NODES, dId, toJsonAsStringNonNull(dUpdate), null, 200); + nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + assertEquals("1.3", nodeResp.getProperties().get("cm:versionLabel")); + + props = new HashMap<>(); + props.put("cm:title","my file title 4"); + dUpdate = new Document(); + dUpdate.setProperties(props); + + response = put(URL_NODES, dId, toJsonAsStringNonNull(dUpdate), null, 200); + nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + assertEquals("1.3", nodeResp.getProperties().get("cm:versionLabel")); + } // -ve test - fail on unknown property props = new HashMap<>();