Projet

Général

Profil

0001-wf-add-external-workflow-action-40204.patch

Serghei Mihai, 01 avril 2020 12:24

Télécharger (24,9 ko)

Voir les différences:

Subject: [PATCH] wf: add external workflow action (#40204)

 tests/test_admin_pages.py     |  72 ++++++++++++-
 tests/test_workflow_import.py |  44 +++++++-
 tests/test_workflows.py       | 185 ++++++++++++++++++++++++++++++++-
 wcs/admin/workflows.py        |   1 +
 wcs/carddef.py                |   2 +-
 wcs/wf/external_workflow.py   | 190 ++++++++++++++++++++++++++++++++++
 wcs/workflows.py              |  26 +++++
 7 files changed, 516 insertions(+), 4 deletions(-)
 create mode 100644 wcs/wf/external_workflow.py
tests/test_admin_pages.py
1210 1210
    resp = resp.forms[0].submit()
1211 1211
    resp = resp.follow()
1212 1212
    assert len(FormDef.get(1).fields) == 0
1213
 
1213

  
1214 1214
def test_form_duplicate_field(pub):
1215 1215
    user = create_superuser(pub)
1216 1216
    create_role()
......
3502 3502
    assert Workflow.get(workflow.id).global_actions[0].triggers[0].timeout == '-2'
3503 3503

  
3504 3504

  
3505
def test_workflows_global_actions_external_workflow_triggers(pub):
3506
    create_superuser(pub)
3507

  
3508
    Workflow.wipe()
3509
    workflow = Workflow(name='foo')
3510
    workflow.store()
3511

  
3512
    app = login(get_app(pub))
3513
    resp = app.get('/backoffice/workflows/%s/' % workflow.id)
3514
    resp = resp.click('add global action')
3515
    resp.forms[0]['name'] = 'Global Action with External workflow trigger'
3516

  
3517
    resp = resp.forms[0].submit('submit')
3518
    resp = resp.follow()
3519

  
3520
    # adding an external trigger
3521
    resp.forms[1]['type'] = 'External workflow'
3522
    resp = resp.forms[1].submit()
3523
    resp = resp.follow()
3524

  
3525
    assert 'External workflow (not configured)' in resp.text
3526
    resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[1].id, index=0)
3527
    resp.form['event_name'] = ''
3528
    resp = resp.form.submit()
3529
    assert 'required field' in resp.text
3530
    resp.form['event_name'] = 'Test'
3531
    resp = resp.form.submit('submit').follow()
3532
    assert Workflow.get(workflow.id).global_actions[0].triggers[1].event_name == 'Test'
3533

  
3534

  
3535
def test_workflows_global_actions_external_workflow_action(pub):
3536
    create_superuser(pub)
3537
    Workflow.wipe()
3538

  
3539
    wf = Workflow(name='external')
3540
    action = wf.add_global_action('Global action')
3541
    trigger = action.append_trigger('external_workflow')
3542
    trigger.event_name = 'test'
3543
    item = action.append_item('remove')
3544
    wf.store()
3545

  
3546
    formdef = FormDef()
3547
    formdef.name = 'external'
3548
    formdef.workflow = wf
3549
    formdef.store()
3550
    workflow = Workflow(name='foo')
3551
    st = workflow.add_status('New')
3552
    workflow.store()
3553

  
3554
    app = login(get_app(pub))
3555
    resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st.id))
3556
    resp.forms[0]['action-formdata-action'] = 'External workflow'
3557
    resp = resp.forms[0].submit().follow()
3558
    assert 'External workflow (not completed)' in resp.text
3559

  
3560
    resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (workflow.id, st.id))
3561
    resp.forms[0]['slug'] = 'formdef:%s' % formdef.url_name
3562
    resp = resp.forms[0].submit('submit').follow().follow()
3563
    assert 'External workflow (not completed)' in resp.text
3564
    resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (workflow.id, st.id))
3565
    assert resp.forms[0]['target$type'].value == 'auto'
3566
    resp.forms[0]['target$type'] = 'expression'
3567
    resp = resp.forms[0].submit('submit')
3568
    assert "Expression must be filled" in resp
3569
    resp.forms[0]['target$type'] = 'auto'
3570
    resp.forms[0]['event'] = trigger.id
3571
    resp = resp.forms[0].submit('submit').follow().follow()
