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
index e95ce9b7a4..1f9f6aea3e 100644
--- 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
@@ -41,12 +41,23 @@
+
+ json
+
+
+
+
json
-
+
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
index 321d5972da..e69a986e8a 100644
--- 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
@@ -1,5 +1,16 @@
<#escape x as jsonUtils.encodeJSONString(x)>
{
- "linkNodeRef": "${linkNodeRef}"
+ "linkNodes" :
+ [
+ <#list results as result>
+ {
+ "nodeRef" : "${result}"
+ }
+ <#if result_has_next>,#if>
+ #list>
+ ],
+ "successCount": "${successCount}",
+ "failureCount": "${failureCount}",
+ "overallSuccess": "${overallSuccess?c}"
}
#escape>
\ 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 5e2e150b76..6ce6f52f33 100644
--- a/config/alfresco/web-scripts-application-context.xml
+++ b/config/alfresco/web-scripts-application-context.xml
@@ -1846,6 +1846,7 @@
+
+
diff --git a/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java b/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java
index 8e38144138..43a54bf75e 100644
--- a/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java
+++ b/source/java/org/alfresco/repo/web/scripts/doclink/AbstractDocLink.java
@@ -23,122 +23,171 @@
* along with Alfresco. If not, see .
* #L%
*/
-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;
- }
-}
+package org.alfresco.repo.web.scripts.doclink;
+
+import java.io.StringWriter;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.web.scripts.links.AbstractLinksWebScript;
+import org.alfresco.service.cmr.activities.ActivityService;
+import org.alfresco.service.cmr.links.LinkInfo;
+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.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.JSONStringer;
+import org.json.simple.JSONObject;
+import org.springframework.extensions.webscripts.DeclarativeWebScript;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+import org.springframework.extensions.webscripts.json.JSONWriter;
+
+/**
+ * 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";
+
+ private static final String ACTIVITY_TOOL = "documentLinkService";
+
+ protected NodeService nodeService;
+ protected SiteService siteService;
+ protected DocumentLinkService documentLinkService;
+ protected ActivityService activityService;
+
+ private static Log logger = LogFactory.getLog(AbstractDocLink.class);
+
+ 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;
+ }
+
+ /**
+ * Generates an activity entry for the link
+ */
+
+ protected void addActivityEntry(String activityType, String title, String nodeRef, String site)
+ {
+ try
+ {
+ StringWriter activityJson = new StringWriter();
+ JSONWriter activity = new JSONWriter(activityJson);
+ activity.startObject();
+ activity.writeValue("title", title);
+ activity.writeValue("nodeRef", nodeRef);
+ activity.writeValue("page", "document-details?nodeRef=" + nodeRef);
+ activity.endObject();
+
+ activityService.postActivity(
+ activityType,
+ site,
+ ACTIVITY_TOOL,
+ activityJson.toString());
+ }
+ catch (Exception e)
+ {
+ // Warn, but carry on
+ logger.warn("Error adding link event to activities feed", e);
+ }
+ }
+
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ public void setSiteService(SiteService siteService)
+ {
+ this.siteService = siteService;
+ }
+
+ public void setDocumentLinkService(DocumentLinkService documentLinkService)
+ {
+ this.documentLinkService = documentLinkService;
+ }
+
+ public void setActivityService(ActivityService activityService)
+ {
+ this.activityService = activityService;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java b/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java
index d0feef5c06..1e9e74d374 100644
--- a/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java
+++ b/source/java/org/alfresco/repo/web/scripts/doclink/DocLinkPost.java
@@ -23,95 +23,169 @@
* along with Alfresco. If not, see .
* #L%
*/
-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;
- }
-}
+package org.alfresco.repo.web.scripts.doclink;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.activities.ActivityType;
+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.JSONArray;
+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 final String PARAM_DESTINATION_NODE = "destinationNodeRef";
+ private static final String PARAM_MULTIPLE_FILES = "multipleFiles";
+
+ @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);
+
+ List nodeRefs = new ArrayList();
+ if (json.containsKey(PARAM_MULTIPLE_FILES))
+ {
+ JSONArray multipleFiles = (JSONArray) json.get(PARAM_MULTIPLE_FILES);
+ for (int i = 0; i < multipleFiles.size(); i++)
+ {
+ String nodeRefString = (String) multipleFiles.get(i);
+ if (nodeRefString != null)
+ {
+ try
+ {
+ NodeRef nodeRefToCreateLink = new NodeRef(nodeRefString);
+ nodeRefs.add(nodeRefToCreateLink);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid Arguments: " + ex.getMessage());
+ }
+ }
+ }
+ }
+ else
+ {
+ nodeRefs.add(sourceNodeRef);
+ }
+
+ // getSite for destination folder
+ String siteName = siteService.getSiteShortName(destinationNodeRef);
+
+ List linksResults = new ArrayList();
+ NodeRef linkNodeRef = null;
+ int successCount = 0;
+ int failureCount = 0;
+
+ if (nodeRefs != null && nodeRefs.size() > 0)
+ {
+ for (NodeRef sourceNode : nodeRefs)
+ {
+ /* Create link */
+ linkNodeRef = createLink(destinationNodeRef, sourceNode);
+
+ if (linkNodeRef != null)
+ {
+ String sourceName = (String) nodeService.getProperty(sourceNode, ContentModel.PROP_NAME);
+ if (siteName != null)
+ {
+ addActivityEntry(ActivityType.DOCLINK_CREATED, sourceName, sourceNode.toString(), siteName);
+ }
+ linksResults.add(linkNodeRef.toString());
+ successCount++;
+ }
+ }
+ }
+
+ failureCount = nodeRefs.size() - successCount;
+ Map model = new HashMap();
+ model.put("results", linksResults);
+ model.put("successCount", successCount);
+ model.put("failureCount", failureCount);
+ model.put("overallSuccess", failureCount == 0);
+ return model;
+ }
+
+ /**
+ * Create link for sourceNodeRef in destinationNodeRef location
+ *
+ * @param destinationNodeRef
+ * @param sourceNodeRef
+ * @return
+ */
+ private NodeRef createLink(NodeRef destinationNodeRef, NodeRef sourceNodeRef)
+ {
+ 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");
+ }
+ return linkNodeRef;
+ }
+}
diff --git a/source/test-java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java b/source/test-java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java
index a0fa15047d..9ae49bc4e5 100644
--- a/source/test-java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java
+++ b/source/test-java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java
@@ -45,6 +45,7 @@ import org.alfresco.repo.web.scripts.groups.GroupsTest;
import org.alfresco.repo.web.scripts.invitation.InvitationWebScriptTest;
import org.alfresco.repo.web.scripts.invite.InviteServiceTest;
import org.alfresco.repo.web.scripts.links.LinksRestApiTest;
+import org.alfresco.repo.web.scripts.node.NodeWebScripTest;
import org.alfresco.repo.web.scripts.person.PersonServiceTest;
import org.alfresco.repo.web.scripts.preference.PreferenceServiceTest;
import org.alfresco.repo.web.scripts.publishing.PublishingRestApiTest;
@@ -117,6 +118,7 @@ public class WebScriptTestSuite extends TestSuite
suite.addTestSuite( ReadOnlyTransactionInGetRestApiTest.class );
suite.addTestSuite( CustomModelImportTest.class );
suite.addTestSuite( SurfConfigTest.class );
+ suite.addTestSuite( NodeWebScripTest.class );
// This uses a slightly different context
// As such, we can't run it in the same suite as the others,
// due to finalisers closing caches when we're not looking
diff --git a/source/test-java/org/alfresco/repo/web/scripts/node/NodeWebScripTest.java b/source/test-java/org/alfresco/repo/web/scripts/node/NodeWebScripTest.java
index 533e393105..f01490d4ff 100644
--- a/source/test-java/org/alfresco/repo/web/scripts/node/NodeWebScripTest.java
+++ b/source/test-java/org/alfresco/repo/web/scripts/node/NodeWebScripTest.java
@@ -26,9 +26,12 @@
package org.alfresco.repo.web.scripts.node;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.node.archive.NodeArchiveService;
@@ -37,6 +40,7 @@ import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
@@ -44,10 +48,12 @@ import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
+import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.PropertyMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.context.support.AbstractRefreshableApplicationContext;
@@ -377,4 +383,209 @@ public class NodeWebScripTest extends BaseWebScriptTest
AuthenticationUtil.setFullyAuthenticatedUser(USER_TWO);
sendRequest(req, Status.STATUS_FORBIDDEN);
}
+
+ @SuppressWarnings("unchecked")
+ public void testLinkCreation() throws Exception
+ {
+ // Create a folder within the DocLib
+ NodeRef siteDocLib = siteService.getContainer(TEST_SITE.getShortName(), SiteService.DOCUMENT_LIBRARY);
+
+ String testFolder1Name = "testingLinkCreationFolder1";
+ Map testFolderProps = new HashMap();
+ testFolderProps.put(ContentModel.PROP_NAME, testFolder1Name);
+ NodeRef testFolder1 = nodeService.createNode(siteDocLib, ContentModel.ASSOC_CONTAINS,
+ QName.createQName("testingLinkCreationFolder1"), ContentModel.TYPE_FOLDER, testFolderProps).getChildRef();
+
+ JSONObject jsonReq = null;
+ JSONObject json = null;
+ JSONArray jsonArray = new JSONArray();
+ JSONArray jsonLinkNodes = null;
+ JSONObject jsonLinkNode = null;
+
+ //Create files in the folder
+ NodeRef testFile1 = createNode(testFolder1, "testingLinkCreationFile1", ContentModel.TYPE_CONTENT,
+ AuthenticationUtil.getAdminUserName());
+ NodeRef testFile2 = createNode(testFolder1, "testingLinkCreationFile2", ContentModel.TYPE_CONTENT,
+ AuthenticationUtil.getAdminUserName());
+ NodeRef testFile3 = createNode(testFolder1, "testingLinkCreationFile3", ContentModel.TYPE_CONTENT,
+ AuthenticationUtil.getAdminUserName());
+
+ //Create another folder in the folder
+ String testFolder2Name = "testingLinkCreationFolder2";
+ testFolderProps = new HashMap();
+ testFolderProps.put(ContentModel.PROP_NAME, testFolder2Name);
+ NodeRef testFolder2 = nodeService.createNode(siteDocLib, ContentModel.ASSOC_CONTAINS,
+ QName.createQName("testingLinkCreationFolder2"), ContentModel.TYPE_FOLDER, testFolderProps).getChildRef();
+
+ // Create link to file1 in same folder
+ Request req = new Request("POST", "/api/node/doclink/" + testFile1.getStoreRef().getProtocol() + "/"
+ + testFile1.getStoreRef().getIdentifier() + "/" + testFile1.getId());
+ jsonReq = new JSONObject();
+ jsonReq.put("destinationNodeRef", testFolder1.toString());
+
+ jsonArray.add(testFile1.toString());
+ jsonReq.put("multipleFiles", jsonArray);
+ req.setBody(jsonReq.toString().getBytes());
+ req.setType(MimetypeMap.MIMETYPE_JSON);
+
+ json = asJSON(sendRequest(req, Status.STATUS_OK));
+ jsonLinkNodes = (JSONArray) json.get("linkNodes");
+ assertNotNull(jsonLinkNodes);
+ assertEquals(1, jsonLinkNodes.size());
+ assertEquals("true", json.get("overallSuccess"));
+ assertEquals("1", json.get("successCount"));
+ assertEquals("0", json.get("failureCount"));
+
+ jsonLinkNode = (JSONObject) jsonLinkNodes.get(0);
+ String nodeRef = (String) jsonLinkNode.get("nodeRef");
+ NodeRef file1Link = new NodeRef(nodeRef);
+
+ //Check that app:linked aspect is added on sourceNode
+ assertEquals(true, nodeService.hasAspect(testFile1, ApplicationModel.ASPECT_LINKED));
+ assertEquals(true, nodeService.exists(file1Link));
+ nodeService.deleteNode(file1Link);
+ assertEquals(false, nodeService.hasAspect(testFile1, ApplicationModel.ASPECT_LINKED));
+
+ //Create link to testFolder2 in same folder (testFolder1)
+ req = new Request("POST", "/api/node/doclink/" + testFolder2.getStoreRef().getProtocol() + "/"
+ + testFolder2.getStoreRef().getIdentifier() + "/" + testFolder2.getId());
+ jsonReq = new JSONObject();
+ jsonReq.put("destinationNodeRef", testFolder1.toString());
+ jsonArray = new JSONArray();
+ jsonArray.add(testFolder2.toString());
+ jsonReq.put("multipleFiles", jsonArray);
+ req.setBody(jsonReq.toString().getBytes());
+ req.setType(MimetypeMap.MIMETYPE_JSON);
+
+ json = asJSON(sendRequest(req, Status.STATUS_OK));
+ jsonLinkNodes = (JSONArray) json.get("linkNodes");
+ assertNotNull(jsonLinkNodes);
+ assertEquals(1, jsonLinkNodes.size());
+ assertEquals("true", json.get("overallSuccess"));
+ assertEquals("1", json.get("successCount"));
+ assertEquals("0", json.get("failureCount"));
+
+ jsonLinkNode = (JSONObject) jsonLinkNodes.get(0);
+ nodeRef = (String) jsonLinkNode.get("nodeRef");
+ NodeRef folder2Link = new NodeRef(nodeRef);
+ assertEquals(true, nodeService.hasAspect(testFolder2, ApplicationModel.ASPECT_LINKED));
+ assertEquals(true, nodeService.exists(folder2Link));
+
+ // create another link of testFolder2 in siteDocLib
+ req = new Request("POST", "/api/node/doclink/" + testFolder2.getStoreRef().getProtocol() + "/"
+ + testFolder2.getStoreRef().getIdentifier() + "/" + testFolder2.getId());
+ jsonReq = new JSONObject();
+ jsonReq.put("destinationNodeRef", siteDocLib.toString());
+ jsonArray = new JSONArray();
+ jsonArray.add(testFolder2.toString());
+ jsonReq.put("multipleFiles", jsonArray);
+ req.setBody(jsonReq.toString().getBytes());
+ req.setType(MimetypeMap.MIMETYPE_JSON);
+
+ json = asJSON(sendRequest(req, Status.STATUS_OK));
+ jsonLinkNodes = (JSONArray) json.get("linkNodes");
+ assertNotNull(jsonLinkNodes);
+ assertEquals(1, jsonLinkNodes.size());
+ assertEquals("true", json.get("overallSuccess"));
+ assertEquals("1", json.get("successCount"));
+ assertEquals("0", json.get("failureCount"));
+
+ jsonLinkNode = (JSONObject) jsonLinkNodes.get(0);
+ nodeRef = (String) jsonLinkNode.get("nodeRef");
+ NodeRef folder2Link2 = new NodeRef(nodeRef);
+
+ // delete folder2Link and check that aspect exists since we have another
+ // link for testFolder2
+ nodeService.deleteNode(folder2Link);
+ assertEquals(true, nodeService.hasAspect(testFolder2, ApplicationModel.ASPECT_LINKED));
+ nodeService.deleteNode(folder2Link2);
+ assertEquals(false, nodeService.hasAspect(testFolder2, ApplicationModel.ASPECT_LINKED));
+
+ // Create link to testFile1, testFile2 and testFile3 in same testFolder1
+ req = new Request("POST", "/api/node/doclink/" + testFolder1.getStoreRef().getProtocol() + "/"
+ + testFolder1.getStoreRef().getIdentifier() + "/" + testFolder1.getId());
+ jsonReq = new JSONObject();
+ jsonReq.put("destinationNodeRef", testFolder1.toString());
+ jsonArray = new JSONArray();
+ jsonArray.add(testFile1.toString());
+ jsonArray.add(testFile2.toString());
+ jsonArray.add(testFile3.toString());
+ jsonReq.put("multipleFiles", jsonArray);
+ req.setBody(jsonReq.toString().getBytes());
+ req.setType(MimetypeMap.MIMETYPE_JSON);
+
+ json = asJSON(sendRequest(req, Status.STATUS_OK));
+ jsonLinkNodes = (JSONArray) json.get("linkNodes");
+ assertNotNull(jsonLinkNodes);
+ assertEquals(3, jsonLinkNodes.size());
+ assertEquals("true", json.get("overallSuccess"));
+ assertEquals("3", json.get("successCount"));
+ assertEquals("0", json.get("failureCount"));
+
+ NodeRef fileLink = null;
+ List fileLinks = new ArrayList();
+ for (int i = 0; i < jsonLinkNodes.size(); i++)
+ {
+ jsonLinkNode = (JSONObject) jsonLinkNodes.get(i);
+ nodeRef = (String) jsonLinkNode.get("nodeRef");
+ fileLink = new NodeRef(nodeRef);
+ fileLinks.add(fileLink);
+ assertEquals(true, nodeService.exists(fileLink));
+ }
+
+ //try to create another link in the same location - an exception should be thrown
+ req = new Request("POST", "/api/node/doclink/" + testFolder1.getStoreRef().getProtocol() + "/"
+ + testFolder1.getStoreRef().getIdentifier() + "/" + testFolder1.getId());
+ jsonReq = new JSONObject();
+ jsonReq.put("destinationNodeRef", testFolder1.toString());
+ jsonArray = new JSONArray();
+ jsonArray.add(testFile1.toString());
+ jsonReq.put("multipleFiles", jsonArray);
+ req.setBody(jsonReq.toString().getBytes());
+ req.setType(MimetypeMap.MIMETYPE_JSON);
+
+ json = asJSON(sendRequest(req, Status.STATUS_BAD_REQUEST));
+
+ // delete all 3 files and check that the links are deleted too
+ nodeService.deleteNode(testFile1);
+ nodeService.deleteNode(testFile2);
+ nodeService.deleteNode(testFile3);
+ for (NodeRef linkNodeRef : fileLinks)
+ {
+ assertEquals(false, nodeService.exists(linkNodeRef));
+ }
+
+ //try create a link to a site
+ SiteInfo site2 = createSite("Site2TestingNodeCreateLink");
+ NodeRef siteNodeRef = site2.getNodeRef();
+
+ req = new Request("POST", "/api/node/doclink/" + testFolder1.getStoreRef().getProtocol() + "/"
+ + testFolder1.getStoreRef().getIdentifier() + "/" + testFolder1.getId());
+ jsonReq = new JSONObject();
+ jsonReq.put("destinationNodeRef", testFolder1.toString());
+ jsonArray = new JSONArray();
+ jsonArray.add(siteNodeRef.toString());
+ jsonReq.put("multipleFiles", jsonArray);
+ req.setBody(jsonReq.toString().getBytes());
+ req.setType(MimetypeMap.MIMETYPE_JSON);
+
+ json = asJSON(sendRequest(req, Status.STATUS_BAD_REQUEST));
+
+ siteService.deleteSite(site2.getShortName());
+ nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteNodeRef));
+ }
+
+ private NodeRef createNode(NodeRef parentNode, String nodeCmName, QName nodeType, String ownerUserName)
+ {
+ QName childName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, nodeCmName);
+
+ Map props = new HashMap();
+ props.put(ContentModel.PROP_NAME, nodeCmName);
+ ChildAssociationRef childAssoc = nodeService.createNode(parentNode,
+ ContentModel.ASSOC_CONTAINS,
+ childName,
+ nodeType,
+ props);
+ return childAssoc.getChildRef();
+ }
}
\ No newline at end of file