Author: thimal
Date: Wed Aug 6 18:02:52 2014
New Revision: 1616294
URL: http://svn.apache.org/r1616294
Log:
Improved the duplicate ticket search. Now it search for partial and complete
phrases enter into the summary in new ticket.
change the keywords suggest : add the query page javascript to separate file,
change the db use so it can find keywords in query page also.
Modified:
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/theme.py
Modified:
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/theme.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/theme.py?rev=1616294&r1=1616293&r2=1616294&view=diff
==============================================================================
---
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/theme.py
(original)
+++
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/theme.py
Wed Aug 6 18:02:52 2014
@@ -19,8 +19,9 @@
import sys
+import re
+
from trac.util.datefmt import format_datetime, user_time
-from collections import Counter
import fnmatch
@@ -28,8 +29,6 @@ from genshi.builder import tag
from genshi.core import TEXT, Markup
from genshi.filters.transform import Transformer
from genshi.output import DocType
-from bhsearch.api import BloodhoundSearchApi
-from bhsearch.web_ui import RequestContext
from trac.config import ListOption, Option
from trac.core import Component, TracError, implements
@@ -861,8 +860,7 @@ class KeywordSuggestModule(Component):
self.log.debug("""
No keywords found. KeywordSuggestPlugin is disabled.""")
keywords = []
- # data = {'keywords': keywords}
- # add_script_data(req, data)
+
if filename == 'bh_ticket.html':
# add_script(req, 'theme/js/keywordsuggest_ticket.js')
if req.path_info.startswith('/ticket/'):
@@ -890,61 +888,10 @@ class KeywordSuggestModule(Component):
});"""
if filename == 'bh_query.html':
- js = """jQuery(document).ready(function ($) {
- function addAutocompleteBehavior() {
- var filters = $('#filters');
- var contains = $.contains // jQuery 1.4+
- || function (container, contained) {
- while (contained !== null) {
- if (container === contained)
- return true;
- contained = contained.parentNode;
- }
- return false;
- };
- var listener = function (event) {
- var target = event.target || event.srcElement;
- filters.each(function () {
- if (contains(this, target)) {
- var input =
$(this).find('input:text').filter(function () {
- return target === this;
- });
- var name = input.attr('name');
- if (input.attr('autocomplete') !== 'off' &&
- /^(?:[0-9]+_)?(?:keywords)$/.test(name)) {
- input.tagsinput({
- typeahead: {
- source: %(keywords)s
- }
- });
- input.focus(); // XXX Workaround for Trac
0.12.2 and jQuery 1.4.2
- }
- }
- });
- };
- if ($.fn.on) {
- // delegate method is available in jQuery 1.7+
- filters.on('focusin', 'input:text', listener);
- }
- else if ($.fn.delegate) {
- // delegate method is available in jQuery 1.4.2+
- filters.delegate('input:text', 'focus',
listener);
- }
- else if (window.addEventListener) {
- // use capture=true cause focus event doesn't
bubble in the default
- filters.each(function () {
- this.addEventListener('focus', listener, true);
- });
- }
- else {
- // focusin event bubbles, the event is avialable
for IE only
- filters.each(function () {
- this.attachEvent('onfocusin', listener);
- });
- }
- }
- addAutocompleteBehavior();
- });"""
+ data = {'keywords': keywords}
+ add_script_data(req, data)
+ add_script(req, 'theme/js/keywordsuggest_query.js')
+
# inject transient part of javascript directly into ticket.html
template
if req.path_info.startswith('/ticket/') or \
req.path_info.startswith('/newticket'):
@@ -952,9 +899,6 @@ class KeywordSuggestModule(Component):
'keywords': keywords
}
stream = stream |
Transformer('.//head').append(tag.script(Markup(js_ticket),
type='text/javascript'))
- if req.path_info.startswith('/query'):
- js_ticket = js % {'keywords': keywords}
- stream = stream |
Transformer('.//head').append(tag.script(Markup(js_ticket),
type='text/javascript'))
return stream
@@ -964,29 +908,30 @@ class KeywordSuggestModule(Component):
"""
#currently all the keywords are taken through the db query and then
sort them according to there frequency
# get keywords from db
- db = self.env.get_db_cnx()
- cursor = db.cursor()
keywords = []
- if self.env.product is not None:
- product = self.env.product._data['prefix']
- product_sql = " AND t.product = '%s'" % product
- else:
- product_sql = ""
- sql = """SELECT t.keywords FROM ticket AS t WHERE t.keywords IS NOT
null%s""" % product_sql
+ with self.env.db_direct_query as db:
+ cursor = db.cursor()
+
+ if self.env.product is not None:
+ product = self.env.product._data['prefix']
+ product_sql = " AND t.product = '%s'" % product
+ else:
+ product_sql = ""
+ sql = """SELECT t.keywords FROM ticket AS t WHERE t.keywords IS
NOT null%s""" % product_sql
- cursor.execute(sql)
+ cursor.execute(sql)
- for row in cursor:
- if not row[0] == '':
- row_val = str(row[0]).split(',')
- for val in row_val:
- keywords.append(val.strip())
- # sort keywords according to frequency of occurrence
- if keywords:
- keyword_dic = Counter(keywords)
- keywords = sorted(keyword_dic, key=lambda key: -keyword_dic[key])
- else:
- keywords = ''
+ for row in cursor:
+ if not row[0] == '':
+ row_val = str(row[0]).split(',')
+ for val in row_val:
+ keywords.append(val.strip())
+ # sort keywords according to frequency of occurrence
+ if keywords:
+ keyword_dic = {keyword: keywords.count(keyword) for keyword in
keywords}
+ keywords = sorted(keyword_dic, key=lambda key:
-keyword_dic[key])
+ else:
+ keywords = ''
return keywords
@@ -1001,6 +946,7 @@ class DuplicateTicketSearch(Component):
# ITemplateStreamFilter methods
def filter_stream(self, req, method, filename, stream, data):
+
add_script(req, 'theme/js/popoverDupSearch.js')
if filename == 'bh_ticket.html':
@@ -1015,15 +961,17 @@ class DuplicateTicketSearch(Component):
def match_request(self, req):
"""Handle requests sent to /user_list and /ticket/user_list
"""
- return req.path_info.rstrip('/') == '/duplicate_ticket_search'
+ return re.match('.*/duplicate_ticket_search$', req.path_info)
def process_request(self, req):
- terms = req.args.get('q').split(' ')
+
+ terms = self._terms_to_search(req)
+ term_split = req.args.get('q').split(' ')
with self.env.db_direct_query as db:
- sql, args = self._search_to_sql(db, ['summary', 'keywords',
'description'], terms)
- sql2, args2 = self._search_to_sql(db, ['newvalue'], terms)
- sql3, args3 = self._search_to_sql(db, ['value'], terms)
+ sql, args = self._sql_to_search(db, ['summary', 'keywords',
'description'], terms)
+ sql2, args2 = self._sql_to_search(db, ['newvalue'], terms)
+ sql3, args3 = self._sql_to_search(db, ['value'], terms)
if self.env.product is not None:
product_sql = "product='%s' AND" %
self.env.product._data['prefix']
else:
@@ -1048,9 +996,9 @@ class DuplicateTicketSearch(Component):
summary_term_count = 0
summary_list = summary.split(' ')
for s in summary_list:
- for t in terms:
+ for t in term_split:
if s.lower() == t.lower():
- summary = summary.replace(s,'<em>'+t+'</em>')
+ summary = summary.replace(s, '<em>'+t+'</em>')
summary_term_count += 1
break
@@ -1064,7 +1012,7 @@ class DuplicateTicketSearch(Component):
# Private methods
- def _search_to_sql(self, db, columns, terms):
+ def _sql_to_search(self, db, columns, terms):
"""Convert a search query into an SQL WHERE clause and corresponding
parameters.
@@ -1080,17 +1028,22 @@ class DuplicateTicketSearch(Component):
args.extend(['%' + db.like_escape(t) + '%'] * len(columns))
return sql, tuple(args)
+ def _terms_to_search(self, req):
+ """Convert a search query into different terms to search.
+ The result is returned as a list of terms.
+ """
+ search_string = req.args.get('q')
+ terms = [search_string]
+ temp_string = search_string
+ search_string_split = search_string.split(' ')
+
+ for i in range(len(search_string_split)-3):
+ search_string = re.sub('^'+search_string_split[i]+' ', '',
search_string)
+ terms.append(search_string)
+ search_string = temp_string
+ for i in reversed(xrange(3, len(search_string_split))):
+ search_string = re.sub(' '+search_string_split[i]+'$', '',
search_string)
+ terms.append(search_string)
-
-
-
-
-
-
-
-
-
-
-
-
+ return terms
\ No newline at end of file