3572
    assert 'External workflow (event « test » on external)' in resp.text
3573

  
3574

  
3505 3575
def test_workflows_criticality_levels(pub):
3506 3576
    create_superuser(pub)
3507 3577
    create_role()
tests/test_workflow_import.py
14 14
    Workflow, CommentableWorkflowStatusItem, WorkflowCriticalityLevel,
15 15
    WorkflowBackofficeFieldsFormDef, SendmailWorkflowStatusItem,
16 16
    SendSMSWorkflowStatusItem, WorkflowImportError, ChoiceWorkflowStatusItem,
17
    JumpOnSubmitWorkflowStatusItem)
17
    JumpOnSubmitWorkflowStatusItem, WorkflowGlobalActionExternalWorkflowTrigger)
18 18
from wcs.wf.wscall import WebserviceCallStatusItem
19 19
from wcs.wf.dispatch import DispatchWorkflowStatusItem
20 20
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
......
22 22
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
23 23
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
24 24
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
25
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction
25 26
from wcs.roles import Role
26 27
from wcs.fields import StringField, FileField
27 28

  
......
753 754
    wf.store()
754 755

  
755 756
    assert_import_export_works(wf, include_id=True)
757

  
758

  
759
def test_external_workflow(pub):
760
    target_wf = Workflow(name='External global action')
761
    action = target_wf.add_global_action('Delete', 'delete')
762
    trigger = action.append_trigger('external_workflow')
763
    trigger.event_name = 'Cleanup'
764
    target_wf.store()
765

  
766
    target_formdef = FormDef()
767
    target_formdef.name = 'target form'
768
    target_formdef.workflow = target_wf
769
    target_formdef.store()
770

  
771
    wf = Workflow(name='External workflow call')
772
    st1 = wf.add_status('New')
773
    st2 = wf.add_status('Call external workflow')
774

  
775
    jump = ChoiceWorkflowStatusItem()
776
    jump.id = '_external'
777
    jump.label = 'Cleanup'
778
    jump.by = ['_submitter']
779
    jump.status = st2.id
780
    jump.parent = st1
781
    st1.items.append(jump)
782

  
783
    external_workflow = ExternalWorkflowGlobalAction()
784
    external_workflow.id = '_external_workflow'
785
    external_workflow.slug = 'formdef:%s' % target_formdef.url_name
786
    external_workflow.event = trigger.id
787

  
788
    external_workflow.target = {
789
        'type': 'expression',
790
        'expression': '{{ form_var_id }}'
791
    }
792
    external_workflow.parent = st2
793
    st2.items.append(external_workflow)
794

  
795
    wf.store()
796

  
797
    assert_import_export_works(wf, include_id=True)
tests/test_workflows.py
34 34
        CommentableWorkflowStatusItem, ChoiceWorkflowStatusItem,
35 35
        DisplayMessageWorkflowStatusItem,
36 36
        AbortActionException, WorkflowCriticalityLevel,
37
        AttachmentEvolutionPart, WorkflowBackofficeFieldsFormDef)
37
        AttachmentEvolutionPart, WorkflowBackofficeFieldsFormDef,
38
        perform_items)
38 39
from wcs.wf.aggregation_email import (AggregationEmailWorkflowStatusItem,
39 40
        AggregationEmail, send_aggregation_emails)
