From 22d66ca3e735fe83bf70ac14e3a565490aea5ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 4 Jan 2016 16:04:22 +0100 Subject: [PATCH 3/3] workflows: add possibility to dispatch function according to a variable (#9091) --- tests/test_admin_pages.py | 33 +++++++++++++++ tests/test_workflows.py | 41 ++++++++++++++++++ wcs/wf/dispatch.py | 104 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 171 insertions(+), 7 deletions(-) diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py index 75a2c16..b62be08 100644 --- a/tests/test_admin_pages.py +++ b/tests/test_admin_pages.py @@ -1329,6 +1329,39 @@ def test_workflows_add_all_actions(pub): resp = resp.follow() # redirect to items/ resp = resp.follow() # redirect to ./ +def test_workflows_edit_dispatch_action(pub): + create_superuser(pub) + role = create_role() + Workflow.wipe() + workflow = Workflow(name='foo') + workflow.add_status(name='baz') + workflow.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/workflows/1/') + resp = resp.click('baz') + + resp.forms[0]['type'] = 'Assign a Function' + resp = resp.forms[0].submit() + resp = resp.follow() + + resp = resp.click('Assign a Function') + resp.form['rules$element0$value'].value = 'FOOBAR' + resp.form['rules$element0$role_id'].value = str(role.id) + resp = resp.form.submit('submit') + resp = resp.follow() + resp = resp.follow() + + resp = resp.click('Assign a Function') + assert resp.form['rules$element0$value'].value == 'FOOBAR' + resp.form['rules$element1$value'].value = 'BARFOO' + resp.form['rules$element1$role_id'].value = str(role.id) + resp = resp.form.submit('submit') + + workflow = Workflow.get(workflow.id) + assert workflow.possible_status[0].items[0].rules == [ + {'value': 'FOOBAR', 'role_id': '1'}, {'value': 'BARFOO', 'role_id': '1'}] + def test_workflows_variables(pub): create_superuser(pub) create_role() diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 1b65900..a4347e8 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -170,6 +170,47 @@ def test_dispatch(pub): item.perform(formdata) assert formdata.workflow_roles == {'_receiver': '1'} +def test_dispatch_auto(pub): + formdef = FormDef() + formdef.name = 'baz' + formdef.fields = [ + StringField(id='1', label='Test', type='string', varname='foo'), + ] + formdef.store() + + item = DispatchWorkflowStatusItem() + item.role_key = '_receiver' + item.dispatch_type = 'automatic' + + formdata = formdef.data_class()() + pub.substitutions.feed(formdata) + item.perform(formdata) + assert not formdata.workflow_roles + + item.variable = 'form_var_foo' + item.rules = [ + {'role_id': '1', 'value': 'foo'}, + {'role_id': '2', 'value': 'bar'}, + ] + + item.perform(formdata) + assert not formdata.workflow_roles + + # no match + formdata.data = {'1': 'XXX'} + item.perform(formdata) + assert not formdata.workflow_roles + + # match + formdata.data = {'1': 'foo'} + item.perform(formdata) + assert formdata.workflow_roles == {'_receiver': '1'} + + # other match + formdata.data = {'1': 'bar'} + item.perform(formdata) + assert formdata.workflow_roles == {'_receiver': '2'} + def test_roles(pub): user = pub.user_class() user.store() diff --git a/wcs/wf/dispatch.py b/wcs/wf/dispatch.py index 7e6df67..2f33edd 100644 --- a/wcs/wf/dispatch.py +++ b/wcs/wf/dispatch.py @@ -14,19 +14,53 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see . +import collections + from qommon.form import * from wcs.roles import get_user_roles from wcs.workflows import WorkflowStatusItem, register_item_class + +class AutomaticDispatchRowWidget(CompositeWidget): + def __init__(self, name, value=None, **kwargs): + CompositeWidget.__init__(self, name, value, **kwargs) + if not value: + value = {} + self.add(StringWidget, name='value', title=_('Value'), + value=value.get('value'), **kwargs) + self.add(SingleSelectWidget, name='role_id', title=_('Role'), + value=value.get('role_id'), + options=[(None, '----', None)] + get_user_roles()) + + def _parse(self, request): + if self.get('value') or self.get('role_id'): + self.value = { + 'value': self.get('value'), + 'role_id': self.get('role_id') + } + else: + self.value = None + + +class AutomaticDispatchTableWidget(WidgetListAsTable): + readonly = False + def __init__(self, name, **kwargs): + super(AutomaticDispatchTableWidget, self).__init__(name, + element_type=AutomaticDispatchRowWidget, **kwargs) + + class DispatchWorkflowStatusItem(WorkflowStatusItem): description = N_('Assign a Function') key = 'dispatch' role_id = None role_key = None + dispatch_type = 'manual' + variable = None + rules = None def get_parameters(self): - return ('role_key', 'role_id') + return ('role_key', 'role_id', 'dispatch_type', 'variable', 'rules') def role_id_export_to_xml(self, item, charset, include_id=False): self._role_export_to_xml('role_id', item, charset, @@ -49,18 +83,74 @@ class DispatchWorkflowStatusItem(WorkflowStatusItem): form.add(SingleSelectWidget, '%srole_key' % prefix, title=_('Function to Set'), value=self.role_key, options=[(None, '----')] + self.parent.parent.roles.items()) + dispatch_types = collections.OrderedDict( + [('manual', _('Manual')), ('automatic', _('Automatic'))]) + if 'dispatch_type' in parameters: + form.add(RadiobuttonsWidget, '%sdispatch_type' % prefix, + title=_('Type'), + options=dispatch_types.items(), + value=self.dispatch_type, + required=True, + attrs={'data-dynamic-display-parent': 'true'}) if 'role_id' in parameters: form.add(SingleSelectWidget, '%srole_id' % prefix, title=_('Role'), value=str(self.role_id), - options=[(None, '----', None)] + get_user_roles()) + options=[(None, '----', None)] + get_user_roles(), + attrs={ + 'data-dynamic-display-child-of': '%sdispatch_type' % prefix, + 'data-dynamic-display-value': dispatch_types.get('manual'), + } + ) + if 'variable' in parameters: + form.add(StringWidget, '%svariable' % prefix, + title=_('Variable'), + value=self.variable, + attrs={ + 'data-dynamic-display-child-of': '%sdispatch_type' % prefix, + 'data-dynamic-display-value': dispatch_types.get('automatic'), + } + ) + if 'rules' in parameters: + form.add(AutomaticDispatchTableWidget, '%srules' % prefix, + title=_('Rules'), + value=self.rules, + attrs={ + 'data-dynamic-display-child-of': '%sdispatch_type' % prefix, + 'data-dynamic-display-value': dispatch_types.get('automatic'), + } + ) def perform(self, formdata): - if not (self.role_id and self.role_key): - return if not formdata.workflow_roles: formdata.workflow_roles = {} - formdata.workflow_roles[self.role_key] = str(self.role_id) - formdata.store() -register_item_class(DispatchWorkflowStatusItem) + new_role_id = None + + if self.dispatch_type == 'manual' or not self.dispatch_type: + if not (self.role_id and self.role_key): + return + new_role_id = self.role_id + elif self.dispatch_type == 'automatic': + if not (self.role_key and self.variable and self.rules): + return + variables = get_publisher().substitutions.get_context_variables() + # convert the given value to a few different types, to allow more + # diversity in matching. + variable_values = [variables.get(self.variable)] + if not variable_values[0]: + variable_values.append(None) + try: + variable_values.append(int(variable_values[0])) + except (ValueError, TypeError): + pass + for rule in self.rules: + if rule.get('value') in variable_values: + new_role_id = rule.get('role_id') + break + + if new_role_id: + formdata.workflow_roles[self.role_key] = str(new_role_id) + formdata.store() + +register_item_class(DispatchWorkflowStatusItem) -- 2.6.4