From cb39d1bdd3644ccb15e6aa69b48cbb65f17ccdbd Mon Sep 17 00:00:00 2001 From: Lawrence Carvalho Date: Fri, 29 May 2009 14:33:05 +0000 Subject: [PATCH] profile pages of other users now lists their site membership and recently edited content git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14478 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../profile/usercontents.get.desc.xml | 7 + .../slingshot/profile/usercontents.get.js | 28 + .../profile/usercontents.get.json.ftl | 42 ++ .../alfresco/slingshot/search/search.get.js | 570 +---------------- .../alfresco/slingshot/search/search.lib.js | 584 ++++++++++++++++++ 5 files changed, 662 insertions(+), 569 deletions(-) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.js create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/profile/usercontents.get.json.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.lib.js 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 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 item.browseUrl??> + "browseUrl": "${item.browseUrl}", + + "site": + { + "shortName": "${item.site.shortName}", + "title": "${item.site.title}" + }, + "container": "${item.container}", + "src":"${item.src!''}", + "srcP":"${item.srcP!''}" + }<#if item_has_next>, + + ] + } + +<#escape x as jsonUtils.encodeJSONString(x)> +{ + "created": <@formatDataItems data['created'] />, + "modified": <@formatDataItems data['modified'] /> +} + \ 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