40 41
from wcs.wf.anonymise import AnonymiseWorkflowStatusItem
......
55 56
from wcs.wf.notification import SendNotificationWorkflowStatusItem
56 57
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
57 58
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
59
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction
58 60

  
59 61

  
60 62
from utilities import (create_temporary_pub, MockSubstitutionVariables,
......
4632 4634
    assert carddef.data_class().count() == 0
4633 4635
    formdata.perform_workflow()
4634 4636
    assert carddef.data_class().count() == 0
4637

  
4638

  
4639
def test_call_external_workflow_by_object_expression(pub):
4640
    FormDef.wipe()
4641
    LoggedError.wipe()
4642

  
4643
    external_formdef = FormDef()
4644
    external_formdef.name = 'External Form'
4645
    external_formdef.fields = [
4646
        StringField(id='0', label='string', varname='foo_string'),
4647
    ]
4648
    external_wf = Workflow(name='External Workflow')
4649
    action = external_wf.add_global_action('Delete', 'delete')
4650
    action.append_item('remove')
4651
    trigger = action.append_trigger('external_workflow')
4652
    trigger.event_name = 'delete'
4653
    external_wf.store()
4654

  
4655
    external_formdef.workflow = external_wf
4656
    external_formdef.store()
4657

  
4658
    wf = Workflow(name='External call')
4659
    st1 = wf.add_status('Call external workflow')
4660
    external_wf_action = ExternalWorkflowGlobalAction()
4661
    external_wf_action.slug = 'formdef:%s' % external_formdef.url_name
4662
    external_wf_action.event = 'unknown'
4663
    external_wf_action.target  = {
4664
        'type': 'expression',
4665
        'expression': '{{ form_var_target_id }}'
4666
    }
4667
    external_wf_action.parent = st1
4668
    st1.items.append(external_wf_action)
4669
    wf.store()
4670

  
4671
    formdef = FormDef()
4672
    formdef.name = 'External call form'
4673
    formdef.fields = [
4674
        StringField(id='0', label='string', varname='target_id'),
4675
    ]
4676
    formdef.workflow = wf
4677
    formdef.store()
4678

  
4679
    # unknown trigger
4680
    formdata = formdef.data_class()()
4681
    formdata.data = {'0': 'whatever'}
4682
    formdata.store()
4683
    formdata.just_created()
4684
    formdata.perform_workflow()
4685

  
4686
    assert LoggedError.count() == 1
4687
    logged_error = LoggedError.select()[0]
4688
    assert logged_error.summary == 'Could not find trigger for event "unknown"'
4689

  
4690
    # unknown object id
4691
    LoggedError.wipe()
4692

  
4693
    new_wf = Workflow(name='New external call')
4694
    st1 = new_wf.add_status('Call external workflow')
4695
    external_wf_action.event = trigger.id
4696
    st1.items.append(external_wf_action)
4697
    new_wf.store()
4698

  
4699
    formdef.workflow = new_wf
4700
    formdef.store()
4701

  
4702
    formdata = formdef.data_class()()
4703
    formdata.data = {'0': '42'}
4704
    formdata.store()
4705
    formdata.just_created()
4706
    formdata.perform_workflow()
4707

  
4708
    assert LoggedError.count() == 1
4709
    logged_error = LoggedError.select()[0]
4710
    assert logged_error.summary == 'Could not find object "External Form" by id 42'
4711
    assert logged_error.exception_class == 'KeyError'
4712

  
4713
    # no errors
4714
    LoggedError.wipe()
4715
    external_formdata = external_formdef.data_class()()
4716
    external_formdata.data = {'0': 'test'}
4717
    external_formdata.store()
4718
    assert external_formdef.data_class().count() == 1
4719

  
4720
    formdata = formdef.data_class()()
4721
    formdata.data = {'0': external_formdata.id}
4722
    formdata.store()
4723
    formdata.just_created()
4724
    formdata.perform_workflow()
4725

  
4726
    assert LoggedError.count() == 0
4727
    assert external_formdef.data_class().count() == 0
4728

  
4729

  
4730
def test_call_external_workflow_by_linked_object(pub):
4731
    FormDef.wipe()
4732
    CardDef.wipe()
4733
    LoggedError.wipe()
4734

  
4735
    external_wf = Workflow(name='External Workflow')
4736
    st1 = external_wf.add_status(name='New')
4737
    action = external_wf.add_global_action('Delete', 'delete')
4738
    action.append_item('remove')
4739
    trigger = action.append_trigger('external_workflow')
4740
    trigger.event_name = 'delete'
4741
    external_wf.store()
4742

  
4743
    external_formdef = FormDef()
4744
    external_formdef.name = 'External Form'
4745
    external_formdef.fields = [
4746
        StringField(id='0', label='string', varname='form_string'),
4747
    ]
4748
    external_formdef.workflow = external_wf
4749
    external_formdef.store()
4750

  
4751
    external_carddef = CardDef()
4752
    external_carddef.name = 'External Card'
4753
    external_carddef.fields = [
4754
        StringField(id='0', label='string', varname='card_string'),
4755
    ]
4756
    external_carddef.workflow = external_wf
4757
    external_carddef.store()
4758

  
4759
    wf = Workflow(name='External actions')
4760
    st1 = wf.add_status('Create external formdata')
4761
    create_formdata = CreateFormdataWorkflowStatusItem()
4762
    create_formdata.label = 'create linked form'
4763
    create_formdata.formdef_slug = external_formdef.url_name
4764
    create_formdata.varname = 'created_form'
4765
    create_formdata.id = '_create_form'
4766
    mappings = [
4767
        Mapping(field_id='0', expression='{{ form_var_string }}')
4768
    ]
4769
    create_formdata.mappings = mappings
4770
    create_formdata.parent = st1
4771

  
4772
    create_carddata = CreateCarddataWorkflowStatusItem()
4773
    create_carddata.label = 'create linked card'
4774
    create_carddata.formdef_slug = external_carddef.url_name
4775
    create_carddata.varname = 'created_card'
4776
    create_carddata.id = '_create_card'
4777
    create_carddata.mappings = mappings
4778
    create_carddata.parent = st1
4779

  
4780
    st1.items.append(create_formdata)
4781
    st1.items.append(create_carddata)
4782

  
4783
    global_action = wf.add_global_action('Delete external linked object', 'delete')
4784
    action = global_action.append_item('external_workflow_global_action')
4785
    action.slug = 'formdef:%s' % external_formdef.url_name
4786
    action.event = trigger.id
4787
    wf.store()
4788

  
4789
    formdef = FormDef()
4790
    formdef.name = 'External action form'
4791
    formdef.fields = [
4792
        StringField(id='0', label='string', varname='string'),
4793
    ]
4794
    formdef.workflow = wf
4795
    formdef.store()
4796

  
4797
    assert external_formdef.data_class().count() == 0
4798
    assert external_carddef.data_class().count() == 0
4799

  
4800
    formdata = formdef.data_class()()
4801
    formdata.data = {'0': 'test form'}
4802
    formdata.store()
4803
    formdata.just_created()
4804
    formdata.perform_workflow()
4805

  
4806
    assert external_formdef.data_class().count() == 1
4807
    assert external_carddef.data_class().count() == 1
4808
    perform_items([action], formdata)
4809
    assert LoggedError.count() == 0
4810
    assert external_formdef.data_class().count() == 0
4811
    assert external_carddef.data_class().count() == 1
4812

  
4813
    perform_items([action], formdata)
4814
    assert LoggedError.count() == 1
4815
    logged_error = LoggedError.select()[0]
4816
    assert logged_error.summary == 'Could not find linked "External Form" object'
4817
    assert logged_error.exception_class == 'KeyError'
wcs/admin/workflows.py
1301 1301
            ('timeout', _('Automatic')),
1302 1302
            ('manual', _('Manual')),
1303 1303
            ('webservice', _('Webservice')),
1304
            ('external_workflow', _('External workflow')),
1304 1305
        ]
