Projet

Général

Profil

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

Frédéric Péters, 19 juin 2019 16:15

Télécharger (9,71 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  | 148 ++++++++++++++++++++++++++++++++++++++++
 wcs/workflows.py        |   1 +
 4 files changed, 223 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)
......
3972 3973
    assert logged_error.exception_message == "name 'foobar' is not defined"
3973 3974
    assert logged_error.expression == 'foobar == barfoo'
3974 3975
    assert logged_error.expression_type == 'python'
3976

  
3977
def test_notifications(pub, http_requests):
3978
    formdef = FormDef()
3979
    formdef.name = 'baz'
3980
    formdef.fields = []
3981
    formdef.store()
3982

  
3983
    formdata = formdef.data_class()()
3984
    formdata.just_created()
3985
    formdata.store()
3986

  
3987
    assert not SendNotificationWorkflowStatusItem.is_available()
3988

  
3989
    if not pub.site_options.has_section('variables'):
3990
        pub.site_options.add_section('variables')
3991
    pub.site_options.set('variables', 'portal_url', 'https://portal/')
3992
    assert SendNotificationWorkflowStatusItem.is_available()
3993

  
3994
    item = SendNotificationWorkflowStatusItem()
3995
    item.to = ['_submitter']
3996
    item.title = 'xxx'
3997
    item.body = 'XXX'
3998

  
3999
    # no user
4000
    http_requests.empty()
4001
    item.perform(formdata)
4002
    assert http_requests.count() == 0
4003

  
4004
    # user
4005
    http_requests.empty()
4006
    user = pub.user_class()
4007
    user.name_identifiers = ['xxx']
4008
    user.store()
4009
    formdata.user_id = user.id
4010
    formdata.store()
4011

  
4012
    item.perform(formdata)
4013
    assert http_requests.count() == 1
4014
    assert http_requests.get_last('url') == 'https://portal/api/notification/add/?NameID=xxx'
4015
    assert json.loads(http_requests.get_last('body')) == {
4016
            'body': 'XXX',
4017
            'url': formdata.get_url(),
4018
            'id': 'formdata:%s' % formdata.get_display_id(),
4019
            'origin': '',
4020
            'summary': 'xxx'
4021
    }
4022

  
4023
    # roles
4024
    http_requests.empty()
4025

  
4026
    role = Role(name='blah')
4027
    role.store()
4028

  
4029
    user1 = pub.user_class()
4030
    user1.roles = [role.id]
4031
    user1.name_identifiers = ['xxy1']
4032
    user1.store()
4033
    user2 = pub.user_class()
4034
    user2.roles = [role.id]
4035
    user2.name_identifiers = ['xxy2']
4036
    user2.store()
4037

  
4038
    formdef.workflow_roles = {'_receiver': role.id}
4039

  
4040
    item.to = ['_receiver']
4041
    item.perform(formdata)
4042
    assert http_requests.count() == 2
4043
    assert set(x['url'] for x in http_requests.requests) == set([
4044
        'https://portal/api/notification/add/?NameID=xxy1',
4045
        '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 get_parameters(self):
71
        return ('to', 'title', 'body', 'origin', 'condition')
72

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

  
97
    def perform(self, formdata):
98
        if not (self.is_available() and self.to and self.title and self.body):
99
            return
100

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

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

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

  
128
        users = []
129
        for dest in self.to:
130
            if dest == '_submitter':
131
                users.append(formdata.get_user())
132
                continue
133

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

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

  
148
register_item_class(SendNotificationWorkflowStatusItem)
wcs/workflows.py
2801 2801
    import wf.profile
2802 2802
    import wf.backoffice_fields
2803 2803
    import wf.redirect_to_url
2804
    import wf.notification
2804 2805

  
2805 2806
from wf.export_to_model import ExportToModel
2806
-