From a5f8df310a6974467af8002df2c561b383e99a7b Mon Sep 17 00:00:00 2001 From: Tatyana Valkevych Date: Wed, 1 Jul 2015 12:32:43 +0000 Subject: [PATCH] Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud) 107281: Merged NESS/5.1.N-2015-05-26 (5.1.0) to HEAD-BUG-FIX (5.1/Cloud) 105463: ACE-3984 : Add support for link creation via Repository REST API - added the functionality for creating document links 105467: ACE-3984 : Add support for link creation via Repository REST API - reverted fix to add modifications 105468: ACE-3984 : Add support for link creation via Repository REST API - added java backed webscripts for creating and deleting links - added service for handling document links operations 106865: ACE-3984 : Add support for link creation via Repository REST API - added copyright notice - added class level comment to AbstractDocLink git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@107492 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repository/doclink/doclink.post.desc.xml | 52 +++++++ .../repository/doclink/doclink.post.json.ftl | 5 + .../doclink/doclinks.delete.desc.xml | 57 ++++++++ .../doclink/doclinks.delete.json.ftl | 13 ++ .../web-scripts-application-context.xml | 16 ++ .../web/scripts/doclink/AbstractDocLink.java | 137 ++++++++++++++++++ .../repo/web/scripts/doclink/DocLinkPost.java | 110 ++++++++++++++ .../web/scripts/doclink/DocLinksDelete.java | 89 ++++++++++++ 8 files changed, 479 insertions(+) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.json.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.json.ftl create mode 100644 source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java create mode 100644 source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java create mode 100644 source/java/org/alfresco/repo/web/scripts/doclink/DocLinksDelete.java diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.desc.xml new file mode 100644 index 0000000000..13a2b1ae45 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.desc.xml @@ -0,0 +1,52 @@ + + Create document link + Creates a link to a document in a given folder + /api/node/doclink/{store_type}/{store_id}/{id} + /api/site/doclink/{site}/{container}/{path} + /api/site/doclink/{site}/{container} + argument + user + required + + + store_type + Protocol for the source store, e.g. workspace or versionstore. + + + store_id + The source identifier, which may be specific to the protocol, e.g. spacesstore. + + + id + The identifier of the source node. + + + site + The site ID of the source. + + + container + The container folder for the site. + + + path + The path to the source node in the site's container. + + + + + json + + + + + + + + json + + + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.json.ftl new file mode 100644 index 0000000000..321d5972da --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclink.post.json.ftl @@ -0,0 +1,5 @@ +<#escape x as jsonUtils.encodeJSONString(x)> +{ + "linkNodeRef": "${linkNodeRef}" +} + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.desc.xml new file mode 100644 index 0000000000..0ac1c912c7 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.desc.xml @@ -0,0 +1,57 @@ + + Delete links of a document + Delete all links having as given destination + /api/node/doclink/{store_type}/{store_id}/{id}/delete + /api/site/doclink/{site}/{container}/{path}/delete + /api/site/doclink/{site}/{container}/delete + argument + user + required + + + store_type + Protocol for the destination store, e.g. workspace or versionstore. + + + store_id + The destination identifier, which may be specific to the protocol, e.g. spacesstore. + + + id + The identifier of the destination node. + + + site + The site ID of the destination. + + + container + The container folder for the site. + + + path + The path to the destination node in the site's container. + + + + + + + json + + + { + "total": "3", + "deleted": "1", + "error details": [ + "workspace://SpacesStore/48afc4b7-d91a-4167-8b9e-db14961b8fed 04290001 Access Denied. You do not have the appropriate permissions to perform this operation.", + "workspace://SpacesStore/10b18342-8e70-4dc0-ba73-4b0a6fdf5a9b 04290002 Access Denied. You do not have the appropriate permissions to perform this operation." + ] + } + + ]]> + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.json.ftl new file mode 100644 index 0000000000..9e6087fbcb --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/doclink/doclinks.delete.json.ftl @@ -0,0 +1,13 @@ +<#escape x as jsonUtils.encodeJSONString(x)> +{ + "found": "${total_count}", + "deleted": "${deleted_count}", + "error details" : + [ + <#list error_details?keys as key> + "${key} - ${error_details[key]}" + <#if key_has_next>, + + ] +} + \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 1dda62127e..f11410bf84 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -1840,5 +1840,21 @@ + + + + + + + + + + + + diff --git a/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java b/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java new file mode 100644 index 0000000000..8c894a68c4 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.web.scripts.doclink; + +import java.util.Map; +import java.util.StringTokenizer; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.DocumentLinkService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; +import org.alfresco.util.ParameterCheck; +import org.alfresco.util.PropertyCheck; +import org.springframework.extensions.webscripts.DeclarativeWebScript; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; + +/** + * This class contains common code for doclink webscripts controllers + * + * @author Ana Bozianu + * @since 5.1 + */ +public abstract class AbstractDocLink extends DeclarativeWebScript +{ + private static String PARAM_STORE_TYPE = "store_type"; + private static String PARAM_STORE_ID = "store_id"; + private static String PARAM_ID = "id"; + private static String PARAM_SITE = "site"; + private static String PARAM_CONTAINER = "container"; + private static String PARAM_PATH = "path"; + + protected NodeService nodeService; + protected SiteService siteService; + protected DocumentLinkService documentLinkService; + + protected NodeRef parseNodeRefFromTemplateArgs(Map templateVars) + { + if (templateVars == null) + { + return null; + } + + String storeTypeArg = templateVars.get(PARAM_STORE_TYPE); + String storeIdArg = templateVars.get(PARAM_STORE_ID); + String idArg = templateVars.get(PARAM_ID); + + if (storeTypeArg != null) + { + ParameterCheck.mandatoryString("storeTypeArg", storeTypeArg); + ParameterCheck.mandatoryString("storeIdArg", storeIdArg); + ParameterCheck.mandatoryString("idArg", idArg); + + /* + * NodeRef based request + * URL_BASE/{store_type}/{store_id}/{id} + */ + return new NodeRef(storeTypeArg, storeIdArg, idArg); + } + else + { + String siteArg = templateVars.get(PARAM_SITE); + String containerArg = templateVars.get(PARAM_CONTAINER); + String pathArg = templateVars.get(PARAM_PATH); + + if (siteArg != null) + { + ParameterCheck.mandatoryString("siteArg", siteArg); + ParameterCheck.mandatoryString("containerArg", containerArg); + + /* + * Site based request URL_BASE/{site}/{container} or + * URL_BASE/{site}/{container}/{path} + */ + SiteInfo site = siteService.getSite(siteArg); + PropertyCheck.mandatory(this, "site", site); + + NodeRef node = siteService.getContainer(site.getShortName(), containerArg); + if (node == null) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid 'container' variable"); + } + + if (pathArg != null) + { + // URL_BASE/{site}/{container}/{path} + StringTokenizer st = new StringTokenizer(pathArg, "/"); + while (st.hasMoreTokens()) + { + String childName = st.nextToken(); + node = nodeService.getChildByName(node, ContentModel.ASSOC_CONTAINS, childName); + if (node == null) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid 'path' variable"); + } + } + } + + return node; + } + } + return null; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setSiteService(SiteService siteService) + { + this.siteService = siteService; + } + + public void setDocumentLinkService(DocumentLinkService documentLinkService) + { + this.documentLinkService = documentLinkService; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java b/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java new file mode 100644 index 0000000000..e062c30dd3 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.web.scripts.doclink; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.ParameterCheck; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.json.simple.parser.ParseException; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * This class is the controller for the doclink.post webscript doclink.post is a + * webscript for creating a link of a document within a target destination + * + * @author Ana Bozianu + * @since 5.1 + */ +public class DocLinkPost extends AbstractDocLink +{ + private static String PARAM_DESTINATION_NODE = "destinationNodeRef"; + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + NodeRef sourceNodeRef = null; + NodeRef destinationNodeRef = null; + + /* Parse the template vars */ + Map templateVars = req.getServiceMatch().getTemplateVars(); + sourceNodeRef = parseNodeRefFromTemplateArgs(templateVars); + + /* Parse the JSON content */ + JSONObject json = null; + String contentType = req.getContentType(); + if (contentType != null && contentType.indexOf(';') != -1) + { + contentType = contentType.substring(0, contentType.indexOf(';')); + } + if (MimetypeMap.MIMETYPE_JSON.equals(contentType)) + { + try + { + json = (JSONObject) JSONValue.parseWithException(req.getContent().getContent()); + } + catch (IOException io) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid JSON: " + io.getMessage()); + } + catch (ParseException pe) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid JSON: " + pe.getMessage()); + } + } + else + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "invalid request content type"); + } + + /* Parse the destination NodeRef parameter */ + String destinationNodeParam = (String) json.get(PARAM_DESTINATION_NODE); + ParameterCheck.mandatoryString("destinationNodeParam", destinationNodeParam); + destinationNodeRef = new NodeRef(destinationNodeParam); + + /* Create link */ + NodeRef linkNodeRef = null; + try + { + linkNodeRef = documentLinkService.createDocumentLink(sourceNodeRef, destinationNodeRef); + } + catch (IllegalArgumentException ex) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid Arguments: " + ex.getMessage()); + } + catch (AccessDeniedException e) + { + throw new WebScriptException(Status.STATUS_FORBIDDEN, "You don't have permission to perform this operation"); + } + + /* Build response */ + Map model = new HashMap(); + model.put("linkNodeRef", linkNodeRef.toString()); + return model; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/doclink/DocLinksDelete.java b/source/java/org/alfresco/repo/web/scripts/doclink/DocLinksDelete.java new file mode 100644 index 0000000000..974e642aae --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/doclink/DocLinksDelete.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.web.scripts.doclink; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.repository.DeleteLinksStatusReport; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * This class is the controller for the doclink.post webscript doclink.post is a + * webscript for creating a link of a document within a target destination + * + * @author Ana Bozianu + * @since 5.1 + */ +public class DocLinksDelete extends AbstractDocLink +{ + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + NodeRef destinationNodeRef = null; + + /* Parse the template vars */ + Map templateVars = req.getServiceMatch().getTemplateVars(); + destinationNodeRef = parseNodeRefFromTemplateArgs(templateVars); + + /* Delete links */ + DeleteLinksStatusReport report; + try + { + report = documentLinkService.deleteLinksToDocument(destinationNodeRef); + } + catch (IllegalArgumentException ex) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid Arguments: " + ex.getMessage()); + } + catch (AccessDeniedException e) + { + throw new WebScriptException(Status.STATUS_FORBIDDEN, "You don't have permission to perform this operation"); + } + + /* Build response */ + Map model = new HashMap(); + model.put("total_count", report.getTotalLinksFoundCount()); + model.put("deleted_count", report.getDeletedLinksCount()); + + Map errorDetails = new HashMap(); + Iterator> it = report.getErrorDetails().entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry pair = it.next(); + + Throwable th = pair.getValue(); + + errorDetails.put(pair.getKey().toString(), th.getMessage()); + } + + model.put("error_details", errorDetails); + + + return model; + } +}