Example #1
0
 def change_workflow_config(self, lines):
     for (option, value) in lines:
         self.env.config.set('ticket-workflow', option, value)
     self.env.config.save()
     self.clear_ticket_system_field_cache()
     ticket_workflow = ConfigurableTicketWorkflow(self.env)
     ticket_workflow.actions = get_workflow_config(self.env.config)
Example #2
0
    def get_ticket_changes(self, req, ticket, action):
        this_action = ConfigurableTicketWorkflow(self.env).actions[action]

        # Enforce permissions
        if not 'TICKET_MODIFY' in req.perm(ticket.resource):
            # The user does not have any of the listed permissions, so we won't
            # do anything.
            return {}

        updated = {}
        # Status changes
        status = this_action['newstate']
        if status != '*':
            updated['status'] = status

        for operation in this_action['operations']:
            if operation == 'del_evaluation':
                updated['evaluation'] = ''
            elif operation == 'set_evaluation':
                newevaluation = req.args.get(
                    'action_%s_evaluate_evaluation' % action,
                    this_action.get('set_evaluation', '').strip())
                updated['evaluation'] = newevaluation

        return updated
Example #3
0
    def _get_action_controls(self, req, tickets):
        action_controls = []
        ts = TicketSystem(self.env)
        tickets_by_action = {}
        for t in tickets:
            ticket = Ticket(self.env, t['id'])
            available_actions = ts.get_available_actions(req, ticket)
            for action in available_actions:
                tickets_by_action.setdefault(action, []).append(ticket)

        # Sort the allowed actions by the 'default' key.
        allowed_actions = set(tickets_by_action.keys())
        workflow = ConfigurableTicketWorkflow(self.env)
        all_actions = sorted(
            ((action['default'], name)
             for name, action in workflow.get_all_actions().iteritems()),
            reverse=True)
        sorted_actions = [
            action[1] for action in all_actions if action[1] in allowed_actions
        ]
        for action in sorted_actions:
            first_label = None
            hints = []
            widgets = []
            ticket = tickets_by_action[action][0]
            for controller in self._get_action_controllers(
                    req, ticket, action):
                label, widget, hint = controller.render_ticket_action_control(
                    req, ticket, action)
                if not first_label:
                    first_label = label
                widgets.append(widget)
                hints.append(hint)
            action_controls.append((action, first_label, tag(widgets), hints))
        return action_controls
Example #4
0
    def get_ticket_changes(self, req, ticket, action):
        this_action = ConfigurableTicketWorkflow(self.env).actions[action]

        # Enforce permissions
        if not 'TICKET_MODIFY' in req.perm(ticket.resource):
            # The user does not have any of the listed permissions, so we won't
            # do anything.
            return {}

        updated = {}
        # Status changes
        status = this_action['newstate']
        if status != '*':
            updated['status'] = status

        for operation in this_action['operations']:
            if operation == 'del_evaluation':
                updated['evaluation'] = ''
            elif operation == 'set_evaluation':
                newevaluation = req.args.get('action_%s_evaluate_evaluation' %
                                             action,
                                             this_action.get('set_evaluation', '').strip())
                updated['evaluation'] = newevaluation

        return updated
Example #5
0
 def get_ticket_actions(self, req, ticket):
     actions_we_handle = []
     if req.authname != "anonymous" and "TICKET_MODIFY" in req.perm(ticket.resource):
         controller = ConfigurableTicketWorkflow(self.env)
         actions_we_handle = controller.get_actions_by_operation_for_req(req, ticket, "set_milestone")
     self.log.debug("set_milestone handles actions: %r", actions_we_handle)
     return actions_we_handle
Example #6
0
 def change_workflow_config(self, lines):
     for (option, value) in lines:
         self.env.config.set('ticket-workflow', option, value)
     self.env.config.save()
     self.clear_ticket_system_field_cache()
     ticket_workflow = ConfigurableTicketWorkflow(self.env)
     ticket_workflow.actions = get_workflow_config(self.env.config)
Example #7
0
 def get_all_status(self):
     all_status = set()
     controller = ConfigurableTicketWorkflow(self.env)
     for weight, action \
             in controller.get_actions_by_operation('code_review'):
         review_options = self._get_review_options(action)
         all_status.update(review_options.itervalues())
     return all_status
