Edgewall Software

Ticket #454: comments-edit-11-6.patch

File comments-edit-11-6.patch, 11.4 KB (added by andrew.macheret@…, 2 years ago)

Fixed the 11.5 patch to work for 11.6

  • trac/ticket/api.py

     
    345345    def get_permission_actions(self): 
    346346        return ['TICKET_APPEND', 'TICKET_CREATE', 'TICKET_CHGPROP', 
    347347                'TICKET_VIEW', 'TICKET_EDIT_CC', 'TICKET_EDIT_DESCRIPTION', 
     348                'TICKET_EDIT_COMMENT', 
    348349                ('TICKET_MODIFY', ['TICKET_APPEND', 'TICKET_CHGPROP']), 
    349350                ('TICKET_ADMIN', ['TICKET_CREATE', 'TICKET_MODIFY', 
    350351                                  'TICKET_VIEW', 'TICKET_EDIT_CC', 
    351                                   'TICKET_EDIT_DESCRIPTION'])] 
     352                                  'TICKET_EDIT_DESCRIPTION', 
     353                                  'TICKET_EDIT_COMMENT'])] 
    352354 
    353355    # IWikiSyntaxProvider methods 
    354356 
  • trac/ticket/web_ui.py

     
    3939from trac.timeline.api import ITimelineEventProvider 
    4040from trac.util import get_reporter_id 
    4141from trac.util.compat import any 
    42 from trac.util.datefmt import to_timestamp, utc 
     42from trac.util.datefmt import parse_date, pretty_timedelta, to_datetime, \ 
     43                              format_datetime, to_timestamp, utc 
    4344from trac.util.text import CRLF, shorten_line, obfuscate_email_address, \ 
    4445                           exception_to_unicode 
    4546from trac.util.presentation import separated 
     
    465466                return self._render_history(req, ticket, data, text_fields) 
    466467            elif action == 'diff': 
    467468                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 
    469493            # Do any action on the ticket? 
    470494            actions = TicketSystem(self.env).get_available_actions( 
    471495                req, ticket) 
     
    11661190        """Insert ticket data into the template `data`""" 
    11671191        replyto = req.args.get('replyto') 
    11681192        data['replyto'] = replyto 
     1193        if req.args.get('cnum_edit'): 
     1194            data['cnum_edit'] = req.args.get('cnum_edit') 
    11691195        data['version'] = ticket.resource.version 
    11701196        data['description_change'] = None 
    11711197 
     
    13861412                    current['cnum'] = autonum 
    13871413            # some common processing for fields 
    13881414            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)] 
    13891427                current['comment'] = new 
    13901428                if old: 
    13911429                    if '.' in old: # retrieve parent.child relationship 
  • trac/ticket/model.py

     
    349349 
    350350        for listener in TicketSystem(self.env).change_listeners: 
    351351            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() 
    352356 
     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()   
    353362 
    354363def simplify_whitespace(name): 
    355364    """Strip spaces and remove duplicate spaces within names""" 
  • trac/ticket/templates/ticket.html

     
    4949      <a href="#comment:$cnum"><small>$prefix$cnum</small></a> 
    5050    </py:def> 
    5151 
    52     <py:def function="display_change(change)"> 
     52    <py:def function="display_change(change, edit_cnum=0)"> 
    5353      <ul py:if="change.fields" class="changes"> 
    5454        <li py:for="field_name, field in change.fields.items()"> 
    5555          <strong>${field_name}</strong> 
     
    7373          </py:choose> 
    7474        </li> 
    7575      </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> 
    7884      </div> 
    7985    </py:def> 
    8086 
     
    205211        <py:if test="ticket.exists and changes"> 
    206212          <h2>Change History</h2> 
    207213          <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"> 
    209215              <div class="change"> 
    210216                <h3 class="change" id="${'cnum' in change and 'comment:%d' % change.cnum or None}"> 
    211217                  <span class="threading" py:if="replies and 'cnum' in change" 
     
    224230                  </span> 
    225231                  Changed ${dateinfo(change.date)} ago by ${authorinfo(change.author)} 
    226232                </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>               
    230249                </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> 
    232265              </div> 
    233             </form> 
     266            </py:for> 
    234267          </div> 
    235268        </py:if> 
    236269      </py:if> 
  • trac/htdocs/css/ticket.css

     
    7676} 
    7777 
    7878#changelog { border: 1px outset #996; padding: 1em } 
     79#changelog .changelogbuttons { float: right; } 
     80#changelog .changelogbuttons p { margin: 0; } 
    7981#preview { border: 1px solid #d7d7d7; padding: 1em } 
    8082#preview h3, #changelog h3 { 
    8183 border-bottom: 1px solid #d7d7d7; 
  • trac/util/datefmt.py

     
    184184 
    185185_ISO_8601_RE = re.compile(r'(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d))?)?'   # date 
    186186                          r'(?:T(\d\d)(?::?(\d\d)(?::?(\d\d))?)?)?' # time 
    187                           r'(Z?(?:([-+])?(\d\d):?(\d\d)?)?)?$'      # timezone 
     187                          r'(Z*?(?:([-+])?(\d\d):?(\d\d)?)?)?$'      # timezone 
    188188                          ) 
    189189 
    190190def parse_date(text, tzinfo=None):