#12915 closed defect (fixed)
Require Trac v1.0.2 installation onwards
Reported by: | ntmlod | Owned by: | Jun Omae |
---|---|---|---|
Priority: | normal | Component: | WikiAutoCompletePlugin |
Severity: | normal | Keywords: | |
Cc: | Trac Release: | 1.0 |
Description
When attempting to write links to ticket or wiki page, I get no suggestions and the following error in the logging:
Traceback (most recent call last): File "/usr/lib/python2.7/site-packages/trac/web/main.py", line 497, in _dispatch_request dispatcher.dispatch(req) File "/usr/lib/python2.7/site-packages/trac/web/main.py", line 214, in dispatch resp = chosen_handler.process_request(req) File "build/bdist.linux-x86_64/egg/wikiautocomplete/web_ui.py", line 87, in process_request """ % db.prefix_match(), File "/usr/lib/python2.7/site-packages/trac/db/util.py", line 108, in __getattr__ return getattr(self.cnx, name) File "/usr/lib/python2.7/site-packages/trac/db/util.py", line 108, in __getattr__ return getattr(self.cnx, name) File "/usr/lib/python2.7/site-packages/trac/db/util.py", line 108, in __getattr__ return getattr(self.cnx, name) AttributeError: 'psycopg2._psycopg.connection' object has no attribute 'prefix_match'
To generate completions for 'ticket' or 'wikipage' case, the plugin use db.prefix_match
& db.prefix_match_value
methods which are missing in db
directory of our v1.0.1 installation. Actually, these methods have been implemented since 1.0.2 version: https://trac.edgewall.org/changeset/13016.
Probably nothing essential for the plugin, I'm going to try to get this works.
Attachments (0)
Change History (11)
comment:1 follow-up: 3 Changed 8 years ago by
comment:2 Changed 8 years ago by
Also, typing ticket:
leads no suggestion. It would be good to suggest when typing ticket:
as the same as #
.
-
wikiautocompleteplugin/trunk/wikiautocomplete/htdocs/js/wikiautocomplete.js
diff --git a/wikiautocompleteplugin/trunk/wikiautocomplete/htdocs/js/wikiautocomplete.js b/wikiautocompleteplugin/trunk/wikiautocomp index 22e1899..0699a38 100644
a b jQuery(document).ready(function($) { 15 15 }, 16 16 17 17 { // Tickets 18 match: / #(\d*)$/,18 match: /(?:#|\bticket:)(\d*)$/, 19 19 search: function (term, callback) { 20 20 $.getJSON(wikiautocomplete_url + '/ticket', { q: term }) 21 21 .done(function (resp) { callback(resp); })
comment:3 follow-up: 6 Changed 8 years ago by
Replying to jun66j5:
After the following patch, it would scan tickets with primary key of the ticket table.
For 77
would that still find 771, 772, 773, ... or only 770, 7700, 77000, ...?
comment:4 follow-up: 7 Changed 8 years ago by
Well for once I managed to fix it for my environment but perhaps it is not robust enough.
-
wikiautocomplete/web_ui.py
64 64 rows = db(""" 65 65 SELECT id, summary 66 66 FROM ticket 67 WHERE %s %s67 WHERE %s LIKE '%s%%' 68 68 ORDER BY changetime DESC 69 69 LIMIT 10 70 """ % (db.cast('id', 'text'), db.prefix_match()), 71 (db.prefix_match_value(term), )) 70 """ % (db.cast('id', 'text'), term)) 72 71 completions = [{ 73 72 'id': row[0], 74 73 'summary': row[1], … … 81 80 rows = db(""" 82 81 SELECT name 83 82 FROM wiki 84 WHERE name %s83 WHERE name LIKE '%s%%' 85 84 GROUP BY name 86 85 ORDER BY name 87 86 LIMIT 10 88 """ % db.prefix_match(), 89 (db.prefix_match_value(term), )) 87 """ % term) 90 88 completions = [row[0] for row in rows 91 89 if 'WIKI_VIEW' in req.perm(Resource('wiki', row[0]))] 92 90 self._send_json(req, completions)
comment:5 Changed 8 years ago by
Also I modified the js script to split the two cases for 'ticket' links (short one with #
and long one with ticket:
or [ticket:... ...]
because the previous proposition by jun66j5 replace [ticket:... ...]
by [#... ...]
which is not working.
-
wikiautocomplete/htdocs/js/wikiautocomplete.js
31 31 cache: true, 32 32 }, 33 33 34 { // Tickets 35 match: /\bticket:(\w*)$/, 36 search: function (term, callback) { 37 $.getJSON(wikiautocomplete_url + '/ticket', { q: term }) 38 .done(function (resp) { callback(resp); }) 39 .fail(function () { callback([]); }); 40 }, 41 index: 1, 42 template: function (ticket) { 43 return '#' + ticket.id + ' ' + ticket.summary; 44 }, 45 replace: function (ticket) { 46 return 'ticket:' + ticket.id; 47 }, 48 cache: true, 49 }, 50 34 51 { // Wiki pages 35 52 match: /\bwiki:([\w/]*)$/, 36 53 search: function (term, callback) {
Probably not optimized because I guess it is possible to switch the cases after the string match but I'm a real newbie in Js.
I think there is room for improvment in order to add some others Trac useful links like changesets & reports for examples. Perhaps in my easy going time.
comment:6 Changed 8 years ago by
Replying to psuter:
Replying to jun66j5:
After the following patch, it would scan tickets with primary key of the ticket table.
For
77
would that still find 771, 772, 773, ... or only 770, 7700, 77000, ...?
Sorry. I was stupid.
Revised patch:
-
wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py
diff --git a/wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py b/wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py index d57b338..0f5536b 100644
a b from json import JSONEncoder 6 6 7 7 from trac.core import * 8 8 from trac.resource import Resource 9 from trac.ticket.model import Ticket 9 10 from trac.util.text import to_unicode 10 11 from trac.util.translation import dgettext 11 12 from trac.web import IRequestFilter, IRequestHandler … … class WikiAutoCompleteModule(Component): 60 61 self._send_json(req, completions) 61 62 62 63 elif strategy == 'ticket': 63 with self.env.db_query as db: 64 rows = db(""" 65 SELECT id, summary 66 FROM ticket 67 WHERE %s %s 64 try: 65 num = int(term) 66 except: 67 num = 0 68 args = [] 69 mul = 1 70 while num > 0 and Ticket.id_is_valid(num): 71 args.append(num) 72 args.append(num + mul) 73 num *= 10 74 mul *= 10 75 if args: 76 expr = ' OR '.join(['id>=%s AND id<%s'] * (len(args) / 2)) 77 rows = self.env.db_query(""" 78 SELECT id, summary FROM ticket 79 WHERE %(expr)s 68 80 ORDER BY changetime DESC 69 81 LIMIT 10 70 """ % (db.cast('id', 'text'), db.prefix_match()), 71 (db.prefix_match_value(term), )) 82 """ % {'expr': expr}, args) 83 else: 84 rows = self.env.db_query(""" 85 SELECT id, summary FROM ticket 86 ORDER BY changetime DESC LIMIT 10""") 72 87 completions = [{ 73 88 'id': row[0], 74 89 'summary': row[1],
Typing 77
, the following query is generated.
sqlite> EXPLAIN QUERY PLAN ...> SELECT id, summary FROM ticket ...> WHERE id>=77 AND id<78 OR id>=770 AND id<780 OR id>=7700 AND id<7800 OR id>=77000 AND id<78000 OR id>=770000 AND id<780000 OR id>=7700000 AND id<7800000 OR id>=77000000 AND id<78000000 OR id>=770000000 AND id<780000000 ...> ORDER BY changetime DESC ...> LIMIT 10; 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|SEARCH TABLE ticket USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) 0|0|0|USE TEMP B-TREE FOR ORDER BY
comment:7 Changed 8 years ago by
Replying to ntmlod:
Well for once I managed to fix it for my environment but perhaps it is not robust enough.
- WHERE name %s + WHERE name LIKE '%s%%' GROUP BY name ORDER BY name LIMIT 10 - """ % db.prefix_match(), - (db.prefix_match_value(term), )) + """ % term)
The patch has SQL injections....
We could retrieve all page names using WikiSystem().pages
.
-
wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py
diff --git a/wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py b/wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py index d57b338..ea01517 100644
a b class WikiAutoCompleteModule(Component): 77 90 self._send_json(req, completions) 78 91 79 92 elif strategy == 'wikipage': 80 with self.env.db_query as db: 81 rows = db(""" 82 SELECT name 83 FROM wiki 84 WHERE name %s 85 GROUP BY name 86 ORDER BY name 87 LIMIT 10 88 """ % db.prefix_match(), 89 (db.prefix_match_value(term), )) 90 completions = [row[0] for row in rows 91 if 'WIKI_VIEW' in req.perm(Resource('wiki', row[0]))] 93 pages = sorted(page for page in WikiSystem(self.env).pages 94 if page.startswith(term) and 95 'WIKI_VIEW' in req.perm('wiki', page)) 96 completions = pages[:10] 92 97 self._send_json(req, completions) 93 98 94 99 elif strategy == 'macro':
comment:8 follow-up: 9 Changed 8 years ago by
Proposed changes in https://github.com/jun66j5/wikiautocompleteplugin/compare/master...t12915.
comment:9 Changed 8 years ago by
Replying to jun66j5:
Proposed changes in https://github.com/jun66j5/wikiautocompleteplugin/compare/master...t12915.
Looks good to me. Feel free to commit.
comment:11 Changed 8 years ago by
Owner: | changed from Peter Suter to Jun Omae |
---|
Thanks for the reviewing! Committed in [15939].
In that case,
db.prefix_match()
is used withCAST(id AS TEXT)
. It would leads full scan for ticket table and slowness if many tickets.After the following patch, it would scan tickets with primary key of the ticket table.
wikiautocompleteplugin/trunk/wikiautocomplete/web_ui.py