Projet

Général

Profil

0001-workflows-add-notification-action-33817.patch

Frédéric Péters, 09 juin 2019 09:20

Télécharger (9,82 ko)

Voir les différences:

Subject: [PATCH] workflows: add notification action (#33817)

 tests/test_workflows.py |  71 +++++++++++++++++++
 tests/utilities.py      |   3 +
 wcs/wf/notification.py  | 151 ++++++++++++++++++++++++++++++++++++++++
 wcs/workflows.py        |   1 +
 4 files changed, 226 insertions(+)
 create mode 100644 wcs/wf/notification.py
tests/test_workflows.py
45 45
from wcs.wf.geolocate import GeolocateWorkflowStatusItem
46 46
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
47 47
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
48
from wcs.wf.notification import SendNotificationWorkflowStatusItem
48 49

  
49 50
from utilities import (create_temporary_pub, MockSubstitutionVariables,
50 51
        clean_temporary_pub)
......
3878 3879
    assert logged_error.exception_message == "name 'foobar' is not defined"
3879 3880
    assert logged_error.expression == 'foobar == barfoo'
3880 3881
    assert logged_error.expression_type == 'python'
3882

  
3883
def test_notifications(pub, http_requests):
3884
    formdef = FormDef()
3885
    formdef.name = 'baz'
3886
    formdef.fields = []
3887
    formdef.store()
3888

  
3889
    formdata = formdef.data_class()()
3890
    formdata.just_created()
3891
    formdata.store()
3892

  
3893
    assert not SendNotificationWorkflowStatusItem.is_available()
3894

  
3895
    if not pub.site_options.has_section('variables'):
3896
        pub.site_options.add_section('variables')
3897
    pub.site_options.set('variables', 'portal_url', 'https://portal/')
3898
    assert SendNotificationWorkflowStatusItem.is_available()
3899

  
3900
    item = SendNotificationWorkflowStatusItem()
3901
    item.to = ['_submitter']
3902
    item.title = 'xxx'
3903
    item.body = 'XXX'
3904

  
3905
    # no user
3906
    http_requests.empty()
3907
    item.perform(formdata)
3908
    assert http_requests.count() == 0
3909

  
3910
    # user
3911
    http_requests.empty()
3912
    user = pub.user_class()
3913
    user.name_identifiers = ['xxx']
3914
    user.store()
3915
    formdata.user_id = user.id
3916
    formdata.store()
3917

  
3918
    item.perform(formdata)
3919
    assert http_requests.count() == 1
3920
    assert http_requests.get_last('url') == 'https://portal/api/notification/add/?NameID=xxx'
3921
    assert json.loads(http_requests.get_last('body')) == {
3922
            'body': 'XXX',
3923
            'url': formdata.get_url(),
3924
            'id': 'formdata:%s' % formdata.get_display_id(),
3925
            'origin': '',
3926
            'summary': 'xxx'
3927
    }
3928

  
3929
    # roles
3930
    http_requests.empty()
3931

  
3932
    role = Role(name='blah')
3933
    role.store()
3934

  
3935
    user1 = pub.user_class()
3936
    user1.roles = [role.id]
3937
    user1.name_identifiers = ['xxy1']
3938
    user1.store()
3939
    user2 = pub.user_class()
3940
    user2.roles = [role.id]
3941
    user2.name_identifiers = ['xxy2']
3942
    user2.store()
3943

  
3944
    formdef.workflow_roles = {'_receiver': role.id}
3945

  
3946
    item.to = ['_receiver']
3947
    item.perform(formdata)
3948
    assert http_requests.count() == 2
3949
    assert set(x['url'] for x in http_requests.requests) == set([
3950
        'https://portal/api/notification/add/?NameID=xxy1',
3951
        'https://portal/api/notification/add/?NameID=xxy2'])
tests/utilities.py
378 378
    def empty(self):
379 379
        self.requests = []
380 380

  
381
    def count(self):
382
        return len(self.requests)
383

  
381 384

  
382 385
class SMSMocking(wcs.qommon.sms.MobytSMS):
383 386
    def get_sms_class(self, mode):
wcs/wf/notification.py
1
# w.c.s. - web application for online forms
2
# Copyright (C) 2005-2019  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
from quixote import get_publisher
18

  
19
from qommon import _, ezt
20
from qommon.form import *
21
from qommon.template import TemplateError
22
from qommon import get_logger
23

  
24
from wcs.roles import Role
25
from wcs.workflows import (WorkflowStatusItem, register_item_class,
26
        template_on_formdata, get_role_translation)
27
from .wscall import WebserviceCallStatusItem
28

  
29

  
30
class SendNotificationWorkflowStatusItem(WebserviceCallStatusItem):
31
    description = N_('Notification')
32
    key = 'notification'
33
    category = 'interaction'
34
    support_substitution_variables = True
35

  
36
    # parameters
37
    to = []
38
    title = None
39
    body = None
40
    origin = None
41

  
42
    # webservice parameters
43
    varname = 'notification'
44
    post = False
45
    _method = 'POST'
46
    response_type = 'json'
47

  
48
    action_on_app_error = ':pass'
49
    action_on_4xx = ':pass'
50
    action_on_5xx = ':pass'
51
    action_on_bad_data = ':pass'
52
    action_on_network_errors = ':pass'
53
    notify_on_errors = True
54
    record_errors = False
55

  
56
    @classmethod
57
    def is_available(cls, workflow=None):
58
        return bool(cls.get_api_url() is not None)
59

  
60
    @classmethod
61
    def get_api_url(cls):
62
        url = get_publisher().get_site_option('portal_url', 'variables')
63
        if not url:
64
            return None
65
        return url + 'api/notification/add/'
66

  
67
    def get_jump_label(self, target_id):
68
        return self.description
69

  
70
    def fill_admin_form(self, form):
71
        self.add_parameters_widgets(form, self.get_parameters())
72

  
73
    def get_parameters(self):
74
        return ('to', 'title', 'body', 'origin', 'condition')
75

  
76
    def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
77
        if 'to' in parameters:
78
            form.add(WidgetList, '%sto' % prefix, title=_('To'),
79
                     element_type=SingleSelectWidget,
80
                     value=self.to,
81
                     add_element_label=_('Add Role'),
82
                     element_kwargs={'render_br': False,
83
                                     'options': [(None, '---', None)] +
84
                                        self.get_list_of_roles(include_logged_in_users=False)})
85
        if 'title' in parameters:
86
            form.add(StringWidget, '%stitle' % prefix, title=_('Title'),
87
                    value=self.title, size=80,
88
                    validation_function=ComputedExpressionWidget.validate_template)
89
        if 'body' in parameters:
90
            form.add(TextWidget, '%sbody' % prefix, title=_('Body'),
91
                    value=self.body, cols=80, rows=5,
92
                    validation_function=ComputedExpressionWidget.validate_template)
93
        if 'origin' in parameters:
94
            form.add(StringWidget, '%sorigin' % prefix, title=_('Origin'),
95
                    value=self.origin, required=False,
96
                    advanced=not(self.origin))
97
        WorkflowStatusItem.add_parameters_widgets(self, form, parameters,
98
                prefix=prefix, formdef=formdef)
99

  
100
    def perform(self, formdata):
101
        if not (self.is_available() and self.to and self.title and self.body):
102
            return
103

  
104
        try:
105
            title = template_on_formdata(formdata,
106
                    self.compute(self.title, render=False),
107
                    autoescape=False)
108
        except TemplateError as e:
109
            get_logger().error('error in template for notification title [%s], '
110
                               'mail could not be generated: %s' % (notified_url, str(e)))
111
            return
112

  
113
        try:
114
            body = template_on_formdata(formdata,
115
                    self.compute(self.body, render=False),
116
                    autoescape=False)
117
        except TemplateError as e:
118
            get_logger().error('error in template for notification body [%s], '
119
                               'mail could not be generated: %s' % (notified_url, str(e)))
120
            return
121

  
122
        self.post_data = {
123
            'summary': title,
124
            'body': body,
125
            'url': formdata.get_url(),
126
            'origin': self.origin or '',
127
            'id': 'formdata:%s' % formdata.get_display_id(),
128
        }
129
        self.url = self.get_api_url()
130

  
131
        users = []
132
        for dest in self.to:
133
            if dest == '_submitter':
134
                users.append(formdata.get_user())
135
                continue
136

  
137
            dest = get_role_translation(formdata, dest)
138
            try:
139
                role = Role.get(dest)
140
            except KeyError:
141
                continue
142
            users.extend(get_publisher().user_class.get_users_with_role(role.id))
143

  
144
        for user in users:
145
            if not user:
146
                continue
147
            for name_id in (user.name_identifiers or []):
148
                self.qs_data = {'NameID': name_id}
149
                super(SendNotificationWorkflowStatusItem, self).perform(formdata)
150

  
151
register_item_class(SendNotificationWorkflowStatusItem)
wcs/workflows.py
2794 2794
    import wf.profile
2795 2795
    import wf.backoffice_fields
2796 2796
    import wf.redirect_to_url
2797
    import wf.notification
2797 2798

  
2798 2799
from wf.export_to_model import ExportToModel
2799
-