Example #8
0
 def get_all_status(self):
     all_status = set()
     controller = ConfigurableTicketWorkflow(self.env)
     ouractions = controller.get_actions_by_operation("code_review")
     for weight, action in ouractions:
         status = [status for option, status in self._get_review_options(action)]
         all_status.update(status)
     return all_status
Example #9
0
 def get_ticket_actions(self, req, ticket):
     actions_we_handle = []
     if req.is_authenticated and \
             'TICKET_MODIFY' in req.perm(ticket.resource):
         controller = ConfigurableTicketWorkflow(self.env)
         actions_we_handle = controller.get_actions_by_operation_for_req(
             req, ticket, 'set_milestone')
     self.log.debug('set_milestone handles actions: %r', actions_we_handle)
     return actions_we_handle
Example #10
0
 def get_all_status(self):
     all_status = set()
     controller = ConfigurableTicketWorkflow(self.env)
     ouractions = controller.get_actions_by_operation('code_review')
     for weight, action in ouractions:
         status = [status for option, status in
                   self._get_review_options(action)]
         all_status.update(status)
     return all_status
Example #11
0
    def get_ticket_actions(self, req, ticket):
        actions_we_handle = []
        if 'TICKET_MODIFY' in req.perm(ticket.resource):
            controller = ConfigurableTicketWorkflow(self.env)
            actions_we_handle += controller.get_actions_by_operation_for_req(
                req, ticket, 'set_evaluation')
            actions_we_handle += controller.get_actions_by_operation_for_req(
                req, ticket, 'del_evaluation')

        self.log.debug('evaluation handles actions: %r' % actions_we_handle)
        return actions_we_handle
Example #12
0
    def get_ticket_actions(self, req, ticket):
        actions_we_handle = []
        if 'TICKET_MODIFY' in req.perm(ticket.resource):
            controller = ConfigurableTicketWorkflow(self.env)
            actions_we_handle += controller.get_actions_by_operation_for_req(
                req, ticket, 'set_evaluation')
            actions_we_handle += controller.get_actions_by_operation_for_req(
                req, ticket, 'del_evaluation')

        self.log.debug('evaluation handles actions: %r' % actions_we_handle)
        return actions_we_handle
Example #13
0
 def get_ticket_actions(self, req, ticket):
     # The review action is available in those status where it has been
     # configured, for those users who have the TICKET_REVIEW permission, as
     # long as they are not the owner of the ticket (you can't review your
     # own work!).
     actions_we_handle = []
     if req.authname != ticket["owner"] and "TICKET_REVIEW" in req.perm(ticket.resource):
         controller = ConfigurableTicketWorkflow(self.env)
         actions_we_handle = controller.get_actions_by_operation_for_req(req, ticket, "code_review")
     self.log.debug("code review handles actions: %r" % actions_we_handle)
     return actions_we_handle
Example #14
0
    def test_ignores_other_operations(self):
        """Ignores operations not defined by ConfigurableTicketWorkflow.
        """
        self.env.config.set('ticket-workflow', 'review', 'assigned -> review')
        self.env.config.set('ticket-workflow', 'review.operations',
                            'CodeReview')
        ctw = ConfigurableTicketWorkflow(self.env)
        ticket = Ticket(self.env)
        ticket.populate({'summary': '#13013', 'status': 'assigned'})
        ticket.insert()
        req = MockRequest(self.env)

        self.assertNotIn((0, 'review'), ctw.get_ticket_actions(req, ticket))
Example #15
0
 def get_ticket_actions(self, req, ticket):
     # The review action is available in those status where it has been
     # configured, for those users who have the TICKET_REVIEW permission, as
     # long as they are not the owner of the ticket (you can't review your
     # own work!).
     actions_we_handle = []
     if req.authname != ticket['owner'] and \
                 'TICKET_REVIEW' in req.perm(ticket.resource):
         controller = ConfigurableTicketWorkflow(self.env)
         actions_we_handle = controller.get_actions_by_operation_for_req(
             req, ticket, 'code_review')
     self.log.debug('code review handles actions: %r', actions_we_handle)
     return actions_we_handle
