Created
April 17, 2012 05:54
-
-
Save jun66j5/2403786 to your computer and use it in GitHub Desktop.
Patch for Trac-ja 0.11.x on TracLighting 2.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git b/python-lib/trac/trac/htdocs/css/admin.css a/python-lib/trac/trac/htdocs/css/admin.css | |
index f686535..6bc8d0a 100644 | |
--- b/python-lib/trac/trac/htdocs/css/admin.css | |
+++ a/python-lib/trac/trac/htdocs/css/admin.css | |
@@ -19,32 +19,30 @@ | |
color: #000; | |
} | |
-#tabcontent { padding: 0.4em 0 0.4em 2em; margin-left: 12em; min-height: 300px; } | |
+#tabcontent { padding: 0.4em 2em; margin-left: 12em; min-height: 300px; } | |
#tabcontent h2 { color: #333; margin-top: 0; } | |
-#tabcontent form { overflow: auto; padding: 0 1px; } | |
p.help { color: #666; font-size: 90%; margin: 1em .5em .5em; } | |
#enumlist tbody td { vertical-align: middle; } | |
-#tabcontent form.addnew { clear: right; float: right; margin: -2em 0 2em 2em; width: 33%; overflow: visible; padding: 0 } | |
-#tabcontent form.mod { margin-top: 1em; overflow: visible; padding: 0 } | |
-form.mod fieldset { margin: 0 } | |
+form.addnew { clear: right; float: right; margin: -2em 0 4em; width: 33% } | |
+form.mod { margin-top: 1em; } | |
form.mod .field { margin: .5em 0; } | |
form .field em { color: #888; font-size: smaller } | |
form .field .disabled em { color: #d7d7d7 } | |
-table.listing { clear: none; } | |
+table.listing { clear: none; width: 64% } | |
table.listing .sel, table.listing .default { text-align: center; width: 1% } | |
table.listing .num { text-align: right; width: 1% } | |
/* Plugins panel */ | |
form#addplug { width: 35% } | |
.plugin { background: #f7f7f7; border: 1px solid #d7d7d7; margin: 0 0 2em; | |
- padding: 2px .5em; text-align: left; | |
+ padding: 2px .5em; text-align: left; width: 60%; | |
} | |
.plugin h3 { margin: .5em 0; color: #bb0000;} | |
.plugin h3 a { | |
- padding: 2px .5em; text-align: left; | |
+ padding: 2px .5em; text-align: left; width: 60%; | |
} | |
.plugin h3 a { background: url(../expanded.png) 0 50% no-repeat; | |
padding-left: 16px; | |
diff --git b/python-lib/trac/trac/htdocs/js/search.js a/python-lib/trac/trac/htdocs/js/search.js | |
index 5ba8e48..030b661 100644 | |
--- b/python-lib/trac/trac/htdocs/js/search.js | |
+++ a/python-lib/trac/trac/htdocs/js/search.js | |
@@ -31,6 +31,7 @@ | |
if (url.indexOf("?") == -1) return []; | |
var params = url.substr(url.indexOf("?") + 1).split("&"); | |
for (var p in params) { | |
+ if (typeof(params[p])=="function") continue; | |
var param = params[p].split("="); | |
if (param.length < 2) continue; | |
if (param[0] == "q" || param[0] == "p") {// q= for Google, p= for Yahoo | |
diff --git b/python-lib/trac/trac/ticket/notification.py a/python-lib/trac/trac/ticket/notification.py | |
index 1b5b3a5..512e69e 100644 | |
--- b/python-lib/trac/trac/ticket/notification.py | |
+++ a/python-lib/trac/trac/ticket/notification.py | |
@@ -17,9 +17,12 @@ | |
# | |
from trac import __version__ | |
+from trac.attachment import Attachment | |
from trac.core import * | |
from trac.config import * | |
+from trac.mimeview.api import Context | |
from trac.notification import NotifyEmail | |
+from trac.resource import Resource | |
from trac.util import md5 | |
from trac.util.datefmt import to_timestamp | |
from trac.util.text import CRLF, wrap, to_unicode, obfuscate_email_address | |
@@ -133,16 +136,19 @@ class TicketNotifyEmail(NotifyEmail): | |
changes_body += ' * %s: %s%s' % (field, chg, CRLF) | |
if newv: | |
change_data[field] = {'oldvalue': old, 'newvalue': new} | |
- | |
+ else: | |
+ change_data.update({'author': ticket.values['reporter']}) | |
+ | |
self.ticket['description'] = wrap( | |
self.ticket.values.get('description', ''), self.COLS, | |
initial_indent=' ', subsequent_indent=' ', linesep=CRLF) | |
self.ticket['new'] = self.newticket | |
self.ticket['link'] = link | |
- subject = self.format_subj(summary) | |
+ subject = self.format_subj(summary, change_data) | |
if not self.newticket: | |
subject = 'Re: ' + subject | |
+ attachments = [attachment for attachment in Attachment.select(self.env, 'ticket', ticket.id)] | |
self.data.update({ | |
'ticket_props': self.format_props(), | |
'ticket_body_hdr': self.format_hdr(), | |
@@ -150,7 +156,8 @@ class TicketNotifyEmail(NotifyEmail): | |
'ticket': ticket.values, | |
'changes_body': changes_body, | |
'changes_descr': changes_descr, | |
- 'change': change_data | |
+ 'change': change_data, | |
+ 'attachments': attachments, | |
}) | |
NotifyEmail.notify(self, ticket.id, subject) | |
@@ -215,7 +222,7 @@ class TicketNotifyEmail(NotifyEmail): | |
return '#%s: %s' % (self.ticket.id, wrap(self.ticket['summary'], | |
self.COLS, linesep=CRLF)) | |
- def format_subj(self, summary): | |
+ def format_subj(self, summary, change): | |
template = self.config.get('notification','ticket_subject_template') | |
template = TextTemplate(template.encode('utf8')) | |
@@ -227,6 +234,7 @@ class TicketNotifyEmail(NotifyEmail): | |
'prefix': prefix, | |
'summary': summary, | |
'ticket': self.ticket, | |
+ 'change': change, | |
'env': self.env, | |
} | |
diff --git b/python-lib/trac/trac/ticket/query.py a/python-lib/trac/trac/ticket/query.py | |
index 94ff877..26d8159 100644 | |
--- b/python-lib/trac/trac/ticket/query.py | |
+++ a/python-lib/trac/trac/ticket/query.py | |
@@ -956,7 +956,7 @@ class QueryModule(Component): | |
content = StringIO() | |
cols = query.get_columns() | |
writer = csv.writer(content, delimiter=sep, quoting=csv.QUOTE_MINIMAL) | |
- writer.writerow([unicode(c).encode('utf-8') for c in cols]) | |
+ writer.writerow([unicode(c).encode('cp932') for c in cols]) | |
context = Context.from_request(req) | |
results = query.execute(req, self.env.get_db_cnx()) | |
@@ -969,9 +969,9 @@ class QueryModule(Component): | |
if col in ('cc', 'reporter'): | |
value = Chrome(self.env).format_emails(context(ticket), | |
value) | |
- values.append(unicode(value).encode('utf-8')) | |
+ values.append(unicode(value).encode('cp932')) | |
writer.writerow(values) | |
- return (content.getvalue(), '%s;charset=utf-8' % mimetype) | |
+ return (content.getvalue(), '%s;charset=cp932' % mimetype) | |
def export_rss(self, req, query): | |
if 'description' not in query.rows: | |
diff --git b/python-lib/trac/trac/ticket/report.py a/python-lib/trac/trac/ticket/report.py | |
index a37713a..1b61d97 100644 | |
--- b/python-lib/trac/trac/ticket/report.py | |
+++ a/python-lib/trac/trac/ticket/report.py | |
@@ -47,17 +47,37 @@ def cell_value(v): | |
return v is 0 and '0' or v and unicode(v) or '' | |
+class ITicketReportRenderer(Interface): | |
+ """Extension point interface for components that implement new report | |
+ writing formats.""" | |
+ | |
+ def get_report_format(): | |
+ """Called to get the id for a report format, for example: .xls""" | |
+ | |
+ def get_report_mimetype(): | |
+ """Called to get the mimetype string for a report format""" | |
+ | |
+ def get_report_linkname(): | |
+ """Called to get the report link name that will appear on the UI""" | |
+ | |
+ def get_report_linkclass(): | |
+ """Called to get the class of the link that will appear on the UI""" | |
+ | |
+ def render(req, cols, rows, id): | |
+ """Render the report, takes the request, columns and rows, report id""" | |
+ | |
+ | |
class ReportModule(Component): | |
implements(INavigationContributor, IPermissionRequestor, IRequestHandler, | |
IWikiSyntaxProvider) | |
items_per_page = IntOption('report', 'items_per_page', 100, | |
- """レポートの検索結果ページで 1 ページに表示するチケット数の | |
+ u"""レポートの検索結果ページで 1 ページに表示するチケット数の | |
デフォルト値 (''0.11 以降'')""") | |
items_per_page_rss = IntOption('report', 'items_per_page_rss', 0, | |
- """レポートの RSS フィードに掲載するチケット数 | |
+ u"""レポートの RSS フィードに掲載するチケット数 | |
(''0.11 以降'')""") | |
# INavigationContributor methods | |
@@ -80,7 +100,7 @@ class ReportModule(Component): | |
# IRequestHandler methods | |
def match_request(self, req): | |
- match = re.match(r'/report(?:/(?:([0-9]+)|-1))?$', req.path_info) | |
+ match = re.match(r'/report(?:/([0-9]+))?', req.path_info) | |
if match: | |
if match.group(1): | |
req.args['id'] = match.group(1) | |
@@ -133,6 +153,8 @@ class ReportModule(Component): | |
add_stylesheet(req, 'common/css/report.css') | |
return template, data, None | |
+ renderers = ExtensionPoint(ITicketReportRenderer) | |
+ | |
# Internal methods | |
def _do_create(self, req, db): | |
@@ -301,7 +323,7 @@ class ReportModule(Component): | |
page = int(req.args.get('page', '1')) | |
limit = {'rss': self.items_per_page_rss, | |
- 'csv': 0, 'tab': 0}.get(format, self.items_per_page) | |
+ 'csv': 0, 'tab': 0, 'xls': 0}.get(format, self.items_per_page) | |
offset = (page - 1) * limit | |
user = req.args.get('USER', None) | |
@@ -324,11 +346,11 @@ class ReportModule(Component): | |
data['paginator'] = paginator | |
if paginator.has_next_page: | |
next_href = req.href.report(id, asc=asc, sort=sort_col, | |
- page=page + 1, **args) | |
+ USER=user, page=page + 1) | |
add_link(req, 'next', next_href, _('Next Page')) | |
if paginator.has_previous_page: | |
prev_href = req.href.report(id, asc=asc, sort=sort_col, | |
- page=page - 1, **args) | |
+ USER=user, page=page - 1) | |
add_link(req, 'prev', prev_href, _('Previous Page')) | |
pagedata = [] | |
@@ -493,6 +515,10 @@ class ReportModule(Component): | |
filename=filename) | |
else: | |
if id != -1: | |
+ for renderer in self.renderers: | |
+ if renderer.get_report_format()==format: | |
+ renderer.render(req,cols,results,id) | |
+ return None | |
# reuse the session vars of the query module so that | |
# the query navigation links on the ticket can be used to | |
# navigate report results as well | |
@@ -500,10 +526,10 @@ class ReportModule(Component): | |
req.session['query_tickets'] = \ | |
' '.join([str(int(row['id'])) | |
for rg in row_groups for row in rg[1]]) | |
+ #FIXME: I am not sure the extra args are necessary | |
req.session['query_href'] = \ | |
- req.href.report(id, asc=req.args.get('asc', None), | |
- sort=req.args.get('sort', None), | |
- page=page, **args) | |
+ req.href.report(id, asc=not asc and '0' or None, | |
+ sort=sort_col, USER=user, page=page) | |
# Kludge: we have to clear the other query session | |
# variables, but only if the above succeeded | |
for var in ('query_constraints', 'query_time'): | |
@@ -514,7 +540,7 @@ class ReportModule(Component): | |
return 'report_view.html', data, None | |
def add_alternate_links(self, req, args): | |
- params = args.copy() | |
+ params = args | |
if 'sort' in req.args: | |
params['sort'] = req.args['sort'] | |
if 'asc' in req.args: | |
@@ -531,6 +557,19 @@ class ReportModule(Component): | |
if 'REPORT_SQL_VIEW' in req.perm: | |
add_link(req, 'alternate', '?format=sql', _('SQL Query'), | |
'text/plain') | |
+ | |
+ # add link for every loaded component | |
+ # that implements ITicketReportRenderer | |
+ | |
+ for renderer in self.renderers: | |
+ format = renderer.get_report_format() | |
+ mimetype = renderer.get_report_mimetype() | |
+ linkname = renderer.get_report_linkname() | |
+ linkclass = renderer.get_report_linkclass() | |
+ | |
+ add_link(req,'alternate','?format='+format+href, | |
+ linkname,mimetype,linkclass) | |
+ | |
def execute_report(self, req, db, id, sql, args): | |
"""Execute given sql report (0.10 backward compatibility method) | |
@@ -676,16 +715,19 @@ class ReportModule(Component): | |
out = StringIO() | |
writer = csv.writer(out, delimiter=sep) | |
- writer.writerow([unicode(c).encode('utf-8') for c in cols]) | |
+ # | |
+ writer.writerow([unicode(c).encode('cp932') for c in cols]) | |
for row in rows: | |
row = list(row) | |
for i in xrange(len(row)): | |
- row[i] = converters[i](row[i]).encode('utf-8') | |
+ # | |
+ row[i] = converters[i](row[i]).encode('cp932') | |
writer.writerow(row) | |
+ | |
data = out.getvalue() | |
req.send_response(200) | |
- req.send_header('Content-Type', mimetype + ';charset=utf-8') | |
+ req.send_header('Content-Type', mimetype + ';charset=cp932') | |
req.send_header('Content-Length', len(data)) | |
if filename: | |
req.send_header('Content-Disposition', 'filename=' + filename) | |
diff --git b/python-lib/trac/trac/ticket/templates/ticket.html a/python-lib/trac/trac/ticket/templates/ticket.html | |
index 1bfc700..9ec6c97 100644 | |
--- b/python-lib/trac/trac/ticket/templates/ticket.html | |
+++ a/python-lib/trac/trac/ticket/templates/ticket.html | |
@@ -315,7 +315,7 @@ ${comment}</textarea></p> | |
<tr> | |
<th><label for="field-description">${_('Description')}:</label></th> | |
<td class="fullrow" colspan="3"> | |
- <textarea id="field-description" name="field_description" class="wikitext" rows="10" cols="68"> | |
+ <textarea id="field-description" name="field_description" class="wikitext" rows="20" cols="75"> | |
${ticket.description}</textarea> | |
</td> | |
</tr> | |
diff --git b/python-lib/trac/trac/ticket/templates/ticket_notify_email.txt a/python-lib/trac/trac/ticket/templates/ticket_notify_email.txt | |
index d334f16..0836e53 100644 | |
--- b/python-lib/trac/trac/ticket/templates/ticket_notify_email.txt | |
+++ a/python-lib/trac/trac/ticket/templates/ticket_notify_email.txt | |
@@ -6,26 +6,33 @@ $ticket.description | |
#end | |
#otherwise | |
#if changes_body | |
-Changes (by $change.author): | |
+変更点 (by $change.author): | |
$changes_body | |
#end | |
#if changes_descr | |
#if not changes_body and not change.comment and change.author | |
-Description changed by $change.author: | |
+説明の変更 by $change.author: | |
#end | |
$changes_descr | |
-- | |
#end | |
#if change.comment | |
-Comment${not changes_body and '(by %s)' % change.author or ''}: | |
+コメント${not changes_body and '(by %s)' % change.author or ''}: | |
$change.comment | |
#end | |
#end | |
#end | |
+#if attachments | |
+添付ファイル一覧: | |
+ #for attachment in attachments | |
+ * ${attachment.filename} | |
+ ${abs_url_of(attachment.resource, format='raw')} | |
+ #end | |
+#end | |
-- | |
Ticket URL: <$ticket.link> | |
$project.name <${project.url or abs_href()}> | |
diff --git b/python-lib/trac/trac/versioncontrol/api.py a/python-lib/trac/trac/versioncontrol/api.py | |
index cb55eac..5d91687 100644 | |
--- b/python-lib/trac/trac/versioncontrol/api.py | |
+++ a/python-lib/trac/trac/versioncontrol/api.py | |
@@ -150,6 +150,7 @@ class RepositoryManager(Component): | |
tid = threading._get_ident() | |
if tid in self._cache: | |
repos = self._cache[tid] | |
+ repos.authz.auth_name = authname | |
else: | |
rtype, rdir = self.repository_type, self.repository_dir | |
if not os.path.isabs(rdir): | |
diff --git b/python-lib/trac/trac/versioncontrol/svn_authz.py a/python-lib/trac/trac/versioncontrol/svn_authz.py | |
index 2f270b2..6a37789 100644 | |
--- b/python-lib/trac/trac/versioncontrol/svn_authz.py | |
+++ a/python-lib/trac/trac/versioncontrol/svn_authz.py | |
@@ -19,9 +19,10 @@ | |
import os.path | |
from trac.config import Option | |
+from trac.config import Configuration | |
from trac.core import * | |
from trac.versioncontrol import Authorizer | |
- | |
+from trac.util.text import to_unicode | |
class SvnAuthzOptions(Component): | |
@@ -79,14 +80,7 @@ class RealSubversionAuthorizer(Authorizer): | |
self.repos = repos | |
self.auth_name = auth_name | |
self.module_name = module_name | |
- | |
- from ConfigParser import ConfigParser | |
- self.conf_authz = ConfigParser() | |
- if cfg_fp: | |
- self.conf_authz.readfp(cfg_fp, cfg_file) | |
- elif cfg_file: | |
- self.conf_authz.read(cfg_file) | |
- | |
+ self.conf_authz = Configuration(cfg_file) | |
self.groups = self._groups() | |
def has_permission(self, path): | |
@@ -115,7 +109,7 @@ class RealSubversionAuthorizer(Authorizer): | |
# Internal API | |
def _groups(self): | |
- if not self.conf_authz.has_section('groups'): | |
+ if not u'groups' in self.conf_authz.sections(): | |
return [] | |
grp_parents = {} | |
@@ -145,7 +139,8 @@ class RealSubversionAuthorizer(Authorizer): | |
return expanded.keys() | |
def _get_section(self, section): | |
- if not self.conf_authz.has_section(section): | |
+ section = to_unicode(section) | |
+ if not (section in self.conf_authz.sections()): | |
return | |
yield self._get_permission(section, self.auth_name) | |
diff --git b/python-lib/trac/trac/versioncontrol/web_ui/changeset.py a/python-lib/trac/trac/versioncontrol/web_ui/changeset.py | |
index a24f9da..c6da78d 100644 | |
--- b/python-lib/trac/trac/versioncontrol/web_ui/changeset.py | |
+++ a/python-lib/trac/trac/versioncontrol/web_ui/changeset.py | |
@@ -724,7 +724,7 @@ class ChangesetModule(Component): | |
if kind == Node.FILE and change != Changeset.DELETE: | |
assert new_node | |
zipinfo = ZipInfo() | |
- zipinfo.filename = new_node.path.strip('/').encode('utf-8') | |
+ zipinfo.filename = new_node.path.strip('/').encode('shift_jis') | |
# Note: unicode filenames are not supported by zipfile. | |
# UTF-8 is not supported by all Zip tools either, | |
# but as some do, I think UTF-8 is the best option here. | |
diff --git b/python-lib/trac/trac/web/__init__.py a/python-lib/trac/trac/web/__init__.py | |
index 7d6fe60..de5823a 100644 | |
--- b/python-lib/trac/trac/web/__init__.py | |
+++ a/python-lib/trac/trac/web/__init__.py | |
@@ -11,6 +11,8 @@ if not os.path.isdir(get_distribution('genshi').location): | |
import sys | |
if 'trac.web.modpython_frontend' in sys.modules: | |
from trac.web.api import * | |
+ if 'tram.modpython_frontend' in sys.modules: | |
+ from trac.web.api import * | |
except ImportError: | |
from trac.web.api import * | |
else: | |
diff --git b/python-lib/trac/trac/wiki/default-pages/TracLinks a/python-lib/trac/trac/wiki/default-pages/TracLinks | |
index 04916ee..e1b2644 100644 | |
--- b/python-lib/trac/trac/wiki/default-pages/TracLinks | |
+++ a/python-lib/trac/trac/wiki/default-pages/TracLinks | |
@@ -42,7 +42,7 @@ TracLinks が使えるのは: | |
* マイルストーン: milestone:1.0 | |
* 添付ファイル: attachment:example.tgz(現在のページへの添付ファイル), attachment:attachment.1073.diff:ticket:944 (絶対パス) | |
* ファイル: source:trunk/COPYING | |
- * あるリビジョンのファイル: source:/trunk/COPYING#200 | |
+ * あるリビジョンのファイル: source:/trunk/COPYING@200 | |
* あるリビジョンのファイルのある行数: source:/trunk/COPYING@200#L25 | |
'''Note:''' wiki:CamelCase の書式が使われることはほとんどありませんが、 | |
diff --git b/python-lib/trac/trac/wiki/parser.py a/python-lib/trac/trac/wiki/parser.py | |
index 6d7468a..49fe626 100644 | |
--- b/python-lib/trac/trac/wiki/parser.py | |
+++ a/python-lib/trac/trac/wiki/parser.py | |
@@ -149,7 +149,7 @@ class WikiParser(Component): | |
helper_re = re.compile(r'\?P<([a-z\d_]+)>') | |
for rule in syntax: | |
helpers += helper_re.findall(rule)[1:] | |
- rules = re.compile('(?:' + '|'.join(syntax) + ')', re.UNICODE) | |
+ rules = re.compile('(?:' + '|'.join(syntax) + ')', re.UNICODE|re.LOCALE) | |
self._external_handlers = handlers | |
self._helper_patterns = helpers | |
self._compiled_rules = rules |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment