Projet

Général

Profil

0001-orange_sms-initial-version-41092.patch

Nicolas Roche, 30 mars 2020 16:43

Télécharger (10,7 ko)

Voir les différences:

Subject: [PATCH] orange_sms: initial version (#41092)

copied from https://github.com/departement-loire-atlantique/passerelle-orangesms
 passerelle/apps/orange_sms/__init__.py        |   0
 .../orange_sms/migrations/0001_initial.py     |  37 +++++++
 .../apps/orange_sms/migrations/__init__.py    |   0
 passerelle/apps/orange_sms/models.py          |  59 +++++++++++
 passerelle/apps/orange_sms/orange_api.py      | 100 ++++++++++++++++++
 passerelle/settings.py                        |   1 +
 6 files changed, 197 insertions(+)
 create mode 100644 passerelle/apps/orange_sms/__init__.py
 create mode 100644 passerelle/apps/orange_sms/migrations/0001_initial.py
 create mode 100644 passerelle/apps/orange_sms/migrations/__init__.py
 create mode 100644 passerelle/apps/orange_sms/models.py
 create mode 100644 passerelle/apps/orange_sms/orange_api.py
passerelle/apps/orange_sms/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-03-30 12:33
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='OrangeRestSMSGateway',
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
                ('username', models.CharField(max_length=64, verbose_name='Identifiant')),
26
                ('password', models.CharField(max_length=64, verbose_name='Mot de passe')),
27
                ('groupname', models.CharField(max_length=64, verbose_name='Groupe')),
28
                ('default_country_code', models.CharField(default='33', max_length=3, verbose_name='Préfixe pays')),
29
                ('default_trunk_prefix', models.CharField(default='0', max_length=2, verbose_name='Préfixe supprimé par défaut')),
30
                ('users', models.ManyToManyField(blank=True, related_name='_orangerestsmsgateway_users_+', related_query_name='+', to='base.ApiUser')),
31
            ],
32
            options={
33
                'verbose_name': 'Orange REST SMS',
34
                'db_table': 'sms_orangerest',
35
            },
36
        ),
37
    ]
passerelle/apps/orange_sms/models.py
1
# -*- coding: utf-8 -*-
2
# MIT License
3
# Copyright (c) 2020 departement-loire-atlantique
4
#
5
# Permission is hereby granted, free of charge, to any person obtaining a copy
6
# of this software and associated documentation files (the "Software"), to deal
7
# in the Software without restriction, including without limitation the rights
8
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
# copies of the Software, and to permit persons to whom the Software is
10
# furnished to do so, subject to the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included in all
13
# copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
# SOFTWARE.
22

  
23
from django.db import models
24

  
25
from . import orange_api
26
from requests import RequestException
27

  
28
from passerelle.utils.jsonresponse import APIError
29
from passerelle.base.models import SMSResource
30

  
31

  
32
class OrangeRestSMSGateway(SMSResource):
33

  
34
    username = models.CharField(verbose_name='Identifiant', max_length=64)
35
    password = models.CharField(verbose_name='Mot de passe', max_length=64)
36
    groupname = models.CharField(verbose_name='Groupe', max_length=64)
37

  
38
    default_country_code = models.CharField(
39
        verbose_name='Préfixe pays', max_length=3, default=u'33')
40
    default_trunk_prefix = models.CharField(
41
        verbose_name='Préfixe supprimé par défaut', max_length=2, default=u'0')
42

  
43
    manager_view_template_name = 'passerelle/manage/messages_service_view.html'
44

  
45
    class Meta:
46
        verbose_name = 'Orange REST SMS'
47
        db_table = 'sms_orangerest'
48

  
49
    def send_msg(self, text, sender, destinations, **kwargs):
50
        """Send a SMS using the Orange REST"""
51

  
52
        destinations = self.clean_numbers(
53
            destinations, self.default_country_code, self.default_trunk_prefix)
54

  
55
        try:
56
            api = orange_api.OrangeAPI(self.username, self.password)
57
            api.send(self.groupname, destinations, text)
58
        except RequestException as e:
59
            raise APIError('Orange REST SMS API error: %s' % e)
passerelle/apps/orange_sms/orange_api.py
1
# MIT License
2
# Copyright (c) 2020 departement-loire-atlantique
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a copy
5
# of this software and associated documentation files (the "Software"), to deal
6
# in the Software without restriction, including without limitation the rights
7
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
# copies of the Software, and to permit persons to whom the Software is
9
# furnished to do so, subject to the following conditions:
10
#
11
# The above copyright notice and this permission notice shall be included in all
12
# copies or substantial portions of the Software.
13
#
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
# SOFTWARE.
21

  
22
import requests
23
import json
24

  
25

  
26
class OrangeAPI:
27

  
28
    BASE_API = "https://contact-everyone.orange-business.com/api/v1.2/"
29
    URL_TOKEN = BASE_API + "oauth/token"
30
    URL_GROUPS = BASE_API + "groups"
31
    URL_DIFFUSION = BASE_API + "groups/%s/diffusion-requests"
32

  
33
    def __init__(self, username, password):
34
        self.username = username
35
        self.password = password
36
        self.authorization_header = {}
37

  
38
    def login(self):
39
        headers = {'content-type': 'application/x-www-form-urlencoded'}
40
        params = {'username': self.username, 'password': self.password}
41

  
42
        rq = requests.post(self.URL_TOKEN, data=params, headers=headers)
43
        if rq.status_code == 200:
44
            response_json = json.loads(rq.text)
45
            if 'access_token' in response_json:
46
                self.authorization_header = {
47
                    'authorization': "Bearer %s" % response_json['access_token']
48
                }
49
            else:
50
                raise requests.RequestException('Orange API: Access token not found')
51
        else:
52
            raise requests.RequestException(
53
                'Orange API: Bad username or password (%s)', rq.status_code)
54

  
55
    def group_id_from_name(self, group_name):
56
        rq = requests.get(self.URL_GROUPS, headers=self.authorization_header)
57
        if rq.status_code == 200:
58
            groups = json.loads(rq.text)
59
            for group in groups:
60
                if group["name"] == group_name:
61
                    return group["id"]
62

  
63
        raise requests.RequestException("Group name not found: " + group_name)
64

  
65
    def send(self, group_name, destinations, message):
66
        self.login()
67
        group_id = self.group_id_from_name(group_name)
68

  
69
        headers = {"content-type": "application/json"}
70
        headers.update(self.authorization_header)
71

  
72
        payload = json.dumps(
73
            {
74
                "name": "Send a SMS from passerelle",
75
                "msisdns": destinations,
76
                "smsParam": {
77
                    "encoding": "GSM7",
78
                    "body": message
79
                }
80
            })
81

  
82
        rq = requests.post(self.URL_DIFFUSION % group_id, data=payload, headers=headers)
83
        if rq.status_code == 201:
84
            return json.loads(rq.text)
85

  
86
        raise Exception("Send SMS failed %s, %s" % (rq.status_code, rq.text))
87

  
88

  
89
if __name__ == '__main__':
90
    import argparse
91
    parser = argparse.ArgumentParser()
92
    parser.add_argument("--username")
93
    parser.add_argument("--password")
94
    parser.add_argument("--groupname")
95
    parser.add_argument("--mobile")
96
    parser.add_argument("--message")
97
    args = parser.parse_args()
98

  
99
    api = OrangeAPI(args.username, args.password)
100
    api.send(args.groupname, [args.mobile], args.message)
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.orange_sms',
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
165
-