Edgewall Software

Ticket #8884: 8884-worflow-fixes-0.11-r8965.patch

File 8884-worflow-fixes-0.11-r8965.patch, 6.2 KB (added by rblank, 2 years ago)

Backport to 0.11-stable.

  • trac/ticket/model.py

    diff --git a/trac/ticket/model.py b/trac/ticket/model.py
    a b  
    3636 
    3737class Ticket(object): 
    3838 
     39    # Fields that must not be modified directly by the user 
     40    protected_fields = ('resolution', 'status') 
     41 
    3942    id_is_valid = staticmethod(lambda num: 0 < int(num) <= 1L << 31) 
    4043 
    4144    def __init__(self, env, tkt_id=None, db=None, version=None): 
     
    6467    def _init_defaults(self, db=None): 
    6568        for field in self.fields: 
    6669            default = None 
    67             if field['name'] in ['resolution', 'status']: 
     70            if field['name'] in self.protected_fields: 
    6871                # Ignore for new - only change through workflow 
    6972                pass 
    7073            elif not field.get('custom'): 
  • trac/ticket/templates/ticket.html

    diff --git a/trac/ticket/templates/ticket.html b/trac/ticket/templates/ticket.html
    a b  
    401401          </label> 
    402402        </p> 
    403403        <div class="buttons"> 
    404           <input py:if="not ticket.exists" type="hidden" name="field_status" value="new" /> 
    405404          <py:if test="ticket.exists"> 
    406405            <input type="hidden" name="ts" value="${timestamp}" /> 
    407406            <input type="hidden" name="replyto" value="${replyto}" /> 
  • trac/ticket/web_ui.py

    diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
    a b  
    3838from trac.ticket.notification import TicketNotifyEmail 
    3939from trac.timeline.api import ITimelineEventProvider 
    4040from trac.util import get_reporter_id 
    41 from trac.util.compat import any 
     41from trac.util.compat import any, set 
    4242from trac.util.datefmt import to_timestamp, utc 
    4343from trac.util.text import CRLF, shorten_line, obfuscate_email_address, \ 
    4444                           exception_to_unicode 
     
    383383                del req.args['field_owner'] 
    384384 
    385385        self._populate(req, ticket, plain_fields) 
     386        ticket.values['status'] = 'new'     # Force initial status 
    386387        reporter_id = req.args.get(field_reporter) or \ 
    387388                      get_reporter_id(req, 'author') 
    388389        ticket.values['reporter'] = reporter_id 
     
    489490            if problems: 
    490491                for problem in problems: 
    491492                    add_warning(req, problem) 
    492                     add_warning(req, 
    493                                 tag(tag.p('Please review your configuration, ' 
    494                                           'probably starting with'), 
    495                                     tag.pre('[trac]\nworkflow = ...\n'), 
    496                                     tag.p('in your ', tag.tt('trac.ini'), '.')) 
    497                                 ) 
     493                add_warning(req, 
     494                            tag(tag.p('Please review your configuration, ' 
     495                                      'probably starting with'), 
     496                                tag.pre('[trac]\nworkflow = ...\n'), 
     497                                tag.p('in your ', tag.tt('trac.ini'), '.'))) 
    498498 
    499             self._apply_ticket_changes(ticket, field_changes) # Apply changes made by the workflow 
     499            # Apply changes made by the workflow 
     500            self._apply_ticket_changes(ticket, field_changes) 
    500501            # Unconditionally run the validation so that the user gets 
    501502            # information any and all problems.  But it's only valid if it 
    502503            # validates and there were no problems with the workflow side of 
     
    632633        return (action, entry, cc_list) 
    633634         
    634635    def _populate(self, req, ticket, plain_fields=False): 
    635         fields = req.args 
    636636        if not plain_fields: 
    637             fields = dict([(k[6:],v) for k,v in fields.items() 
     637            fields = dict([(k[6:], v) for k, v in req.args.iteritems() 
    638638                           if k.startswith('field_')]) 
     639        else: 
     640            fields = req.args.copy() 
     641        # Prevent direct changes to protected fields (status and resolution are 
     642        # set in the workflow, in get_ticket_changes()) 
     643        for each in Ticket.protected_fields: 
     644            fields.pop(each, None) 
     645            fields.pop('checkbox_' + each, None)    # See Ticket.populate() 
    639646        ticket.populate(fields) 
    640647        # special case for updating the Cc: field 
    641648        if 'cc_update' in req.args: 
     
    888895 
    889896        # If the ticket has been changed, check the proper permissions 
    890897        if ticket.exists and ticket._old: 
    891             cnt = 0 
    892             # EDIT_DESCRIPTION and CHGPROP are independent permissions 
    893             if 'description' in ticket._old: 
    894                 cnt = 1 
    895                 if 'TICKET_EDIT_DESCRIPTION' not in req.perm(resource): 
    896                     add_warning(req, _("No permission to edit description.")) 
    897                     valid = False 
    898             if len(ticket._old) > cnt: 
    899                 errmsg = _("No permission to change ticket fields.") 
    900                 if 'TICKET_CHGPROP' not in req.perm(resource): 
    901                     add_warning(req, errmsg) 
    902                     valid = False 
    903                 else: # per-field additional checks 
    904                    if 'reporter' in ticket._old and \ 
    905                        'TICKET_ADMIN' not in req.perm(resource): 
    906                     add_warning(req, errmsg) 
    907                     valid = False 
     898            # Status and resolution can be modified by the workflow even 
     899            # without having TICKET_CHGPROP 
     900            changed = set(ticket._old) - set(['status', 'resolution']) 
     901            if 'description' in changed \ 
     902                    and 'TICKET_EDIT_DESCRIPTION' not in req.perm(resource): 
     903                add_warning(req, _("No permission to edit the ticket " 
     904                                   "description.")) 
     905                valid = False 
     906            changed.discard('description') 
     907            if 'reporter' in changed \ 
     908                    and 'TICKET_ADMIN' not in req.perm(resource): 
     909                add_warning(req, _("No permission to change the ticket " 
     910                                   "reporter.")) 
     911                valid = False 
     912            changed.discard('reporter') 
     913            if changed and 'TICKET_CHGPROP' not in req.perm(resource): 
     914                add_warning(req, _("No permission to change ticket fields.")) 
     915                valid = False 
    908916            if not valid: 
    909917                ticket.values.update(ticket._old) 
    910918