| Index: appengine/monorail/tracker/issueadvsearch.py
|
| diff --git a/appengine/monorail/tracker/issueadvsearch.py b/appengine/monorail/tracker/issueadvsearch.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c4880bba1db6e9195f17bdb48fe343cd101c93c5
|
| --- /dev/null
|
| +++ b/appengine/monorail/tracker/issueadvsearch.py
|
| @@ -0,0 +1,99 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is govered by a BSD-style
|
| +# license that can be found in the LICENSE file or at
|
| +# https://developers.google.com/open-source/licenses/bsd
|
| +
|
| +"""Classes that implement the advanced search feature page.
|
| +
|
| +The advanced search page simply displays an HTML page with a form.
|
| +The form handler converts the widget-based query into a googley query
|
| +string and redirects the user to the issue list servlet.
|
| +"""
|
| +
|
| +import logging
|
| +import re
|
| +
|
| +from framework import framework_helpers
|
| +from framework import permissions
|
| +from framework import servlet
|
| +from framework import urls
|
| +
|
| +# Patterns for search values that can be words, labels,
|
| +# component paths, or email addresses.
|
| +VALUE_RE = re.compile(r'[-a-zA-Z0-9._>@]+')
|
| +
|
| +
|
| +class IssueAdvancedSearch(servlet.Servlet):
|
| + """IssueAdvancedSearch shows a form to enter an advanced search."""
|
| +
|
| + _PAGE_TEMPLATE = 'tracker/issue-advsearch-page.ezt'
|
| + _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_ISSUES
|
| +
|
| + # This form *only* redirects to a GET request, and permissions are checked
|
| + # in that handler.
|
| + CHECK_SECURITY_TOKEN = False
|
| +
|
| + def GatherPageData(self, mr):
|
| + """Build up a dictionary of data values to use when rendering the page.
|
| +
|
| + Args:
|
| + mr: commonly used info parsed from the request.
|
| +
|
| + Returns:
|
| + Dict of values used by EZT for rendering the page.
|
| + """
|
| +
|
| + # TODO(jrobbins): Allow deep-linking into this page.
|
| +
|
| + return {
|
| + 'issue_tab_mode': 'issueAdvSearch',
|
| + 'page_perms': self.MakePagePerms(mr, None, permissions.CREATE_ISSUE),
|
| + }
|
| +
|
| + def ProcessFormData(self, mr, post_data):
|
| + """Process a posted advanced query form.
|
| +
|
| + Args:
|
| + mr: commonly used info parsed from the request.
|
| + post_data: HTML form data from the request.
|
| +
|
| + Returns:
|
| + String URL to redirect the user to after processing.
|
| + """
|
| + # Default to searching open issues in this project.
|
| + can = post_data.get('can', 2)
|
| +
|
| + terms = []
|
| + self._AccumulateANDTerm('', 'words', post_data, terms)
|
| + self._AccumulateANDTerm('-', 'without', post_data, terms)
|
| + self._AccumulateANDTerm('label:', 'labels', post_data, terms)
|
| + self._AccumulateORTerm('component:', 'components', post_data, terms)
|
| + self._AccumulateORTerm('status:', 'statuses', post_data, terms)
|
| + self._AccumulateORTerm('reporter:', 'reporters', post_data, terms)
|
| + self._AccumulateORTerm('owner:', 'owners', post_data, terms)
|
| + self._AccumulateORTerm('cc:', 'cc', post_data, terms)
|
| + self._AccumulateORTerm('commentby:', 'commentby', post_data, terms)
|
| +
|
| + if 'starcount' in post_data:
|
| + starcount = int(post_data['starcount'])
|
| + if starcount >= 0:
|
| + terms.append('starcount:%s' % starcount)
|
| +
|
| + return framework_helpers.FormatAbsoluteURL(
|
| + mr, urls.ISSUE_LIST, q=' '.join(terms), can=can)
|
| +
|
| + def _AccumulateANDTerm(self, operator, form_field, post_data, search_query):
|
| + """Build a query that matches issues with ALL of the given field values."""
|
| + user_input = post_data.get(form_field)
|
| + if user_input:
|
| + values = VALUE_RE.findall(user_input)
|
| + search_terms = ['%s%s' % (operator, v) for v in values]
|
| + search_query.extend(search_terms)
|
| +
|
| + def _AccumulateORTerm(self, operator, form_field, post_data, search_query):
|
| + """Build a query that matches issues with ANY of the given field values."""
|
| + user_input = post_data.get(form_field)
|
| + if user_input:
|
| + values = VALUE_RE.findall(user_input)
|
| + search_term = '%s%s' % (operator, ','.join(values))
|
| + search_query.append(search_term)
|
|
|