diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.desc.xml
new file mode 100644
index 0000000000..f552a9fc31
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.desc.xml
@@ -0,0 +1,7 @@
+
+ Last edited user contents
+ Last edited user contents
+
+ guest
+ /slingshot/profile/usercontents
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.js
new file mode 100644
index 0000000000..2099029b84
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.js
@@ -0,0 +1,28 @@
+
+
+const MAX_RESULTS = 3;
+
+function getContents(user,type,maxResults)
+{
+ //set range to within last 28 days
+ var date = new Date();
+ var toQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate();
+ date.setDate(date.getDate() - 28);
+ var fromQuery = date.getFullYear() + "\\-" + (date.getMonth()+1) + "\\-" + date.getDate();
+
+ var query = "+PATH:\"/app:company_home//*\" "+
+ "+TYPE:\"{http://www.alfresco.org/model/content/1.0}content\" " +
+ "+@cm\\:modifier:" + user + " " +
+ "+@cm\\:" + type + ":[" + fromQuery + "T00\\:00\\:00 TO " + toQuery + "T23\\:59\\:59]";
+
+ var nodes = [];
+ nodes = search.luceneSearch(query);
+
+ return processResults(nodes, maxResults);
+}
+
+model.data = [];
+model.data['created'] = getContents(args.user,'created',MAX_RESULTS);
+model.data['modified'] = getContents(args.user,'modified',MAX_RESULTS);
+model.user = args.user;
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.json.ftl
new file mode 100644
index 0000000000..ab7ecf304e
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.json.ftl
@@ -0,0 +1,42 @@
+<#macro dateFormat date>${date?string("dd MMM yyyy HH:mm:ss 'GMT'Z '('zzz')'")}#macro>
+<#macro formatDataItems data>
+ {
+ "items":
+ [
+ <#list data.items as item>
+ {
+ "nodeRef": "${item.nodeRef}",
+ "type": "${item.type}",
+ "name": "${item.name!''}",
+ "displayName": "${item.displayName!''}",
+ "description": "${item.description!''}",
+ "createdOn": "<@dateFormat item.createdOn />",
+ "createdBy": "${item.createdBy!''}",
+ "createdByUser": "${item.createdByUser!''}",
+ "modifiedOn": "<@dateFormat item.modifiedOn />",
+ "modifiedByUser": "${item.modifiedByUser}",
+ "modifiedBy": "${item.modifiedBy}",
+ "size": ${item.size?c},
+ "tags": [<#list item.tags as tag>"${tag}"<#if tag_has_next>,#if>#list>],
+ <#if item.browseUrl??>
+ "browseUrl": "${item.browseUrl}",
+ #if>
+ "site":
+ {
+ "shortName": "${item.site.shortName}",
+ "title": "${item.site.title}"
+ },
+ "container": "${item.container}",
+ "src":"${item.src!''}",
+ "srcP":"${item.srcP!''}"
+ }<#if item_has_next>,#if>
+ #list>
+ ]
+ }
+#macro>
+<#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "created": <@formatDataItems data['created'] />,
+ "modified": <@formatDataItems data['modified'] />
+}
+#escape>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js
index 92e125250d..67c2de99a4 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js
@@ -1,572 +1,4 @@
-/**
- * Search Component: search
- *
- * Inputs:
- * optional: site = the site to search into.
- * optional: container = the component the search in
- *
- * Outputs:
- * data.items/data.error - object containing list of search results
- */
-const DEFAULT_MAX_RESULTS = 100;
-const SITES_SPACE_QNAME_PATH = "/app:company_home/st:sites/";
-
-/**
- * Returns site data as returned to the user.
- * { shortName: siteId, title: title }
- *
- * Caches the sites to avoid repeatedly querying the repository.
- */
-var siteDataCache = [];
-function getSiteData(siteId)
-{
- if (siteDataCache[siteId] !== undefined)
- {
- return siteDataCache[siteId];
- }
- var site = siteService.getSite(siteId);
- var data =
- {
- shortName : siteId,
- title : "unknown"
- };
- if (site !== null)
- {
- data.title = site.title;
- }
- siteDataCache[siteId] = data;
- return data;
-}
-
-/**
- * Returns person display name string as returned to the user.
- *
- * Caches the person full name to avoid repeatedly querying the repository.
- */
-var personDataCache = [];
-function getPersonDisplayName(userId)
-{
- if (personDataCache[userId] != undefined)
- {
- return personDataCache[userId];
- }
-
- var displayName = "";
- var person = people.getPerson(userId);
- if (person != null)
- {
- displayName = person.properties.firstName + " " + person.properties.lastName;
- }
- personDataCache[userId] = displayName;
- return displayName;
-}
-
-/**
- * Cache to not display twice the same element (e.g. if two comments of the
- * same blog post match the search criteria
- */
-var processedCache = {};
-function addToProcessed(category, key)
-{
- var cat = processedCache[category];
- if (cat === undefined)
- {
- processedCache[category] = [];
- cat = processedCache[category];
- }
- cat.push(key);
-}
-function checkProcessed(category, key)
-{
- var cat = processedCache[category];
- if (cat !== undefined)
- {
- for (var x in cat)
- {
- if (cat[x] == key)
- {
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * Returns the name path for a space
- */
-function getSpaceNamePath(siteId, containerId, space)
-{
- // first find the container to which we are relative to
- var site = siteService.getSite(siteId);
- var container = site.getContainer(containerId);
- var folders = [];
- while (! space.nodeRef.equals(container.nodeRef))
- {
- folders.push(space.name);
- space = space.parent;
- }
- var path = "";
- for (var x = folders.length - 1; x >= 0; x--)
- {
- path += "/" + folders[x];
- }
- return path;
-}
-
-/**
- * Returns an item of the document library component.
- */
-function getDocumentItem(siteId, containerId, restOfPath, node)
-{
- // PENDING: how to handle comments? the document should
- // be returned instead
-
- // check whether we already processed this document
- if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
- {
- return null;
- }
- addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
-
- // check whether this is a valid folder or a file
- var item = null;
- if (node.isContainer || node.isDocument)
- {
- item =
- {
- site: getSiteData(siteId),
- container: containerId,
- nodeRef: node.nodeRef.toString(),
- tags: (node.tags !== null) ? node.tags : [],
- name: node.name,
- displayName: node.name,
- description: node.properties["cm:description"],
- modifiedOn: node.properties["cm:modified"],
- modifiedByUser: node.properties["cm:modifier"]
- };
- item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
- }
- if (node.isContainer)
- {
- item.type = "folder";
- item.size = -1;
- item.browseUrl = containerId + "#path=" + encodeURIComponent(getSpaceNamePath(siteId, containerId, node));
- }
- else if (node.isDocument)
- {
- item.type = "document";
- item.size = node.size;
- item.browseUrl = "document-details?nodeRef=" + node.nodeRef.toString();
- }
-
- return item;
-}
-
-function getBlogPostItem(siteId, containerId, restOfPath, node)
-{
- /**
- * Investigate the rest of the path. the first item is the blog post, ignore everything that follows
- * are replies or folders
- */
- var site = siteService.getSite(siteId);
- var container = site.getContainer(containerId);
-
- /**
- * Find the direct child of the container
- * Note: this only works for post which are direct children of the blog container
- */
- var child = node;
- var parent = child.parent;
- while ((parent !== null) && (!parent.nodeRef.equals(container.nodeRef)))
- {
- child = parent;
- parent = parent.parent;
- }
-
- // check whether we found the container
- if (parent === null)
- {
- return null;
- }
-
- // check whether we already added this blog post
- if (checkProcessed(siteId + containerId, "" + child.nodeRef.toString()))
- {
- return null;
- }
- addToProcessed(siteId + containerId, "" + child.nodeRef.toString());
-
- // child is our blog post
- item =
- {
- site: getSiteData(siteId),
- container: containerId,
- nodeRef: child.nodeRef.toString(),
- type: "blogpost",
- tags: (child.tags !== null) ? child.tags : [],
- name: child.name,
- modifiedOn: child.properties["cm:modified"],
- modifiedByUser: child.properties["cm:modifier"],
- size: child.size,
- displayName: child.properties["cm:title"],
- browseUrl: "blog-postview?container=" + containerId + "&postId=" + child.name
- };
- item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
-
- return item;
-}
-
-function getForumPostItem(siteId, containerId, restOfPath, node)
-{
- // try to find the first fm:topic node, that's what we return as search result
- var topicNode = node;
- while ((topicNode !== null) && (topicNode.type != "{http://www.alfresco.org/model/forum/1.0}topic"))
- {
- topicNode = topicNode.parent;
- }
- if (topicNode === null)
- {
- return null;
- }
-
- // make sure we haven't already added the post
- if (checkProcessed(siteId + containerId, "" + topicNode.nodeRef.toString()))
- {
- return null;
- }
- addToProcessed(siteId + containerId, "" + topicNode.nodeRef.toString());
-
- // find the first post, which contains the post title
- // PENDING: error prone
- var postNode = topicNode.childAssocs["cm:contains"][0];
-
- // child is our forum post
- var item =
- {
- site: getSiteData(siteId),
- container: containerId,
- nodeRef: topicNode.nodeRef.toString(),
- type: "forumpost",
- tags: (topicNode.tags != null) ? topicNode.tags : [],
- name: topicNode.name,
- description: topicNode.properties["cm:description"],
- modifiedOn: topicNode.properties["cm:modified"],
- modifiedByUser: topicNode.properties["cm:modifier"],
- size: topicNode.size,
- displayName: postNode.properties["cm:title"],
- browseUrl: "discussions-topicview?container=" + containerId + "&topicId=" + topicNode.name
- };
- item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
-
- return item;
-}
-
-function getCalendarItem(siteId, containerId, restOfPath, node)
-{
- // only process nodes of the correct type
- if (node.type != "{http://www.alfresco.org/model/calendar}calendarEvent")
- {
- return null;
- }
-
- // make sure we haven't already added the post
- if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
- {
- return null;
- }
- addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
-
- var item =
- {
- site: getSiteData(siteId),
- container: containerId,
- nodeRef: node.nodeRef.toString(),
- type: "calendarevent",
- tags: (node.tags != null) ? node.tags : [],
- name: node.name,
- description: node.properties["ia:descriptionEvent"],
- modifiedOn: node.properties["cm:modified"],
- modifiedByUser: node.properties["cm:modifier"],
- size: -1,
- displayName: node.properties["ia:whatEvent"],
- browseUrl: containerId // this is "calendar"
- };
- item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
-
- return item;
-}
-
-function getWikiItem(siteId, containerId, restOfPath, node)
-{
- // only process documents
- if (!node.isDocument)
- {
- return null;
- }
-
- // make sure we haven't already added the page
- if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
- {
- return null;
- }
- addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
-
- var item =
- {
- site: getSiteData(siteId),
- container: containerId,
- nodeRef: node.nodeRef.toString(),
- type: "wikipage",
- tags: (node.tags != null) ? node.tags : [],
- name: node.name,
- description: node.properties["cm:description"],
- modifiedOn: node.properties["cm:modified"],
- modifiedByUser: node.properties["cm:modifier"],
- size: node.size,
- displayName: ("" + node.properties["cm:name"]).replace(/_/g, " "),
- browseUrl: "wiki-page?title=" + node.properties["cm:name"]
- };
- item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
-
- return item;
-}
-
-function getLinkItem(siteId, containerId, restOfPath, node)
-{
- // only process documents
- if (!node.isDocument)
- {
- return null;
- }
-
- // make sure we haven't already added this link
- if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
- {
- return null;
- }
- addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
-
- var item =
- {
- site: getSiteData(siteId),
- container: containerId,
- nodeRef: node.nodeRef.toString(),
- type: "link",
- tags: (node.tags !== null) ? node.tags : [],
- name: node.name,
- description: node.properties["cm:description"],
- modifiedOn: node.properties["cm:modified"],
- modifiedByUser: node.properties["cm:modifier"],
- size: -1,
- displayName: node.properties["lnk:title"],
- browseUrl: "links-view?linkId=" + node.properties["cm:name"]
- };
- item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
-
- return item;
-}
-
-/**
- * Delegates the extraction to the correct extraction function
- * depending site/container id.
- */
-function getItem(siteId, containerId, restOfPath, node)
-{
- if (containerId == "documentLibrary")
- {
- return getDocumentItem(siteId, containerId, restOfPath, node);
- }
- else if (containerId == "blog")
- {
- return getBlogPostItem(siteId, containerId, restOfPath, node);
- }
- else if (containerId == "discussions")
- {
- return getForumPostItem(siteId, containerId, restOfPath, node);
- }
- else if (containerId == "calendar")
- {
- return getCalendarItem(siteId, containerId, restOfPath, node);
- }
- else if (containerId == "wiki")
- {
- return getWikiItem(siteId, containerId, restOfPath, node);
- }
- else if (containerId == "links")
- {
- return getLinkItem(siteId, containerId, restOfPath, node);
- }
- else
- {
- // unknown container
- return null;
- }
-}
-
-/**
- * Returns an array with [0] = site and [1] = container or null if the node does not match
- */
-function splitQNamePath(node)
-{
- var path = node.qnamePath;
-
- if (path.match("^"+SITES_SPACE_QNAME_PATH) != SITES_SPACE_QNAME_PATH)
- {
- return null;
- }
-
- var tmp = path.substring(SITES_SPACE_QNAME_PATH.length);
- var pos = tmp.indexOf('/');
- if (pos < 1)
- {
- return null;
- }
-
- var siteId = tmp.substring(0, pos);
- siteId = siteId.substring(siteId.indexOf(":") + 1);
- tmp = tmp.substring(pos + 1);
- pos = tmp.indexOf('/');
- if (pos < 1)
- {
- return null;
- }
-
- var containerId = tmp.substring(0, pos);
- containerId = containerId.substring(containerId.indexOf(":") + 1);
- var restOfPath = tmp.substring(pos + 1);
-
- return [ siteId, containerId, restOfPath ];
-}
-
-/**
- * Processes the search results. Filters out unnecessary nodes
- *
- * @return the final search results object
- */
-function processResults(nodes, maxResults)
-{
- var results = [],
- added = 0,
- parts,
- item,
- i, j;
-
- for (i = 0, j = nodes.length; i < j && added < maxResults; i++)
- {
- /**
- * For each node we extract the site/container qname path and then
- * let the per-container helper function decide what to do.
- */
- parts = splitQNamePath(nodes[i]);
- if (parts !== null)
- {
- item = getItem(parts[0], parts[1], parts[2], nodes[i]);
- if (item !== null)
- {
- results.push(item);
- added++;
- }
- }
- }
-
- return (
- {
- items: results
- });
-}
-
-/**
- * Return Search results with the given search terms
- * Terms are split on whitespace characters.
- *
- * AND, OR and NOT are supported - as their Lucene equivalent.
- */
-function getSearchResults(term, maxResults, siteId, containerId)
-{
- var path = SITES_SPACE_QNAME_PATH;
- if (siteId !== null && siteId.length > 0)
- {
- path += "cm:" + search.ISO9075Encode(siteId) + "/";
- }
- else
- {
- path += "*/";
- }
- if (containerId !== null && containerId.length > 0)
- {
- path += "cm:" + search.ISO9075Encode(containerId) + "/";
- }
- else
- {
- path += "*/";
- }
-
- var luceneQuery = "";
- if (term !== null && term.length !== 0)
- {
- // TODO: Perform smarter term processing. For now we simply split on whitespace
- // which ignores quoted phrases that may be present.
- var terms = term.split(/\s/),
- i, j, t;
-
- for (i = 0, j = terms.length; i < j; i++)
- {
- t = terms[i];
- // remove quotes - TODO: add support for quoted terms later
- t = t.replace(/\"/g, "");
- if (t.length !== 0)
- {
- switch (t.toLowerCase())
- {
- case "and":
- if (i < j - 1 && terms[i + 1].length !== 0)
- {
- luceneQuery += "AND ";
- }
- break;
-
- case "or":
- break;
-
- case "not":
- if (i < j - 1 && terms[i + 1].length !== 0)
- {
- luceneQuery += "NOT ";
- }
- break;
-
- default:
- luceneQuery += "(TEXT:\"" + t + "\"" + // full text
- " @cm\\:name:\"" + t + "\"" + // name property
- " @lnk\\:title:\"" + t + "\"" + // link title
- " @lnk\\:description:\"" + t + "\"" + // link description
- " PATH:\"/cm:taggable/cm:" + search.ISO9075Encode(t) + "/member\"" + // tags
- ") ";
- }
- }
- }
- }
-
- var nodes;
-
- // if we processed the search terms, then suffix the PATH query
- if (luceneQuery.length !== 0)
- {
- luceneQuery = "+PATH:\"" + path + "/*\" +(" + luceneQuery + ")";
- luceneQuery += " -TYPE:\"{http://www.alfresco.org/model/content/1.0}thumbnail\"";
- nodes = search.luceneSearch(luceneQuery);
- }
- else
- {
- // failed to process the search string - empty list returned
- nodes = [];
- }
-
- return processResults(nodes, maxResults);
-}
-
-
+
function main()
{
var siteId = (args.site !== undefined) ? args.site : null;
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.lib.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.lib.js
new file mode 100644
index 0000000000..59b3b0efbb
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.lib.js
@@ -0,0 +1,584 @@
+/**
+ * Search Component: search
+ *
+ * Inputs:
+ * optional: site = the site to search into.
+ * optional: container = the component the search in
+ *
+ * Outputs:
+ * data.items/data.error - object containing list of search results
+ */
+const DEFAULT_MAX_RESULTS = 100;
+const SITES_SPACE_QNAME_PATH = "/app:company_home/st:sites/";
+
+/**
+ * Returns site data as returned to the user.
+ * { shortName: siteId, title: title }
+ *
+ * Caches the sites to avoid repeatedly querying the repository.
+ */
+var siteDataCache = [];
+function getSiteData(siteId)
+{
+ if (siteDataCache[siteId] !== undefined)
+ {
+ return siteDataCache[siteId];
+ }
+ var site = siteService.getSite(siteId);
+ var data =
+ {
+ shortName : siteId,
+ title : "unknown"
+ };
+ if (site !== null)
+ {
+ data.title = site.title;
+ }
+ siteDataCache[siteId] = data;
+ return data;
+}
+
+/**
+ * Returns person display name string as returned to the user.
+ *
+ * Caches the person full name to avoid repeatedly querying the repository.
+ */
+var personDataCache = [];
+function getPersonDisplayName(userId)
+{
+ if (personDataCache[userId] != undefined)
+ {
+ return personDataCache[userId];
+ }
+
+ var displayName = "";
+ var person = people.getPerson(userId);
+ if (person != null)
+ {
+ displayName = person.properties.firstName + " " + person.properties.lastName;
+ }
+ personDataCache[userId] = displayName;
+ return displayName;
+}
+
+/**
+ * Cache to not display twice the same element (e.g. if two comments of the
+ * same blog post match the search criteria
+ */
+var processedCache = {};
+function addToProcessed(category, key)
+{
+ var cat = processedCache[category];
+ if (cat === undefined)
+ {
+ processedCache[category] = [];
+ cat = processedCache[category];
+ }
+ cat.push(key);
+}
+function checkProcessed(category, key)
+{
+ var cat = processedCache[category];
+ if (cat !== undefined)
+ {
+ for (var x in cat)
+ {
+ if (cat[x] == key)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns the name path for a space
+ */
+function getSpaceNamePath(siteId, containerId, space)
+{
+ // first find the container to which we are relative to
+ var site = siteService.getSite(siteId);
+ var container = site.getContainer(containerId);
+ var folders = [];
+ while (! space.nodeRef.equals(container.nodeRef))
+ {
+ folders.push(space.name);
+ space = space.parent;
+ }
+ var path = "";
+ for (var x = folders.length - 1; x >= 0; x--)
+ {
+ path += "/" + folders[x];
+ }
+ return path;
+}
+
+/**
+ * Returns an item of the document library component.
+ */
+function getDocumentItem(siteId, containerId, restOfPath, node)
+{
+ // PENDING: how to handle comments? the document should
+ // be returned instead
+
+ // check whether we already processed this document
+ if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
+ {
+ return null;
+ }
+ addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
+
+ // check whether this is a valid folder or a file
+ var item = null;
+ if (node.isContainer || node.isDocument)
+ {
+ item =
+ {
+ site: getSiteData(siteId),
+ container: containerId,
+ nodeRef: node.nodeRef.toString(),
+ tags: (node.tags !== null) ? node.tags : [],
+ name: node.name,
+ displayName: node.name,
+ description: node.properties["cm:description"],
+ modifiedOn: node.properties["cm:modified"],
+ modifiedByUser: node.properties["cm:modifier"],
+ createdOn: node.properties["cm:created"],
+ createdByUser: node.properties["cm:creator"]
+ };
+ item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
+ item.createdBy = getPersonDisplayName(item.createdByUser);
+ }
+ if (node.isContainer)
+ {
+ item.type = "folder";
+ item.size = -1;
+ item.browseUrl = containerId + "#path=" + encodeURIComponent(getSpaceNamePath(siteId, containerId, node));
+ }
+ else if (node.isDocument)
+ {
+ item.type = "document";
+ item.size = node.size;
+ item.browseUrl = "document-details?nodeRef=" + node.nodeRef.toString();
+ }
+
+ return item;
+}
+
+function getBlogPostItem(siteId, containerId, restOfPath, node)
+{
+ /**
+ * Investigate the rest of the path. the first item is the blog post, ignore everything that follows
+ * are replies or folders
+ */
+ var site = siteService.getSite(siteId);
+ var container = site.getContainer(containerId);
+
+ /**
+ * Find the direct child of the container
+ * Note: this only works for post which are direct children of the blog container
+ */
+ var child = node;
+ var parent = child.parent;
+ while ((parent !== null) && (!parent.nodeRef.equals(container.nodeRef)))
+ {
+ child = parent;
+ parent = parent.parent;
+ }
+
+ // check whether we found the container
+ if (parent === null)
+ {
+ return null;
+ }
+
+ // check whether we already added this blog post
+ if (checkProcessed(siteId + containerId, "" + child.nodeRef.toString()))
+ {
+ return null;
+ }
+ addToProcessed(siteId + containerId, "" + child.nodeRef.toString());
+
+ // child is our blog post
+ item =
+ {
+ site: getSiteData(siteId),
+ container: containerId,
+ nodeRef: child.nodeRef.toString(),
+ type: "blogpost",
+ tags: (child.tags !== null) ? child.tags : [],
+ name: child.name,
+ modifiedOn: child.properties["cm:modified"],
+ modifiedByUser: child.properties["cm:modifier"],
+ createdOn: child.properties["cm:created"],
+ createdByUser: child.properties["cm:creator"],
+ size: child.size,
+ displayName: child.properties["cm:title"],
+ browseUrl: "blog-postview?container=" + containerId + "&postId=" + child.name
+ };
+ item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
+ item.createdBy = getPersonDisplayName(item.createdByUser);
+
+ return item;
+}
+
+function getForumPostItem(siteId, containerId, restOfPath, node)
+{
+ // try to find the first fm:topic node, that's what we return as search result
+ var topicNode = node;
+ while ((topicNode !== null) && (topicNode.type != "{http://www.alfresco.org/model/forum/1.0}topic"))
+ {
+ topicNode = topicNode.parent;
+ }
+ if (topicNode === null)
+ {
+ return null;
+ }
+
+ // make sure we haven't already added the post
+ if (checkProcessed(siteId + containerId, "" + topicNode.nodeRef.toString()))
+ {
+ return null;
+ }
+ addToProcessed(siteId + containerId, "" + topicNode.nodeRef.toString());
+
+ // find the first post, which contains the post title
+ // PENDING: error prone
+ var postNode = topicNode.childAssocs["cm:contains"][0];
+
+ // child is our forum post
+ var item =
+ {
+ site: getSiteData(siteId),
+ container: containerId,
+ nodeRef: topicNode.nodeRef.toString(),
+ type: "forumpost",
+ tags: (topicNode.tags != null) ? topicNode.tags : [],
+ name: topicNode.name,
+ description: topicNode.properties["cm:description"],
+ modifiedOn: topicNode.properties["cm:modified"],
+ modifiedByUser: topicNode.properties["cm:modifier"],
+ createdOn: topicNode.properties["cm:created"],
+ createdByUser: topicNode.properties["cm:creator"],
+ size: topicNode.size,
+ displayName: postNode.properties["cm:title"],
+ browseUrl: "discussions-topicview?container=" + containerId + "&topicId=" + topicNode.name
+ };
+ item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
+ item.createdBy = getPersonDisplayName(item.createdByUser);
+
+ return item;
+}
+
+function getCalendarItem(siteId, containerId, restOfPath, node)
+{
+ // only process nodes of the correct type
+ if (node.type != "{http://www.alfresco.org/model/calendar}calendarEvent")
+ {
+ return null;
+ }
+
+ // make sure we haven't already added the post
+ if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
+ {
+ return null;
+ }
+ addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
+
+ var item =
+ {
+ site: getSiteData(siteId),
+ container: containerId,
+ nodeRef: node.nodeRef.toString(),
+ type: "calendarevent",
+ tags: (node.tags != null) ? node.tags : [],
+ name: node.name,
+ description: node.properties["ia:descriptionEvent"],
+ modifiedOn: node.properties["cm:modified"],
+ modifiedByUser: node.properties["cm:modifier"],
+ createdOn: node.properties["cm:created"],
+ createdByUser: node.properties["cm:creator"],
+ size: -1,
+ displayName: node.properties["ia:whatEvent"],
+ browseUrl: containerId // this is "calendar"
+ };
+ item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
+ item.createdBy = getPersonDisplayName(item.createdByUser);
+
+ return item;
+}
+
+function getWikiItem(siteId, containerId, restOfPath, node)
+{
+ // only process documents
+ if (!node.isDocument)
+ {
+ return null;
+ }
+
+ // make sure we haven't already added the page
+ if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
+ {
+ return null;
+ }
+ addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
+
+ var item =
+ {
+ site: getSiteData(siteId),
+ container: containerId,
+ nodeRef: node.nodeRef.toString(),
+ type: "wikipage",
+ tags: (node.tags != null) ? node.tags : [],
+ name: node.name,
+ description: node.properties["cm:description"],
+ modifiedOn: node.properties["cm:modified"],
+ modifiedByUser: node.properties["cm:modifier"],
+ createdOn: node.properties["cm:created"],
+ createdByUser: node.properties["cm:creator"],
+ size: node.size,
+ displayName: ("" + node.properties["cm:name"]).replace(/_/g, " "),
+ browseUrl: "wiki-page?title=" + node.properties["cm:name"]
+ };
+ item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
+ item.createdBy = getPersonDisplayName(item.createdByUser);
+
+ return item;
+}
+
+function getLinkItem(siteId, containerId, restOfPath, node)
+{
+ // only process documents
+ if (!node.isDocument)
+ {
+ return null;
+ }
+
+ // make sure we haven't already added this link
+ if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
+ {
+ return null;
+ }
+ addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
+
+ var item =
+ {
+ site: getSiteData(siteId),
+ container: containerId,
+ nodeRef: node.nodeRef.toString(),
+ type: "link",
+ tags: (node.tags !== null) ? node.tags : [],
+ name: node.name,
+ description: node.properties["cm:description"],
+ modifiedOn: node.properties["cm:modified"],
+ modifiedByUser: node.properties["cm:modifier"],
+ createdOn: node.properties["cm:created"],
+ createdByUser: node.properties["cm:creator"],
+ size: -1,
+ displayName: node.properties["lnk:title"],
+ browseUrl: "links-view?linkId=" + node.properties["cm:name"]
+ };
+ item.modifiedBy = getPersonDisplayName(item.modifiedByUser);
+ item.createdBy = getPersonDisplayName(item.createdByUser);
+ return item;
+}
+
+/**
+ * Delegates the extraction to the correct extraction function
+ * depending site/container id.
+ */
+function getItem(siteId, containerId, restOfPath, node)
+{
+ if (containerId == "documentLibrary")
+ {
+ return getDocumentItem(siteId, containerId, restOfPath, node);
+ }
+ else if (containerId == "blog")
+ {
+ return getBlogPostItem(siteId, containerId, restOfPath, node);
+ }
+ else if (containerId == "discussions")
+ {
+ return getForumPostItem(siteId, containerId, restOfPath, node);
+ }
+ else if (containerId == "calendar")
+ {
+ return getCalendarItem(siteId, containerId, restOfPath, node);
+ }
+ else if (containerId == "wiki")
+ {
+ return getWikiItem(siteId, containerId, restOfPath, node);
+ }
+ else if (containerId == "links")
+ {
+ return getLinkItem(siteId, containerId, restOfPath, node);
+ }
+ else
+ {
+ // unknown container
+ return null;
+ }
+}
+
+/**
+ * Returns an array with [0] = site and [1] = container or null if the node does not match
+ */
+function splitQNamePath(node)
+{
+ var path = node.qnamePath;
+
+ if (path.match("^"+SITES_SPACE_QNAME_PATH) != SITES_SPACE_QNAME_PATH)
+ {
+ return null;
+ }
+
+ var tmp = path.substring(SITES_SPACE_QNAME_PATH.length);
+ var pos = tmp.indexOf('/');
+ if (pos < 1)
+ {
+ return null;
+ }
+
+ var siteId = tmp.substring(0, pos);
+ siteId = siteId.substring(siteId.indexOf(":") + 1);
+ tmp = tmp.substring(pos + 1);
+ pos = tmp.indexOf('/');
+ if (pos < 1)
+ {
+ return null;
+ }
+
+ var containerId = tmp.substring(0, pos);
+ containerId = containerId.substring(containerId.indexOf(":") + 1);
+ var restOfPath = tmp.substring(pos + 1);
+
+ return [ siteId, containerId, restOfPath ];
+}
+
+/**
+ * Processes the search results. Filters out unnecessary nodes
+ *
+ * @return the final search results object
+ */
+function processResults(nodes, maxResults)
+{
+ var results = [],
+ added = 0,
+ parts,
+ item,
+ i, j;
+
+ for (i = 0, j = nodes.length; i < j && added < maxResults; i++)
+ {
+ /**
+ * For each node we extract the site/container qname path and then
+ * let the per-container helper function decide what to do.
+ */
+ parts = splitQNamePath(nodes[i]);
+ if (parts !== null)
+ {
+ item = getItem(parts[0], parts[1], parts[2], nodes[i]);
+ if (item !== null)
+ {
+ results.push(item);
+ added++;
+ }
+ }
+ }
+
+ return (
+ {
+ items: results
+ });
+}
+
+/**
+ * Return Search results with the given search terms
+ * Terms are split on whitespace characters.
+ *
+ * AND, OR and NOT are supported - as their Lucene equivalent.
+ */
+function getSearchResults(term, maxResults, siteId, containerId)
+{
+ var path = SITES_SPACE_QNAME_PATH;
+ if (siteId !== null && siteId.length > 0)
+ {
+ path += "cm:" + search.ISO9075Encode(siteId) + "/";
+ }
+ else
+ {
+ path += "*/";
+ }
+ if (containerId !== null && containerId.length > 0)
+ {
+ path += "cm:" + search.ISO9075Encode(containerId) + "/";
+ }
+ else
+ {
+ path += "*/";
+ }
+
+ var luceneQuery = "";
+ if (term !== null && term.length !== 0)
+ {
+ // TODO: Perform smarter term processing. For now we simply split on whitespace
+ // which ignores quoted phrases that may be present.
+ var terms = term.split(/\s/),
+ i, j, t;
+
+ for (i = 0, j = terms.length; i < j; i++)
+ {
+ t = terms[i];
+ // remove quotes - TODO: add support for quoted terms later
+ t = t.replace(/\"/g, "");
+ if (t.length !== 0)
+ {
+ switch (t.toLowerCase())
+ {
+ case "and":
+ if (i < j - 1 && terms[i + 1].length !== 0)
+ {
+ luceneQuery += "AND ";
+ }
+ break;
+
+ case "or":
+ break;
+
+ case "not":
+ if (i < j - 1 && terms[i + 1].length !== 0)
+ {
+ luceneQuery += "NOT ";
+ }
+ break;
+
+ default:
+ luceneQuery += "(TEXT:\"" + t + "\"" + // full text
+ " @cm\\:name:\"" + t + "\"" + // name property
+ " @lnk\\:title:\"" + t + "\"" + // link title
+ " @lnk\\:description:\"" + t + "\"" + // link description
+ " PATH:\"/cm:taggable/cm:" + search.ISO9075Encode(t) + "/member\"" + // tags
+ ") ";
+ }
+ }
+ }
+ }
+
+ var nodes;
+
+ // if we processed the search terms, then suffix the PATH query
+ if (luceneQuery.length !== 0)
+ {
+ luceneQuery = "+PATH:\"" + path + "/*\" +(" + luceneQuery + ")";
+ luceneQuery += " -TYPE:\"{http://www.alfresco.org/model/content/1.0}thumbnail\"";
+ nodes = search.luceneSearch(luceneQuery);
+ }
+ else
+ {
+ // failed to process the search string - empty list returned
+ nodes = [];
+ }
+
+ return processResults(nodes, maxResults);
+}
\ No newline at end of file