Ticket #454: comments-edit-11-6.patch
| File comments-edit-11-6.patch, 11.4 KB (added by andrew.macheret@…, 2 years ago) |
|---|
-
trac/ticket/api.py
345 345 def get_permission_actions(self): 346 346 return ['TICKET_APPEND', 'TICKET_CREATE', 'TICKET_CHGPROP', 347 347 'TICKET_VIEW', 'TICKET_EDIT_CC', 'TICKET_EDIT_DESCRIPTION', 348 'TICKET_EDIT_COMMENT', 348 349 ('TICKET_MODIFY', ['TICKET_APPEND', 'TICKET_CHGPROP']), 349 350 ('TICKET_ADMIN', ['TICKET_CREATE', 'TICKET_MODIFY', 350 351 'TICKET_VIEW', 'TICKET_EDIT_CC', 351 'TICKET_EDIT_DESCRIPTION'])] 352 'TICKET_EDIT_DESCRIPTION', 353 'TICKET_EDIT_COMMENT'])] 352 354 353 355 # IWikiSyntaxProvider methods 354 356 -
trac/ticket/web_ui.py
39 39 from trac.timeline.api import ITimelineEventProvider 40 40 from trac.util import get_reporter_id 41 41 from trac.util.compat import any 42 from trac.util.datefmt import to_timestamp, utc 42 from trac.util.datefmt import parse_date, pretty_timedelta, to_datetime, \ 43 format_datetime, to_timestamp, utc 43 44 from trac.util.text import CRLF, shorten_line, obfuscate_email_address, \ 44 45 exception_to_unicode 45 46 from trac.util.presentation import separated … … 465 466 return self._render_history(req, ticket, data, text_fields) 466 467 elif action == 'diff': 467 468 return self._render_diff(req, ticket, data, text_fields) 468 elif req.method == 'POST': # 'Preview' or 'Submit' 469 # Comment edit preview is a special case, similar to 'View' action 470 elif (req.method == 'POST' and 'preview_comment' in req.args and 471 'TICKET_EDIT_COMMENT' in req.perm(ticket.resource)): 472 data['comment_preview'] = req.args.get('edited_comment') 473 data['cnum_edit'] = req.args.get('comment_num') 474 field_changes = {} 475 elif req.method == 'POST': # 'Preview' or 'Submit' or Comment Edit 476 # Cancel comment edit 477 if 'cancel_comment' in req.args: 478 req.redirect(req.href.ticket(ticket.id)) 479 # Edit a ticket comment 480 elif ('edit_comment' in req.args and 481 'TICKET_EDIT_COMMENT' in req.perm(ticket.resource)): 482 author = req.args.get('comment_author') 483 if (author == req.authname or 484 'TRAC_ADMIN' in req.perm(ticket.resource)): 485 comment = req.args.get('edited_comment') 486 comment += "^^%s&%s^^" % (to_timestamp(datetime.now(utc)), 487 get_reporter_id(req, 'author')) 488 when = req.args.get('edit_comment_when') 489 when_ts = to_timestamp(parse_date(when, req.tz)) 490 ticket.edit_comment(comment, when_ts) 491 req.redirect(req.href.ticket(ticket.id)) 492 469 493 # Do any action on the ticket? 470 494 actions = TicketSystem(self.env).get_available_actions( 471 495 req, ticket) … … 1166 1190 """Insert ticket data into the template `data`""" 1167 1191 replyto = req.args.get('replyto') 1168 1192 data['replyto'] = replyto 1193 if req.args.get('cnum_edit'): 1194 data['cnum_edit'] = req.args.get('cnum_edit') 1169 1195 data['version'] = ticket.resource.version 1170 1196 data['description_change'] = None 1171 1197 … … 1386 1412 current['cnum'] = autonum 1387 1413 # some common processing for fields 1388 1414 if field == 'comment': 1415 # find comments that have been edited and create pretty 1416 # "edited by" messages for them 1417 m = re.search('\^\^(.+?)\&(.+?)\^\^$', new) 1418 if m: 1419 ts = int(m.group(1)) 1420 user = m.group(2) 1421 verb = 'Edited' 1422 if re.search('^\^\^(.+?)\&(.+?)\^\^$', new): 1423 verb = 'Comment removed' # Comment is empty! 1424 current['comment_edited'] = ("\n\n''%s %s ago by %s.''" 1425 % (verb, pretty_timedelta(to_datetime(ts)), user)) 1426 new = new[:m.start(0)] 1389 1427 current['comment'] = new 1390 1428 if old: 1391 1429 if '.' in old: # retrieve parent.child relationship -
trac/ticket/model.py
349 349 350 350 for listener in TicketSystem(self.env).change_listeners: 351 351 listener.ticket_deleted(self) 352 353 def edit_comment(self, cmt, ts, db=None): 354 db, handle_ta = self._get_db_for_write(db) 355 cursor = db.cursor() 352 356 357 cursor.execute("UPDATE ticket_change SET newvalue=%s " 358 "WHERE ticket=%s AND time=%s AND field='comment'", 359 (cmt, self.id, ts)) 360 if handle_ta: 361 db.commit() 353 362 354 363 def simplify_whitespace(name): 355 364 """Strip spaces and remove duplicate spaces within names""" -
trac/ticket/templates/ticket.html
49 49 <a href="#comment:$cnum"><small>$prefix$cnum</small></a> 50 50 </py:def> 51 51 52 <py:def function="display_change(change )">52 <py:def function="display_change(change, edit_cnum=0)"> 53 53 <ul py:if="change.fields" class="changes"> 54 54 <li py:for="field_name, field in change.fields.items()"> 55 55 <strong>${field_name}</strong> … … 73 73 </py:choose> 74 74 </li> 75 75 </ul> 76 <div py:if="'comment' in change" class="comment searchable" xml:space="preserve"> 77 ${wiki_to_html(context, change.comment, escape_newlines=preserve_newlines)} 76 <div py:if="'comment' in change and (str(change.cnum) != cnum_edit or comment_preview)" class="comment searchable ${(comment_preview and cnum_edit == str(change.cnum)) and 'ticketdraft'}" xml:space="preserve"> 77 <py:choose test="comment_preview and cnum_edit == str(change.cnum)"> 78 <py:when>${wiki_to_html(context, comment_preview, escape_newlines=preserve_newlines)}</py:when> 79 <py:otherwise>${wiki_to_html(context, change.comment, escape_newlines=preserve_newlines)}</py:otherwise> 80 </py:choose> 81 <py:if test="change.comment_edited and not (comment_preview and cnum_edit == str(change.cnum))"> 82 ${wiki_to_html(context, change.comment_edited, escape_newlines=preserve_newlines)} 83 </py:if> 78 84 </div> 79 85 </py:def> 80 86 … … 205 211 <py:if test="ticket.exists and changes"> 206 212 <h2>Change History</h2> 207 213 <div id="changelog"> 208 < form py:for="change in changes" method="get" action="#comment" class="printableform">214 <py:for each="change in changes" class="printableform"> 209 215 <div class="change"> 210 216 <h3 class="change" id="${'cnum' in change and 'comment:%d' % change.cnum or None}"> 211 217 <span class="threading" py:if="replies and 'cnum' in change" … … 224 230 </span> 225 231 Changed ${dateinfo(change.date)} ago by ${authorinfo(change.author)} 226 232 </h3> 227 <div py:if="'cnum' in change and can_append" class="inlinebuttons"> 228 <input type="hidden" name="replyto" value="${change.cnum}" /> 229 <input type="submit" value="Reply" title="Reply to comment ${change.cnum}" /> 233 <div class="inlinebuttons"> 234 <form py:if="'cnum' in change and can_append" 235 method="get" action="#comment" class="changelogbuttons"> 236 <p> 237 <input type="hidden" name="replyto" value="${change.cnum}" /> 238 <input type="submit" value="${_('Reply')}" title="Reply to comment ${change.cnum}" /> 239 </p> 240 </form> 241 <form py:if="'TICKET_EDIT_COMMENT' in perm(ticket.resource) and 242 (authname == change.author or 'TRAC_ADMIN' in perm(ticket.resource))" 243 method="get" action="#comment:${change.cnum}" class="changelogbuttons"> 244 <p> 245 <input type="hidden" name="cnum_edit" value="${change.cnum}" /> 246 <input type="submit" value="${_('Edit')}" title="Edit comment ${change.cnum}" /> 247 </p> 248 </form> 230 249 </div> 231 ${display_change(change)} 250 ${display_change(change, ('TICKET_EDIT_COMMENT' in perm(ticket.resource) and cnum_edit or 0))} 251 <form method="post" py:if="'TICKET_EDIT_COMMENT' in perm(ticket.resource) and str(change.cnum) == cnum_edit"> 252 <p> 253 <py:choose test="comment_preview"> 254 <py:when><textarea name="edited_comment" class="wikitext" rows="10" cols="78">${comment_preview}</textarea></py:when> 255 <py:otherwise><textarea name="edited_comment" class="wikitext" rows="10" cols="78">${change.comment}</textarea></py:otherwise> 256 </py:choose> 257 </p> 258 <input type="hidden" name="edit_comment_when" value="${change.date.isoformat()}" /> 259 <input type="hidden" name="comment_author" value="${change.author}" /> 260 <input type="hidden" name="comment_num" value="${change.cnum}" /> 261 <input type="submit" name="preview_comment" value="${_('Preview')}" title='Preview changes to comment ${change.cnum}' /> 262 <input type="submit" name="edit_comment" value="${_('Submit changes')}" title="Submit changes to comment ${change.cnum}" /> 263 <input type="submit" name="cancel_comment" value="${_('Cancel')}" title="Cancel comment edit" /> 264 </form> 232 265 </div> 233 </ form>266 </py:for> 234 267 </div> 235 268 </py:if> 236 269 </py:if> -
trac/htdocs/css/ticket.css
76 76 } 77 77 78 78 #changelog { border: 1px outset #996; padding: 1em } 79 #changelog .changelogbuttons { float: right; } 80 #changelog .changelogbuttons p { margin: 0; } 79 81 #preview { border: 1px solid #d7d7d7; padding: 1em } 80 82 #preview h3, #changelog h3 { 81 83 border-bottom: 1px solid #d7d7d7; -
trac/util/datefmt.py
184 184 185 185 _ISO_8601_RE = re.compile(r'(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d))?)?' # date 186 186 r'(?:T(\d\d)(?::?(\d\d)(?::?(\d\d))?)?)?' # time 187 r'(Z ?(?:([-+])?(\d\d):?(\d\d)?)?)?$' # timezone187 r'(Z*?(?:([-+])?(\d\d):?(\d\d)?)?)?$' # timezone 188 188 ) 189 189 190 190 def parse_date(text, tzinfo=None):
