Projet

Général

Profil

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

Nicolas Roche, 14 juillet 2020 16:37

Télécharger (7,24 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    | 36 +++++++
 passerelle/apps/twilio/migrations/__init__.py |  0
 passerelle/apps/twilio/models.py              | 96 +++++++++++++++++++
 passerelle/settings.py                        |  1 +
 5 files changed, 133 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-05-02 09:38
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
                ('default_country_code', models.CharField(default='33', max_length=3, verbose_name='Default country code')),
28
                ('default_trunk_prefix', models.CharField(default='0', max_length=2, verbose_name='Default trunk prefix')),
29
                ('users', models.ManyToManyField(blank=True, related_name='_twiliosmsgateway_users_+', related_query_name='+', to='base.ApiUser')),
30
            ],
31
            options={
32
                'verbose_name': 'Twilio',
33
                'db_table': 'sms_twilio',
34
            },
35
        ),
36
    ]
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
import requests
17
from requests.auth import HTTPBasicAuth
18

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

  
22
from passerelle.utils.jsonresponse import APIError
23
from passerelle.sms.models import SMSResource
24

  
25

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

  
30
    class Meta:
31
        verbose_name = 'Twilio'
32
        db_table = 'sms_twilio'
33

  
34
    TEST_DEFAULTS = {
35
        'create_kwargs': {
36
            'account_sid': 'ACxxx',
37
            'auth_token': 'yyy',
38
        },
39
        'test_vectors': [
40
            {
41
                'status_code': 400,
42
                'response': 'my error message',
43
                'result': {
44
                    'err': 1,
45
                    'err_desc': 'Twilio error: some destinations failed',
46
                    'data': [
47
                        ['+33688888888', "Twilio error: my error message"],
48
                        ['+33677777777', "Twilio error: my error message"],
49
                    ],
50
                }
51
            },
52
            {
53
                'status_code': 201,
54
                'result': {
55
                    'err': 0,
56
                    'data': None,
57
                }
58
            }
59
        ],
60
    }
61
    URL = 'https://api.twilio.com/2010-04-01/Accounts'
62

  
63
    def send_msg(self, text, sender, destinations, **kwargs):
64
        """Send a SMS using the Twilio provider"""
65
        # from https://www.twilio.com/docs/usage/requests-to-twilio
66

  
67
        # set destinations phone number in E.164 format
68
        # [+][country code][phone number including area code]
69
        numbers = []
70
        for dest in destinations:
71
            numbers.append('+' + dest[2:])
72
        destinations = numbers
73

  
74
        url = '%s/%s/Messages.json' % (TwilioSMSGateway.URL, self.account_sid)
75
        auth = HTTPBasicAuth(self.account_sid, self.auth_token)
76
        results = []
77
        for dest in destinations:
78
            params = {
79
                'Body': text,
80
                'From': sender,
81
                'To': dest
82
            }
83
            try:
84
                resp = self.requests.post(url, params, auth=auth)
85
            except requests.RequestException as exc:
86
                raise APIError('Twilio error: POST failed, %s' % exc)
87
            else:
88
                if resp.status_code != 201:
89
                    results.append('Twilio error: %s' % resp.text)
90
                else:
91
                    results.append(0)
92
        if any(results):
93
            raise APIError(
94
                'Twilio error: some destinations failed',
95
                data=list(zip(destinations, results)))
96
        return None
passerelle/settings.py
150 150
    'passerelle.apps.okina',
151 151
    'passerelle.apps.opendatasoft',
152 152
    'passerelle.apps.opengis',
153 153
    'passerelle.apps.orange',
154 154
    'passerelle.apps.ovh',
155 155
    'passerelle.apps.oxyd',
156 156
    'passerelle.apps.phonecalls',
157 157
    'passerelle.apps.solis',
158
    'passerelle.apps.twilio',
158 159
    'passerelle.apps.vivaticket',
159 160
    # backoffice templates and static
160 161
    'gadjo',
161 162
)
162 163

  
163 164
# disable some applications for now
164 165
PASSERELLE_APP_BDP_ENABLED = False
165 166
PASSERELLE_APP_GDC_ENABLED = False
166
-