You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by an...@apache.org on 2013/02/10 18:56:36 UTC
svn commit: r1444577 - in
/incubator/bloodhound/trunk/bloodhound_search/bhsearch: ./
search_resources/ tests/ tests/search_resources/
Author: andrej
Date: Sun Feb 10 17:56:35 2013
New Revision: 1444577
URL: http://svn.apache.org/r1444577
Log:
#260 Bloodhound Search, make code refactoring, improve pylint results
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/__init__.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/base.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/wiki_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/__init__.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/__init__.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/__init__.py Sun Feb 10 17:56:35 2013
@@ -29,6 +29,7 @@ from trac.core import TracError
TracError.__str__ = lambda self: unicode(self).encode('ascii', 'ignore')
try:
+ # pylint: disable=wildcard-import
from bhsearch import *
msg = 'Ok'
except Exception, exc:
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py Sun Feb 10 17:56:35 2013
@@ -124,10 +124,13 @@ class ISearchParticipant(Interface):
def format_search_results(contents):
"""Called to see if the module wants to format the search results."""
- def get_search_filters(req):
+ def is_allowed(req):
"""Called when we want to build the list of components with search.
Passes the request object to do permission checking."""
+ def get_type():
+ """Return type of search participant"""
+
def get_title():
"""Return resource title."""
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/base.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/base.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/base.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/base.py Sun Feb 10 17:56:35 2013
@@ -34,6 +34,8 @@ class BaseSearchParticipant(Component):
default_view = None
default_grid_fields = None
default_facets = None
+ participant_type = None
+ required_permission = None
def get_default_facets(self):
return self.default_facets
@@ -45,3 +47,9 @@ class BaseSearchParticipant(Component):
if view == "grid":
return self.default_grid_fields
return None
+
+ def is_allowed(self, req=None):
+ return (not req or self.required_permission in req.perm)
+
+ def get_participant_type(self):
+ return self.participant_type
\ No newline at end of file
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py Sun Feb 10 17:56:35 2013
@@ -117,6 +117,9 @@ class MilestoneIndexer(BaseIndexer):
class MilestoneSearchParticipant(BaseSearchParticipant):
implements(ISearchParticipant)
+ participant_type = MILESTONE_TYPE
+ required_permission = 'MILESTONE_VIEW'
+
default_facets = []
default_grid_fields = [
MilestoneFields.ID, MilestoneFields.DUE, MilestoneFields.COMPLETED]
@@ -141,10 +144,6 @@ class MilestoneSearchParticipant(BaseSea
doc="""Default fields for grid view for specific resource""")
#ISearchParticipant members
- def get_search_filters(self, req=None):
- if not req or 'MILESTONE_VIEW' in req.perm:
- return MILESTONE_TYPE
-
def get_title(self):
return "Milestone"
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py Sun Feb 10 17:56:35 2013
@@ -62,6 +62,7 @@ class TicketIndexer(BaseIndexer):
def ticket_changed(self, ticket, comment, author, old_values):
"""Reindex a recently modified ticket."""
+ # pylint: disable=unused-argument
self._index_ticket(ticket)
def ticket_deleted(self, ticket):
@@ -123,6 +124,9 @@ class TicketIndexer(BaseIndexer):
class TicketSearchParticipant(BaseSearchParticipant):
implements(ISearchParticipant)
+ participant_type = TICKET_TYPE
+ required_permission = 'TICKET_VIEW'
+
default_facets = [
TicketFields.STATUS,
TicketFields.MILESTONE,
@@ -156,10 +160,6 @@ class TicketSearchParticipant(BaseSearch
doc="""Default fields for grid view for specific resource""")
#ISearchParticipant members
- def get_search_filters(self, req=None):
- if not req or 'TICKET_VIEW' in req.perm:
- return TICKET_TYPE
-
def get_title(self):
return "Ticket"
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py Sun Feb 10 17:56:35 2013
@@ -37,8 +37,10 @@ class WikiIndexer(BaseIndexer):
"""Index a recently created ticket."""
self._index_wiki(page)
+
def wiki_page_changed(self, page, version, t, comment, author, ipnr):
"""Reindex a recently modified ticket."""
+ # pylint: disable=too-many-arguments, unused-argument
self._index_wiki(page)
def wiki_page_deleted(self, page):
@@ -110,6 +112,9 @@ class WikiIndexer(BaseIndexer):
class WikiSearchParticipant(BaseSearchParticipant):
implements(ISearchParticipant)
+ participant_type = WIKI_TYPE
+ required_permission = 'WIKI_VIEW'
+
default_facets = []
default_grid_fields = [
IndexFields.ID,
@@ -138,10 +143,6 @@ class WikiSearchParticipant(BaseSearchPa
doc="""Default fields for grid view for specific resource""")
#ISearchParticipant members
- def get_search_filters(self, req=None):
- if not req or 'WIKI_VIEW' in req.perm:
- return WIKI_TYPE
-
def get_title(self):
return "Wiki"
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py Sun Feb 10 17:56:35 2013
@@ -24,15 +24,15 @@ from bhsearch.tests.search_resources imp
milestone_search)
def suite():
- suite = unittest.TestSuite()
- suite.addTest(index_with_whoosh.suite())
- suite.addTest(whoosh_backend.suite())
- suite.addTest(web_ui.suite())
- suite.addTest(api.suite())
- suite.addTest(ticket_search.suite())
- suite.addTest(wiki_search.suite())
- suite.addTest(milestone_search.suite())
- return suite
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(index_with_whoosh.suite())
+ test_suite.addTest(whoosh_backend.suite())
+ test_suite.addTest(web_ui.suite())
+ test_suite.addTest(api.suite())
+ test_suite.addTest(ticket_search.suite())
+ test_suite.addTest(wiki_search.suite())
+ test_suite.addTest(milestone_search.suite())
+ return test_suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')
\ No newline at end of file
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py Sun Feb 10 17:56:35 2013
@@ -101,8 +101,9 @@ class BaseBloodhoundSearchTest(unittest.
return milestone
def process_request(self):
- response = BloodhoundSearchModule(self.env).process_request(self.req)
- url, data, x = response
+ # pylint: disable=unused-variable
+ url, data, x = BloodhoundSearchModule(self.env).process_request(
+ self.req)
print "Received url: %s data:" % url
pprint(data)
if data.has_key("results"):
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py Sun Feb 10 17:56:35 2013
@@ -143,11 +143,12 @@ class MilestoneSearchParticipantTestCase
self.assertIsNotNone(default_grid_fields)
def suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(MilestoneIndexerEventsTestCase, 'test'))
- suite.addTest(
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(
+ unittest.makeSuite(MilestoneIndexerEventsTestCase, 'test'))
+ test_suite.addTest(
unittest.makeSuite(MilestoneSearchParticipantTestCase, 'test'))
- return suite
+ return test_suite
if __name__ == '__main__':
unittest.main()
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/wiki_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/wiki_search.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/wiki_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/wiki_search.py Sun Feb 10 17:56:35 2013
@@ -129,11 +129,11 @@ class WikiIndexerEventsTestCase(BaseBloo
self.assertEqual("version1", results.docs[0]["content"])
def suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(unittest.makeSuite(
WikiIndexerSilenceOnExceptionTestCase, 'test'))
- suite.addTest(unittest.makeSuite(WikiIndexerEventsTestCase, 'test'))
- return suite
+ test_suite.addTest(unittest.makeSuite(WikiIndexerEventsTestCase, 'test'))
+ return test_suite
if __name__ == '__main__':
unittest.main()
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py Sun Feb 10 17:56:35 2013
@@ -530,6 +530,16 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
self.assertEqual(["T2", "T1", "T3"], ids)
+ def test_that_title_is_set_for_free_text_view(self):
+ #arrange
+ self.insert_ticket("T1", component="c1", status="new", milestone="A")
+ #act
+ self.req.args[RequestParameters.QUERY] = "*"
+ data = self.process_request()
+ #assert
+ self.assertIn("title", data["results"].items[0])
+
+
def _count_parameter_in_url(self, url, parameter_name, value):
parameter_to_find = (parameter_name, value)
parsed_parameters = parse_arg_list(url)
@@ -597,10 +607,10 @@ class RequestParametersTest(unittest.Tes
def suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(WebUiTestCaseWithWhoosh, 'test'))
- suite.addTest(unittest.makeSuite(RequestParametersTest, 'test'))
- return suite
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(unittest.makeSuite(WebUiTestCaseWithWhoosh, 'test'))
+ test_suite.addTest(unittest.makeSuite(RequestParametersTest, 'test'))
+ return test_suite
if __name__ == '__main__':
unittest.main()
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py Sun Feb 10 17:56:35 2013
@@ -495,12 +495,12 @@ class WhooshEmptyFacetErrorWorkaroundTes
self.assertEquals('(type:ticket AND milestone:aaa)', str(result_filter))
def suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(WhooshBackendTestCase, 'test'))
- suite.addTest(unittest.makeSuite(WhooshFunctionalityTestCase, 'test'))
- suite.addTest(unittest.makeSuite(WhooshEmptyFacetErrorWorkaroundTestCase,
- 'test'))
- return suite
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(unittest.makeSuite(WhooshBackendTestCase, 'test'))
+ test_suite.addTest(unittest.makeSuite(WhooshFunctionalityTestCase, 'test'))
+ test_suite.addTest(
+ unittest.makeSuite(WhooshEmptyFacetErrorWorkaroundTestCase, 'test'))
+ return test_suite
if __name__ == '__main__':
unittest.main()
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py?rev=1444577&r1=1444576&r2=1444577&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Sun Feb 10 17:56:35 2013
@@ -187,26 +187,8 @@ class RequestParameters(object):
if name in params:
del params[name]
- def is_show_all_mode(self):
- return self.type is None
-
-
class BloodhoundSearchModule(Component):
"""Main search page"""
- DATA_HEADERS = "headers"
- DATA_ALL_VIEWS = "all_views"
- DATA_ACTIVE_VIEW = "active_view"
- DATA_VIEW = "view"
- DATA_VIEW_GRID = "grid"
- #bhsearch may support more pluggable views later
- VIEWS_SUPPORTED = {
- None: "Free text",
- DATA_VIEW_GRID: "Grid"
- }
- VIEWS_WITH_KNOWN_FIELDS = [DATA_VIEW_GRID]
- OBLIGATORY_FIELDS_TO_SELECT = [IndexFields.ID, IndexFields.TYPE]
- DEFAULT_SORT = [(SCORE, ASC), ("time", DESC)]
-
implements(INavigationContributor, IPermissionRequestor, IRequestHandler,
ITemplateProvider,
# IWikiSyntaxProvider #todo: implement later
@@ -231,6 +213,7 @@ class BloodhoundSearchModule(Component):
default_facets = ListOption(
BHSEARCH_CONFIG_SECTION,
prefix + '_default_facets',
+ default=",".join([IndexFields.TYPE]),
doc="""Default facets applied to search view of all resources""")
default_view = Option(
@@ -239,7 +222,7 @@ class BloodhoundSearchModule(Component):
doc="""If true, show grid as default view for specific resource in
Bloodhound Search results""")
- default_grid_fields = ListOption(
+ all_grid_fields = ListOption(
BHSEARCH_CONFIG_SECTION,
prefix + '_default_grid_fields',
default=",".join(default_grid_fields),
@@ -248,6 +231,7 @@ class BloodhoundSearchModule(Component):
# INavigationContributor methods
def get_active_navigation_item(self, req):
+ # pylint: disable=unused-argument
return 'bhsearch'
def get_navigation_items(self, req):
@@ -266,178 +250,181 @@ class BloodhoundSearchModule(Component):
def process_request(self, req):
req.perm.assert_permission(SEARCH_PERMISSION)
- parameters = RequestParameters(req)
- allowed_participants = self._get_allowed_participants(req)
- data = {
- 'query': parameters.query,
- }
- self._prepare_allowed_types(allowed_participants, parameters, data)
- self._prepare_active_filter_queries(
- parameters,
- data,
+ request_context = RequestContext(
+ self.env,
+ req,
+ self.search_participants,
+ self.default_view,
+ self.all_grid_fields,
+ self.default_facets
)
- #TBD: should search return results on empty query?
- # if not any((
- # query,
- # parameters.type,
- # parameters.filter_queries,
- # )):
- # return self._return_data(req, data)
-
- self._prepare_quick_jump(
- parameters,
- data)
- fields = self._prepare_fields_and_view(
- allowed_participants, parameters, data)
-
- query_filter = self._prepare_query_filter(
- parameters, allowed_participants)
-
- facets = self._prepare_facets(parameters, allowed_participants)
-
- sort = parameters.sort if parameters.sort else self.DEFAULT_SORT
-
- query_system = BloodhoundSearchApi(self.env)
- query_result = query_system.query(
- parameters.query,
- pagenum=parameters.page,
- pagelen=parameters.pagelen,
- sort=sort,
- fields=fields,
- facets=facets,
- filter=query_filter,
+ query_result = BloodhoundSearchApi(self.env).query(
+ request_context.parameters.query,
+ pagenum=request_context.page,
+ pagelen=request_context.pagelen,
+ sort=request_context.sort,
+ fields=request_context.fields,
+ facets=request_context.facets,
+ filter=request_context.query_filter,
)
- is_free_text_view = (self.DATA_VIEW not in data)
- ui_docs = [self._process_doc(
- doc, req, allowed_participants, is_free_text_view)
- for doc in query_result.docs]
+ request_context.process_results(query_result)
+ return self._return_data(req, request_context.data)
- results = Paginator(
- ui_docs,
- parameters.page - 1,
- parameters.pagelen,
- query_result.hits)
-
- results.shown_pages = self._prepare_shown_pages(
- parameters,
- shown_pages=results.get_shown_pages(parameters.pagelen))
+ def _return_data(self, req, data):
+ add_stylesheet(req, 'common/css/search.css')
+ return 'bhsearch.html', data, None
- results.current_page = {'href': None,
- 'class': 'current',
- 'string': str(results.page + 1),
- 'title': None}
+ # ITemplateProvider methods
+ def get_htdocs_dirs(self):
+ # return [('bhsearch',
+ # pkg_resources.resource_filename(__name__, 'htdocs'))]
+ return []
- if results.has_next_page:
- next_href = parameters.create_href(page=parameters.page + 1)
- add_link(req, 'next', next_href, _('Next Page'))
+ def get_templates_dirs(self):
+ return [pkg_resources.resource_filename(__name__, 'templates')]
- if results.has_previous_page:
- prev_href = parameters.create_href(page=parameters.page - 1)
- add_link(req, 'prev', prev_href, _('Previous Page'))
+class RequestContext(object):
+ DATA_ACTIVE_FILTER_QUERIES = 'active_filter_queries'
+ DATA_ACTIVE_TYPE = "active_type"
+ DATA_TYPES = "types"
+ DATA_HEADERS = "headers"
+ DATA_ALL_VIEWS = "all_views"
+ DATA_ACTIVE_VIEW = "active_view"
+ DATA_VIEW = "view"
+ DATA_VIEW_GRID = "grid"
+ DATA_FACET_COUNTS = 'facet_counts'
+ DATA_DEBUG = 'debug'
+ DATA_PAGE_HREF = 'page_href'
+ DATA_RESULTS = 'results'
+ DATA_QUICK_JUMP = "quickjump"
- data['results'] = results
- data['debug'] = query_result.debug
- self._prepare_result_facet_counts(
- parameters,
- query_result,
- data,
- )
+ #bhsearch may support more pluggable views later
+ VIEWS_SUPPORTED = {
+ None: "Free text",
+ DATA_VIEW_GRID: "Grid"
+ }
- data['page_href'] = parameters.create_href()
- return self._return_data(req, data)
+ VIEWS_WITH_KNOWN_FIELDS = [DATA_VIEW_GRID]
+ OBLIGATORY_FIELDS_TO_SELECT = [IndexFields.ID, IndexFields.TYPE]
+ DEFAULT_SORT = [(SCORE, ASC), ("time", DESC)]
+ def __init__(
+ self,
+ env,
+ req,
+ search_participants,
+ default_view,
+ all_grid_fields,
+ default_facets,
+ ):
+ self.env = env
+ self.req = req
+ self.parameters = RequestParameters(req)
+ self.search_participants = search_participants
+ self.default_view = default_view
+ self.all_grid_fields = all_grid_fields
+ self.default_facets = default_facets
+ self.view = None
+ self.page = self.parameters.page
+ self.pagelen = self.parameters.pagelen
+ self.allowed_participants, self.sorted_participants = \
+ self._get_allowed_participants(req)
+
+ if self.parameters.type in self.allowed_participants:
+ self.active_type = self.parameters.type
+ self.active_participant = self.allowed_participants[
+ self.active_type]
+ else:
+ self.active_type = None
+ self.active_participant = None
- def _prepare_fields_and_view(self, allowed_participants, parameters, data):
- self._add_views_selector(parameters, data)
- active_participant = self._get_active_participant(
- parameters, allowed_participants)
- view = self._get_view(parameters, active_participant)
- if view:
- data[self.DATA_VIEW] = view
- fields_to_select = None
- if view in self.VIEWS_WITH_KNOWN_FIELDS:
- if active_participant:
- fields_in_view = active_participant.get_default_view_fields(
- view)
- elif view == self.DATA_VIEW_GRID:
- fields_in_view = self.default_grid_fields
- else:
- raise TracError("Unsupported view: %s" % view)
- data[self.DATA_HEADERS] = [self._create_headers_item(field)
- for field in fields_in_view]
- fields_to_select = self._optionally_add_obligatory_fields(
- fields_in_view)
- return fields_to_select
+ self.data = {'query': self.parameters.query}
+ self._prepare_allowed_types()
+ self._prepare_active_filter_queries()
+ self._prepare_quick_jump()
+ self.fields = self._prepare_fields_and_view()
+ self.query_filter = self._prepare_query_filter()
+ self.facets = self._prepare_facets()
- def _add_views_selector(self, parameters, data):
- active_view = parameters.view
- all_views = []
- for view, label in self.VIEWS_SUPPORTED.iteritems():
- all_views.append(dict(
- label=_(label),
- href=parameters.create_href(
- view=view, skip_view=(view is None)),
- is_active = (view == active_view)
- ))
- data[self.DATA_ALL_VIEWS] = all_views
- if parameters.view:
- data[self.DATA_ACTIVE_VIEW] = parameters.view
+ self.sort = self.parameters.sort if self.parameters.sort \
+ else self.DEFAULT_SORT
- def _optionally_add_obligatory_fields(self, fields_in_view):
- fields_to_select = list(fields_in_view)
- for obligatory_field in self.OBLIGATORY_FIELDS_TO_SELECT:
- if obligatory_field is not fields_to_select:
- fields_to_select.append(obligatory_field)
- return fields_to_select
- def _create_headers_item(self, field):
- return dict(
- name=field,
- href="",
- #TODO:add translated column label. Now it is really temporary
- #workaround
- label=field,
- sort=None,
- )
- def _get_view(self, parameters, active_participant):
- view = parameters.view
- if view is None:
- if active_participant is not None:
- view = active_participant.get_default_view()
- else:
- view = self.default_view
- if view is not None:
- view = view.strip().lower()
- return view
+ def _get_allowed_participants(self, req):
+ allowed_participants = {}
+ ordered_participants = []
+ for participant in self.search_participants:
+ if participant.is_allowed(req):
+ allowed_participants[
+ participant.get_participant_type()] = participant
+ ordered_participants.append(participant)
+ return allowed_participants, ordered_participants
- def _get_active_participant(self, parameters, allowed_participants):
- active_type = parameters.type
- if active_type is not None and \
- active_type in allowed_participants:
- return allowed_participants[active_type]
- else:
- return None
+ def _prepare_allowed_types(self):
+ active_type = self.parameters.type
+ if active_type and active_type not in self.allowed_participants:
+ raise TracError(_("Unsupported resource type: '%(name)s'",
+ name=active_type))
+ allowed_types = [
+ dict(
+ label=_("All"),
+ active=(active_type is None),
+ href=self.parameters.create_href(
+ skip_type=True,
+ skip_page=True,
+ force_filters=[],
+ ),
+ )
+ ]
+ #we want obtain the same order as in search participants options
+ for participant in self.sorted_participants:
+ allowed_types.append(dict(
+ label=_(participant.get_title()),
+ active=(participant.get_participant_type() == active_type),
+ href=self.parameters.create_href(
+ type=participant.get_participant_type(),
+ skip_page=True,
+ force_filters=[],
+ ),
+ ))
+ self.data[self.DATA_TYPES] = allowed_types
+ self.data[self.DATA_ACTIVE_TYPE] = active_type
+
+ def _prepare_active_filter_queries(self):
+ current_filters = self.parameters.filter_queries
+ def remove_filters_from_list(filer_to_cut_from):
+ return current_filters[:current_filters.index(filer_to_cut_from)]
- def _prepare_quick_jump(self,
- parameters,
- data):
- if not parameters.query:
+ active_filter_queries = [
+ dict(
+ href=self.parameters.create_href(
+ force_filters=remove_filters_from_list(filter_query)
+ ),
+ label=filter_query,
+ query=filter_query,
+ ) for filter_query in self.parameters.filter_queries
+ ]
+ self.data[self.DATA_ACTIVE_FILTER_QUERIES] = active_filter_queries
+
+ def _prepare_quick_jump(self):
+ if not self.parameters.query:
return
check_result = self._check_quickjump(
- parameters.req,
- parameters.query)
+ self.req,
+ self.parameters.query)
if check_result:
- data["quickjump"] = check_result
+ self.data[self.DATA_QUICK_JUMP] = check_result
#the method below is "copy/paste" from trac search/web_ui.py
def _check_quickjump(self, req, kwd):
"""Look for search shortcuts"""
+ # pylint: disable=maybe-no-member
noquickjump = int(req.args.get('noquickjump', '0'))
# Source quickjump FIXME: delegate to ISearchSource.search_quickjump
quickjump_href = None
@@ -463,65 +450,155 @@ class BloodhoundSearchModule(Component):
req.redirect(quickjump_href)
- def _prepare_allowed_types(self, allowed_participants, parameters, data):
- active_type = parameters.type
- if active_type and active_type not in allowed_participants:
- raise TracError(_("Unsupported resource type: '%(name)s'",
- name=active_type))
- allowed_types = [
- dict(
- label=_("All"),
- active=(active_type is None),
- href=parameters.create_href(
- skip_type=True,
- skip_page=True,
- force_filters=[],
- ),
- )
- ]
-
- #we want obtain the same order as in search participants options
- participant_with_type = dict((participant, type)
- for type, participant in allowed_participants.iteritems())
- for participant in self.search_participants:
- if participant in participant_with_type:
- type = participant_with_type[participant]
- allowed_types.append(dict(
- label=_(participant.get_title()),
- active=(type == active_type),
- href=parameters.create_href(
- type=type,
- skip_page=True,
- force_filters=[],
- ),
- ))
- data["types"] = allowed_types
- data["active_type"] = active_type
+ def _prepare_fields_and_view(self):
+ self._add_views_selector()
+ self.view = self._get_view()
+ if self.view:
+ self.data[self.DATA_VIEW] = self.view
+ fields_to_select = None
+ if self.view in self.VIEWS_WITH_KNOWN_FIELDS:
+ if self.active_participant:
+ fields_in_view = self.active_participant.\
+ get_default_view_fields(self.view)
+ elif self.view == self.DATA_VIEW_GRID:
+ fields_in_view = self.all_grid_fields
+ else:
+ raise TracError("Unsupported view: %s" % self.view)
+ self.data[self.DATA_HEADERS] = [self._create_headers_item(field)
+ for field in fields_in_view]
+ fields_to_select = self._add_obligatory_fields(
+ fields_in_view)
+ return fields_to_select
+ def _add_views_selector(self):
+ active_view = self.parameters.view
+ if active_view:
+ self.data[self.DATA_ACTIVE_VIEW] = active_view
- def _prepare_active_filter_queries(
- self,
- parameters,
- data):
- active_filter_queries = []
- for filter_query in parameters.filter_queries:
- active_filter_queries.append(dict(
- href=parameters.create_href(
- force_filters=self._cut_filters(
- parameters.filter_queries,
- filter_query)),
- label=filter_query,
- query=filter_query,
+ all_views = []
+ for view, label in self.VIEWS_SUPPORTED.iteritems():
+ all_views.append(dict(
+ label=_(label),
+ href=self.parameters.create_href(
+ view=view, skip_view=(view is None)),
+ is_active = (view == active_view)
))
- data['active_filter_queries'] = active_filter_queries
+ self.data[self.DATA_ALL_VIEWS] = all_views
- def _cut_filters(self, filter_queries, filer_to_cut_from):
- return filter_queries[:filter_queries.index(filer_to_cut_from)]
+ def _get_view(self):
+ view = self.parameters.view
+ if view is None:
+ if self.active_participant:
+ view = self.active_participant.get_default_view()
+ else:
+ view = self.default_view
+ if view is not None:
+ view = view.strip().lower()
+ if view == "":
+ view = None
+ return view
+ def _add_obligatory_fields(self, fields_in_view):
+ fields_to_select = list(fields_in_view)
+ for obligatory_field in self.OBLIGATORY_FIELDS_TO_SELECT:
+ if obligatory_field is not fields_to_select:
+ fields_to_select.append(obligatory_field)
+ return fields_to_select
- def _prepare_result_facet_counts(self, parameters, query_result, data):
- """
+ def _create_headers_item(self, field):
+ return dict(
+ name=field,
+ href="",
+ #TODO:add translated column label. Now it is really temporary
+ #workaround
+ label=field,
+ sort=None,
+ )
+
+ def _prepare_query_filter(self):
+ query_filters = list(self.parameters.filter_queries)
+ if self.active_type:
+ query_filters.append(
+ self._create_term_expression(
+ IndexFields.TYPE, self.active_type))
+ return query_filters
+
+ def _create_term_expression(self, field, field_value):
+ if field_value is None:
+ query = "NOT (%s:*)" % field
+ elif isinstance(field_value, basestring):
+ query = '%s:"%s"' % (field, field_value)
+ else:
+ query = '%s:%s' % (field, field_value)
+ return query
+
+ def _prepare_facets(self):
+ #TODO: add possibility of specifying facets in query parameters
+ if self.active_participant:
+ facets = self.active_participant.get_default_facets()
+ else:
+ facets = self.default_facets
+ return facets
+
+ def _process_doc(self, doc):
+ ui_doc = dict(doc)
+ ui_doc["href"] = self.req.href(doc['type'], doc['id'])
+ #todo: perform content adaptation here
+ if doc.has_key('content'):
+ ui_doc['content'] = shorten_result(doc['content'])
+ if doc.has_key('time'):
+ ui_doc['date'] = user_time(self.req, format_datetime, doc['time'])
+
+ is_free_text_view = self.view is None
+ if is_free_text_view:
+ ui_doc['title'] = self.allowed_participants[
+ doc['type']].format_search_results(doc)
+ return ui_doc
+
+ def _prepare_results(self, result_docs, hits):
+ ui_docs = [self._process_doc(doc) for doc in result_docs]
+
+ results = Paginator(
+ ui_docs,
+ self.page - 1,
+ self.pagelen,
+ hits)
+
+ self._prepare_shown_pages(results)
+ results.current_page = {'href': None,
+ 'class': 'current',
+ 'string': str(results.page + 1),
+ 'title': None}
+
+ parameters = self.parameters
+ if results.has_next_page:
+ next_href = parameters.create_href(page=parameters.page + 1)
+ add_link(self.req, 'next', next_href, _('Next Page'))
+
+ if results.has_previous_page:
+ prev_href = parameters.create_href(page=parameters.page - 1)
+ add_link(self.req, 'prev', prev_href, _('Previous Page'))
+ self.data[self.DATA_RESULTS] = results
+
+ def _prepare_shown_pages(self, results):
+ shown_pages = results.get_shown_pages(self.pagelen)
+ page_data = []
+ for shown_page in shown_pages:
+ page_href = self.parameters.create_href(page=shown_page)
+ page_data.append([page_href, None, str(shown_page),
+ 'page ' + str(shown_page)])
+ fields = ['href', 'class', 'string', 'title']
+ results.shown_pages = [dict(zip(fields, p)) for p in page_data]
+
+ def process_results(self, query_result):
+ self._prepare_results(query_result.docs, query_result.hits)
+ self._prepare_result_facet_counts(query_result.facets)
+ self.data[self.DATA_DEBUG] = query_result.debug
+ self.data[self.DATA_PAGE_HREF] = self.parameters.create_href()
+
+ def _prepare_result_facet_counts(self, result_facets):
+ """
Sample query_result.facets content returned by query
{
'component': {None:2},
@@ -538,19 +615,18 @@ class BloodhoundSearchModule(Component):
}
"""
- result_facets = query_result.facets
facet_counts = dict()
if result_facets:
for field, facets_dict in result_facets.iteritems():
per_field_dict = dict()
for field_value, count in facets_dict.iteritems():
if field == IndexFields.TYPE:
- href = parameters.create_href(
+ href = self.parameters.create_href(
skip_page=True,
force_filters=[],
type=field_value)
else:
- href = parameters.create_href(
+ href = self.parameters.create_href(
skip_page=True,
additional_filter=self._create_term_expression(
field,
@@ -562,82 +638,5 @@ class BloodhoundSearchModule(Component):
)
facet_counts[_(field)] = per_field_dict
- data['facet_counts'] = facet_counts
-
- def _create_term_expression(self, field, field_value):
- if field_value is None:
- query = "NOT (%s:*)" % field
- elif isinstance(field_value, basestring):
- query = '%s:"%s"' % (field, field_value)
- else:
- query = '%s:%s' % (field, field_value)
- return query
-
- def _prepare_query_filter(self, parameters, allowed_participants):
- query_filters = list(parameters.filter_queries)
- type = parameters.type
- if type in allowed_participants:
- query_filters.append(
- self._create_term_expression(IndexFields.TYPE, type))
- else:
- self.log.debug("Unsupported type in web request: %s", type)
- return query_filters
-
- def _prepare_facets(self, parameters, allowed_participants):
- #TODO: add possibility of specifying facets in query parameters
- if parameters.is_show_all_mode():
- facets = [IndexFields.TYPE]
- facets.extend(self.default_facets)
- else:
- type_participant = allowed_participants[parameters.type]
- facets = type_participant.get_default_facets()
- return facets
-
- def _get_allowed_participants(self, req):
- allowed_participants = {}
- for participant in self.search_participants:
- type = participant.get_search_filters(req)
- if type is not None:
- allowed_participants[type] = participant
- return allowed_participants
-
- def _return_data(self, req, data):
- add_stylesheet(req, 'common/css/search.css')
- return 'bhsearch.html', data, None
-
- def _process_doc(self, doc, req, allowed_participants, is_free_text_view):
- ui_doc = dict(doc)
- ui_doc["href"] = req.href(doc['type'], doc['id'])
- #todo: perform content adaptation here
- if doc.has_key('content'):
-# ui_doc['excerpt'] = shorten_result(doc['content'])
- ui_doc['content'] = shorten_result(doc['content'])
- if doc.has_key('time'):
- ui_doc['date'] = user_time(req, format_datetime, doc['time'])
-
- if is_free_text_view:
- ui_doc['title'] = allowed_participants[
- doc['type']].format_search_results(doc)
- return ui_doc
-
- def _prepare_shown_pages(self, parameters, shown_pages):
- page_data = []
- for shown_page in shown_pages:
- page_href = parameters.create_href(page=shown_page)
- page_data.append([page_href, None, str(shown_page),
- 'page ' + str(shown_page)])
- fields = ['href', 'class', 'string', 'title']
- result_shown_pages = [dict(zip(fields, p)) for p in page_data]
- return result_shown_pages
-
-
- # ITemplateProvider methods
- def get_htdocs_dirs(self):
- # return [('bhsearch',
- # pkg_resources.resource_filename(__name__, 'htdocs'))]
- return []
-
- def get_templates_dirs(self):
- return [pkg_resources.resource_filename(__name__, 'templates')]
-
+ self.data[self.DATA_FACET_COUNTS] = facet_counts