Example #16
0
    def apply_action_side_effects(self, req, ticket, action):
        """Add a cross-reference comment to the other ticket"""
        # TODO: This needs a lot more error checking.
        id = 'action_%s_xref' % action
        ticketnum = req.args.get(id).strip('#')
        actions = ConfigurableTicketWorkflow(self.env).actions
        author = req.authname

        # Add a comment to the "remote" ticket to indicate this ticket is
        # related to it.
        format_string = actions[action].get('xref',
                                        'Ticket %s is related to this ticket')
        comment = format_string % ('#%s' % ticket.id)
        # FIXME: This assumes the referenced ticket exists.
        xticket = model.Ticket(self.env, ticketnum)
        # FIXME: We _assume_ we have sufficient permissions to comment on the
        # other ticket.
        xticket.save_changes(author, comment)

        # Add a comment to this ticket to indicate that the "remote" ticket is
        # related to it.  (But only if <action>.xref_local was set in the
        # config.)
        format_string = actions[action].get('xref_local',
            'Ticket %s was marked as related to this ticket')
        if format_string:
            comment = format_string % ('#%s' % ticketnum)
            time.sleep(1) # FIXME: Hack around IntegrityError
            # HACK: Grab a new ticket object to avoid getting
            # "OperationalError: no such column: new"
            xticket = model.Ticket(self.env, ticket.id)
            xticket.save_changes(author, comment)
Example #17
0
    def render_ticket_action_control(self, req, ticket, action):
        id, grade = self._get_grade(req, action)

        review_options = self._get_review_options(action)
        actions = ConfigurableTicketWorkflow(self.env).actions

        selected_value = grade or review_options[0][0]

        label = actions[action]['name']
        control = tag([
            "as: ",
            tag.select([
                tag.option(option, selected=(option == selected_value or None))
                for option, status in review_options
            ],
                       name=id,
                       id=id)
        ])
        if grade:
            new_status = self._get_new_status(req, ticket, action,
                                              review_options)
            hint = "Next status will be '%s'" % new_status
        else:
            hint = "Next status will be one of " + \
                   ', '.join(["'%s'" % status
                              for option, status in review_options])
        return (label, control, hint)
Example #18
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     hint = 'The owner will change to %s' % ticket['reporter']
     control = tag('')
     return (label, control, hint)
Example #19
0
 def render_ticket_action_control(self, req, ticket, action):
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['label']
     res_ms = self.__get_resolution_milestone_dict(ticket, action)
     resolutions = ''
     milestone = None
     for i, resolution in enumerate(res_ms):
         if i > 0:
             resolutions = "%s, '%s'" % (resolutions, resolution)
         else:
             resolutions = "'%s'" % resolution
             milestone = res_ms[resolution]
     hint = None
     if res_ms:
         try:
             Milestone(self.env, milestone)
         except ResourceNotFound:
             pass
         else:
             hint = _(
                 "For resolution %(resolutions)s the milestone will "
                 "be set to '%(milestone)s'.",
                 resolutions=resolutions,
                 milestone=milestone)
     return label, None, hint
Example #20
0
 def _get_ticket_transitions(self):
     groups_config = self.env.config['itteco-whiteboard-groups']
     
     if self._old_groups!=groups_config or self._transitions is None:
         actions = ConfigurableTicketWorkflow(self.env).actions
         transitions = [
             {
                 'newstatus': act_info['newstate'], 
                 'action': act_id, 
                 'oldstatuses':act_info['oldstates']
             } \
             for act_id, act_info in actions.iteritems()
                 if act_id!='_reset'
         ]
         
         self.env.log.debug('transitions="%s"' % transitions)
         self._transitions = transitions
     return self._transitions
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['label']
     hint = _("The '%(field)s' field will be set to '%(username)s'.",
              field=self._field_name(action, ticket),
              username=req.authname)
     control = html('')
     return (label, control, hint)
Example #22
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     hint = self.config.get('ticket-workflow',
                            action + '.run_external').strip()
     if hint is None:
         hint = "Will run external script."
     return (label, tag(''), hint)
