Edgewall Software

Ticket #8884: 8884-workflow-fixes-r8981.patch

File 8884-workflow-fixes-r8981.patch, 5.9 KB (added by rblank, 2 years ago)

Updated with feedback from this ticket and IRC.

  • trac/ticket/model.py

    diff --git a/trac/ticket/model.py b/trac/ticket/model.py
    a b  
    3535 
    3636class Ticket(object): 
    3737 
     38    # Fields that must not be modified directly by the user 
     39    protected_fields = ('resolution', 'status', 'time', 'changetime') 
     40 
    3841    @staticmethod 
    3942    def id_is_valid(num): 
    4043        return 0 < int(num) <= 1L << 31 
     
    7376    def _init_defaults(self, db=None): 
    7477        for field in self.fields: 
    7578            default = None 
    76             if field['name'] in ['resolution', 'status', 'time', 'changetime']: 
     79            if field['name'] in self.protected_fields: 
    7780                # Ignore for new - only change through workflow 
    7881                pass 
    7982            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  
    487487          <a href="#attachments" title="Go to the list of attachments">Attachments</a> &uarr; 
    488488        </div> 
    489489        <div class="buttons"> 
    490           <input py:if="not ticket.exists" type="hidden" name="field_status" value="new" /> 
    491490          <py:if test="ticket.exists"> 
    492491            <input type="hidden" name="ts" value="${timestamp}" /> 
    493492            <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  
    374374                del req.args['field_owner'] 
    375375 
    376376        self._populate(req, ticket, plain_fields) 
     377        ticket.values['status'] = 'new'     # Force initial status 
    377378        reporter_id = req.args.get(field_reporter) or \ 
    378379                      get_reporter_id(req, 'author') 
    379380        ticket.values['reporter'] = reporter_id 
     
    506507            if problems: 
    507508                for problem in problems: 
    508509                    add_warning(req, problem) 
    509                     add_warning(req, 
    510                                 tag(tag.p('Please review your configuration, ' 
    511                                           'probably starting with'), 
    512                                     tag.pre('[trac]\nworkflow = ...\n'), 
    513                                     tag.p('in your ', tag.tt('trac.ini'), '.')) 
    514                                 ) 
     510                add_warning(req, 
     511                            tag(tag.p('Please review your configuration, ' 
     512                                      'probably starting with'), 
     513                                tag.pre('[trac]\nworkflow = ...\n'), 
     514                                tag.p('in your ', tag.tt('trac.ini'), '.'))) 
    515515 
    516             self._apply_ticket_changes(ticket, field_changes) # Apply changes made by the workflow 
     516            # Apply changes made by the workflow 
     517            self._apply_ticket_changes(ticket, field_changes) 
    517518            # Unconditionally run the validation so that the user gets 
    518519            # information any and all problems.  But it's only valid if it 
    519520            # validates and there were no problems with the workflow side of 
     
    658659        return (action, entry, cc_list) 
    659660         
    660661    def _populate(self, req, ticket, plain_fields=False): 
    661         fields = req.args 
    662662        if not plain_fields: 
    663             fields = dict([(k[6:], v) for k, v in fields.items() 
     663            fields = dict([(k[6:], v) for k, v in req.args.iteritems() 
    664664                           if k.startswith('field_')]) 
     665        else: 
     666            fields = req.args.copy() 
     667        # Prevent direct changes to protected fields (status and resolution are 
     668        # set in the workflow, in get_ticket_changes()) 
     669        for each in Ticket.protected_fields: 
     670            fields.pop(each, None) 
     671            fields.pop('checkbox_' + each, None)    # See Ticket.populate() 
    665672        ticket.populate(fields) 
    666673        # special case for updating the Cc: field 
    667674        if 'cc_update' in req.args: 
     
    10491056 
    10501057        # If the ticket has been changed, check the proper permissions 
    10511058        if ticket.exists and ticket._old: 
    1052             cnt = 0 
    1053             # EDIT_DESCRIPTION and CHGPROP are independent permissions 
    1054             if 'description' in ticket._old: 
    1055                 cnt = 1 
    1056                 if 'TICKET_EDIT_DESCRIPTION' not in req.perm(resource): 
    1057                     add_warning(req, _("No permission to edit description.")) 
    1058                     valid = False 
    1059             if len(ticket._old) > cnt: 
    1060                 errmsg = _("No permission to change ticket fields.") 
    1061                 if 'TICKET_CHGPROP' not in req.perm(resource): 
    1062                     add_warning(req, errmsg) 
    1063                     valid = False 
    1064                 else: # per-field additional checks 
    1065                     if 'reporter' in ticket._old and \ 
    1066                        'TICKET_ADMIN' not in req.perm(resource): 
    1067                         add_warning(req, errmsg) 
    1068                         valid = False 
     1059            # Status and resolution can be modified by the workflow even 
     1060            # without having TICKET_CHGPROP 
     1061            changed = set(ticket._old) - set(['status', 'resolution']) 
     1062            if 'description' in changed \ 
     1063                    and 'TICKET_EDIT_DESCRIPTION' not in req.perm(resource): 
     1064                add_warning(req, _("No permission to edit the ticket " 
     1065                                   "description.")) 
     1066                valid = False 
     1067            changed.discard('description') 
     1068            if 'reporter' in changed \ 
     1069                    and 'TICKET_ADMIN' not in req.perm(resource): 
     1070                add_warning(req, _("No permission to change the ticket " 
     1071                                   "reporter.")) 
     1072                valid = False 
     1073            changed.discard('reporter') 
     1074            if changed and 'TICKET_CHGPROP' not in req.perm(resource): 
     1075                add_warning(req, _("No permission to change ticket fields.")) 
     1076                valid = False 
    10691077            if not valid: 
    10701078                ticket.values.update(ticket._old) 
    10711079