Author: bpoussin Date: 2011-08-21 20:16:39 +0200 (Sun, 21 Aug 2011) New Revision: 317 Url: http://chorem.org/repositories/revision/bow/317 Log: Evolution #430: Permit search prefix configurable for each user - move open search action in new package - refactore open search action to simplify prefix search - add support of suggest for alias - add support for user configuration prefix (backend) Added: trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/ trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchBaseAction.java trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchResultAction.java trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchSuggestionAction.java Removed: trunk/bow-ui/src/main/java/org/chorem/bow/SuggestionsComparator.java trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchResultAction.java trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java Modified: trunk/bow-ui/src/main/java/org/chorem/bow/BowConfig.java trunk/bow-ui/src/main/java/org/chorem/bow/BowConfigOption.java trunk/bow-ui/src/main/java/org/chorem/bow/BowSession.java trunk/bow-ui/src/main/java/org/chorem/bow/action/AliasAction.java trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties trunk/bow-ui/src/main/xmi/bow.zargo Modified: trunk/bow-ui/src/main/java/org/chorem/bow/BowConfig.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/BowConfig.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/BowConfig.java 2011-08-21 18:16:39 UTC (rev 317) @@ -248,4 +248,130 @@ return config.getOption(BowConfigOption.BOW_ADMINS.key + ".password." + admin); } + /** + * Retourne le separateur choisi par l'utilisateur entre les prefix d'action + * et la chaine. + * + * @return + */ + public static String getPrefixSeparator() { + return getPrefixSeparator(getConfig()); + } + + /** + * Retourne le separateur choisi par l'utilisateur entre les prefix d'action + * et la chaine. + * + * @return + */ + public static String getPrefixSeparator(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_PREFIX_SEPARATOR.key); + } + + /** + * Retourne le prefix par defaut a utiliser si l'utilisateur a mis le + * separateur de prefix mais sans prefix + * @return + */ + public static String getDefaultPrefix() { + return getDefaultPrefix(getConfig()); + } + + /** + * Retourne le prefix par defaut a utiliser si l'utilisateur a mis le + * separateur de prefix mais sans prefix + * @return + */ + public static String getDefaultPrefix(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_DEFAULT_PREFIX.key); + } + + /** + * Indique l'action par defaut a faire, si l'utilisateur n'indique ni + * prefix ni separateur de prefix + * @return + */ + public static String getDefaultAction() { + return getDefaultAction(getConfig()); + } + + /** + * Indique l'action par defaut a faire, si l'utilisateur n'indique ni + * prefix ni separateur de prefix + * @return + */ + public static String getDefaultAction(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_DEFAULT_ACTION.key); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur les tags + * @return + */ + public static String getTagSearchPrefix() { + return getTagSearchPrefix(getConfig()); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur les tags + * @return + */ + public static String getTagSearchPrefix(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_TAG_SEARCH_PREFIX.key); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur fulltext + * dans bow + * @return + */ + public static String getFullTextSearchPrefix() { + return getFullTextSearchPrefix(getConfig()); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur fulltext + * dans bow + * @return + */ + public static String getFullTextSearchPrefix(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_FULLTEXT_SEARCH_PREFIX.key); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur les alias + * prive et une rediection automatique vers cette page + * @return + */ + public static String getAliasPrefix() { + return getAliasPrefix(getConfig()); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur les alias + * prive et une rediection automatique vers cette page + * @return + */ + public static String getAliasPrefix(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_ALIAS_PREFIX.key); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur le web + * via le moteur de recherche configurer + * @return + */ + public static String getWebSearchPrefix() { + return getWebSearchPrefix(getConfig()); + } + + /** + * le prefix pour indiquer que l'on souhaite une recherche sur le web + * via le moteur de recherche configurer + * @return + */ + public static String getWebSearchPrefix(ApplicationConfig config) { + return config.getOption(BowConfigOption.OPEN_SEARCH_WEB_SEARCH_PREFIX.key); + } + } Modified: trunk/bow-ui/src/main/java/org/chorem/bow/BowConfigOption.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/BowConfigOption.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/BowConfigOption.java 2011-08-21 18:16:39 UTC (rev 317) @@ -49,10 +49,6 @@ "alias.url", _("bow.config.alias.url.description"), "alias/", String.class, false, false), - SEARCH_ENGINE( - "search.engine", - _("bow.config.search.engine.description"), - null, String.class, false, false), BOW_SMTPSERVER( "bow.smtpServer", _("bow.config.bow.smtpServer.description"), @@ -64,7 +60,39 @@ BOW_ADMINS( "bow.admins", _("bow.config.bow.admins.description"), - null, String.class, false, false); + null, String.class, false, false), + SEARCH_ENGINE( + "search.engine", + _("bow.config.search.engine.description"), + null, String.class, false, false), + OPEN_SEARCH_DEFAULT_ACTION( + "opensearch.default.action", + _("bow.config.opensearch.default.action.description"), + "w", String.class, false, false), + OPEN_SEARCH_PREFIX_SEPARATOR( + "opensearch.prefix.separator", + _("bow.config.opensearch.prefix.separator.description"), + ":", String.class, false, false), + OPEN_SEARCH_DEFAULT_PREFIX( + "opensearch.default.prefix", + _("bow.config.opensearch.default.prefix.description"), + "t", String.class, false, false), + OPEN_SEARCH_TAG_SEARCH_PREFIX( + "opensearch.tag.search.prefix", + _("bow.config.opensearch.tag.search.prefix.description"), + "t", String.class, false, false), + OPEN_SEARCH_FULLTEXT_SEARCH_PREFIX( + "opensearch.fulltext.search.prefix", + _("bow.config.opensearch.fulltext.search.prefix.description"), + "f", String.class, false, false), + OPEN_SEARCH_WEB_SEARCH_PREFIX( + "opensearch.web.search.prefix", + _("bow.config.opensearch.web.search.prefix.description"), + "w", String.class, false, false), + OPEN_SEARCH_ALIAS_PREFIX( + "opensearch.alias.prefix", + _("bow.config.opensearch.alias.prefix.description"), + "a", String.class, false, false); public String key; public String description; Modified: trunk/bow-ui/src/main/java/org/chorem/bow/BowSession.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/BowSession.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/BowSession.java 2011-08-21 18:16:39 UTC (rev 317) @@ -28,9 +28,9 @@ import javax.servlet.http.HttpSession; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.nuiton.wikitty.entities.Wikitty; /** * Classe utilisee pour stocker les objets utils en session utilisateur @@ -130,6 +130,24 @@ if (preference.getSearchEngineUrlSuggestions() == null) { preference.setSearchEngineUrlSuggestions(""); // TODO add default value in config } + if (StringUtils.isBlank(preference.getPrefixSeparator())) { + preference.setPrefixSeparator(BowConfig.getPrefixSeparator()); + } + if (StringUtils.isBlank(preference.getTagSearchPrefix())) { + preference.setPrefixSeparator(BowConfig.getTagSearchPrefix()); + } + if (StringUtils.isBlank(preference.getFullTextSearchPrefix())) { + preference.setFullTextSearchPrefix(BowConfig.getFullTextSearchPrefix()); + } + if (StringUtils.isBlank(preference.getWebSearchPrefix())) { + preference.setWebSearchPrefix(BowConfig.getWebSearchPrefix()); + } + if (StringUtils.isBlank(preference.getAliasPrefix())) { + preference.setAliasPrefix(BowConfig.getAliasPrefix()); + } + if (StringUtils.isBlank(preference.getDefaultAction())) { + preference.setDefaultAction(BowConfig.getDefaultAction()); + } } public String getPermanentToken() { Deleted: trunk/bow-ui/src/main/java/org/chorem/bow/SuggestionsComparator.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/SuggestionsComparator.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/SuggestionsComparator.java 2011-08-21 18:16:39 UTC (rev 317) @@ -1,47 +0,0 @@ -/* - * #%L - * bow - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2010 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * #L% - */ -package org.chorem.bow; - -import java.util.Comparator; -import org.nuiton.wikitty.search.FacetTopic; - -/** - * - * @author bbrossaud - */ -public class SuggestionsComparator implements Comparator<FacetTopic> { - - @Override - public int compare(FacetTopic o1, FacetTopic o2) { - int result = 0; - - if (o1.getCount() < o2.getCount()) { - result = 1; - } - else if (o1.getCount() > o2.getCount()) { - result = -1; - } - return result; - } -} Modified: trunk/bow-ui/src/main/java/org/chorem/bow/action/AliasAction.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/AliasAction.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/AliasAction.java 2011-08-21 18:16:39 UTC (rev 317) @@ -44,6 +44,7 @@ /** to use log facility, just put in your code: log.info(\"...\"); */ static private Log log = LogFactory.getLog(AliasAction.class); + private static final long serialVersionUID = 1L; protected String redirectTo = "/"; protected String alias; Deleted: trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchResultAction.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchResultAction.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchResultAction.java 2011-08-21 18:16:39 UTC (rev 317) @@ -1,140 +0,0 @@ -/* - * #%L - * bow - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2010 - 2011 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * #L% - */ -package org.chorem.bow.action; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringUtils; -import org.apache.struts2.interceptor.ServletResponseAware; -import org.chorem.bow.BowBookmark; -import org.chorem.bow.BowConfig; -import org.chorem.bow.BowUtils; -import org.chorem.bow.BowUser; -import org.nuiton.wikitty.search.Criteria; -import org.nuiton.wikitty.WikittyProxy; -import org.nuiton.wikitty.search.Search; - -/** - * Traite toutes les demandes faite via l'opensearch - * a:, :, t:, ... - * - * @author poussin - */ -public class OpenSearchResultAction extends BowBaseAction implements ServletResponseAware { - private static final long serialVersionUID = -1691325797986483856L; - - protected String token; - protected String redirectTo; - protected HttpServletResponse response; - protected String searchLine; - - public String getSearchLine() { - return searchLine; - } - - public void setSearchLine(String searchLine) { - this.searchLine = searchLine; - } - - /** - * @return the token - */ - public String getToken() { - return token; - } - - /** - * @param token the token to set - */ - public void setToken(String token) { - this.token = token; - } - - /** - * @return the redirectTo - */ - public String getRedirectTo() { - return redirectTo; - } - - @Override - public void setServletResponse(HttpServletResponse response) { - this.response = response; - } - - @Override - public String execute() { - BowUser user = getBowSession().getUser(); - - if (searchLine != null && searchLine.matches("^http://[^ ]*")) { - redirectTo = searchLine; - } else if (searchLine != null - && (searchLine.startsWith(":") || searchLine.startsWith("t:"))) { - - // Search on tags - int index = searchLine.indexOf(":"); - searchLine = searchLine.substring(index + 1); //Suppresses first ":" - - redirectTo = BowUtils.redirectTo(searchLine, null); - } else if (searchLine != null && searchLine.startsWith("f:")) { - // Fulltext search in bow - String fullText = searchLine.substring(2); - redirectTo = BowUtils.redirectTo(null, fullText); - } else if (searchLine != null && searchLine.startsWith("a:")) { - // Redirects to the requested alias - String privateAlias = searchLine.substring(2); - WikittyProxy proxy = getBowProxy(); - Criteria criteria = Search.query() - .eq(BowBookmark.FQ_FIELD_WIKITTYAUTHORISATION_OWNER, user.getWikittyId()) - .eq(BowBookmark.FQ_FIELD_BOWBOOKMARK_PRIVATEALIAS, privateAlias) - .criteria(); - String bookmarkId = proxy.findIdByCriteria(criteria); - // si on retrouve l'alias prive on l'utilise, - // sinon on espere qu'il existe un alias public portant ce nom - if (bookmarkId != null) { - redirectTo = BowConfig.getAliasUrl() + bookmarkId + ".action"; - if (log.isDebugEnabled()) { - log.debug("Private alias found, redirect to: " + redirectTo); - } - } else { - redirectTo = BowConfig.getAliasUrl() + privateAlias + ".action"; - if (log.isDebugEnabled()) { - log.debug("Private alias not found, redirect to: " + redirectTo); - } - } - } else { - // Search on the chosen search engine - BowUser pref = getBowSession().getUser(); - - String searchEngineURL = pref.getSearchEngineUrlResults(); - if (StringUtils.isEmpty(searchEngineURL)) { - searchEngineURL = BowConfig.getSearchEngine(); - } - searchEngineURL = searchEngineURL.replace("{searchTerms}", searchLine); - searchEngineURL = response.encodeRedirectURL(searchEngineURL); - redirectTo = searchEngineURL; - } - return SUCCESS; - } -} Deleted: trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java 2011-08-21 18:16:39 UTC (rev 317) @@ -1,176 +0,0 @@ -/* - * #%L - * bow - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2010 - 2011 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * #L% - */ -package org.chorem.bow.action; - -import com.opensymphony.xwork2.ActionContext; -import java.io.InputStream; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import org.apache.commons.io.input.ReaderInputStream; -import org.apache.commons.lang.StringUtils; -import org.chorem.bow.BookmarkUtils; - -import org.chorem.bow.BowBookmark; -import org.chorem.bow.OpenSearchActions; -import org.chorem.bow.BowUser; -import org.chorem.bow.BowUtils; -import org.nuiton.wikitty.search.Criteria; -import org.nuiton.wikitty.search.FacetTopic; -import org.nuiton.wikitty.search.PagedResult; -import org.nuiton.wikitty.WikittyProxy; -import org.nuiton.wikitty.entities.Wikitty; -import org.nuiton.wikitty.search.Search; - -/** - * Retourne les suggestions pour l'opensearch en fonction de ce qui a ete deja - * saisi - * - * @author poussin - */ -public class OpenSearchSuggestionAction extends BowBaseAction { - - private static final long serialVersionUID = 3973618635494129146L; - - static public OpenSearchSuggestionAction getAction() { - Object action = ActionContext.getContext().get(CONTEXT_ACTION_KEY); - return (OpenSearchSuggestionAction) action; - } - - /** le token utilise pour faire l'appel (permanent ou temporaire) */ - protected String token; - protected String searchLine; - protected InputStream inputStream; - - public InputStream getInputStream() { - return inputStream; - } - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - - public String getSearchLine() { - return searchLine; - } - - public void setSearchLine(String searchLine) { - this.searchLine = searchLine; - } - - @Override - public String execute() { - if (log.isDebugEnabled()) { - log.debug(String.format("Start opensearch suggest for '%s'", searchLine)); - } - - // preparation de la reponse. Un toString sur une liste retourne - // la bonne syntaxe pour une reponse json :) si on triche un peu - // en ajoutant des '' pour les chaines - List json = new ArrayList(); - List<String> completions = new ArrayList<String>(); - List<String> descriptions = new ArrayList<String>(); - List<String> queryUrls = new ArrayList<String>(); - - json.add("'" + searchLine + "'"); - json.add(completions); - json.add(descriptions); - json.add(queryUrls); - - if (searchLine != null) { - BowUser user = getBowSession().getUser(); - WikittyProxy proxy = getBowProxy(); - - // on ajoute * a la fin du dernier tag, car il n'est peut-etre pas fini - String searchLineStar = searchLine + "*"; - - // on recupere le dernier tag en train d'etre ecrit - String lastTag; - if (searchLine.contains(" ")) { - lastTag = StringUtils.substringAfterLast(searchLine, " "); - } else { - lastTag = searchLine; - } - - Set<String> searchLineList = BowUtils.getWords(searchLineStar); - - Search search = BookmarkUtils.addEqUser(Search.query(), user.getWikittyId()); - search.exteq(BowBookmark.EXT_WIKITTYLABEL); - search.contains(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS, searchLineList); - - Criteria criteria= search - .criteria() - .setEndIndex(0) // on ne veut aucun resultat, c'est la facet dont on a besoin - .setFacetMinCount(1) // on demande meme les labels avec 1 seul item - .setFacetLimit(Integer.MAX_VALUE) // ne ne met pas -1 pour qu'il soit trie par ordre de count - .addFacetField(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); - - PagedResult<Wikitty> result = proxy.findAllByCriteria(criteria); - // lorsqu'on demande tout (facetLimit(-1)), les topics sont trie - // alphabetiquement pas besoin de les retrier - List<FacetTopic> topics = result.getTopic(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); - if (log.isTraceEnabled()) { - log.trace("all topics: %s" + topics); - } - - // on en retourne un suggestion que le meme nombre de tag qu'il souhaite - // voir affiche - int count = user.getTags(); - for(FacetTopic t : topics) { - // on ne met que les topics qui qui commence par lastTag - String completion = t.getTopicName(); - if (log.isTraceEnabled()) { - log.trace(String.format("'%s' startsWith '%s' ? ", completion, lastTag)); - } - if (completion.startsWith(lastTag)) { - String description = _("%s results",t.getCount()); - String queryUrl = String.format("%shome?token=%s&tagLine=%s", - getConfig().getBowUrl(), - token, - searchLine + StringUtils.removeStart(completion, lastTag)); - - completions.add("'" + completion + "'"); - descriptions.add("'" + description + "'"); - queryUrls.add("'" + queryUrl + "'"); - - // on s'arrete si l'on en a assez - count--; - if (count <= 0) { - break; - } - } - } - } - if (log.isDebugEnabled()) { - log.debug(String.format("opensearch suggest result: %s", json)); - } - inputStream = new ReaderInputStream(new StringReader(json.toString())); - return SUCCESS; - } -} \ No newline at end of file Copied: trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchBaseAction.java (from rev 313, trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchResultAction.java) =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchBaseAction.java (rev 0) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchBaseAction.java 2011-08-21 18:16:39 UTC (rev 317) @@ -0,0 +1,121 @@ +/* + * #%L + * bow + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2010 - 2011 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ +package org.chorem.bow.action.opensearch; + +import org.apache.commons.lang.StringUtils; +import org.chorem.bow.BowUser; +import org.chorem.bow.action.BowBaseAction; + +/** + * Traite toutes les demandes faite via l'opensearch + * a:, :, t:, ... + * + * Cette classe recherche le prefix et redirige vers la bonne methode execute. + * Les classes filles n'ont plus qu'a implanter les methodes + * + * @author poussin + */ +abstract public class OpenSearchBaseAction extends BowBaseAction { + private static final long serialVersionUID = 1L; + + /** [in] le token d'identification */ + protected String token; + /** [in] la ligne de recherche soumise par l'utilisateur */ + protected String searchLine; + + /** + * [out] le prefix trouve ou calculer par rapport a searchLine + * avoir acces a cette valeur, peut-etre utile dans certaine implantation + * de {@link #executeNotSupportedPrefixAction} + */ + protected String prefix; + + public String getSearchLine() { + return searchLine; + } + + public void setSearchLine(String searchLine) { + this.searchLine = searchLine; + } + + /** + * @return the token + */ + public String getToken() { + return token; + } + + /** + * @param token the token to set + */ + public void setToken(String token) { + this.token = token; + } + + public String getPrefix() { + return prefix; + } + + abstract protected String executeTagSearchAction(String query); + + abstract protected String executeFulltextSearchAction(String query); + + abstract protected String executeWebSearchAction(String query); + + abstract protected String executeAliasSearchAction(String privateAlias); + + abstract protected String executeNotSupportedPrefixAction(String query); + + @Override + public String execute() { + BowUser user = getBowSession().getUser(); + + String prefixSeparator = user.getPrefixSeparator(); + prefix = StringUtils.substringBefore(searchLine, prefixSeparator); + String query = StringUtils.substringAfter(searchLine, prefixSeparator); + + if (StringUtils.isEmpty(prefix)) { + // on a le separateur mais pas de prefix + prefix = user.getDefaultPrefix(); + } else if (StringUtils.equals(searchLine, query)) { + // on a pas de separateur + prefix = user.getDefaultAction(); + } + + String result = SUCCESS; + if (StringUtils.equals(prefix, user.getTagSearchPrefix())) { + result = executeTagSearchAction(query); + } else if (StringUtils.equals(prefix, user.getFullTextSearchPrefix())) { + result = executeFulltextSearchAction(query); + } else if (StringUtils.equals(prefix, user.getWebSearchPrefix())) { + result = executeWebSearchAction(query); + } else if (StringUtils.equals(prefix, user.getAliasPrefix())) { + result = executeAliasSearchAction(query); + } else { + result = executeNotSupportedPrefixAction(query); + } + + return result; + } +} Copied: trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchResultAction.java (from rev 313, trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchResultAction.java) =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchResultAction.java (rev 0) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchResultAction.java 2011-08-21 18:16:39 UTC (rev 317) @@ -0,0 +1,120 @@ +/* + * #%L + * bow + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2010 - 2011 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ +package org.chorem.bow.action.opensearch; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.apache.struts2.interceptor.ServletResponseAware; +import org.chorem.bow.BowBookmark; +import org.chorem.bow.BowConfig; +import org.chorem.bow.BowUtils; +import org.chorem.bow.BowUser; +import org.nuiton.wikitty.search.Criteria; +import org.nuiton.wikitty.WikittyProxy; +import org.nuiton.wikitty.search.Search; + +/** + * Traite toutes les demandes faite via l'opensearch + * a:, :, t:, ... + * + * @author poussin + */ +public class OpenSearchResultAction extends OpenSearchBaseAction implements ServletResponseAware { + private static final long serialVersionUID = 1L; + + protected String redirectTo; + protected HttpServletResponse response; + + /** + * @return the redirectTo + */ + public String getRedirectTo() { + return redirectTo; + } + + @Override + public void setServletResponse(HttpServletResponse response) { + this.response = response; + } + + protected String executeTagSearchAction(String query) { + redirectTo = BowUtils.redirectTo(searchLine, null); + return SUCCESS; + } + + protected String executeFulltextSearchAction(String query) { + redirectTo = BowUtils.redirectTo(null, searchLine); + return SUCCESS; + } + + protected String executeWebSearchAction(String query) { + // Search on the chosen search engine + BowUser user = getBowSession().getUser(); + + String result = user.getSearchEngineUrlResults(); + if (StringUtils.isEmpty(result)) { + result = BowConfig.getSearchEngine(); + } + result = result.replace("{searchTerms}", query); + result = response.encodeRedirectURL(result); + redirectTo = result; + return SUCCESS; + } + + protected String executeAliasSearchAction(String privateAlias) { + BowUser user = getBowSession().getUser(); + WikittyProxy proxy = getBowProxy(); + Criteria criteria = Search.query() + .eq(BowBookmark.FQ_FIELD_WIKITTYAUTHORISATION_OWNER, user.getWikittyId()) + .eq(BowBookmark.FQ_FIELD_BOWBOOKMARK_PRIVATEALIAS, privateAlias) + .criteria(); + String bookmarkId = proxy.findIdByCriteria(criteria); + + String result; + // si on retrouve l'alias prive on l'utilise, + // sinon on espere qu'il existe un alias public portant ce nom + if (bookmarkId != null) { + result = BowConfig.getAliasUrl() + bookmarkId + ".action"; + if (log.isDebugEnabled()) { + log.debug("Private alias found, redirect to: " + result); + } + } else { + result = BowConfig.getAliasUrl() + privateAlias + ".action"; + if (log.isDebugEnabled()) { + log.debug("Private alias not found, redirect to: " + result); + } + } + redirectTo = result; + return SUCCESS; + } + + @Override + protected String executeNotSupportedPrefixAction(String query) { + // prefix inconnu, on va sur la home + redirectTo = BowUtils.redirectTo(null, null); + return SUCCESS; + } + +} Copied: trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchSuggestionAction.java (from rev 315, trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java) =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchSuggestionAction.java (rev 0) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/opensearch/OpenSearchSuggestionAction.java 2011-08-21 18:16:39 UTC (rev 317) @@ -0,0 +1,231 @@ +/* + * #%L + * bow + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2010 - 2011 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ +package org.chorem.bow.action.opensearch; + +import com.opensymphony.xwork2.ActionContext; +import java.io.InputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.commons.lang.StringUtils; +import org.chorem.bow.BookmarkUtils; + +import org.chorem.bow.BowBookmark; +import org.chorem.bow.BowUser; +import org.chorem.bow.BowUtils; +import org.nuiton.wikitty.search.Criteria; +import org.nuiton.wikitty.search.FacetTopic; +import org.nuiton.wikitty.search.PagedResult; +import org.nuiton.wikitty.WikittyProxy; +import org.nuiton.wikitty.entities.Wikitty; +import org.nuiton.wikitty.search.Search; + +/** + * Retourne les suggestions pour l'opensearch en fonction de ce qui a ete deja + * saisi + * + * @author poussin + */ +public class OpenSearchSuggestionAction extends OpenSearchBaseAction { + private static final long serialVersionUID = 1L; + + static public OpenSearchSuggestionAction getAction() { + Object action = ActionContext.getContext().get(CONTEXT_ACTION_KEY); + return (OpenSearchSuggestionAction) action; + } + + protected InputStream inputStream; + + public InputStream getInputStream() { + return inputStream; + } + + @Override + protected String executeTagSearchAction(String query) { + if (log.isDebugEnabled()) { + log.debug(String.format("Start opensearch tag suggest for '%s'", query)); + } + + // preparation de la reponse. Un toString sur une liste retourne + // la bonne syntaxe pour une reponse json :) si on triche un peu + // en ajoutant des '' pour les chaines + List json = new ArrayList(); + List<String> completions = new ArrayList<String>(); + List<String> descriptions = new ArrayList<String>(); + List<String> queryUrls = new ArrayList<String>(); + + json.add("'" + query + "'"); + json.add(completions); + json.add(descriptions); + json.add(queryUrls); + + if (query != null) { + BowUser user = getBowSession().getUser(); + WikittyProxy proxy = getBowProxy(); + + // on ajoute * a la fin du dernier tag, car il n'est peut-etre pas fini + String searchLineStar = query + "*"; + + // on recupere le dernier tag en train d'etre ecrit + String lastTag; + if (query.contains(" ")) { + lastTag = StringUtils.substringAfterLast(query, " "); + } else { + lastTag = query; + } + + Set<String> searchLineList = BowUtils.getWords(searchLineStar); + + Search search = BookmarkUtils.addEqUser(Search.query(), user.getWikittyId()); + search.exteq(BowBookmark.EXT_WIKITTYLABEL); + search.contains(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS, searchLineList); + + Criteria criteria= search + .criteria() + .setEndIndex(0) // on ne veut aucun resultat, c'est la facet dont on a besoin + .setFacetMinCount(1) // on demande meme les labels avec 1 seul item + .setFacetLimit(Integer.MAX_VALUE) // ne ne met pas -1 pour qu'il soit trie par ordre de count + .addFacetField(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); + + PagedResult<Wikitty> result = proxy.findAllByCriteria(criteria); + // lorsqu'on demande tout (facetLimit(-1)), les topics sont trie + // alphabetiquement pas besoin de les retrier + List<FacetTopic> topics = result.getTopic(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); + if (log.isTraceEnabled()) { + log.trace("all topics: %s" + topics); + } + + // on en retourne un suggestion que le meme nombre de tag qu'il souhaite + // voir affiche + int count = user.getTags(); + for(FacetTopic t : topics) { + // on ne met que les topics qui qui commence par lastTag + String completion = t.getTopicName(); + if (log.isTraceEnabled()) { + log.trace(String.format("'%s' startsWith '%s' ? ", completion, lastTag)); + } + if (completion.startsWith(lastTag)) { + String description = _("%s results",t.getCount()); + String tags = query + StringUtils.removeStart(completion, lastTag); + String queryUrl = getConfig().getBowUrl() + BowUtils.redirectTo(tags, null); + + completions.add("'" + completion + "'"); + descriptions.add("'" + description + "'"); + queryUrls.add("'" + queryUrl + "'"); + + // on s'arrete si l'on en a assez + count--; + if (count <= 0) { + break; + } + } + } + } + if (log.isDebugEnabled()) { + log.debug(String.format("opensearch suggest result: %s", json)); + } + inputStream = new ReaderInputStream(new StringReader(json.toString())); + return SUCCESS; + } + + @Override + protected String executeFulltextSearchAction(String query) { + return executeNotSupportedPrefixAction(query); + } + + @Override + protected String executeWebSearchAction(String query) { + return executeNotSupportedPrefixAction(query); + } + + @Override + protected String executeAliasSearchAction(String privateAlias) { + if (log.isDebugEnabled()) { + log.debug(String.format("Start opensearch alias suggest for '%s'", privateAlias)); + } + + // preparation de la reponse. Un toString sur une liste retourne + // la bonne syntaxe pour une reponse json :) si on triche un peu + // en ajoutant des '' pour les chaines + List json = new ArrayList(); + List<String> completions = new ArrayList<String>(); + List<String> descriptions = new ArrayList<String>(); + List<String> queryUrls = new ArrayList<String>(); + + json.add("'" + privateAlias + "'"); + json.add(completions); + json.add(descriptions); + json.add(queryUrls); + + if (privateAlias != null) { + BowUser user = getBowSession().getUser(); + WikittyProxy proxy = getBowProxy(); + + // on ajoute * a la fin, car il n'est peut-etre pas fini + String privateAliasStar = privateAlias + "*"; + + Search search = BookmarkUtils.addEqUser(Search.query(), user.getWikittyId()); + search.eq(BowBookmark.FQ_FIELD_BOWBOOKMARK_PRIVATEALIAS, privateAliasStar); + + Criteria criteria= search.criteria() + .setEndIndex(15); // on recupere que les 15 premiers resultats + + PagedResult<BowBookmark> result = proxy.findAllByCriteria(BowBookmark.class, criteria); + + for(BowBookmark b: result) { + String completion = b.getPrivateAlias(); + String description = b.getDescription(); + String queryUrl = String.format("%s%s?token=%s", + getConfig().getAliasUrl(), completion, token); + completions.add("'" + completion + "'"); + descriptions.add("'" + description + "'"); + queryUrls.add("'" + queryUrl + "'"); + } + + } + if (log.isDebugEnabled()) { + log.debug(String.format("opensearch alias suggest result: %s", json)); + } + inputStream = new ReaderInputStream(new StringReader(json.toString())); + return SUCCESS; + } + + /** + * On ne renvoie aucune suggestion + * + * @param prefix + * @param query + * @return + */ + @Override + protected String executeNotSupportedPrefixAction(String query) { + String result = String.format("['%s', [], [], []]", query); + inputStream = new ReaderInputStream(new StringReader(result)); + return SUCCESS; + } + + +} \ No newline at end of file Modified: trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties =================================================================== --- trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties 2011-08-21 18:16:39 UTC (rev 317) @@ -31,6 +31,13 @@ bow.config.bow.url.description= bow.config.configFileName.description= bow.config.data.dir.description= +bow.config.opensearch.alias.prefix.description= +bow.config.opensearch.default.action.description= +bow.config.opensearch.default.prefix.description= +bow.config.opensearch.fulltext.search.prefix.description= +bow.config.opensearch.prefix.separator.description= +bow.config.opensearch.tag.search.prefix.description= +bow.config.opensearch.web.search.prefix.description= bow.config.search.engine.description= bow.config.servlet.bow.description= bow.error.internal=An internal error occurred, please contact an administrator if the problem persists Modified: trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties =================================================================== --- trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties 2011-08-21 16:06:25 UTC (rev 316) +++ trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties 2011-08-21 18:16:39 UTC (rev 317) @@ -31,6 +31,13 @@ bow.config.bow.url.description= bow.config.configFileName.description= bow.config.data.dir.description= +bow.config.opensearch.alias.prefix.description= +bow.config.opensearch.default.action.description= +bow.config.opensearch.default.prefix.description= +bow.config.opensearch.fulltext.search.prefix.description= +bow.config.opensearch.prefix.separator.description= +bow.config.opensearch.tag.search.prefix.description= +bow.config.opensearch.web.search.prefix.description= bow.config.search.engine.description= bow.config.servlet.bow.description= bow.error.internal=Une erreur interne est survenue, merci de contacter un administrateur si cette erreur persiste Modified: trunk/bow-ui/src/main/xmi/bow.zargo =================================================================== (Binary files differ)