Example #23
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     id = 'action_%s_xref' % action
     ticketnum = req.args.get(id, '')
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     hint = actions[action].get('xref_hint',
         'The specified ticket will be cross-referenced with this ticket')
     control = tag.input(type='text', id=id, name=id, value=ticketnum)
     return (label, control, hint)
Example #24
0
class TaskBoardChangeHandler(Component):
    implements(IRequestHandler)

    def __init__(self):
        self.controller = ConfigurableTicketWorkflow(self.env)

    # IRequestHandler methods

    def match_request(self, req):
        return req.path_info == '/taskboard'

    def process_request(self, req):
        self.env.log.debug("taskboard API received: %s" % req.args)
        if not req.args.get('id') or not req.args.get('status'):
            self._write_response(req, 400, {})
            return

        ticket = Ticket(self.env, int(req.args['id']))
        ticket_available_actions = []
        for weight, action in self.controller.get_ticket_actions(req, ticket):
            changes = self.controller.get_ticket_changes(req, ticket, action)
            if not changes.get('status'):
                continue
            if changes['status'] == req.args['status']:
                ticket_available_actions.append([ weight, action ])
        ticket_available_actions.sort()
        self.env.log.debug("taskboard API actions: %s" % ticket_available_actions)

        if len(ticket_available_actions) > 0:
            actions = ticket_available_actions.pop()
            self._write_response(req, 200, { 'action': actions[1] })
        else:
            self._write_response(req, 400, {})

    def _write_response(self, req, status=200, data={}):
        body = json.dumps(data)
        req.send_response(int(status))
        req.send_header('Content-Type', 'application/json; charset=UTF-8')
        req.send_header('Content-Length', str(len(body)))
        req.send_header('Cache-Control', 'no-cache')
        req.end_headers()
        req.write(body)
Example #25
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     new_owner = self._new_owner(ticket)
     if new_owner:
         hint = 'The owner will change to %s' % new_owner
     else:
         hint = 'The owner will be deleted.'
     control = tag('')
     return (label, control, hint)
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['label']
     fields = ["'%s'" % x for x in self._field_names(action, ticket)]
     hint = ngettext("The %(fields)s field will be cleared.",
                     "The %(fields)s fields will be cleared.",
                     len(fields),
                     fields=', '.join(fields))
     control = html('')
     return (label, control, hint)
Example #27
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     new_status = self._new_status(ticket, action)
     if new_status != ticket['status']:
         hint = 'The status will change to %s.' % new_status
     else:
         hint = ''
     control = tag('')
     return (label, control, hint)
Example #28
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     # check if the assigned milestone has been completed
     milestone = Milestone(self.env,ticket['milestone'])
     if milestone.is_completed:
         hint = 'The milestone will be reset'
     else:
         hint = ''
     control = tag('')
     return (label, control, hint)
Example #29
0
 def render_ticket_action_control(self, req, ticket, action):
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     res_ms = self.__get_resolution_milestone_dict(ticket, action)
     resolutions = ''
     milestone = None
     for i, resolution in enumerate(res_ms):
         if i > 0:
             resolutions = "%s, '%s'" % (resolutions, resolution)
         else:
             resolutions = "'%s'" % resolution
             milestone = res_ms[resolution]
     hint = _("For resolution %(resolutions)s the milestone will be "
              "set to '%(milestone)s'.",
              resolutions=resolutions, milestone=milestone)
     return (label, None, hint)
