-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathcomment.py
161 lines (135 loc) · 5.81 KB
/
comment.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import re
import locale
import trac.wiki.formatter
from trac.mimeview.api import Context
from time import strftime, localtime
from code_comments import db
from trac.util import Markup
try:
import json
except ImportError:
import simplejson as json
try:
import hashlib
md5_hexdigest = lambda s: hashlib.md5(s).hexdigest()
except ImportError:
import md5
md5_hexdigest = lambda s: md5.new(s).hexdigest()
VERSION = 1
class Comment:
columns = [column.name for column in db.schema['code_comments'].columns]
required = 'text', 'author'
_email_map = None
def __init__(self, req, env, data):
if isinstance(data, dict):
self.__dict__ = data
else:
self.__dict__ = dict(zip(self.columns, data))
self.env = env
self.req = req
if self._empty('version'):
self.version = VERSION
self.html = format_to_html(self.req, self.env, self.text)
email = self.email_map().get(self.author, '[email protected]')
self.email_md5 = md5_hexdigest(email)
attachment_info = self.attachment_info()
self.is_comment_to_attachment = attachment_info['is']
self.attachment_ticket = attachment_info['ticket']
self.attachment_filename = attachment_info['filename']
self.is_comment_to_changeset = self.revision and not self.path
self.is_comment_to_file = self.revision and self.path
def _empty(self, column_name):
return not hasattr(self, column_name) or not getattr(self, column_name)
def email_map(self):
if Comment._email_map is None:
Comment._email_map = {}
for username, name, email in self.env.get_known_users():
if email:
Comment._email_map[username] = email
return Comment._email_map
def validate(self):
missing = [column_name for column_name in self.required if self._empty(column_name)]
if missing:
raise ValueError("Comment column(s) missing: %s" % ', '.join(missing))
def href(self):
if self.is_comment_to_file:
href = self.req.href.browser(self.path, rev=self.revision, codecomment=self.id)
elif self.is_comment_to_changeset:
href = self.req.href.changeset(self.revision, codecomment=self.id)
elif self.is_comment_to_attachment:
href = self.req.href('/attachment/ticket/%d/%s' % (self.attachment_ticket, self.attachment_filename), codecomment=self.id)
if self.line:
href += '#L' + str(self.line)
return href
def link_text(self):
if self.revision and not self.path:
return '[%s]' % self.revision
if self.path.startswith('attachment:'):
return self.attachment_link_text()
# except the two specials cases of changesets (revision-only)
# and arrachments (path-only), we must always have them both
assert self.path and self.revision
link_text = self.path + '@' + str(self.revision)
if self.line:
link_text += '#L' + str(self.line)
return link_text
def attachment_link_text(self):
return '#%s: %s' % (self.attachment_ticket, self.attachment_filename)
def trac_link(self):
if self.is_comment_to_attachment:
return '[%s %s]' % (self.req.href())
return 'source:' + self.link_text()
def attachment_info(self):
info = {'is': False, 'ticket': None, 'filename': None}
info['is'] = self.path.startswith('attachment:')
if not info['is']:
return info
match = re.match(r'attachment:/ticket/(\d+)/(.*)', self.path)
if not match:
return info
info['ticket'] = int(match.group(1))
info['filename'] = match.group(2)
return info
def path_link_tag(self):
return Markup('<a href="%s">%s</a>' % (self.href(), self.link_text()))
def formatted_date(self):
encoding = locale.getlocale()[1] if locale.getlocale()[1] else 'utf-8'
return strftime('%d %b %Y, %H:%M', localtime(self.time)).decode(encoding)
def get_ticket_relations(self):
relations = set()
db = self.env.get_db_cnx()
cursor = db.cursor()
query = """SELECT ticket FROM ticket_custom WHERE name = 'code_comment_relation' AND
(value LIKE '%(comment_id)d' OR
value LIKE '%(comment_id)d,%%' OR
value LIKE '%%,%(comment_id)d' OR value LIKE '%%,%(comment_id)d,%%')""" % {'comment_id': self.id}
result = {}
@self.env.with_transaction()
def get_ticket_ids(db):
cursor = db.cursor()
cursor.execute(query)
result['tickets'] = cursor.fetchall()
return set([int(row[0]) for row in result['tickets']])
def get_ticket_links(self):
relations = self.get_ticket_relations()
links = ['[[ticket:%s]]' % relation for relation in relations]
return format_to_html(self.req, self.env, ', '.join(links))
def delete(self):
@self.env.with_transaction()
def delete_comment(db):
cursor = db.cursor()
cursor.execute("DELETE FROM code_comments WHERE id=%s", [self.id])
class CommentJSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Comment):
for_json = dict([(name, getattr(o, name)) for name in o.__dict__ if isinstance(getattr(o, name), (basestring, int, list, dict))])
for_json['formatted_date'] = o.formatted_date()
for_json['permalink'] = o.href()
for_json['id'] = o.id
for_json['line'] = o.line
return for_json
else:
return json.JSONEncoder.default(self, o)
def format_to_html(req, env, text):
context = Context.from_request(req)
return trac.wiki.formatter.format_to_html(env, context, text)