0001-orange_sms-initial-version-41092.patch
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 |
- |