Projet

Général

Profil

0001-sms-add-a-twilio-connector-19663.patch

Nicolas Roche, 09 avril 2020 20:26

Télécharger (7,67 ko)

Voir les différences:

Subject: [PATCH] sms: add a twilio connector (#19663)

 passerelle/apps/twilio/__init__.py            |  0
 .../apps/twilio/migrations/0001_initial.py    | 34 +++++++++++
 passerelle/apps/twilio/migrations/__init__.py |  0
 passerelle/apps/twilio/models.py              | 58 +++++++++++++++++++
 passerelle/settings.py                        |  1 +
 setup.py                                      |  1 +
 tests/test_sms.py                             |  3 +
 7 files changed, 97 insertions(+)
 create mode 100644 passerelle/apps/twilio/__init__.py
 create mode 100644 passerelle/apps/twilio/migrations/0001_initial.py
 create mode 100644 passerelle/apps/twilio/migrations/__init__.py
 create mode 100644 passerelle/apps/twilio/models.py
passerelle/apps/twilio/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-04-09 18:07
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    initial = True
11

  
12
    dependencies = [
13
        ('base', '0018_smslog'),
14
    ]
15

  
16
    operations = [
17
        migrations.CreateModel(
18
            name='TwilioSMSGateway',
19
            fields=[
20
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
                ('title', models.CharField(max_length=50, verbose_name='Title')),
22
                ('slug', models.SlugField(unique=True, verbose_name='Identifier')),
23
                ('description', models.TextField(verbose_name='Description')),
24
                ('max_message_length', models.IntegerField(default=160, verbose_name='Maximum message length')),
25
                ('account_sid', models.CharField(max_length=64, verbose_name='Account Sid')),
26
                ('auth_token', models.CharField(max_length=64, verbose_name='Auth Token')),
27
                ('users', models.ManyToManyField(blank=True, related_name='_twiliosmsgateway_users_+', related_query_name='+', to='base.ApiUser')),
28
            ],
29
            options={
30
                'verbose_name': 'Twilio',
31
                'db_table': 'sms_twilio',
32
            },
33
        ),
34
    ]
passerelle/apps/twilio/models.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2020  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from twilio.base.exceptions import TwilioRestException
18
from twilio.rest import Client
19

  
20
from django.db import models
21
from django.utils.translation import ugettext_lazy as _
22

  
23
from passerelle.utils.jsonresponse import APIError
24
from passerelle.base.models import SMSResource
25

  
26

  
27
class TwilioSMSGateway(SMSResource):
28
    account_sid = models.CharField(verbose_name=_('Account Sid'), max_length=64)
29
    auth_token = models.CharField(verbose_name=_('Auth Token'), max_length=64)
30

  
31
    manager_view_template_name = 'passerelle/manage/messages_service_view.html'
32

  
33
    class Meta:
34
        verbose_name = 'Twilio'
35
        db_table = 'sms_twilio'
36

  
37
    def send_msg(self, text, sender, destinations, **kwargs):
38
        """Send a SMS using the Twilio provider"""
39

  
40
        client = Client(self.account_sid, self.auth_token)
41
        results = []
42
        for dest in destinations:
43
            params = {
44
                'body': text,
45
                'from_': self.phone_number,
46
                'to': dest
47
            }
48
            try:
49
                client.messages.create(**params)
50
            except TwilioRestException as e:
51
                results.append('Twilio error: POST failed, %s' % e)
52
            else:
53
                results.append(0)
54
        if any(results):
55
            raise APIError(
56
                'Twilio error: some destinations failed',
57
                data=list(zip(destinations, results)))
58
        return None
passerelle/settings.py
149 149
    'passerelle.apps.opengis',
150 150
    'passerelle.apps.orange',
151 151
    'passerelle.apps.ovh',
152 152
    'passerelle.apps.oxyd',
153 153
    'passerelle.apps.pastell',
154 154
    'passerelle.apps.phonecalls',
155 155
    'passerelle.apps.solis',
156 156
    'passerelle.apps.vivaticket',
157
    'passerelle.apps.twilio',
157 158
    # backoffice templates and static
158 159
    'gadjo',
159 160
)
160 161

  
161 162
# disable some applications for now
162 163
PASSERELLE_APP_BDP_ENABLED = False
163 164
PASSERELLE_APP_GDC_ENABLED = False
164 165
PASSERELLE_APP_PASTELL_ENABLED = False
setup.py
105 105
            'zeep >= 3.2',
106 106
            'pycrypto',
107 107
            'pycryptodomex',
108 108
            'unidecode',
109 109
            'paramiko',
110 110
            'pdfrw',
111 111
            'httplib2',
112 112
            'xmlschema',
113
            'twilio',
113 114
        ],
114 115
        cmdclass={
115 116
            'build': build,
116 117
            'compile_translations': compile_translations,
117 118
            'install_lib': install_lib,
118 119
            'sdist': eo_sdist,
119 120
        },
120 121
      package_data={'passerelle': ['*.xsd']}
tests/test_sms.py
1 1
import mock
2 2
import pytest
3 3

  
4 4
from django.contrib.contenttypes.models import ContentType
5 5

  
6 6
from passerelle.apps.ovh.models import OVHSMSGateway
7
from passerelle.apps.twilio.models import TwilioSMSGateway
7 8
from passerelle.base.models import ApiUser, AccessRight, SMSResource, SMSLog
8 9

  
9 10
from test_manager import login, admin_user
10 11

  
11 12
import utils
12 13

  
13 14
pytestmark = pytest.mark.django_db
14 15

  
......
50 51
    assert result.json['err'] == 1
51 52
    assert result.json['err_desc'].startswith('Payload error: ')
52 53

  
53 54
    payload = {
54 55
        'message': 'hello',
55 56
        'from': '+33699999999',
56 57
        'to': ['+33688888888', '+33677777777'],
57 58
    }
59
    if connector == TwilioSMSGateway:
60
        return  # twilio do not expose an URL to mock
58 61
    for test_vector in getattr(connector, 'TEST_DEFAULTS', {}).get('test_vectors', []):
59 62
        with utils.mock_url(connector.URL, test_vector['response']):
60 63
            result = app.post_json(path, params=payload)
61 64
            for key, value in test_vector['result'].items():
62 65
                assert key in result.json
63 66
                assert result.json[key] == value
64 67

  
65 68

  
66
-