1305 1306
        form.add(SingleSelectWidget, 'type', title=_('Type'),
1306 1307
                required=True, options=available_triggers)
wcs/carddef.py
22 22

  
23 23
from wcs.carddata import CardData
24 24
from wcs.formdef import FormDef
25
from wcs.workflows import Workflow
26 25

  
27 26
if not hasattr(types, 'ClassType'):
28 27
    types.ClassType = type
......
81 80
    @classmethod
82 81
    def get_default_workflow(cls):
83 82
        from wcs.workflows import EditableWorkflowStatusItem, ChoiceWorkflowStatusItem
83
        from wcs.workflows import Workflow
84 84
        from wcs.wf.remove import RemoveWorkflowStatusItem
85 85
        workflow = Workflow(name=_('Default (cards)'))
86 86
        workflow.id = '_carddef_default'
wcs/wf/external_workflow.py
1
# w.c.s. - web application for online forms
2
# Copyright (C) 2005-2016  Entr'ouvert
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16

  
17
import time
18
import xml.etree.ElementTree as ET
19

  
20
from quixote import get_request, get_session, get_publisher
21
from quixote.html import htmltext
22

  
23
from django.utils.functional import cached_property
24

  
25
from wcs.qommon import _
26
from wcs.qommon.form import (SingleSelectWidget, ComputedExpressionWidget,
27
                             CompositeWidget)
