diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index ad232c6ef2..c80d5a5c2b 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -46,6 +46,7 @@ import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingResults; import org.alfresco.repo.content.ContentLimitViolationException; import org.alfresco.repo.model.Repository; +import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.rest.antlr.WhereClauseParser; @@ -81,6 +82,7 @@ import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; @@ -576,7 +578,7 @@ public class NodesImpl implements Nodes catch (FileNotFoundException fnfe) { // convert checked exception - throw new InvalidNodeRefException(fnfe.getMessage()+" ["+path+"]", parentNodeRef); + throw new EntityNotFoundException(fnfe.getMessage()+" ["+parentNodeRef+","+path+"]"); } return fileInfo.getNodeRef(); @@ -1037,6 +1039,7 @@ public class NodesImpl implements Nodes } catch (DuplicateChildNodeNameException dcne) { + // duplicate - name clash throw new ConstraintViolatedException(dcne.getMessage()); } } @@ -1083,6 +1086,13 @@ public class NodesImpl implements Nodes } } + NodeRef parentNodeRef = nodeInfo.getParentId(); + if (parentNodeRef != null) + { + // move/rename - with exception mapping + move(nodeRef, parentNodeRef, name); + } + List aspectNames = nodeInfo.getAspectNames(); if (aspectNames != null) { @@ -1166,6 +1176,39 @@ public class NodesImpl implements Nodes return getFolderOrDocument(nodeRef.getId(), parameters); } + private void move(NodeRef nodeRef, NodeRef parentNodeRef, String name) + { + NodeRef currentParentNodeRef = getParentNodeRef(nodeRef); + if (! currentParentNodeRef.equals(parentNodeRef)) + { + try + { + // updating "parentId" means moving primary parent ! + // note: in the future (as and when we support secondary parent/child assocs) we may also + // wish to select which parent to "move from" (in case where the node resides in multiple locations) + fileFolderService.move(nodeRef, parentNodeRef, name); + } + catch (InvalidNodeRefException inre) + { + throw new EntityNotFoundException(inre.getMessage()+" ["+nodeRef+","+parentNodeRef+"]"); + } + catch (FileNotFoundException fnfe) + { + // convert checked exception + throw new EntityNotFoundException(fnfe.getMessage()+" ["+nodeRef+","+parentNodeRef+"]"); + } + catch (FileExistsException fee) + { + // duplicate - name clash + throw new ConstraintViolatedException(fee.getMessage()); + } + catch (FileFolderServiceImpl.InvalidTypeException ite) + { + throw new InvalidArgumentException("Expect target parentId to be a folder: "+parentNodeRef); + } + } + } + @Override public BinaryResource getContent(String fileNodeId, Parameters parameters) { 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 04462f9342..78b4921beb 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -98,6 +98,8 @@ import org.springframework.util.ResourceUtils; *
  • {@literal :/alfresco/api//public/alfresco/versions/1/nodes//children}
  • * * + * TODO replace most (all ?) usages of repoService/repositoryHelper test data setup code with actual REST v1 API calls + * * @author Jamal Kaabi-Mofrad * @author janv */ @@ -905,6 +907,97 @@ public class NodeApiTest extends AbstractBaseApiTest delete("nodes", user1, chNodeRef.getId(), 403); } + /** + * Tests move (file or folder) + *

    PUT:

    + * {@literal :/alfresco/api/-default-/public/alfresco/versions/1/nodes/} + */ + @Test + public void testMove() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(user1); + + String postUrl = getChildrenUrl(Nodes.PATH_MY); + + Folder f = new Folder(); + f.setName("f1"); + f.setNodeType("cm:folder"); + + // create folder f1 + HttpResponse response = post(postUrl, user1, toJsonAsStringNonNull(f), 201); + Folder folderResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Folder.class); + String f1Id = folderResp.getId(); + + f = new Folder(); + f.setName("f2"); + f.setNodeType("cm:folder"); + + // create folder f2 + response = post(postUrl, user1, toJsonAsStringNonNull(f), 201); + folderResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Folder.class); + String f2Id = folderResp.getId(); + + // create doc d1 + NodeRef f1Ref = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, f1Id); + String d1Name = "content" + System.currentTimeMillis() + "_1"; + NodeRef d1Ref = repoService.createDocument(f1Ref, d1Name, "The quick brown fox jumps over the lazy dog."); + String d1Id = d1Ref.getId(); + + // create doc d2 + NodeRef f2Ref = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, f2Id); + String d2Name = "content" + System.currentTimeMillis() + "_2"; + NodeRef d2Ref = repoService.createDocument(f2Ref, d2Name, "The quick brown fox jumps over the lazy dog 2."); + String d2Id = d2Ref.getId(); + + // move file (without rename) + + Document dUpdate = new Document(); + dUpdate.setParentId(f2Id); + + response = put("nodes", user1, d1Id, toJsonAsStringNonNull(dUpdate), null, 200); + Document documentResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class); + + assertEquals(d1Name, documentResp.getName()); + assertEquals(f2Id, documentResp.getParentId()); + + // move file (with rename) + + String d1NewName = d1Name+" updated !!"; + + dUpdate = new Document(); + dUpdate.setName(d1NewName); + dUpdate.setParentId(f1Id); + + response = put("nodes", user1, d1Id, toJsonAsStringNonNull(dUpdate), null, 200); + documentResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class); + + assertEquals(d1NewName, documentResp.getName()); + assertEquals(f1Id, documentResp.getParentId()); + + // -ve tests + + // name already exists + dUpdate = new Document(); + dUpdate.setName(d2Name); + dUpdate.setParentId(f2Id); + put("nodes", user1, d1Id, toJsonAsStringNonNull(dUpdate), null, 409); + + // unknown source nodeId + dUpdate = new Document(); + dUpdate.setParentId(f2Id); + put("nodes", user1, UUID.randomUUID().toString(), toJsonAsStringNonNull(dUpdate), null, 404); + + // unknown target nodeId + dUpdate = new Document(); + dUpdate.setParentId(UUID.randomUUID().toString()); + put("nodes", user1, d1Id, toJsonAsStringNonNull(dUpdate), null, 404); + + // target is not a folder + dUpdate = new Document(); + dUpdate.setParentId(d2Id); + put("nodes", user1, d1Id, toJsonAsStringNonNull(dUpdate), null, 400); + } + /** * Tests create folder. *

    POST: