Edgewall Software

source: trunk/svntrac/Ticket.py@ 1

Last change on this file since 1 was 1, checked in by Jonas Borgström, 20 years ago

Initial import

File size: 11.8 KB
Line 
1# svntrac
2#
3# Copyright (C) 2003 Jonas Borgström <jonas@xyche.com>
4#
5# svntrac is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as
7# published by the Free Software Foundation; either version 2 of the
8# License, or (at your option) any later version.
9#
10# svntrac is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18#
19# Author: Jonas Borgström <jonas@xyche.com>
20
21import time
22import string
23import StringIO
24
25from util import *
26from Module import Module
27import perm
28import auth
29import db
30
31fields = ['time', 'component', 'severity', 'priority', 'milestone', 'reporter',
32 'owner', 'cc', 'url', 'version', 'status', 'resolution',
33 'summary', 'description']
34
35class Newticket (Module):
36 template_key = 'newticket_template'
37 def render (self):
38 default_component = self.config.get('ticket', 'default_component')
39 default_milestone = self.config.get('ticket', 'default_milestone')
40 default_priority = self.config.get('ticket', 'default_priority')
41 default_severity = self.config.get('ticket', 'default_severity')
42 default_version = self.config.get('ticket', 'default_version')
43
44 self.namespace['title'] = 'create a new ticket'
45 self.namespace['component_select'] = enum_selector ('SELECT name FROM component ORDER by name',
46 'component',
47 default_component)
48 self.namespace['milestone_select'] = enum_selector ('SELECT name FROM milestone ORDER BY name',
49 'milestone',
50 default_milestone)
51 self.namespace['severity_select'] = enum_selector ('SELECT name FROM enum WHERE type=\'severity\' ORDER BY name',
52 'severity',
53 default_severity)
54 self.namespace['priority_select'] = enum_selector ('SELECT name FROM enum WHERE type=\'priority\' ORDER BY name',
55 'priority',
56 default_priority)
57 self.namespace['version_select'] = enum_selector ('SELECT name FROM version ORDER BY name',
58 'version')
59 if auth.get_authname() == 'anonymous':
60 self.namespace['reporter'] = ''
61 else:
62 self.namespace['reporter'] = auth.get_authname()
63
64
65class Ticket (Module):
66 template_key = 'ticket_template'
67
68 def get_ticket (self, id):
69 global fields
70 cnx = db.get_connection ()
71 cursor = cnx.cursor ()
72
73 fetch = string.join(fields, ',')
74
75 cursor.execute(('SELECT %s FROM ticket ' % fetch) + 'WHERE id=%s', id)
76 row = cursor.fetchone ()
77 cursor.close ()
78
79 info = {'ticket': id }
80 for i in range(len(fields)):
81 info[fields[i]] = row[i] or ''
82 return info
83
84 def save_changes (self, id, old, new):
85 global fields
86
87 if new.has_key('action'):
88 if new['action'] == 'accept':
89 new['status'] = 'assigned'
90 new['owner'] = auth.get_authname()
91 if new['action'] == 'resolve':
92 new['status'] = 'closed'
93 new['resolution'] = new['resolve_resolution']
94 elif new['action'] == 'reassign':
95 new['owner'] = new['reassign_owner']
96 new['status'] = 'assigned'
97 elif new['action'] == 'reopen':
98 new['status'] = 'reopened'
99 new['resolution'] = ''
100
101 changed = 0
102 change = ''
103 cnx = db.get_connection ()
104 cursor = cnx.cursor()
105 now = int(time.time())
106 authname = auth.get_authname ()
107 for name in fields.keys():
108 if new.has_key(name) and (not old.has_key(name) or old[name] != new[name]):
109 cursor.execute ('INSERT INTO ticket_change '
110 '(ticket, time, author, field, oldvalue, newvalue) '
111 'VALUES (%s, %s, %s, %s, %s, %s)',
112 id, now, authname, name, old[name], new[name])
113 cursor.execute ('UPDATE ticket SET %s=%s WHERE id=%s',
114 name, new[name], id)
115 changed = 1
116 if new.has_key('comment') and len(new['comment']) > 0:
117 cursor.execute ('INSERT INTO ticket_change '
118 '(ticket,time,author,field,oldvalue,newvalue) '
119 "VALUES (%s, %s, %s, 'comment', '', %s)",
120 id, now, authorname, new['comment'])
121 changed = 1
122 if changed:
123 cursor.execute ('UPDATE ticket SET changetime=%s WHERE id=%s',
124 now, id)
125 cnx.commit()
126
127 def create_ticket (self):
128 perm.assert_permission (perm.TICKET_CREATE)
129
130 cnx = db.get_connection ()
131 cursor = cnx.cursor()
132 global fields
133 data = {}
134 for field in fields:
135 if self.args.has_key(field):
136 data[field] = self.args[field]
137 now = int(time.time())
138 data['time'] = now
139 data['changetime'] = now
140
141 if not data.has_key('owner') or data['owner'] == '':
142 # Assign it to the default owner
143 cursor.execute('SELECT owner FROM component '
144 'WHERE name=%s', data['component'])
145 owner = cursor.fetchone()[0]
146 data['owner'] = owner
147
148 nstr = string.join (data.keys(), ',')
149 vstr = ('%s,' * len(data.keys()))[:-1]
150
151 cursor.execute ('INSERT INTO ticket (%s) VALUES(%s)' % (nstr, vstr),
152 *data.values())
153 id = cnx.db.sqlite_last_insert_rowid ()
154 cnx.commit()
155
156 # redirect to the Ticket module to get a GET request
157 redirect (ticket_href(id))
158
159 def get_changes(self, id):
160 cnx = db.get_connection ()
161 cursor = cnx.cursor()
162 cursor.execute('SELECT time, author, field, oldvalue, newvalue '
163 'FROM ticket_change '
164 'WHERE ticket=%s ORDER BY time', id)
165
166 out = StringIO.StringIO()
167 curr_author = None
168 curr_date = 0
169 comment = None
170 while 1:
171 row = cursor.fetchone()
172 if row == None:
173 break
174
175 date = int(row[0])
176 author = row[1]
177 field = row[2]
178 old = row[3]
179 new = row[4]
180 if date != curr_date or author != curr_author:
181 if comment:
182 out.write ('\ncomment:\n%s\n' % comment)
183 comment = None
184 curr_date = date
185 curr_author = author
186 out.write('\n--- modified by %s %s ---\n\n'
187 % (curr_author,
188 time.strftime('%F %H:%M', time.localtime(curr_date))))
189 if field == 'comment':
190 comment = new
191 continue
192 if new == '':
193 out.write ("cleared <b>%s</b>\n" %
194 (field))
195 elif old == '':
196 out.write ("<b>%s</b> set to <b>%s</b>\n" %
197 (field, new))
198 else:
199 out.write ("<b>%s</b> changed from <b>%s</b> to <b>%s</b>\n" %
200 (field, old, new))
201 if comment:
202 out.write ('\ncomment:\n%s\n' % comment)
203 comment = None
204
205 return out.getvalue()
206
207 def get_actions(self, info):
208 out = StringIO.StringIO()
209 out.write ('<input type="radio" name="action" value="leave" '
210 'checked="checked">&nbsp;leave as %s<br>' % info['status'])
211
212 if info['status'] == 'new':
213 out.write ('<input type="radio" name="action" value="accept">'
214 '&nbsp;accept ticket<br>')
215 if info['status'] == 'closed':
216 out.write ('<input type="radio" name="action" value="reopen">'
217 '&nbsp;reopen ticket<br>')
218 if info['status'] in ['new', 'assigned', 'reopened']:
219 out.write ('<input type="radio" name="action" value="resolve">'
220 '&nbsp;resolve as: '
221 '<select name="resolve_resolution">'
222 '<option selected>fixed</option>'
223 '<option>invalid</option>'
224 '<option>wontfix</option>'
225 '<option>duplicate</option>'
226 '<option>worksforme</option>'
227 '</select><br>')
228 out.write ('<input type="radio" name="action" value="reassign">'
229 '&nbsp;reassign ticket to:'
230 '&nbsp<input type="text" name="reassign_owner" '
231 'value="%s">' % info['owner'])
232 return out.getvalue()
233
234 def render (self):
235
236 if self.args.has_key('action'):
237 action = self.args['action']
238 else:
239 action = 'view'
240
241 if action == 'create':
242 self.create_ticket ()
243 try:
244 id = int(self.args['id'])
245 except:
246 redirect (menu_href ())
247
248 if action in ['leave', 'accept', 'reopen', 'resolve', 'reassign']:
249 # save changes and redirect to avoid the POST request
250 old = self.get_ticket(id)
251 perm.assert_permission (perm.TICKET_MODIFY)
252 self.save_changes (id, old, self.args)
253 redirect (ticket_href (id))
254
255 perm.assert_permission (perm.TICKET_VIEW)
256
257 info = self.get_ticket(id)
258 for key in info.keys():
259 self.namespace[key] = info[key]
260
261 self.namespace['title'] = 'Ticket #%d' % id
262
263 self.namespace['component_select'] = enum_selector ('SELECT name FROM component ORDER BY name',
264 'component',
265 info['component'])
266 self.namespace['milestone_select'] = enum_selector ('SELECT name FROM milestone ORDER BY name',
267 'milestone',
268 info['milestone'])
269 self.namespace['severity_select'] = enum_selector ('SELECT name FROM enum WHERE type=\'severity\' ORDER BY name',
270 'severity',
271 info['severity'])
272 self.namespace['priority_select'] = enum_selector ('SELECT name FROM enum WHERE type=\'priority\' ORDER BY name',
273 'priority',
274 info['priority'])
275 self.namespace['version_select'] = enum_selector ('SELECT name FROM version ORDER BY name',
276 'version',
277 info['version'])
278
279 self.namespace['actions'] = self.get_actions(info)
280 self.namespace['changes'] = self.get_changes(id)
281 self.namespace['opened'] = time.strftime('%F %H:%M',
282 time.localtime(int(info['time'])))
283
Note: See TracBrowser for help on using the repository browser.