28

  
29
from wcs.logged_errors import LoggedError
30
from wcs.workflows import WorkflowStatusItem, perform_items, register_item_class
31
from wcs.workflows import WorkflowGlobalActionExternalWorkflowTrigger, Workflow
32
from wcs.wf.create_formdata import LinkedFormdataEvolutionPart
33
from wcs.carddef import CardDef
34
from wcs.formdef import FormDef
35

  
36

  
37
class TargetWidget(CompositeWidget):
38
    target_types = [
39
        ('auto', _('Automatic'), 'auto'),
40
        ('expression', _('Expression'), 'expression')
41
    ]
42

  
43
    def __init__(self, name, value={}, **kwargs):
44
        print(kwargs)
45
        super(TargetWidget, self).__init__(name, value, **kwargs)
46
        self.add(SingleSelectWidget, 'type',
47
                 value=self.value.get('type') or 'auto',
48
                 options=self.target_types,
49
                 render_br=False,
50
                 attrs={'data-dynamic-display-parent': 'true'}
51
        )
52
        self.add(ComputedExpressionWidget, 'expression',
53
                 value=value['expression'],
54
                 extra_css_class='grid-3-4',
55
                 render_br=False,
56
                 attrs={
57
                     'data-dynamic-display-child-of': '%s$type' % name,
58
                     'data-dynamic-display-value': 'expression'
59
                 }
60
        )
61
        # put widgets in grid
62
        self.widgets[0].extra_css_class = 'grid-1-4'
63
        self.widgets[1].extra_css_class = 'grid-3-4'
64

  
65
    def _parse(self, request):
66
        super(TargetWidget, self)._parse(request)
67
        if self.get('type') == 'expression' and not self.get('expression'):
68
            self.error = _('Expression must be filled')
69
            return
70
        self.value = {
71
            'type': self.get('type'),
72
            'expression': self.get('expression')
73
        }
74

  
75

  
76
class ExternalWorkflowGlobalAction(WorkflowStatusItem):
77

  
78
    description = _('External workflow')
79
    key = 'external_workflow_global_action'
80
    category = 'formdata-action'
81

  
82

  
83

  
84
    slug = None
85
    target = {'type': 'auto', 'expression': ''}
86
    event = None
87

  
88
    def get_workflow_external_triggers(self, workflow):
89
        triggers = []
90
        for action in workflow.global_actions or []:
91
            for trigger in action.triggers or []:
92
                if isinstance(trigger, WorkflowGlobalActionExternalWorkflowTrigger):
93
                    triggers.append(trigger)
94
        return triggers
95

  
96
    def get_object_def(self):
97
        object_type, slug = self.slug.split(':')
98
        if object_type == 'formdef':
99
            object_class = FormDef
100
        elif object_type == 'carddef':
101
            object_class = CardDef
102
        try:
103
            return object_class.get_by_urlname(slug)
104
        except Exception as e:
105
            pass
106

  
107
    def get_trigger_by_event(self, workflow):
108
        for trigger in self.get_workflow_external_triggers(workflow):
109
            if trigger.id == self.event:
110
                return trigger
111

  
112
    def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
113
        super(ExternalWorkflowGlobalAction, self).add_parameters_widgets(
114
            form, parameters, prefix=prefix, formdef=formdef)
115

  
116
        if 'slug' in parameters:
117
            objects = [(None, '---', '')]
118
            for wf in Workflow.select():
119
                if self.get_workflow_external_triggers(wf):
120
                    for objectdef in wf.formdefs() + wf.carddefs():
121
                        object_slug = '%s:%s' % (objectdef.__class__.__name__.lower(),
122
                                                 objectdef.url_name)
123
                        objects += [(object_slug, objectdef.name, object_slug)]
124
            objects.sort(key=lambda x: x[1])
125
            form.add(SingleSelectWidget, 'slug',
126
                     title=_('Object type'),
127
                     value=self.slug,
128
                     options=objects)
129
        if 'target' in parameters and self.slug:
130
            form.add(TargetWidget, '%starget' % prefix,
131
                     title=_('Target object'),
132
                     value=self.target
133
            )
134

  
135
        if 'event' in parameters and self.slug:
136
            events = [(None, '---', '')]
137
            obj_def = self.get_object_def()
138
            for trigger in self.get_workflow_external_triggers(obj_def.workflow):
139
                events += [(trigger.id, trigger.event_name, trigger.id)]
140
            form.add(SingleSelectWidget, 'event',
141
                     title=_('Event'),
142
                     value=self.event,
143
                     options=events)
144

  
145
    def get_line_details(self):
