You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LuceneSearchPage.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * Copyright 2012 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit.wicket.pages;
  17. import java.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.LinkedHashSet;
  20. import java.util.List;
  21. import java.util.Set;
  22. import org.apache.wicket.Component;
  23. import org.apache.wicket.PageParameters;
  24. import org.apache.wicket.markup.html.basic.Label;
  25. import org.apache.wicket.markup.html.form.CheckBox;
  26. import org.apache.wicket.markup.html.form.ListMultipleChoice;
  27. import org.apache.wicket.markup.html.form.TextField;
  28. import org.apache.wicket.markup.html.panel.Fragment;
  29. import org.apache.wicket.markup.repeater.Item;
  30. import org.apache.wicket.markup.repeater.data.DataView;
  31. import org.apache.wicket.markup.repeater.data.ListDataProvider;
  32. import org.apache.wicket.model.Model;
  33. import org.eclipse.jgit.lib.Constants;
  34. import com.gitblit.Constants.SearchType;
  35. import com.gitblit.Keys;
  36. import com.gitblit.models.RepositoryModel;
  37. import com.gitblit.models.SearchResult;
  38. import com.gitblit.models.UserModel;
  39. import com.gitblit.utils.ArrayUtils;
  40. import com.gitblit.utils.StringUtils;
  41. import com.gitblit.wicket.GitBlitWebSession;
  42. import com.gitblit.wicket.SessionlessForm;
  43. import com.gitblit.wicket.StringChoiceRenderer;
  44. import com.gitblit.wicket.WicketUtils;
  45. import com.gitblit.wicket.panels.LinkPanel;
  46. import com.gitblit.wicket.panels.PagerPanel;
  47. public class LuceneSearchPage extends RootPage {
  48. public LuceneSearchPage() {
  49. super();
  50. setup(null);
  51. }
  52. public LuceneSearchPage(PageParameters params) {
  53. super(params);
  54. setup(params);
  55. }
  56. private void setup(PageParameters params) {
  57. setupPage("", "");
  58. // default values
  59. ArrayList<String> repositories = new ArrayList<String>();
  60. String query = "";
  61. boolean allRepos = false;
  62. int page = 1;
  63. int pageSize = app().settings().getInteger(Keys.web.itemsPerPage, 50);
  64. // display user-accessible selections
  65. UserModel user = GitBlitWebSession.get().getUser();
  66. List<String> availableRepositories = new ArrayList<String>();
  67. for (RepositoryModel model : app().repositories().getRepositoryModels(user)) {
  68. if (model.hasCommits && !ArrayUtils.isEmpty(model.indexedBranches)) {
  69. availableRepositories.add(model.name);
  70. }
  71. }
  72. if (params != null) {
  73. String repository = WicketUtils.getRepositoryName(params);
  74. if (!StringUtils.isEmpty(repository)) {
  75. repositories.add(repository);
  76. }
  77. page = WicketUtils.getPage(params);
  78. if (params.containsKey("repositories")) {
  79. String value = params.getString("repositories", "");
  80. List<String> list = StringUtils.getStringsFromValue(value);
  81. repositories.addAll(list);
  82. }
  83. allRepos = params.getAsBoolean("allrepos", false);
  84. if (allRepos) {
  85. repositories.addAll(availableRepositories);
  86. }
  87. if (params.containsKey("query")) {
  88. query = params.getString("query", "");
  89. } else {
  90. String value = WicketUtils.getSearchString(params);
  91. String type = WicketUtils.getSearchType(params);
  92. com.gitblit.Constants.SearchType searchType = com.gitblit.Constants.SearchType.forName(type);
  93. if (!StringUtils.isEmpty(value)) {
  94. if (searchType == SearchType.COMMIT) {
  95. query = "type:" + searchType.name().toLowerCase() + " AND \"" + value + "\"";
  96. } else {
  97. query = searchType.name().toLowerCase() + ":\"" + value + "\"";
  98. }
  99. }
  100. }
  101. }
  102. boolean luceneEnabled = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true);
  103. if (luceneEnabled) {
  104. if (availableRepositories.size() == 0) {
  105. info(getString("gb.noIndexedRepositoriesWarning"));
  106. }
  107. } else {
  108. error(getString("gb.luceneDisabled"));
  109. }
  110. // enforce user-accessible repository selections
  111. Set<String> uniqueRepositories = new LinkedHashSet<String>();
  112. for (String selectedRepository : repositories) {
  113. if (availableRepositories.contains(selectedRepository)) {
  114. uniqueRepositories.add(selectedRepository);
  115. }
  116. }
  117. ArrayList<String> searchRepositories = new ArrayList<String>(uniqueRepositories);
  118. // search form
  119. final Model<String> queryModel = new Model<String>(query);
  120. final Model<ArrayList<String>> repositoriesModel = new Model<ArrayList<String>>(searchRepositories);
  121. final Model<Boolean> allreposModel = new Model<Boolean>(allRepos);
  122. SessionlessForm<Void> form = new SessionlessForm<Void>("searchForm", getClass()) {
  123. private static final long serialVersionUID = 1L;
  124. @Override
  125. public void onSubmit() {
  126. String q = queryModel.getObject();
  127. if (StringUtils.isEmpty(q)) {
  128. error(getString("gb.undefinedQueryWarning"));
  129. return;
  130. }
  131. if (repositoriesModel.getObject().size() == 0 && !allreposModel.getObject()) {
  132. error(getString("gb.noSelectedRepositoriesWarning"));
  133. return;
  134. }
  135. PageParameters params = new PageParameters();
  136. params.put("repositories", StringUtils.flattenStrings(repositoriesModel.getObject()));
  137. params.put("query", queryModel.getObject());
  138. params.put("allrepos", allreposModel.getObject());
  139. LuceneSearchPage page = new LuceneSearchPage(params);
  140. setResponsePage(page);
  141. }
  142. };
  143. ListMultipleChoice<String> selections = new ListMultipleChoice<String>("repositories",
  144. repositoriesModel, availableRepositories, new StringChoiceRenderer());
  145. selections.setMaxRows(8);
  146. form.add(selections.setEnabled(luceneEnabled));
  147. form.add(new TextField<String>("query", queryModel).setEnabled(luceneEnabled));
  148. form.add(new CheckBox("allrepos", allreposModel));
  149. add(form.setEnabled(luceneEnabled));
  150. // execute search
  151. final List<SearchResult> results = new ArrayList<SearchResult>();
  152. if (!ArrayUtils.isEmpty(searchRepositories) && !StringUtils.isEmpty(query)) {
  153. results.addAll(app().repositories().search(query, page, pageSize, searchRepositories));
  154. }
  155. // results header
  156. if (results.size() == 0) {
  157. if (!ArrayUtils.isEmpty(searchRepositories) && !StringUtils.isEmpty(query)) {
  158. add(new Label("resultsHeader", query).setRenderBodyOnly(true));
  159. add(new Label("resultsCount", getString("gb.noHits")).setRenderBodyOnly(true));
  160. } else {
  161. add(new Label("resultsHeader").setVisible(false));
  162. add(new Label("resultsCount").setVisible(false));
  163. }
  164. } else {
  165. add(new Label("resultsHeader", query).setRenderBodyOnly(true));
  166. add(new Label("resultsCount", MessageFormat.format(getString("gb.queryResults"),
  167. results.get(0).hitId, results.get(results.size() - 1).hitId, results.get(0).totalHits)).
  168. setRenderBodyOnly(true));
  169. }
  170. // search results view
  171. ListDataProvider<SearchResult> resultsDp = new ListDataProvider<SearchResult>(results);
  172. final DataView<SearchResult> resultsView = new DataView<SearchResult>("searchResults", resultsDp) {
  173. private static final long serialVersionUID = 1L;
  174. @Override
  175. public void populateItem(final Item<SearchResult> item) {
  176. final SearchResult sr = item.getModelObject();
  177. switch(sr.type) {
  178. case commit: {
  179. Label icon = WicketUtils.newIcon("type", "icon-refresh");
  180. WicketUtils.setHtmlTooltip(icon, "commit");
  181. item.add(icon);
  182. item.add(new LinkPanel("summary", null, sr.summary, CommitPage.class, WicketUtils.newObjectParameter(sr.repository, sr.commitId)));
  183. // show tags
  184. Fragment fragment = new Fragment("tags", "tagsPanel", LuceneSearchPage.this);
  185. List<String> tags = sr.tags;
  186. if (tags == null) {
  187. tags = new ArrayList<String>();
  188. }
  189. ListDataProvider<String> tagsDp = new ListDataProvider<String>(tags);
  190. final DataView<String> tagsView = new DataView<String>("tag", tagsDp) {
  191. private static final long serialVersionUID = 1L;
  192. @Override
  193. public void populateItem(final Item<String> item) {
  194. String tag = item.getModelObject();
  195. Component c = new LinkPanel("tagLink", null, tag, TagPage.class,
  196. WicketUtils.newObjectParameter(sr.repository, Constants.R_TAGS + tag));
  197. WicketUtils.setCssClass(c, "tagRef");
  198. item.add(c);
  199. }
  200. };
  201. fragment.add(tagsView);
  202. item.add(fragment);
  203. break;
  204. }
  205. case blob: {
  206. Label icon = WicketUtils.newIcon("type", "icon-file");
  207. WicketUtils.setHtmlTooltip(icon, "blob");
  208. item.add(icon);
  209. item.add(new LinkPanel("summary", null, sr.path, BlobPage.class, WicketUtils.newPathParameter(sr.repository, sr.branch, sr.path)));
  210. item.add(new Label("tags").setVisible(false));
  211. break;
  212. }
  213. }
  214. item.add(new Label("fragment", sr.fragment).setEscapeModelStrings(false).setVisible(!StringUtils.isEmpty(sr.fragment)));
  215. item.add(new LinkPanel("repository", null, sr.repository, SummaryPage.class, WicketUtils.newRepositoryParameter(sr.repository)));
  216. if (StringUtils.isEmpty(sr.branch)) {
  217. item.add(new Label("branch", "null"));
  218. } else {
  219. item.add(new LinkPanel("branch", "branch", StringUtils.getRelativePath(Constants.R_HEADS, sr.branch), LogPage.class, WicketUtils.newObjectParameter(sr.repository, sr.branch)));
  220. }
  221. item.add(new Label("author", sr.author));
  222. item.add(WicketUtils.createDatestampLabel("date", sr.date, getTimeZone(), getTimeUtils()));
  223. }
  224. };
  225. add(resultsView.setVisible(results.size() > 0));
  226. PageParameters pagerParams = new PageParameters();
  227. pagerParams.put("repositories", StringUtils.flattenStrings(repositoriesModel.getObject()));
  228. pagerParams.put("query", queryModel.getObject());
  229. boolean showPager = false;
  230. int totalPages = 0;
  231. if (results.size() > 0) {
  232. totalPages = (results.get(0).totalHits / pageSize) + (results.get(0).totalHits % pageSize > 0 ? 1 : 0);
  233. showPager = results.get(0).totalHits > pageSize;
  234. }
  235. add(new PagerPanel("topPager", page, totalPages, LuceneSearchPage.class, pagerParams).setVisible(showPager));
  236. add(new PagerPanel("bottomPager", page, totalPages, LuceneSearchPage.class, pagerParams).setVisible(showPager));
  237. }
  238. }