Author: thimal
Date: Thu Jul 17 19:25:49 2014
New Revision: 1611444

URL: http://svn.apache.org/r1611444
Log:
add the duplicate feature to popover ticket create and did some style change 
according to the bloodhound style

Added:
    
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/popoverDupSearch.js
   (with props)
Modified:
    
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/DupeSearch.js
    
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/theme.py

Modified: 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/DupeSearch.js
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/DupeSearch.js?rev=1611444&r1=1611443&r2=1611444&view=diff
==============================================================================
--- 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/DupeSearch.js
 (original)
+++ 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/DupeSearch.js
 Thu Jul 17 19:25:49 2014
@@ -1,17 +1,17 @@
-$(document).ready(function() {
+jQuery(document).ready(function() {
 
        $('div#content.ticket h2#vc-summary').blur(function() {
                var text = $('div#content.ticket h2#vc-summary').text();
                if (text.length > 0) {
 
                        var html = '<h5 class="loading">Loading related 
tickets..</h5>';
-                       var dupeticketlistDiv = $('div#content.ticket 
h2#vc-summary + div#dupeticketlist');
-                       if (dupeticketlistDiv.length == 0) {
+                       var duplicate_eticket_list_div = $('div#content.ticket 
h2#vc-summary + div#dupeticketlist');
+                       if (duplicate_eticket_list_div.length == 0) {
                                $('div#content.ticket 
h2#vc-summary').after('<div id="dupeticketlist" style="display:none;"></div>');
-                               dupeticketlistDiv = $('div#content.ticket 
h2#vc-summary + div#dupeticketlist');
+                               duplicate_eticket_list_div = 
$('div#content.ticket h2#vc-summary + div#dupeticketlist');
                        }
-                       $('ul',dupeticketlistDiv).slideUp('fast');
-                       dupeticketlistDiv.html(html).slideDown();
+                       $('ul',duplicate_eticket_list_div).slideUp('fast');
+                       duplicate_eticket_list_div.html(html).slideDown();
 
                        $.ajax({
                                url:'duplicate_ticket_search',
@@ -20,48 +20,51 @@ $(document).ready(function() {
 
                                success: function(data, status) {
                                        var tickets =data;
-                                       var ticketBaseHref =  'ticket/';
-                                       var searchBaseHref =  
'bhsearch?type=ticket&q=';
-                                       var maxTickets = 15;
+                                       var ticket_base_Href =  'ticket/';
+                                       var search_base_Href =  
'bhsearch?type=ticket&q=';
+                                       var max_tickets = 15;
 
                                        var html = '';
                                        if (tickets === null) {
                                                // error
-                                               dupeticketlistDiv.html('<h5 
class="error">Error loading tickets.</h5>');
+                                               
duplicate_eticket_list_div.html('<h5 class="error">Error loading 
tickets.</h5>');
                                        } else if (tickets.length <= 0) {
                                                // no dupe tickets
-                                               dupeticketlistDiv.slideUp();
+                                               
duplicate_eticket_list_div.slideUp();
                                        } else {
-                                               html = '<h5>Possible related 
tickets:</h5><ul style="display:none;">'
+                                               html = '<h5>Possible related 
tickets:</h5><ul id="results">'
                                                tickets = tickets.reverse();
 
-                                               for (var i = 0; i < 
tickets.length && i < maxTickets; i++) {
+                                               for (var i = 0; i < 
tickets.length && i < max_tickets; i++) {
                                                        var ticket = tickets[i];
                                                        html += '<li 
class="highlight_matches" title="' + ticket.description +
-                                                                   '"><a 
href="' + ticketBaseHref + ticket.url +
+                                                                   '"><a 
href="' + ticket_base_Href + ticket.url +
                                                                    '"><span 
class="' + htmlencode(ticket.status) + '">#' +
-                                                                   ticket.url 
+ '</span></a>: ' + htmlencode(ticket.type) + ': ' +
-                                                                   
ticket.summary + '(' + htmlencode(ticket.status) +
-                                                                   (ticket.url 
? ': ' + htmlencode(ticket.url) : '') +
-                                                                   ')' + 
'</li>'
+                                                                   ticket.url 
+ '</span></a>: ' +
+                                                                   
ticket.summary + ' (' + htmlencode(ticket.status)
+                                                                   +': '+ 
htmlencode(ticket.type) +
+                                                                   ') ' 
+'<span class="author">created by '+ticket.owner +'</span> <span 
class="date">at ' +ticket.date+ '</span></li>'
                                                }
                                                html += '</ul>';
-                                               if (tickets.length > 
maxTickets) {
+                                               if (tickets.length > 
max_tickets) {
                                                        var text = 
$('div#content.ticket input#field-summary').val();
-                                                       html += '<a href="' + 
searchBaseHref + escape(text) + '">More..</a>';
+                                                       html += '<a href="' + 
search_base_Href + escape(text) + '">More..</a>';
                                                }
 
-                                               dupeticketlistDiv.html(html);
-                                               $('> ul', 
dupeticketlistDiv).slideDown();
+                                               
duplicate_eticket_list_div.html(html);
+                                               $('> ul', 
duplicate_eticket_list_div).slideDown();
 
                                        }
 
                                },
                                error: function(xhr, textStatus, exception) {
-                                       dupeticketlistDiv.html('<h5 
class="error">Error loading tickets: ' + textStatus + '</h5>');
+                                       duplicate_eticket_list_div.html('<h5 
class="error">Error loading tickets: ' + textStatus + '</h5>');
                                }
                        });
-               }
+               }else{
+            var duplicate_eticket_list_div = $('div#content.ticket 
div#dupeticketlist');
+            duplicate_eticket_list_div.slideUp('fast');
+        }
        });
        
        function htmlencode(text) {

Added: 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/popoverDupSearch.js
URL: 
http://svn.apache.org/viewvc/bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/popoverDupSearch.js?rev=1611444&view=auto
==============================================================================
--- 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/popoverDupSearch.js
 (added)
+++ 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/popoverDupSearch.js
 Thu Jul 17 19:25:49 2014
@@ -0,0 +1,73 @@
+jQuery(document).ready(function() {
+
+       $('input#field-summary.input-block-level').blur(function() {
+               var text = $('input#field-summary.input-block-level').val();
+               if (text.length > 0) {
+
+                       var html = '<h5 class="loading">Loading related 
tickets..</h5>';
+                       var dupelicate_ticket_list_div = $('div.popover-content 
input#field-summary + div#dupeticketlist');
+                       if (dupelicate_ticket_list_div.length == 0) {
+                               $('div.popover-content 
input#field-summary').after('<div id="dupeticketlist" 
style="display:none;"></div>');
+                               dupelicate_ticket_list_div = 
$('div.popover-content input#field-summary + div#dupeticketlist');
+                       }
+                       $(dupelicate_ticket_list_div).slideUp('fast');
+                       dupelicate_ticket_list_div.html(html).slideDown();
+
+                       $.ajax({
+                               url:'duplicate_ticket_search',
+                data:{q:text},
+                               type:'GET',
+                               success: function(data, status) {
+                                       var tickets =data;
+                                       var ticket_base_href =  'ticket/';
+                                       var search_base_Href =  
'bhsearch?type=ticket&q=';
+                                       var max_tickets = 5;
+
+                                       var html = '';
+                                       if (tickets === null) {
+                                               // error
+                                               
dupelicate_ticket_list_div.html('<h5 class="error">Error loading 
tickets.</h5>');
+                                       } else if (tickets.length <= 0) {
+                                               // no dupe tickets
+                                               
dupelicate_ticket_list_div.slideUp();
+                                       } else {
+                                               html = '<h5>Possible related 
tickets:</h5><ul style="display:none;">';
+                                               //tickets = tickets.reverse();
+
+                                               for (var i = 0; i < 
tickets.length && i < max_tickets; i++) {
+                                                       var ticket = tickets[i];
+                                                       html += '<li 
class="highlight_matches" title="' + ticket.description +
+                                                                   '"><a 
href="' + ticket_base_href + ticket.url +
+                                                                   '"><span 
class="' + htmlencode(ticket.status) + '">#' +
+                                                                   ticket.url 
+ '</span></a>: ' + htmlencode(ticket.type) + ': ' +
+                                                                   
ticket.summary + '(' + htmlencode(ticket.status) +
+                                                                   (ticket.url 
? ': ' + htmlencode(ticket.url) : '') +
+                                                                   ')' + 
'</li>'
+                                               }
+                                               html += '</ul>';
+                                               if (tickets.length > 
max_tickets) {
+                                                       var text = 
$('div.popover-content input#field-summary').val();
+                                                       html += '<a href="' + 
search_base_Href + escape(text) + '">More..</a>';
+                                               }
+
+                                               
dupelicate_ticket_list_div.html(html);
+                                               $('> ul', 
dupelicate_ticket_list_div).slideDown();
+
+                                       }
+
+                               },
+                               error: function(xhr, textStatus, exception) {
+                                       dupelicate_ticket_list_div.html('<h5 
class="error">Error loading tickets: ' + textStatus + '</h5>');
+                               }
+                       });
+               }else{
+            var dupelicate_ticket_list_div = $('div.popover-content 
input#field-summary + div#dupeticketlist');
+            dupelicate_ticket_list_div.slideUp();
+        }
+       });
+
+       function htmlencode(text) {
+               return $('<div/>').text(text).html().replace(/"/g, 
'&quot;').replace(/'/g, '&apos;');
+       }
+});
+

Propchange: 
bloodhound/branches/bep_0013_dynamic_clientside_features/bloodhound_theme/bhtheme/htdocs/js/popoverDupSearch.js
------------------------------------------------------------------------------
    svn:eol-style = native

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=1611444&r1=1611443&r2=1611444&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
 Thu Jul 17 19:25:49 2014
@@ -19,6 +19,7 @@
 
 import sys
 
+from trac.util.datefmt import format_datetime, user_time
 from collections import Counter
 
 import fnmatch
@@ -42,7 +43,7 @@ from trac.util.presentation import to_js
 from trac.versioncontrol.web_ui.browser import BrowserModule
 from trac.web.api import IRequestFilter, IRequestHandler, ITemplateStreamFilter
 from trac.web.chrome import (add_stylesheet, add_warning, 
INavigationContributor,
-                             ITemplateProvider, prevnext_nav, Chrome, 
add_script)
+                             ITemplateProvider, prevnext_nav, Chrome, 
add_script, add_script_data)
 from trac.wiki.admin import WikiAdmin
 from trac.wiki.formatter import format_to_html
 
@@ -694,8 +695,8 @@ class AutocompleteUsers(Component):
     implements(IRequestFilter, IRequestHandler,
                ITemplateProvider, ITemplateStreamFilter)
 
-    selectfields = ListOption('autocomplete', 'fields', default='',
-                              doc='select fields to transform to autocomplete 
text boxes')
+    select_fields = ListOption('autocomplete', 'fields', default='',
+                               doc='select fields to transform to autocomplete 
text boxes')
 
     # IRequestHandler methods
 
@@ -711,16 +712,15 @@ class AutocompleteUsers(Component):
         if req.args.get('users', '1') == '1':
             users = self._get_users(req)
             if req.perm.has_permission('EMAIL_VIEW'):
-                subjects = ['{"label":"%s %s %s","value":"%s"}' % (user[USER] 
and '%s' % user[USER] or '',
-                                          user[EMAIL] and '<%s>' % user[EMAIL] 
or '',
-                                          user[NAME] and '%s' % user[NAME] or 
'',
-                                            user[USER])
-                                for value, user in users]  # value unused 
(placeholder needed for sorting)
+                subjects = ['{"label":"%s %s %s","value":"%s"}' % (user[USER] 
and '%s' % user[USER] or
+                                                                   '', 
user[EMAIL] and '<%s>' % user[EMAIL] or
+                                                                   '', 
user[NAME] and '%s' % user[NAME] or
+                                                                   '', 
user[USER])
+                            for value, user in users]
             else:
-                subjects = ['{"label":"%s %s","value":"%s"}' % (user[USER] and 
'%s' % user[USER] or '',
-                                          user[NAME] and '%s' % user[NAME] or 
'',
-                                            user[USER])
-                                for value, user in users]  # value unused 
(placeholder needed for sorting)
+                subjects = ['{"label":"%s %s","value":"%s"}' % (user[USER] and 
'%s' % user[USER] or '', user[NAME] and
+                                                                '%s' % 
user[NAME] or'', user[USER])
+                            for value, user in users]
 
         respond_str = ','.join(subjects).encode('utf-8')
         respond_str = '[' + respond_str + ']'
@@ -730,7 +730,6 @@ class AutocompleteUsers(Component):
 
     def get_htdocs_dirs(self):
         from pkg_resources import resource_filename
-
         return [('autocompleteusers', resource_filename(__name__, 'htdocs'))]
 
     def get_templates_dirs(self):
@@ -750,7 +749,6 @@ class AutocompleteUsers(Component):
             add_script(req, 'autocompleteusers/js/format_item.js')
             if template == 'query.html':
                 add_script(req, 'autocompleteusers/js/autocomplete_query.js')
-
         return template, data, content_type
 
     # ITemplateStreamFilter methods
@@ -762,7 +760,7 @@ class AutocompleteUsers(Component):
             fields = [field['name'] for field in data['ticket'].fields
                       if field['type'] == 'select']
             fields = set(sum([fnmatch.filter(fields, pattern)
-                              for pattern in self.selectfields], []))
+                              for pattern in self.select_fields], []))
 
         js = ""
 
@@ -770,7 +768,7 @@ class AutocompleteUsers(Component):
 
             restrict_owner = self.env.config.getbool('ticket', 
'restrict_owner')
             if req.path_info.startswith('/ticket/'):
-                js = """$(document).bind('DOMSubtreeModified', function (){
+                js = """jQuery(document).bind('DOMSubtreeModified', function 
(){
                             $( "#field-cc" ).autocomplete({
                                 source: "user_list"
                                 multiple: true,
@@ -779,7 +777,7 @@ class AutocompleteUsers(Component):
                             });
                         });"""
                 if not restrict_owner:
-                    js = """$(document).bind('DOMSubtreeModified', function (){
+                    js = """jQuery(document).bind('DOMSubtreeModified', 
function (){
 
                             $( "#field-cc" ).autocomplete({
                                 source: "user_list",
@@ -817,16 +815,14 @@ class AutocompleteUsers(Component):
                                 formatItem: formatItem
                             });
                         });"""
-            stream = stream | 
Transformer('.//head').append(tag.script(Markup(js),
-                                                                   
type='text/javascript'))
+            stream = stream | 
Transformer('.//head').append(tag.script(Markup(js), type='text/javascript'))
 
         elif filename == 'bh_admin_perms.html':
             users = self._get_users(req)
-            subjects = ['{"label":"%s %s %s","value":"%s"}' % (user[USER] and 
'%s' % user[USER] or '',
-                                      user[EMAIL] and '<%s>' % user[EMAIL] or 
'',
-                                      user[NAME] and '%s' % user[NAME] or '',
-                                        user[USER])
-                            for value, user in users]  # value unused 
(placeholder needed for sorting)
+            subjects = ['{"label":"%s %s %s","value":"%s"}' % (user[USER] and 
'%s' % user[USER] or '', user[EMAIL] and
+                                                               '<%s>' % 
user[EMAIL] or '', user[NAME] and
+                                                               '%s' % 
user[NAME] or '', user[USER])
+                        for value, user in users]
 
             groups = self._get_groups(req)
             if groups:
@@ -839,7 +835,7 @@ class AutocompleteUsers(Component):
                 respond_str_groups = ','.join(subjects_groups).encode('utf-8')
                 respond_str_groups = '[' + respond_str_groups + ']'
 
-            js = """$(document).ready(function () {
+            js = """jQuery(document).ready(function () {
                     var subjects =  %(subject)s
                     var groups =  %(group)s
                       $("#gp_subject").autocomplete( {
@@ -855,15 +851,12 @@ class AutocompleteUsers(Component):
                         formatItem: formatItem
                       });
                     });"""
-            js_ticket = js % {'subject': respond_str_subjects,
-                                'group': respond_str_groups
+            js_ticket = js % {'subject': respond_str_subjects, 'group': 
respond_str_groups
                               }
-            stream = stream | 
Transformer('.//head').append(tag.script(Markup(js_ticket),
-                                                                   
type='text/javascript'))
 
+            stream = stream | 
Transformer('.//head').append(tag.script(Markup(js_ticket), 
type='text/javascript'))
         return stream
 
-
     # Private methods
 
     def _get_groups(self, req):
@@ -877,9 +870,10 @@ class AutocompleteUsers(Component):
         db = self.env.get_db_cnx()
         cursor = db.cursor()
         cursor.execute("""SELECT DISTINCT username FROM permission""")
-        usernames = [user[0] for user in self.env.get_known_users()]
-        return sorted([row[0] for row in cursor if not row[0] in usernames
-        and row[0].lower().startswith(query)])
+        user_names = [user[0] for user in self.env.get_known_users()]
+        return sorted([row[0]
+                       for row in cursor
+                       if not row[0] in user_names and 
row[0].lower().startswith(query)])
 
     def _get_users(self, req):
         # instead of known_users, could be
@@ -929,8 +923,7 @@ class KeywordSuggestModule(Component):
     def post_process_request(self, req, template, data, content_type):
         """add the necessary javascript and css files
         """
-        if req.path_info.startswith('/ticket/') or \
-                req.path_info.startswith('/newticket') or \
+        if req.path_info.startswith('/ticket/') or 
req.path_info.startswith('/newticket') or \
                 (req.path_info.startswith('/query')):
                 add_script(req, 'keywordssuggest/js/bootstrap-tagsinput.js')
                 add_stylesheet(req, 
'keywordssuggest/css/bootstrap-tagsinput.css')
@@ -942,8 +935,7 @@ class KeywordSuggestModule(Component):
         """add the jQuery tagsinput function to ticket and query pages
         """
 
-        if not (filename == 'bh_ticket.html' or
-                    (filename == 'bh_query.html')):
+        if not (filename == 'bh_ticket.html' or (filename == 'bh_query.html')):
             return stream
 
         keywords = self._get_keywords_string(req)
@@ -970,7 +962,6 @@ class KeywordSuggestModule(Component):
                 js = """jQuery(document).ready(function($) {
                             var keywords =  %(keywords)s
 
-
                             $('%(field)s').tagsinput({
                                 typeahead: {
                                     source: keywords
@@ -979,7 +970,7 @@ class KeywordSuggestModule(Component):
                         });"""
 
         if filename == 'bh_query.html':
-            js = """$(document).ready(function ($) {
+            js = """jQuery(document).ready(function ($) {
                           function addAutocompleteBehavior() {
                             var filters = $('#filters');
                             var contains = $.contains // jQuery 1.4+
@@ -1040,14 +1031,10 @@ class KeywordSuggestModule(Component):
             js_ticket = js % {'field': '#field-' + self.field_opt,
                               'keywords': keywords
                               }
-            stream = stream | Transformer('.//head').append \
-                (tag.script(Markup(js_ticket),
-                            type='text/javascript'))
+            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'))
+            stream = stream | 
Transformer('.//head').append(tag.script(Markup(js_ticket), 
type='text/javascript'))
 
         return stream
 
@@ -1070,16 +1057,18 @@ class KeywordSuggestModule(Component):
         # get keywords from db
         db = self.env.get_db_cnx()
         cursor = db.cursor()
-        product = self.env.product._data['prefix']
-        sql = """SELECT t.keywords FROM ticket AS t WHERE t.keywords IS NOT 
null AND t.product ='%s'""" % product
-
-        cursor.execute(sql)
         keywords = []
-        for row in cursor:
-            if not row[0] == '':
-                row_val = str(row[0]).split(',')
-                for val in row_val:
-                    keywords.append(val.strip())
+        if self.env.product is not None:
+            product = self.env.product._data['prefix']
+            sql = """SELECT t.keywords FROM ticket AS t WHERE t.keywords IS 
NOT null AND t.product ='%s'""" % product
+
+            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)
@@ -1092,8 +1081,10 @@ class KeywordSuggestModule(Component):
 # component to find duplicate tickets
 #DuplicateTicketSearch component basic structure is taken from trac 
DuplicateTicketSearch plugin
 #https://trac-hacks.org/wiki/DuplicateTicketSearchPlugin
+
+
 class DuplicateTicketSearch(Component):
-    implements(ITemplateProvider, ITemplateStreamFilter,IRequestHandler)
+    implements(ITemplateProvider, ITemplateStreamFilter, IRequestHandler)
 
     # ITemplateProvider methods
 
@@ -1104,10 +1095,10 @@ class DuplicateTicketSearch(Component):
     def get_templates_dirs(self):
         return []
 
-
     # ITemplateStreamFilter methods
 
     def filter_stream(self, req, method, filename, stream, data):
+        add_script(req, 'duplicateticketsearch/js/popoverDupSearch.js')
 
         if filename == 'bh_ticket.html':
             ticket = data.get('ticket')
@@ -1116,7 +1107,7 @@ class DuplicateTicketSearch(Component):
 
         return stream
 
-        # IRequestHandler methods
+    # IRequestHandler methods
 
     def match_request(self, req):
         """Handle requests sent to /user_list and /ticket/user_list
@@ -1124,23 +1115,78 @@ class DuplicateTicketSearch(Component):
         return req.path_info.rstrip('/') == '/duplicate_ticket_search'
 
     def process_request(self, req):
-        product = self.env.product._data['prefix']
-        query_result = BloodhoundSearchApi(self.env).query(
-            req.args.get('q'),
-            pagenum=1,
-            pagelen=10,
-            filter=['type:"ticket"', 'product:"'+product+'"'],
-            highlight=True,
-        )
-        ticket_list = []
-        cnt = 0
-        for ticket in query_result.docs:
-            ticket_list.append(to_json({'summary': 
query_result.highlighting[cnt]['summary'], 'description': 
query_result.highlighting[cnt]['content'],'type':ticket['type'] 
,'status':ticket['status'] , 'owner':ticket['author'] 
,'date':ticket['time'].strftime('%m/%d/%Y') ,'url': ticket['id']}))
-            cnt+1
+        terms = 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)
+            if self.env.product is not None:
+                product_sql = "product='%s' AND" % 
self.env.product._data['prefix']
+            else:
+                product_sql = ""
+            ticket_list = []
+            ticket_list_value = []
+            for summary, desc, author, type, tid, ts, status, resolution in \
+                    db("""SELECT summary, description, reporter, type, id,
+                                 time, status, resolution
+                          FROM ticket
+                          WHERE (%s id IN (
+                              SELECT id FROM ticket WHERE %s
+                            UNION
+                              SELECT ticket FROM ticket_change
+                              WHERE field='comment' AND %s
+                            UNION
+                              SELECT ticket FROM ticket_custom WHERE %s
+                          ))
+                          """ % (product_sql, sql, sql2, sql3),
+                       args + args2 + args3):
+
+                summary_term_count = 0
+                summary_list = summary.split(' ')
+                for s in summary_list:
+                    for t in terms:
+                        if s.lower() == t.lower():
+                            summary = summary.replace(s,'<em>'+t+'</em>')
+                            summary_term_count += 1
+                            break
+
+                ticket_list.append(to_json({'summary': summary, 'description': 
desc, 'type': type, 'status': status,
+                                            'owner': author, 'date': 
user_time(req, format_datetime, ts), 'url': tid}))
+                ticket_list_value.append(summary_term_count)
+        ticket_list = [x for (y, x) in sorted(zip(ticket_list_value, 
ticket_list))]
         str_list = '['+','.join(ticket_list)+']'
 
         req.send(str_list, 'application/json')
 
+    # Private methods
+
+    def _search_to_sql(self, db, columns, terms):
+        """Convert a search query into an SQL WHERE clause and corresponding
+        parameters.
+
+        The result is returned as an `(sql, params)` tuple.
+        """
+        assert columns and terms
+
+        likes = ['%s %s' % (i, db.like()) for i in columns]
+        c = ' OR '.join(likes)
+        sql = '(' + ') OR ('.join([c] * len(terms)) + ')'
+        args = []
+        for t in terms:
+            args.extend(['%' + db.like_escape(t) + '%'] * len(columns))
+        return sql, tuple(args)
+
+
+
+
+
+
+
+
+
+
+
 
 
 


Reply via email to