146
        if self.slug and self.event:
147
            objectdef = self.get_object_def()
148
            trigger = self.get_trigger_by_event(objectdef.workflow)
149
            if trigger and objectdef:
150
                return _('event « %s » on %s' % (trigger.event_name, objectdef.name))
151
        return _('not completed')
152

  
153
    def iter_target_datas(self, formdata, objectdef):
154
        data_ids = []
155
        if self.target['type'] == 'expression':
156
            data_id = self.compute(self.target['expression'], formdata=formdata)
157
            data_ids.append(data_id)
158
            error_msg = 'Could not find object "%s" by id %s' % (objectdef.name, data_id)
159
        else:
160
            for part in formdata.iter_evolution_parts():
161
                if isinstance(part, LinkedFormdataEvolutionPart) and part.formdef_class == objectdef.__class__:
162
                    data_ids.append(part.formdata_id)
163
            error_msg = 'Could not find linked "%s" object' % objectdef.name
164

  
165
        for target_id in data_ids:
166
            try:
167
                yield objectdef.data_class().get(target_id)
168
            except KeyError as e:
169
                # use custom error message depending on target type
170
                LoggedError.record(error_msg, formdata=formdata, exception=e)
171

  
172
    def get_parameters(self):
173
        return ('slug',  'target', 'event', 'condition')
174

  
175
    def perform(self, formdata):
176
        objectdef = self.get_object_def()
177
        if not objectdef:
178
            return
179

  
180
        trigger = self.get_trigger_by_event(objectdef.workflow)
181
        if not trigger:
182
            LoggedError.record('Could not find trigger for event "%s"' % self.event,
183
                               formdata=formdata)
184
            return
185

  
186
        for target_data in self.iter_target_datas(formdata, objectdef):
187
            perform_items(trigger.parent.items, target_data)
188

  
189

  
190
register_item_class(ExternalWorkflowGlobalAction)
wcs/workflows.py
44 44
from .roles import Role, logged_users_role, get_user_roles
45 45
from .fields import FileField
46 46
from .formdef import FormDef
47
from .carddef import CardDef
47 48
from .formdata import Evolution
48 49

  
49 50
if not __name__.startswith('wcs.') and not __name__ == "__main__":
......
834 835
    def formdefs(self, **kwargs):
835 836
        return list(FormDef.select(lambda x: x.workflow_id == self.id, **kwargs))
836 837

  
838
    def carddefs(self, **kwargs):
839
        return list(CardDef.select(lambda x: x.workflow_id == self.id, **kwargs))
840

  
837 841

  
838 842
class XmlSerialisable(object):
839 843
    node_name = None
......
1307 1311
        return [('hooks', WorkflowGlobalActionWebserviceHooksDirectory(formdata))]
1308 1312

  
1309 1313

  
1314
class WorkflowGlobalActionExternalWorkflowTrigger(WorkflowGlobalActionManualTrigger):
1315
    key = 'external_workflow'
1316
    event_name = None
1317

  
1318
    def get_parameters(self):
1319
        return ('event_name',)
1320

  
1321
    def render_as_line(self):
1322
        if self.event_name:
1323
            return _('External workflow (by event "%s")') % self.event_name
1324
        else:
1325
            return _('External workflow (not configured)')
1326

  
1327
    def form(self, workflow):
1328
        form = Form(enctype='multipart/form-data')
1329
        form.add(StringWidget, 'event_name', title=_('Event name'),
1330
                 required=True, value=self.event_name)
1331
        return form
1332

  
1333

  
1310 1334
class WorkflowGlobalAction(object):
1311 1335
    id = None
1312 1336
    name = None
......
1336 1360
            'manual': WorkflowGlobalActionManualTrigger,
1337 1361
            'timeout': WorkflowGlobalActionTimeoutTrigger,
1338 1362
            'webservice': WorkflowGlobalActionWebserviceTrigger,
1363
            'external_workflow': WorkflowGlobalActionExternalWorkflowTrigger,
1339 1364
        }
1340 1365
        o = trigger_types.get(type)()
1341 1366
        if not self.triggers:
......
2927 2952
    from .wf import notification
2928 2953
    from .wf import create_formdata
2929 2954
    from .wf import create_carddata
2955
    from .wf import external_workflow
2930 2956

  
2931 2957
from .wf.export_to_model import ExportToModel
2932
-