##// END OF EJS Templates
#589 search urlgenerator didn't properly escape special chars on url
marcink -
r2913:bfffaa9a beta
parent child Browse files
Show More
@@ -1,144 +1,146
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.search
3 rhodecode.controllers.search
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Search controller for RhodeCode
6 Search controller for RhodeCode
7
7
8 :created_on: Aug 7, 2010
8 :created_on: Aug 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
25 import logging
26 import traceback
26 import traceback
27
27 import urllib
28 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
29 from pylons import request, config, tmpl_context as c
29 from pylons import request, config, tmpl_context as c
30
30
31 from rhodecode.lib.auth import LoginRequired
31 from rhodecode.lib.auth import LoginRequired
32 from rhodecode.lib.base import BaseController, render
32 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
33 from rhodecode.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
34 IDX_NAME, WhooshResultWrapper
34 IDX_NAME, WhooshResultWrapper
35
35
36 from webhelpers.paginate import Page
36 from webhelpers.paginate import Page
37 from webhelpers.util import update_params
37 from webhelpers.util import update_params
38
38
39 from whoosh.index import open_dir, EmptyIndexError
39 from whoosh.index import open_dir, EmptyIndexError
40 from whoosh.qparser import QueryParser, QueryParserError
40 from whoosh.qparser import QueryParser, QueryParserError
41 from whoosh.query import Phrase, Wildcard, Term, Prefix
41 from whoosh.query import Phrase, Wildcard, Term, Prefix
42 from rhodecode.model.repo import RepoModel
42 from rhodecode.model.repo import RepoModel
43 from rhodecode.lib.utils2 import safe_str, safe_int
43 from rhodecode.lib.utils2 import safe_str, safe_int
44
44
45
45 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
46
47
47
48
48 class SearchController(BaseController):
49 class SearchController(BaseController):
49
50
50 @LoginRequired()
51 @LoginRequired()
51 def __before__(self):
52 def __before__(self):
52 super(SearchController, self).__before__()
53 super(SearchController, self).__before__()
53
54
54 def index(self, search_repo=None):
55 def index(self, search_repo=None):
55 c.repo_name = search_repo
56 c.repo_name = search_repo
56 c.formated_results = []
57 c.formated_results = []
57 c.runtime = ''
58 c.runtime = ''
58 c.cur_query = request.GET.get('q', None)
59 c.cur_query = request.GET.get('q', None)
59 c.cur_type = request.GET.get('type', 'content')
60 c.cur_type = request.GET.get('type', 'content')
60 c.cur_search = search_type = {'content': 'content',
61 c.cur_search = search_type = {'content': 'content',
61 'commit': 'message',
62 'commit': 'message',
62 'path': 'path',
63 'path': 'path',
63 'repository': 'repository'
64 'repository': 'repository'
64 }.get(c.cur_type, 'content')
65 }.get(c.cur_type, 'content')
65
66
66 index_name = {
67 index_name = {
67 'content': IDX_NAME,
68 'content': IDX_NAME,
68 'commit': CHGSET_IDX_NAME,
69 'commit': CHGSET_IDX_NAME,
69 'path': IDX_NAME
70 'path': IDX_NAME
70 }.get(c.cur_type, IDX_NAME)
71 }.get(c.cur_type, IDX_NAME)
71
72
72 schema_defn = {
73 schema_defn = {
73 'content': SCHEMA,
74 'content': SCHEMA,
74 'commit': CHGSETS_SCHEMA,
75 'commit': CHGSETS_SCHEMA,
75 'path': SCHEMA
76 'path': SCHEMA
76 }.get(c.cur_type, SCHEMA)
77 }.get(c.cur_type, SCHEMA)
77
78
78 log.debug('IDX: %s' % index_name)
79 log.debug('IDX: %s' % index_name)
79 log.debug('SCHEMA: %s' % schema_defn)
80 log.debug('SCHEMA: %s' % schema_defn)
80
81
81 if c.cur_query:
82 if c.cur_query:
82 cur_query = c.cur_query.lower()
83 cur_query = c.cur_query.lower()
83 log.debug(cur_query)
84 log.debug(cur_query)
84
85
85 if c.cur_query:
86 if c.cur_query:
86 p = safe_int(request.params.get('page', 1), 1)
87 p = safe_int(request.params.get('page', 1), 1)
87 highlight_items = set()
88 highlight_items = set()
88 try:
89 try:
89 idx = open_dir(config['app_conf']['index_dir'],
90 idx = open_dir(config['app_conf']['index_dir'],
90 indexname=index_name)
91 indexname=index_name)
91 searcher = idx.searcher()
92 searcher = idx.searcher()
92
93
93 qp = QueryParser(search_type, schema=schema_defn)
94 qp = QueryParser(search_type, schema=schema_defn)
94 if c.repo_name:
95 if c.repo_name:
95 cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
96 cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
96 try:
97 try:
97 query = qp.parse(unicode(cur_query))
98 query = qp.parse(unicode(cur_query))
98 # extract words for highlight
99 # extract words for highlight
99 if isinstance(query, Phrase):
100 if isinstance(query, Phrase):
100 highlight_items.update(query.words)
101 highlight_items.update(query.words)
101 elif isinstance(query, Prefix):
102 elif isinstance(query, Prefix):
102 highlight_items.add(query.text)
103 highlight_items.add(query.text)
103 else:
104 else:
104 for i in query.all_terms():
105 for i in query.all_terms():
105 if i[0] in ['content', 'message']:
106 if i[0] in ['content', 'message']:
106 highlight_items.add(i[1])
107 highlight_items.add(i[1])
107
108
108 matcher = query.matcher(searcher)
109 matcher = query.matcher(searcher)
109
110
110 log.debug('query: %s' % query)
111 log.debug('query: %s' % query)
111 log.debug('hl terms: %s' % highlight_items)
112 log.debug('hl terms: %s' % highlight_items)
112 results = searcher.search(query)
113 results = searcher.search(query)
113 res_ln = len(results)
114 res_ln = len(results)
114 c.runtime = '%s results (%.3f seconds)' % (
115 c.runtime = '%s results (%.3f seconds)' % (
115 res_ln, results.runtime
116 res_ln, results.runtime
116 )
117 )
117
118
118 def url_generator(**kw):
119 def url_generator(**kw):
120 q = urllib.quote(safe_str(c.cur_query))
119 return update_params("?q=%s&type=%s" \
121 return update_params("?q=%s&type=%s" \
120 % (safe_str(c.cur_query), safe_str(c.cur_type)), **kw)
122 % (q, safe_str(c.cur_type)), **kw)
121 repo_location = RepoModel().repos_path
123 repo_location = RepoModel().repos_path
122 c.formated_results = Page(
124 c.formated_results = Page(
123 WhooshResultWrapper(search_type, searcher, matcher,
125 WhooshResultWrapper(search_type, searcher, matcher,
124 highlight_items, repo_location),
126 highlight_items, repo_location),
125 page=p,
127 page=p,
126 item_count=res_ln,
128 item_count=res_ln,
127 items_per_page=10,
129 items_per_page=10,
128 url=url_generator
130 url=url_generator
129 )
131 )
130
132
131 except QueryParserError:
133 except QueryParserError:
132 c.runtime = _('Invalid search query. Try quoting it.')
134 c.runtime = _('Invalid search query. Try quoting it.')
133 searcher.close()
135 searcher.close()
134 except (EmptyIndexError, IOError):
136 except (EmptyIndexError, IOError):
135 log.error(traceback.format_exc())
137 log.error(traceback.format_exc())
136 log.error('Empty Index data')
138 log.error('Empty Index data')
137 c.runtime = _('There is no index to search in. '
139 c.runtime = _('There is no index to search in. '
138 'Please run whoosh indexer')
140 'Please run whoosh indexer')
139 except (Exception):
141 except (Exception):
140 log.error(traceback.format_exc())
142 log.error(traceback.format_exc())
141 c.runtime = _('An error occurred during this search operation')
143 c.runtime = _('An error occurred during this search operation')
142
144
143 # Return a rendered template
145 # Return a rendered template
144 return render('/search/search.html')
146 return render('/search/search.html')
General Comments 0
You need to be logged in to leave comments. Login now