Author: andrej
Date: Thu Feb 7 15:03:31 2013
New Revision: 1443531
URL: http://svn.apache.org/viewvc?rev=1443531&view=rev
Log:
#361 Bloodhound Search add support or sort parameter
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/ticket_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/tests/wiki_search.py
incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css
Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py?rev=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py Thu Feb 7
15:03:31 2013
@@ -245,6 +245,7 @@ class BloodhoundSearchApi(Component):
for post_processor in self.result_post_processors:
post_processor.post_process(query_result)
+ query_result.debug["api_parameters"] = query_parameters
return query_result
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=1443531&r1=1443530&r2=1443531&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
Thu Feb 7 15:03:31 2013
@@ -114,7 +114,8 @@ class WikiSearchParticipant(BaseSearchPa
default_grid_fields = [
IndexFields.ID,
IndexFields.TIME,
- IndexFields.AUTHOR
+ IndexFields.AUTHOR,
+ IndexFields.CONTENT,
]
prefix = WIKI_TYPE
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html?rev=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
---
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
(original)
+++
incubator/bloodhound/trunk/bloodhound_search/bhsearch/templates/bhsearch.html
Thu Feb 7 15:03:31 2013
@@ -107,7 +107,7 @@
</py:if>
<div py:if="results" class="row">
- <div class="span3">
+ <div class="span3 facets">
<py:if test="facet_counts">
<!--Render facet counts-->
<h3>Facets</h3>
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py?rev=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
---
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py
(original)
+++
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py
Thu Feb 7 15:03:31 2013
@@ -19,7 +19,6 @@
# under the License.
import unittest
-import tempfile
import shutil
from bhsearch.api import BloodhoundSearchApi
from bhsearch.search_resources.milestone_search import MilestoneIndexer
@@ -27,13 +26,11 @@ from bhsearch.tests.base import BaseBloo
from bhsearch.search_resources.ticket_search import TicketIndexer
from bhsearch.whoosh_backend import WhooshBackend
-from trac.test import EnvironmentStub
class IndexWhooshTestCase(BaseBloodhoundSearchTest):
def setUp(self):
- self.env = EnvironmentStub(enable=['bhsearch.*'])
- self.env.path = tempfile.mkdtemp('bhsearch-tempenv')
+ super(IndexWhooshTestCase, self).setUp()
self.whoosh_backend = WhooshBackend(self.env)
self.whoosh_backend.recreate_index()
self.search_api = BloodhoundSearchApi(self.env)
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/ticket_search.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/ticket_search.py?rev=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
---
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/ticket_search.py
(original)
+++
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/ticket_search.py
Thu Feb 7 15:03:31 2013
@@ -18,20 +18,14 @@
# specific language governing permissions and limitations
# under the License.
import unittest
-import tempfile
from bhsearch.tests.base import BaseBloodhoundSearchTest
from bhsearch.search_resources.ticket_search import TicketIndexer
-from trac.test import EnvironmentStub
-
-
class TicketIndexerSilenceOnExceptionTestCase(BaseBloodhoundSearchTest):
def setUp(self):
- self.env = EnvironmentStub(
- enable=['bhsearch.*'],
- path=tempfile.mkdtemp('bhsearch-tempenv'),
- )
+ super(TicketIndexerSilenceOnExceptionTestCase, self).setUp()
+ self.env.config.set('bhsearch', 'silence_on_error', "True")
self.ticket_indexer = TicketIndexer(self.env)
def tearDown(self):
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=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py Thu
Feb 7 15:03:31 2013
@@ -18,17 +18,17 @@
# specific language governing permissions and limitations
# under the License.
import unittest
-import tempfile
-import shutil
from urllib import urlencode, unquote
+from bhsearch.api import ASC, DESC
from bhsearch.tests.base import BaseBloodhoundSearchTest
from bhsearch.web_ui import RequestParameters
from bhsearch.whoosh_backend import WhooshBackend
-from trac.test import EnvironmentStub, Mock, MockPerm
+from trac.test import Mock, MockPerm
from trac.ticket import Ticket
+from trac.core import TracError
from trac.util.datefmt import FixedOffset
from trac.util import format_datetime
from trac.web import Href, arg_list_to_args, parse_arg_list, RequestDone
@@ -514,6 +514,21 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
#assert
self.assertEqual("grid", data["active_view"])
+ def test_can_apply_sorting(self):
+ #arrange
+ self.insert_ticket("T1", component="c1", status="new", milestone="A")
+ self.insert_ticket("T2", component="c1", status="new", milestone="B")
+ self.insert_ticket("T3", component="c3", status="new", milestone="C")
+ #act
+ self.req.args[RequestParameters.QUERY] = "*"
+ self.req.args[RequestParameters.SORT] = "component, milestone desc"
+ data = self.process_request()
+ #assert
+ api_sort = data["debug"]["api_parameters"]["sort"]
+ self.assertEqual([("component", ASC), ("milestone", DESC)], api_sort)
+ ids = [item["summary"] for item in data["results"].items]
+ self.assertEqual(["T2", "T1", "T3"], ids)
+
def _count_parameter_in_url(self, url, parameter_name, value):
parameter_to_find = (parameter_name, value)
@@ -539,8 +554,53 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
for i in range(1, n+1):
self.insert_wiki("test %s" % i)
+class RequestParametersTest(unittest.TestCase):
+ def setUp(self):
+ self.req = Mock(
+ perm=MockPerm(),
+ chrome={'logo': {}},
+ href=Href("/main"),
+ base_path=BASE_PATH,
+ args=arg_list_to_args([]),
+ )
+
+ def test_can_parse_multiple_sort_terms(self):
+ self.assertEqual(
+ None,
+ self._evaluate_sort(" "))
+ self.assertEqual(
+ None,
+ self._evaluate_sort(" , , "))
+ self.assertEqual(
+ [("f1", ASC),],
+ self._evaluate_sort(" f1 "))
+ self.assertEqual(
+ [("f1", ASC),],
+ self._evaluate_sort(" f1 asc"))
+ self.assertEqual(
+ [("f1", DESC),],
+ self._evaluate_sort("f1 desc"))
+ self.assertEqual(
+ [("f1", ASC), ("f2", DESC)],
+ self._evaluate_sort("f1, f2 desc"))
+
+ def test_can_raise_error_on_invalid_sort_term(self):
+ self.assertRaises(
+ TracError,
+ self._evaluate_sort,
+ "f1 desc bb")
+
+ def _evaluate_sort(self, sort_condition):
+ self.req.args[RequestParameters.SORT] = sort_condition
+ parameters = RequestParameters(self.req)
+ return parameters.sort
+
+
def suite():
- return unittest.makeSuite(WebUiTestCaseWithWhoosh, 'test')
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(WebUiTestCaseWithWhoosh, 'test'))
+ suite.addTest(unittest.makeSuite(RequestParametersTest, 'test'))
+ return 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=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
---
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py
(original)
+++
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py
Thu Feb 7 15:03:31 2013
@@ -27,7 +27,6 @@ from bhsearch.query_parser import Defaul
from bhsearch.tests.base import BaseBloodhoundSearchTest
from bhsearch.whoosh_backend import (WhooshBackend,
WhooshEmptyFacetErrorWorkaround)
-from trac.test import EnvironmentStub
from trac.util.datefmt import FixedOffset, utc
from whoosh import index, sorting, query
from whoosh.fields import Schema, ID, TEXT, KEYWORD
@@ -37,8 +36,7 @@ from whoosh.qparser import MultifieldPlu
class WhooshBackendTestCase(BaseBloodhoundSearchTest):
def setUp(self):
- self.env = EnvironmentStub(enable=['bhsearch.*'])
- self.env.path = tempfile.mkdtemp('bhsearch-tempenv')
+ super(WhooshBackendTestCase, self).setUp()
self.whoosh_backend = WhooshBackend(self.env)
self.whoosh_backend.recreate_index()
self.parser = DefaultQueryParser(self.env)
@@ -453,8 +451,7 @@ class WhooshFunctionalityTestCase(unitte
class WhooshEmptyFacetErrorWorkaroundTestCase(BaseBloodhoundSearchTest):
def setUp(self):
- self.env = EnvironmentStub(enable=['bhsearch.*'])
- self.env.path = tempfile.mkdtemp('bhsearch-tempenv')
+ super(WhooshEmptyFacetErrorWorkaroundTestCase, self).setUp()
self.whoosh_backend = WhooshBackend(self.env)
self.whoosh_backend.recreate_index()
self.parser = DefaultQueryParser(self.env)
Modified:
incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/wiki_search.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/wiki_search.py?rev=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/wiki_search.py
(original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/wiki_search.py
Thu Feb 7 15:03:31 2013
@@ -19,25 +19,21 @@
# under the License.
import shutil
import unittest
-import tempfile
from bhsearch.api import BloodhoundSearchApi
from bhsearch.query_parser import DefaultQueryParser
-from bhsearch.tests.utils import BaseBloodhoundSearchTest
+from bhsearch.tests.base import BaseBloodhoundSearchTest
from bhsearch.whoosh_backend import WhooshBackend
from bhsearch.search_resources.wiki_search import (
WikiIndexer, WikiSearchParticipant)
-from trac.test import EnvironmentStub
from trac.wiki import WikiSystem, WikiPage
class WikiIndexerSilenceOnExceptionTestCase(BaseBloodhoundSearchTest):
def setUp(self):
- self.env = EnvironmentStub(
- enable=['bhsearch.*'],
- path=tempfile.mkdtemp('bhsearch-tempenv'),
- )
+ super(WikiIndexerSilenceOnExceptionTestCase, self).setUp()
+ self.env.config.set('bhsearch', 'silence_on_error', "True")
self.wiki_indexer = WikiIndexer(self.env)
def tearDown(self):
@@ -57,9 +53,7 @@ class WikiIndexerEventsTestCase(BaseBloo
DUMMY_PAGE_NAME = "dummyName"
def setUp(self):
- self.env = EnvironmentStub(enable=['bhsearch.*'])
- self.env.path = tempfile.mkdtemp('bhsearch-tempenv')
- self.env.config.set('bhsearch', 'silence_on_error', "False")
+ super(WikiIndexerEventsTestCase, self).setUp()
self.wiki_system = WikiSystem(self.env)
self.whoosh_backend = WhooshBackend(self.env)
self.whoosh_backend.recreate_index()
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=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Thu Feb 7
15:03:31 2013
@@ -43,8 +43,6 @@ from trac.wiki.formatter import extract_
SEARCH_PERMISSION = 'SEARCH_VIEW'
DEFAULT_RESULTS_PER_PAGE = 10
-DEFAULT_SORT = [(SCORE, ASC), ("time", DESC)]
-#VIEW_GRID = "grid"
class RequestParameters(object):
"""
@@ -59,6 +57,7 @@ class RequestParameters(object):
PAGELEN = "pagelen"
FILTER_QUERY = "fq"
VIEW = "view"
+ SORT = "sort"
def __init__(self, req):
self.req = req
@@ -76,14 +75,14 @@ class RequestParameters(object):
self.filter_queries = self._remove_possible_duplications(
self.filter_queries)
- #TODO: retrieve sort from query string
- self.sort = DEFAULT_SORT
+ sort_string = req.args.getfirst(self.SORT)
+ self.sort = self._parse_sort(sort_string)
self.pagelen = int(req.args.getfirst(
RequestParameters.PAGELEN,
DEFAULT_RESULTS_PER_PAGE))
self.page = int(req.args.getfirst(self.PAGE, '1'))
- self.type = req.args.getfirst(self.TYPE, None)
+ self.type = req.args.getfirst(self.TYPE)
self.params = {
RequestParameters.FILTER_QUERY: []
@@ -103,6 +102,42 @@ class RequestParameters(object):
self.params[self.TYPE] = self.type
if self.filter_queries:
self.params[RequestParameters.FILTER_QUERY] = self.filter_queries
+ if sort_string:
+ self.params[RequestParameters.SORT] = sort_string
+
+ def _parse_sort(self, sort_string):
+ if not sort_string:
+ return None
+ sort_terms = sort_string.split(",")
+ sort = []
+
+ def parse_sort_order(sort_order):
+ sort_order = sort_order.lower()
+ if sort_order == ASC:
+ return ASC
+ elif sort_order == DESC:
+ return DESC
+ else:
+ raise TracError(
+ "Invalid sort order %s in sort parameter %s" %
+ (sort_order, sort_string))
+
+ for term in sort_terms:
+ term = term.strip()
+ if not term:
+ continue
+ term_parts = term.split()
+ parts_count = len(term_parts)
+ if parts_count == 1:
+ sort.append((term_parts[0], ASC))
+ elif parts_count == 2:
+ sort.append((term_parts[0], parse_sort_order(term_parts[1])))
+ else:
+ raise TracError("Invalid sort term %s " % term)
+
+ return sort if sort else None
+
+
def _remove_possible_duplications(self, parameters_list):
seen = set()
@@ -169,8 +204,8 @@ class BloodhoundSearchModule(Component):
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,
@@ -261,12 +296,14 @@ class BloodhoundSearchModule(Component):
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=parameters.sort,
+ sort=sort,
fields=fields,
facets=facets,
filter=query_filter,
@@ -301,6 +338,7 @@ class BloodhoundSearchModule(Component):
add_link(req, 'prev', prev_href, _('Previous Page'))
data['results'] = results
+ data['debug'] = query_result.debug
self._prepare_result_facet_counts(
parameters,
@@ -572,7 +610,8 @@ class BloodhoundSearchModule(Component):
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['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'])
Modified:
incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css?rev=1443531&r1=1443530&r2=1443531&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css
(original)
+++ incubator/bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css
Thu Feb 7 15:03:31 2013
@@ -542,6 +542,12 @@ input[type="submit"].btn.btn-micro {
}
}
+@media (min-width: 1200px) {
+ .facets {
+ width: 220px;
+ }
+}
+
@media (min-width: 979px) and (max-width: 1199px) {
.main-nav ul {
background-color: red;