| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2010-2015 Roberto Longobardi |
|---|
| 4 | # |
|---|
| 5 | # This file is part of the Test Manager plugin for Trac. |
|---|
| 6 | # |
|---|
| 7 | # This software is licensed as described in the file COPYING, which |
|---|
| 8 | # you should have received as part of this distribution. The terms |
|---|
| 9 | # are also available at: |
|---|
| 10 | # https://trac-hacks.org/wiki/TestManagerForTracPluginLicense |
|---|
| 11 | # |
|---|
| 12 | # Author: Roberto Longobardi <otrebor.dev@gmail.com> |
|---|
| 13 | # |
|---|
| 14 | |
|---|
| 15 | from trac.core import Component, implements |
|---|
| 16 | from trac.perm import PermissionSystem |
|---|
| 17 | from trac.util.html import html as tag |
|---|
| 18 | from trac.util.text import obfuscate_email_address |
|---|
| 19 | from trac.web.chrome import Chrome |
|---|
| 20 | |
|---|
| 21 | from codereview.tracgenericworkflow.api import IWorkflowOperationProvider |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | # Out-of-the-box operations |
|---|
| 25 | class WorkflowStandardOperations(Component): |
|---|
| 26 | """Adds a set of standard, out-of-the-box workflow operations.""" |
|---|
| 27 | |
|---|
| 28 | implements(IWorkflowOperationProvider) |
|---|
| 29 | |
|---|
| 30 | # IWorkflowOperationProvider methods |
|---|
| 31 | def get_implemented_operations(self): |
|---|
| 32 | self.log.debug(">>> WorkflowStandardOperations - get_implemented_operations") |
|---|
| 33 | self.log.debug("<<< WorkflowStandardOperations - get_implemented_operations") |
|---|
| 34 | |
|---|
| 35 | yield 'set_owner' |
|---|
| 36 | yield 'set_owner_to_self' |
|---|
| 37 | yield 'std_notify' |
|---|
| 38 | |
|---|
| 39 | def get_operation_control(self, req, action, operation, res_wf_state, resource): |
|---|
| 40 | self.log.debug(">>> WorkflowStandardOperations - get_operation_control: %s" % operation) |
|---|
| 41 | |
|---|
| 42 | id_ = 'action_%s_operation_%s' % (action, operation) |
|---|
| 43 | |
|---|
| 44 | # A custom field named "owner" is required in the ResourceWorkflowState |
|---|
| 45 | # class for this operation to be available |
|---|
| 46 | |
|---|
| 47 | self.env.log.debug(res_wf_state.fields) |
|---|
| 48 | |
|---|
| 49 | if operation == 'set_owner' and self._has_field_named('owner', res_wf_state.fields): |
|---|
| 50 | self.log.debug("Creating control for setting owner.") |
|---|
| 51 | |
|---|
| 52 | current_owner = res_wf_state['owner'] or '(none)' |
|---|
| 53 | if not (Chrome(self.env).show_email_addresses |
|---|
| 54 | or 'EMAIL_VIEW' in req.perm(resource)): |
|---|
| 55 | format_user = obfuscate_email_address |
|---|
| 56 | else: |
|---|
| 57 | format_user = lambda address: address |
|---|
| 58 | current_owner = format_user(current_owner) |
|---|
| 59 | |
|---|
| 60 | self.log.debug("Current owner is %s." % current_owner) |
|---|
| 61 | |
|---|
| 62 | selected_owner = req.args.get(id_, req.authname) |
|---|
| 63 | |
|---|
| 64 | control = None |
|---|
| 65 | hint = '' |
|---|
| 66 | |
|---|
| 67 | owners = None |
|---|
| 68 | |
|---|
| 69 | available_owners = self.config.get(resource.realm, 'available_owners') |
|---|
| 70 | if available_owners is not None and not available_owners == '': |
|---|
| 71 | owners = [x.strip() for x in |
|---|
| 72 | available_owners.split(',')] |
|---|
| 73 | elif self.config.getbool(resource.realm, 'restrict_owner'): |
|---|
| 74 | target_permission = self.config.get(resource.realm, 'restrict_owner_to_permission') |
|---|
| 75 | if target_permission is not None and not target_permission == '': |
|---|
| 76 | perm = PermissionSystem(self.env) |
|---|
| 77 | owners = perm.get_users_with_permission(target_permission) |
|---|
| 78 | owners.sort() |
|---|
| 79 | |
|---|
| 80 | if owners == None: |
|---|
| 81 | owner = req.args.get(id_, req.authname) |
|---|
| 82 | control = tag('Assign to ', |
|---|
| 83 | tag.input(type='text', id=id_, |
|---|
| 84 | name=id_, value=owner)) |
|---|
| 85 | hint = "The owner will be changed from %s" % current_owner |
|---|
| 86 | elif len(owners) == 1: |
|---|
| 87 | owner = tag.input(type='hidden', id=id_, name=id_, |
|---|
| 88 | value=owners[0]) |
|---|
| 89 | formatted_owner = format_user(owners[0]) |
|---|
| 90 | control = tag('Assign to ', |
|---|
| 91 | tag(formatted_owner, owner)) |
|---|
| 92 | if res_wf_state['owner'] != owners[0]: |
|---|
| 93 | hint = "The owner will be changed from %s to %s" % (current_owner, formatted_owner) |
|---|
| 94 | else: |
|---|
| 95 | control = tag('Assign to ', tag.select( |
|---|
| 96 | [tag.option(format_user(x), value=x, |
|---|
| 97 | selected=(x == selected_owner or None)) |
|---|
| 98 | for x in owners], |
|---|
| 99 | id=id_, name=id_)) |
|---|
| 100 | hint = "The owner will be changed from %s" % current_owner |
|---|
| 101 | |
|---|
| 102 | return control, hint |
|---|
| 103 | |
|---|
| 104 | elif operation == 'set_owner_to_self' and self._has_field_named('owner', res_wf_state.fields) and \ |
|---|
| 105 | res_wf_state['owner'] != req.authname: |
|---|
| 106 | |
|---|
| 107 | current_owner = res_wf_state['owner'] or '(none)' |
|---|
| 108 | if not (Chrome(self.env).show_email_addresses |
|---|
| 109 | or 'EMAIL_VIEW' in req.perm(resource)): |
|---|
| 110 | format_user = obfuscate_email_address |
|---|
| 111 | else: |
|---|
| 112 | format_user = lambda address: address |
|---|
| 113 | current_owner = format_user(current_owner) |
|---|
| 114 | |
|---|
| 115 | control = tag('') |
|---|
| 116 | hint = "The owner will be changed from %s to %s" % (current_owner, req.authname) |
|---|
| 117 | |
|---|
| 118 | self.log.debug("<<< WorkflowStandardOperations - get_operation_control - set_owner_to_self") |
|---|
| 119 | |
|---|
| 120 | return control, hint |
|---|
| 121 | |
|---|
| 122 | elif operation == 'std_notify': |
|---|
| 123 | pass |
|---|
| 124 | |
|---|
| 125 | self.log.debug("<<< WorkflowStandardOperations - get_operation_control") |
|---|
| 126 | |
|---|
| 127 | return None, '' |
|---|
| 128 | |
|---|
| 129 | def perform_operation(self, req, action, operation, old_state, new_state, res_wf_state, resource): |
|---|
| 130 | self.log.debug("---> Performing operation %s while transitioning from %s to %s." |
|---|
| 131 | % (operation, old_state, new_state)) |
|---|
| 132 | |
|---|
| 133 | if operation == 'set_owner': |
|---|
| 134 | if self.config.getbool(resource.realm, 'set_owners'): |
|---|
| 135 | target_owners = self.config.getstring(resource.realm, 'restrict_to_permission') |
|---|
| 136 | new_owner = target_owners.strip() |
|---|
| 137 | else: |
|---|
| 138 | new_owner = req.args.get('action_%s_operation_%s' % (action, operation), None) |
|---|
| 139 | |
|---|
| 140 | if new_owner is not None and len(new_owner.strip()) > 0: |
|---|
| 141 | res_wf_state['owner'] = new_owner.strip() |
|---|
| 142 | #res_wf_state.save_changes() |
|---|
| 143 | else: |
|---|
| 144 | self.log.debug("Unable to get the new owner!") |
|---|
| 145 | |
|---|
| 146 | elif operation == 'set_owner_to_self': |
|---|
| 147 | res_wf_state['owner'] = req.authname.strip() |
|---|
| 148 | |
|---|
| 149 | def _has_field_named(self, field_name, fields): |
|---|
| 150 | for f in fields: |
|---|
| 151 | if 'name' in f and f['name'] == field_name: |
|---|
| 152 | return True |
|---|
| 153 | |
|---|
| 154 | return False |
|---|