• R/O
  • SSH
  • HTTPS

shibuya-trac: コミット


コミットメタ情報

リビジョン865 (tree)
日時2015-04-26 02:44:35
作者jun66j5

ログメッセージ

TracCompleteUserPlugin: new version 0.5.0

- fixed wrong default value of [complete-user] single_fields option
- use config api rather than Configuration.get* methods
- use add_script_data rather than filter_stream
- use db api to avoid SQL injection

変更サマリ

差分

--- plugins/completeuserplugin/trunk/completeuser/web_ui.py (revision 864)
+++ plugins/completeuserplugin/trunk/completeuser/web_ui.py (revision 865)
@@ -1,64 +1,34 @@
11 # -*- coding: utf-8 -*-
2-from trac.core import *
3-from trac.config import Option, BoolOption, Configuration
4-from trac.web.chrome import add_script,add_stylesheet,ITemplateProvider
5-from trac.web.main import IRequestHandler, IRequestFilter
6-from trac.web.api import ITemplateStreamFilter
7-from trac.util.html import Markup
82
9-from genshi.filters.transform import Transformer
10-from genshi.template import MarkupTemplate
11-from json.encoder import JSONEncoder
123 import re
134
5+from trac.config import BoolOption, FloatOption, ListOption
6+from trac.core import Component, implements
7+from trac.util.presentation import to_json
8+from trac.web.chrome import ITemplateProvider, add_script, add_script_data, \
9+ add_stylesheet
10+from trac.web.main import IRequestHandler, IRequestFilter
1411
12+
1513 class CompleteUserWeb(Component):
16- implements(IRequestHandler, IRequestFilter, ITemplateProvider, ITemplateStreamFilter)
1714
18- single_fields = Option('complete-user','single_fields',['owner','reporter'], u"""単一ユーザを補完するフィールド設定します。""");
19- composite_fields = Option('complete-user','composite_fields','cc', u"""複数ユーザを補完するフィールド設定します。""");
20- name_check = BoolOption('complete-user','name_check', 'true', u"""ユーザを検索する際にNameが設定されているユーザのみを検索するかどうかを設定します。""");
21- popup_delay = Option('complete-user','popup_delay','1.5',
22- u"""補完ウィンドウのポップアップ表示までの遅延時間を設定します。
23-
24- 単位は秒で小数点も利用することができます
25- """)
15+ implements(IRequestHandler, IRequestFilter, ITemplateProvider)
2616
17+ single_fields = ListOption('complete-user', 'single_fields', 'owner,reporter',
18+ doc=u"""単一ユーザを補完するフィールド設定します。""")
19+ composite_fields = ListOption('complete-user', 'composite_fields', 'cc',
20+ doc=u"""複数ユーザを補完するフィールド設定します。""")
21+ name_check = BoolOption('complete-user', 'name_check', 'true',
22+ doc=u"""ユーザを検索する際にNameが設定されているユーザのみを検索するかどうかを設定します。""")
23+ popup_delay = FloatOption('complete-user', 'popup_delay', '1.5',
24+ doc=u"""補完ウィンドウのポップアップ表示までの遅延時間を設定します。
2725
28- def filter_stream(self, req, method, filename, stream, data):
29- if re.match(r'^/(ticket|newticket|admin|query)', req.path_info):
30- single_fields = Configuration.getlist(self.config,"complete-user","single_fields",['owner','reporter']);
31- composite_fields = Configuration.getlist(self.config,"complete-user","composite_fields","cc");
32- popup_delay = Configuration.get(self.config,"complete-user","popup_delay","1.5");
33- name_check = Configuration.getbool(self.config,"complete-user","name_check", "true");
26+ 単位は秒で小数点も利用することができます""")
3427
35- script = "<script type='text/javascript'>\n"
36- script = script+"(function($){\n"
37- script = script+"$(function(){\n"
38- script = script+" ultimania.trac.POPUP_DELAY = " + popup_delay + ";\n"
28+ # IRequestFilter methods
3929
40- script = script+" ultimania.trac.setAutoComplete('action_reassign_reassign_owner','" + req.base_path + "/completeuser',false);\n"
41- script = script+" ultimania.trac.setAutoComplete('gp_subject','" + req.base_path + "/completeuser',false);\n"
42- script = script+" ultimania.trac.setAutoComplete('sg_subject','" + req.base_path + "/completeuser',false);\n"
43- script = script+" ultimania.trac.setAutoComplete('bmod_value_owner','" + req.base_path + "/completeuser',false);\n"
44- script = script+" ultimania.trac.setAutoComplete('bmod_value_cc','" + req.base_path + "/completeuser',true);\n"
45- for field in single_fields:
46- script = script+" ultimania.trac.setAutoComplete('field-" + field + "','" + req.base_path + "/completeuser',false);\n"
47- for field in composite_fields:
48- script = script+" ultimania.trac.setAutoComplete('field-" + field + "','" + req.base_path + "/completeuser',true);\n"
49- script = script+"})\n"
50- script = script+"})(jQuery);\n"
51- script = script+"</script>"
52- return stream | Transformer('//div[@id="footer"]').before(MarkupTemplate(script).generate())
53- else:
54- return stream
55-
56- # IRequestFilter methods
5730 def pre_process_request(self, req, handler):
5831 return handler
59-
60- def post_process_request(self, req, template, content_type):
61- return (template, content_type)
6232
6333 def post_process_request(self, req, template, data, content_type):
6434 if re.match(r'^/(ticket|newticket|admin|query)', req.path_info):
@@ -67,47 +37,43 @@
6737 add_script(req, 'completeuser/js/yui/utilities/utilities.js')
6838 add_script(req, 'completeuser/js/yui/autocomplete/autocomplete-min.js')
6939 add_script(req, 'completeuser/js/trac-completeuser.js')
70- return (template, data, content_type)
40+ script_data = {'base_path': req.href(),
41+ 'single_fields': self.single_fields,
42+ 'composite_fields': self.composite_fields,
43+ 'popup_delay': self.popup_delay}
44+ add_script_data(req, {'completeuser': script_data})
45+ return template, data, content_type
7146
7247 # IRequestHandler methods
48+
7349 def match_request(self, req):
74- if req.path_info in ('/login/completeuser', '/completeuser'):
75- self.log.debug("%s matches %s" % (req.path_info, True))
76- return True
77- return False
50+ return req.path_info in ('/login/completeuser', '/completeuser')
7851
7952 def process_request(self, req):
80- name_check = Configuration.getbool(self.config,"complete-user","name_check", "True");
8153 query = req.args.get('query')
82- db = self.env.get_db_cnx()
83- cursor = db.cursor();
84- join = ""
85- where = ""
86-
87- if name_check:
88- join = "JOIN"
54+ db = self.env.get_read_db()
55+ cursor = db.cursor()
56+
57+ join = ("LEFT OUTER JOIN", "JOIN")[self.name_check]
58+ sql = ("SELECT s.sid, sa.value FROM session s " +
59+ "%s session_attribute sa ON s.sid=sa.sid AND sa.name='name' " +
60+ "WHERE s.authenticated=1") % join
61+ if query:
62+ like = db.like()
63+ sql += " AND (s.sid %s OR sa.value %s)" % (like, like)
64+ args = ['%' + db.like_escape(query) + '%'] * 2
8965 else:
90- join = "LEFT OUTER JOIN"
91- if query != None:
92- where = ("AND (s.sid LIKE '%%%s%%' or sa.value LIKE '%%%s%%')") % (query,query)
93-
94- sql = ("SELECT s.sid, sa.value FROM session s %s session_attribute sa ON s.sid = sa.sid AND sa.name = 'name' WHERE s.authenticated = 1 %s") % (join,where)
66+ args = []
9567
96- cursor.execute(sql)
97- userlist = []
98- for sid, value in cursor:
99- userlist.append({"Id":sid, "Name": value});
100- response = JSONEncoder().encode({"UserList":userlist}).encode('utf-8')
101- self.log.debug("%s matches %s" % (req.path_info, True))
68+ cursor.execute(sql, args)
69+ userlist = [{'Id': sid, 'Name': value} for sid, value in cursor]
70+ response = to_json({'UserList': userlist})
71+ if isinstance(response, unicode):
72+ response = response.encode('utf-8')
73+ req.send(response, 'application/json')
10274
103- req.send_response(200)
104- req.send_header('Content-Type', 'application/json; charset=utf-8')
105- req.send_header('Content-Length', len(response.encode("utf-8")))
75+ # ITemplateProvider methods
10676
107- req.end_headers()
108- req.write(response)
109-
110- # ITemplateProvider methods
11177 def get_templates_dirs(self):
11278 return []
11379
--- plugins/completeuserplugin/trunk/completeuser/htdocs/js/trac-completeuser.js (revision 864)
+++ plugins/completeuserplugin/trunk/completeuser/htdocs/js/trac-completeuser.js (revision 865)
@@ -46,3 +46,23 @@
4646 );
4747 */
4848 }
49+jQuery(document).ready(function($){
50+ var data = window.completeuser;
51+ if (data === undefined)
52+ return;
53+ var url = data.base_path + '/completeuser';
54+ var single_fields = data.single_fields || [];
55+ var composite_fields = data.composite_fields || [];
56+ ultimania.trac.POPUP_DELAY = data.popup_delay || 0.5;
57+ ultimania.trac.setAutoComplete('action_reassign_reassign_owner', url, false);
58+ ultimania.trac.setAutoComplete('gp_subject', url, false);
59+ ultimania.trac.setAutoComplete('sg_subject', url, false);
60+ ultimania.trac.setAutoComplete('bmod_value_owner', url, false);
61+ ultimania.trac.setAutoComplete('bmod_value_cc', url, true);
62+ $.each(single_fields, function(idx, field) {
63+ ultimania.trac.setAutoComplete('field-' + field, url, false);
64+ });
65+ $.each(composite_fields, function(idx, field) {
66+ ultimania.trac.setAutoComplete('field-' + field, url, true);
67+ });
68+});
--- plugins/completeuserplugin/trunk/setup.py (revision 864)
+++ plugins/completeuserplugin/trunk/setup.py (revision 865)
@@ -5,7 +5,7 @@
55
66 setup(
77 name='TracCompleteUserPlugin',
8- version='0.4',
8+ version='0.5.0',
99 zip_safe = True,
1010 packages=find_packages(exclude=['*.tests*']),
1111
@@ -20,11 +20,13 @@
2020 'completeuser.web_ui = completeuser.web_ui',
2121 ]
2222 },
23- package_data={'completeuser': [
24-'htdocs/js/trac-completeuser.js',
25-'htdocs/js/yui/autocomplete/autocomplete-min.js',
26-'htdocs/js/yui/utilities/utilities.js',
27-'htdocs/css/trac-completeuser.css',
28-'htdocs/js/yui/autocomplete/assets/skins/sam/autocomplete.css']},
29-
30-)
\ No newline at end of file
23+ package_data={
24+ 'completeuser': [
25+ 'htdocs/js/trac-completeuser.js',
26+ 'htdocs/js/yui/autocomplete/autocomplete-min.js',
27+ 'htdocs/js/yui/utilities/utilities.js',
28+ 'htdocs/css/trac-completeuser.css',
29+ 'htdocs/js/yui/autocomplete/assets/skins/sam/autocomplete.css',
30+ ],
31+ },
32+)
旧リポジトリブラウザで表示