Example #30
0
    def render_ticket_action_control(self, req, ticket, action):
        this_action = ConfigurableTicketWorkflow(self.env).actions[action]
        status = this_action['newstate']
        operations = this_action['operations']

        control = []  # default to nothing
        hints = []
        if 'set_evaluation' in operations:
            evaluations = self._get_evaluation_options()
            if not evaluations:
                raise TracError(
                    _('Your workflow attempts to set an evaluation '
                      'but none is defined (configuration issue, '
                      'please contact your Trac admin).'))
            id = 'action_%s_evaluate_evaluation' % action
            if len(evaluations) == 1:
                evaluation = tag.input(type='hidden',
                                       id=id,
                                       name=id,
                                       value=evaluations[0])
                control.append(
                    tag_('as %(evaluation)s',
                         evaluation=tag(evaluations[0], evaluation)))
                hints.append(
                    _('The evaluation will be set to %(name)s',
                      name=evaluations[0]))
            else:
                selected_option = 1
                control.append(
                    tag_(
                        'as %(evaluation)s',
                        evaluation=tag.select([
                            tag.option(x,
                                       value=x,
                                       selected=(x == selected_option or None))
                            for x in evaluations
                        ],
                                              id=id,
                                              name=id)))
                hints.append(_('The evaluation will be set'))
        #if 'del_evaluation' in operations:
        #    hints.append(_('The evaluation will be deleted'))

        return (this_action['name'], tag(*control),
                '. '.join(hints) + '.' if hints else '')
Example #31
0
 def render_ticket_action_control(self, req, ticket, action):
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['label']
     hint = None
     old_milestone = ticket._old.get('milestone')
     if old_milestone is None:
         resolutions, milestone = \
             self._get_resolutions_and_milestone(action)
         if resolutions:
             try:
                 Milestone(self.env, milestone)
             except ResourceNotFound:
                 pass
             else:
                 res_hint = ', '.join("'%s'" % r for r in resolutions)
                 hint = _("For resolution %(resolutions)s the milestone "
                          "will be set to '%(milestone)s'.",
                          resolutions=res_hint, milestone=milestone)
     return label, None, hint
Example #32
0
    def render_ticket_action_control(self, req, ticket, action):
        id, selected = self._get_selected(req, action)

        review_options = self._get_review_options(action)
        actions = ConfigurableTicketWorkflow(self.env).actions

        label = actions[action]['label']
        control = tag(["as: ",
                       tag.select([
                           tag.option(option,
                                      selected=(option == selected or None))
                           for option in review_options],
                           name=id, id=id)])
        if selected:
            new_status = self._get_new_status(req, action, review_options)
            hint = "Next status will be '%s'" % new_status
        else:
            hint = "Next status will be one of " + \
                   ', '.join("'%s'" % st for st in review_options.itervalues())
        return label, control, hint
 def get_ticket_actions(self, req, ticket):
     actions =  \
         ConfigurableTicketWorkflow.get_ticket_actions(self, req, ticket)
     actions = self.filter_actions(actions, ticket)
     return actions
Example #34
0
 def get_ticket_actions(self, req, ticket):
     """Finds the actions that use this operation"""
     controller = ConfigurableTicketWorkflow(self.env)
     return controller.get_actions_by_operation_for_req(req, ticket,
                                                        'run_external')
Example #35
0
 def render_ticket_action_control(self, req, ticket, action):
     """Returns the action control"""
     actions = ConfigurableTicketWorkflow(self.env).actions
     label = actions[action]['name']
     return (label, tag(''), '')
Example #36
0
 def get_ticket_actions(self, req, ticket):
     """Finds the actions that use this operation"""
     controller = ConfigurableTicketWorkflow(self.env)
     return controller.get_actions_by_operation_for_req(req, ticket,
                                                        'run_external')
Example #37
0
 def get_ticket_actions(self, req, ticket):
     controller = ConfigurableTicketWorkflow(self.env)
     return controller.get_actions_by_operation_for_req(req, ticket, 'vote')
 def get_configurable_workflow(self):
     controllers = TicketSystem(self.env).action_controllers
     for controller in controllers:
         if isinstance(controller, ConfigurableTicketWorkflow):
             return controller
     return ConfigurableTicketWorkflow(self.env)
Example #39
0
 def get_ticket_actions(self, req, ticket):        
     actions =  ConfigurableTicketWorkflow.get_ticket_actions(self, req, ticket)        
     actions = self.filter_actions(actions, ticket)
     return actions
Example #40
0
 def get_ticket_actions(self, req, ticket):
     controller = ConfigurableTicketWorkflow(self.env)
     return controller.get_actions_by_operation_for_req(req, ticket, 'vote')
Example #41
0
 def __init__(self):
     self.controller = ConfigurableTicketWorkflow(self.env)