search: allow result sorting for elasticsearch6

This commit is contained in:
Marcin Kuzminski 2019-10-01 15:20:44 +02:00
parent 7cf63ac4ad
commit bf69ffc8f0
6 changed files with 97 additions and 16 deletions

View file

@ -44,6 +44,7 @@ def perform_search(request, tmpl_context, repo_name=None, repo_group_name=None):
search_tags = []
search_params = {}
errors = []
try:
search_params = schema.deserialize(
dict(
@ -61,8 +62,8 @@ def perform_search(request, tmpl_context, repo_name=None, repo_group_name=None):
def url_generator(**kw):
q = urllib.quote(safe_str(search_query))
return update_params(
"?q=%s&type=%s&max_lines=%s" % (
q, safe_str(search_type), search_max_lines), **kw)
"?q=%s&type=%s&max_lines=%s&sort=%s" % (
q, safe_str(search_type), search_max_lines, search_sort), **kw)
c = tmpl_context
search_query = search_params.get('search_query')
@ -99,7 +100,6 @@ def perform_search(request, tmpl_context, repo_name=None, repo_group_name=None):
c.perm_user = c.auth_user
c.repo_name = repo_name
c.repo_group_name = repo_group_name
c.sort = search_sort
c.url_generator = url_generator
c.errors = errors
c.formatted_results = formatted_results
@ -109,6 +109,11 @@ def perform_search(request, tmpl_context, repo_name=None, repo_group_name=None):
c.searcher = searcher
c.search_tags = search_tags
direction, sort_field = searcher.get_sort(search_type, search_sort)
c.sort = '{}:{}'.format(direction, sort_field)
c.sort_tag = sort_field
c.sort_tag_dir = direction
class SearchView(BaseAppView):
def load_default_context(self):

View file

@ -46,6 +46,8 @@ class BaseSearcher(object):
query_lang_doc = ''
es_version = None
name = None
DIRECTION_ASC = 'asc'
DIRECTION_DESC = 'desc'
def __init__(self):
pass
@ -87,6 +89,37 @@ class BaseSearcher(object):
"""
return val
@staticmethod
def get_sort(search_type, search_val):
"""
Method used to parse the GET search sort value to a field and direction.
e.g asc:lines == asc, lines
There's also a legacy support for newfirst/oldfirst which defines commit
sorting only
"""
direction = BaseSearcher.DIRECTION_ASC
sort_field = None
if not search_val:
return direction, sort_field
if search_val.startswith('asc:'):
sort_field = search_val[4:]
direction = BaseSearcher.DIRECTION_ASC
elif search_val.startswith('desc:'):
sort_field = search_val[5:]
direction = BaseSearcher.DIRECTION_DESC
elif search_val == 'newfirst' and search_type == 'commit':
sort_field = 'date'
direction = BaseSearcher.DIRECTION_DESC
elif search_val == 'oldfirst' and search_type == 'commit':
sort_field = 'date'
direction = BaseSearcher.DIRECTION_ASC
return direction, sort_field
def search_config(config, prefix='search.'):
_config = {}

View file

@ -22,6 +22,18 @@
import colander
def sort_validator(node, value):
if value in ['oldfirst', 'newfirst']:
return value
if value.startswith('asc:'):
return value
if value.startswith('desc:'):
return value
msg = u'Invalid search sort, must be `oldfirst`, `newfirst`, or start with asc: or desc:'
raise colander.Invalid(node, msg)
class SearchParamsSchema(colander.MappingSchema):
search_query = colander.SchemaNode(
colander.String(),
@ -33,7 +45,7 @@ class SearchParamsSchema(colander.MappingSchema):
search_sort = colander.SchemaNode(
colander.String(),
missing='newfirst',
validator=colander.OneOf(['oldfirst', 'newfirst']))
validator=sort_validator)
search_max_lines = colander.SchemaNode(
colander.Integer(),
missing=10)

View file

@ -60,6 +60,20 @@
<i class="icon-repo-group"></i>
</%def>
<%def name="field_sort(field_name)">
<%
if c.sort.startswith('asc:'):
return c.url_generator(sort='desc:{}'.format(field_name))
elif c.sort.startswith('desc:'):
return c.url_generator(sort='asc:{}'.format(field_name))
return 'asc:{}'.format(field_name)
%>
</%def>
<%def name="main()">
<div class="box">
%if c.repo_name:
@ -114,6 +128,16 @@
</span>
%endif
% if c.sort_tag:
<span class="tag tag8">
% if c.sort_tag_dir == 'asc':
<i class="icon-angle-down"></i>
% elif c.sort_tag_dir == 'desc':
<i class="icon-angle-up"></i>
% endif
${_('sort')}:${c.sort_tag}
</span>
% endif
% for search_tag in c.search_tags:
<br/><span class="tag disabled" style="margin-top: 3px">${search_tag}</span>
@ -130,7 +154,7 @@
</span>
% endfor
<div class="field">
<p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Query Langague examples')}</p>
<p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Query Language examples')}</p>
<pre id="search-help" style="display: none">\
% if c.searcher.name == 'whoosh':

View file

@ -8,15 +8,15 @@
<th>${_('Repository')}</th>
<th>${_('Commit')}</th>
<th></th>
<th>${_('Commit message')}</th>
<th>
%if c.sort == 'newfirst':
<a href="${c.url_generator(sort='oldfirst')}">${_('Age (new first)')}</a>
%else:
<a href="${c.url_generator(sort='newfirst')}">${_('Age (old first)')}</a>
%endif
<a href="${search.field_sort('message.raw')}">${_('Commit message')}</a>
</th>
<th>
<a href="${search.field_sort('date')}">${_('Age')}</a>
</th>
<th>
<a href="${search.field_sort('author.email.raw')}">${_('Author')}</a>
</th>
<th>${_('Author')}</th>
</tr>
%for entry in c.formatted_results:
## search results are additionally filtered, and this check is just a safe gate

View file

@ -5,9 +5,15 @@
<table class="rctable search-results">
<tr>
<th>${_('Repository')}</th>
<th>${_('File')}</th>
<th>${_('Size')}</th>
<th>${_('Lines')}</th>
<th>
<a href="${search.field_sort('file.raw')}">${_('File')}</a>
</th>
<th>
<a href="${search.field_sort('size')}">${_('Size')}</a>
</th>
<th>
<a href="${search.field_sort('lines')}">${_('Lines')}</a>
</th>
</tr>
%for entry in c.formatted_results:
## search results are additionally filtered, and this check is just a safe gate
@ -19,6 +25,7 @@
${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
</td>
<td class="td-componentname">
<i class="icon-file"></i>
${h.link_to(h.literal(entry['f_path']),
h.route_path('repo_files',repo_name=entry['repository'],commit_id='tip',f_path=entry['f_path']))}
</td>
@ -29,7 +36,7 @@
</td>
<td>
%if entry.get('lines'):
${entry.get('lines', 0.)} ${_ungettext('line', 'lines', entry.get('lines', 0.))}
${entry.get('lines', 0.)}
%endif
</td>
</tr>