diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java index c175ff10bd..b4c0228393 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java @@ -73,7 +73,7 @@ import org.springframework.beans.factory.annotation.Autowired; public abstract class BaseAPI { // logger - private static final Logger LOGGER = LoggerFactory.getLogger(BaseAPI.class); + protected static final Logger LOGGER = LoggerFactory.getLogger(BaseAPI.class); /** exception key in JSON response body */ private static final String EXCEPTION_KEY = "exception"; @@ -216,6 +216,7 @@ public abstract class BaseAPI client.getAlfrescoUrl(), URLEncodedUtils.format(parameters, "UTF-8")); } + LOGGER.info("On GET {}, received following response: ", requestURL); client.close(); return doGetRequest(username, password, requestURL); } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java index 176b51d2d8..0e4af8732e 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/SearchAPI.java @@ -36,6 +36,7 @@ import org.alfresco.rest.core.v0.BaseAPI; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.message.BasicNameValuePair; +import org.json.JSONException; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -56,6 +57,9 @@ public class SearchAPI extends BaseAPI /** faceted search API endpoint */ private static final String FACETED_SEARCH_ENDPOINT = "{0}alfresco/s/slingshot/rmsearch/faceted/rmsearch?{1}"; + /** share live search API endpoint */ + private static final String SHARE_LIVE_SEARCH_DOCS_ENDPOINT = "{0}alfresco/s/slingshot/live-search-docs?{1}"; + /** RM search URL template */ private static final String RM_SEARCH_ENDPOINT = "{0}alfresco/s/slingshot/rmsearch/{1}?{2}"; @@ -138,6 +142,20 @@ public class SearchAPI extends BaseAPI return facetedRequest(username, password, parameters, FACETED_SEARCH_ENDPOINT); } + /** + * Execute share live search for documents. + * + * @param searchUser + * @param searchPassword + * @param searchTerm + * @return search results (see API reference for more details) + */ + public JSONObject liveSearchForDocuments(String searchUser, String searchPassword, String searchTerm) + { + return facetedRequest(searchUser, searchPassword, Arrays.asList(new BasicNameValuePair("t", searchTerm)), + SHARE_LIVE_SEARCH_DOCS_ENDPOINT); + } + /** * Execute faceted search for term. * @param searchUser @@ -165,6 +183,20 @@ public class SearchAPI extends BaseAPI return getItemNames(facetedSearchForTerm(username, password, term)); } + /** + * Helper method to search for documents as a user using share live search. + * @param username to search as + * @param password for username + * @param term search term + * @return list of document names found + */ + public List liveSearchForDocumentsAsUser(String username, String password, String term) throws JSONException + { + JSONObject searchResult = liveSearchForDocuments(username, password, term); + LOGGER.info(searchResult.toString(3)); + return getItemNames(searchResult); + } + /** * Helper method to extract list of names from search result. * @param searchResult diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/search/ShareLiveSearch.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/search/ShareLiveSearch.java new file mode 100644 index 0000000000..aba1c00aee --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/search/ShareLiveSearch.java @@ -0,0 +1,60 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.rm.community.search; + +import static org.testng.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.v0.SearchAPI; +import org.alfresco.test.AlfrescoTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.Test; + +public class ShareLiveSearch extends BaseRMRestTest +{ + @Autowired + SearchAPI searchApi; + + /** + * Given the RM site has been created When I search for "vital" Then the "Vital Records Due for Review" search + * object should not appear as a link in the quick search results drop down + */ + @Test + @AlfrescoTest(jira = "RM-5882") + public void liveSearchForVitalWord() throws Exception + { + createRMSiteIfNotExists(); + List results = searchApi.liveSearchForDocumentsAsUser(getAdminUser().getUsername(), getAdminUser().getPassword(), "vital"); + assertTrue(results.isEmpty() || !results.stream().anyMatch("Vital Records due for Review"::equalsIgnoreCase), + "Share Live Search should return 0 results when searching for RM Saved Search filter words, but it returned:" + + Arrays.toString(results.toArray())); + } +} diff --git a/rm-community/rm-community-repo/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/live-search.lib.js b/rm-community/rm-community-repo/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/live-search.lib.js new file mode 100644 index 0000000000..930890813a --- /dev/null +++ b/rm-community/rm-community-repo/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/live-search.lib.js @@ -0,0 +1,316 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +/** + * NOTE: This file is a copy of the ~/slingshot/search/live-search.lib.js from core repository code and replaces that + * file when built with RM, in order to exclude some RM specific files from live search results. Ideally, any changes + * to the core file should be replicated here. + */ + +/** + * Live Search Component + * + * Takes the following object as Input: + * params + * { + * type: search mode type - one of "documents|sites|people" + * term: search terms + * maxResults: maximum results to return + * }; + * + * Outputs: + * items - Array of objects containing the search results + */ + +const DEFAULT_MAX_RESULTS = 5; +const SITES_SPACE_QNAME_PATH = "/app:company_home/st:sites/"; +const SURF_CONFIG_QNAMEPATH = "/cm:surf-config/"; + +/** + * Returns site information data structure. + * { shortName: siteId, title: title } + * + * Caches the data to avoid repeatedly querying the repository. + */ +var siteDataCache = {}; + +function getSiteData(siteId) { + if (typeof siteDataCache[siteId] === "object") + { + return siteDataCache[siteId]; + } + var site = siteService.getSite(siteId); + var data = + { + shortName : siteId, + title : (site !== null ? site.title : "unknown") + }; + siteDataCache[siteId] = data; + return data; +} + +/** + * Return the fts-alfresco query template to use. + * The default searches name, title, descripton, calendar, link, full text and tag fields. + * It is configurable via the .config.xml attached to this webscript. + */ +function getQueryTemplate() { + var t = + [{ + field: "keywords", + template: "%(cm:name cm:title cm:description TEXT TAG)" + }], + qt = new XML(config.script)["default-query-template"]; + if (qt != null && qt.length() != 0) + { + t[0].template = qt.toString(); + } + return t; +} + +/** + * Process and return a document item node + */ +function getDocumentItem(container, node) { + // check whether this is a valid folder or a file + var item = null; + if (node.qnamePath.indexOf(SURF_CONFIG_QNAMEPATH) === -1) + { + if (node.isDocument) + { + item = + { + nodeRef: node.nodeRef.toString(), + name: node.name, + title: node.properties["cm:title"], + description: node.properties["cm:description"], + modifiedOn: node.properties["cm:modified"], + modifiedBy: node.properties["cm:modifier"], + createdOn: node.properties["cm:created"], + createdBy: node.properties["cm:creator"], + mimetype: node.mimetype, + size: node.size + }; + if (container.siteId !== null) + { + item.site = getSiteData(container.siteId); + item.container = container.containerId; + } + if (node.hasAspect("{http://www.alfresco.org/model/content/1.0}thumbnailModification")) + { + var dates = node.properties["lastThumbnailModification"]; + for (var i=0; i= 1) + { + var siteQName = Packages.org.alfresco.util.ISO9075.decode(tmp.split("/")[0]); + siteId = siteQName.substring(siteQName.indexOf(":") + 1); + tmp = tmp.substring(pos + 1); + pos = tmp.indexOf('/'); + if (pos >= 1) + { + // strip container id from the path + var containerId = tmp.substring(0, pos); + containerId = containerId.substring(containerId.indexOf(":") + 1); + + container.siteId = siteId; + container.containerId = containerId; + } + } + } + + return container; +} + +/** + * Dispatch a live search to the appropriate search method for the requested result type. + */ +function liveSearch(params) { + switch (params.type) + { + case "documents": + return getDocResults(params); + break; + case "sites": + return getSiteResults(params); + break; + case "people": + return getPeopleResults(params); + break; + } +} + +/** + * Return Document Search results with the given search terms. + * + * "AND" is the default operator unless configured otherwise, OR, AND and NOT are also supported - + * as is any other valid fts-alfresco elements such as "quoted terms" and (bracket terms) and also + * propname:propvalue syntax. + * + * @param params Object containing search parameters - see API description above + */ +function getDocResults(params) { + // ensure a TYPE is specified + var ftsQuery = params.term + ' AND +TYPE:"cm:content"'; + + // site constraint + if (params.siteId !== null) + { + // use SITE syntax to restrict to specific site + ftsQuery += ' AND SITE:"' + params.siteId + '"'; + } + + // root node - generally used for overridden Repository root in Share + if (params.rootNode !== null) + { + ftsQuery = 'PATH:"' + rootNode.qnamePath + '//*" AND (' + ftsQuery + ')'; + } + + // main query construction + ftsQuery = '(' + ftsQuery + ') AND -TYPE:"cm:thumbnail" AND -TYPE:"cm:failedThumbnail" AND -TYPE:"cm:rating" AND -TYPE:"fm:post" AND -ASPECT:"sys:hidden" AND -ASPECT:"rma:savedSearch" AND -cm:creator:system'; + + if (logger.isLoggingEnabled()) + logger.log("LiveQuery:\r\n" + ftsQuery); + + // get default fts operator from the config + // + // TODO: common search lib - for both live and standard e.g. to get values like this... + // + var operator = "AND"; + var cf = new XML(config.script)["default-operator"]; + if (cf != null && cf.length != 0) + { + operator = cf.toString(); + } + + // perform fts-alfresco language query + var queryDef = { + query: ftsQuery, + language: "fts-alfresco", + templates: getQueryTemplate(), + defaultField: "keywords", + defaultOperator: operator, + onerror: "no-results", + page: { + maxItems: params.maxResults, + skipCount: params.startIndex + } + }; + var rs = search.queryResultSet(queryDef); + nodes = rs.nodes, + results = []; + + if (logger.isLoggingEnabled()) + logger.log("Processing resultset of length: " + nodes.length); + + for (var i=0, item; ialfresco-rm-community-repo true ${project.build.directory}/solr/home + + 5.1.1 1.4 @@ -362,7 +364,7 @@ ${alfresco.groupId} alfresco-repository - ${alfresco.version} + ${alfresco.h2scripts.version} h2scripts @@ -613,7 +615,7 @@ ${alfresco.groupId} alfresco-repository - ${alfresco.version} + ${alfresco.h2scripts.version} h2scripts