0001-orange-add-an-option-to-pass-sender-name-56345.patch
passerelle/apps/orange/migrations/0010_orangesmsgateway_provide_sender.py | ||
---|---|---|
1 |
# Generated by Django 2.2.19 on 2021-08-24 14:30 |
|
2 | ||
3 |
from django.db import migrations, models |
|
4 | ||
5 | ||
6 |
class Migration(migrations.Migration): |
|
7 | ||
8 |
dependencies = [ |
|
9 |
('orange', '0009_auto_20210202_1304'), |
|
10 |
] |
|
11 | ||
12 |
operations = [ |
|
13 |
migrations.AddField( |
|
14 |
model_name='orangesmsgateway', |
|
15 |
name='provide_sender', |
|
16 |
field=models.BooleanField( |
|
17 |
default=False, |
|
18 |
help_text='Sender name must be allowed by orange', |
|
19 |
verbose_name='Use sender configurated with Publik', |
|
20 |
), |
|
21 |
), |
|
22 |
] |
passerelle/apps/orange/models.py | ||
---|---|---|
44 | 44 | |
45 | 45 |
class OrangeSMSGateway(SMSResource): |
46 | 46 |
hide_description_fields = ['groupname'] |
47 | 47 | |
48 | 48 |
username = models.CharField(verbose_name=_('Identifier'), max_length=64) |
49 | 49 |
password = models.CharField(verbose_name=_('Password'), max_length=64) |
50 | 50 |
groupname = models.CharField(verbose_name=_('Group'), max_length=64) |
51 | 51 | |
52 |
provide_sender = models.BooleanField( |
|
53 |
_('Use sender configurated with Publik'), |
|
54 |
default=False, |
|
55 |
help_text=_('Sender name must be allowed by orange'), |
|
56 |
) |
|
57 | ||
52 | 58 |
class Meta: |
53 | 59 |
verbose_name = _('Orange') |
54 | 60 |
db_table = 'sms_orange' |
55 | 61 | |
56 | 62 |
def get_access_token(self): |
57 | 63 |
headers = {'content-type': 'application/x-www-form-urlencoded'} |
58 | 64 |
params = {'username': self.username, 'password': self.password} |
59 | 65 |
response = self.requests.post(URL_TOKEN, data=params, headers=headers) |
... | ... | |
74 | 80 |
for group in response_json: |
75 | 81 |
if group['name'] == self.groupname: |
76 | 82 |
group_id = group['id'] |
77 | 83 |
break |
78 | 84 |
if not group_id: |
79 | 85 |
raise APIError('Group name not found: ' + self.groupname) |
80 | 86 |
return group_id |
81 | 87 | |
82 |
def diffusion(self, access_token, group_id, destinations, message): |
|
88 |
def diffusion(self, access_token, group_id, destinations, message, sender):
|
|
83 | 89 |
headers = { |
84 | 90 |
'content-type': 'application/json', |
85 | 91 |
'authorization': 'Bearer %s' % access_token, |
86 | 92 |
} |
87 | 93 |
payload = { |
88 | 94 |
'name': 'Send a SMS from passerelle', |
89 | 95 |
'msisdns': destinations, |
90 | 96 |
'smsParam': {'encoding': 'GSM7', 'body': message}, |
91 | 97 |
} |
98 |
if self.provide_sender: |
|
99 |
payload['smsParam']['senderName'] = sender |
|
92 | 100 |
response = self.requests.post(URL_DIFFUSION % group_id, json=payload, headers=headers) |
93 | 101 |
if response.status_code != 201: |
94 | 102 |
raise OrangeError('Orange fails to send SMS: %s, %s' % (response.status_code, response.text)) |
95 | 103 |
return get_json(response) |
96 | 104 | |
97 | 105 |
def send_msg(self, text, sender, destinations, **kwargs): |
98 | 106 |
'''Send a SMS using the Orange provider''' |
99 | 107 | |
100 | 108 |
access_token = self.get_access_token() |
101 | 109 |
group_id = self.group_id_from_name(access_token) |
102 |
response = self.diffusion(access_token, group_id, destinations, text) |
|
110 |
response = self.diffusion(access_token, group_id, destinations, text, sender)
|
|
103 | 111 |
return response |
tests/test_orange.py | ||
---|---|---|
25 | 25 |
from passerelle.apps.orange.models import OrangeError, OrangeSMSGateway |
26 | 26 |
from passerelle.base.models import AccessRight, ApiUser, Job |
27 | 27 |
from passerelle.utils.jsonresponse import APIError |
28 | 28 | |
29 | 29 |
NETLOC = 'contact-everyone.orange-business.com' |
30 | 30 |
JSON_HEADERS = {'content-type': 'application/json'} |
31 | 31 |
PAYLOAD = { |
32 | 32 |
'message': 'hello', |
33 |
'from': '+33699999999',
|
|
33 |
'from': 'john',
|
|
34 | 34 |
'to': ['+33688888888', '+33677777777'], |
35 | 35 |
} |
36 | 36 | |
37 | 37 | |
38 | 38 |
@httmock.urlmatch(netloc=NETLOC, path='/api/v1.2/oauth/token', method='POST') |
39 | 39 |
def response_token_ok(url, request): |
40 | 40 |
assert 'username=jdoe' in request.body |
41 | 41 |
assert 'password=secret' in request.body |
... | ... | |
54 | 54 |
return httmock.response(200, content, JSON_HEADERS) |
55 | 55 | |
56 | 56 | |
57 | 57 |
@httmock.urlmatch(netloc=NETLOC, path='/api/v1.2/groups/gid2/diffusion-requests', method='POST') |
58 | 58 |
def response_diffusion_ok(url, request): |
59 | 59 |
assert request.headers['authorization'] == 'Bearer my_token' |
60 | 60 |
request_body = json.loads(force_text(request.body)) |
61 | 61 |
assert request_body['smsParam']['body'] == PAYLOAD['message'] |
62 |
assert 'senderName' not in request_body['smsParam'].keys() |
|
62 | 63 |
'33688888888' in request_body['msisdns'][0] |
63 | 64 |
'33677777777' in request_body['msisdns'][1] |
64 | 65 |
content = json.dumps({'status': "I'm ok"}) |
65 | 66 |
return httmock.response(201, content, JSON_HEADERS) |
66 | 67 | |
67 | 68 | |
68 | 69 |
@httmock.urlmatch(netloc=NETLOC) |
69 | 70 |
def response_500(url, request): |
... | ... | |
142 | 143 |
with pytest.raises(OrangeError, match='Orange returned Invalid JSON content'): |
143 | 144 |
with httmock.HTTMock(response_invalid_json): |
144 | 145 |
orange.group_id_from_name('my_token') |
145 | 146 | |
146 | 147 | |
147 | 148 |
def test_diffusion(app, connector): |
148 | 149 |
orange = OrangeSMSGateway() |
149 | 150 |
with httmock.HTTMock(response_diffusion_ok): |
150 |
resp = orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message']) |
|
151 |
resp = orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from'])
|
|
151 | 152 |
assert resp['status'] == "I'm ok" |
152 | 153 | |
153 | 154 |
# not 201 |
154 | 155 |
with pytest.raises(OrangeError, match='Orange fails to send SMS'): |
155 | 156 |
with httmock.HTTMock(response_500): |
156 |
orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message']) |
|
157 |
orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from'])
|
|
157 | 158 | |
158 | 159 |
# not json |
159 | 160 |
@httmock.urlmatch(netloc=NETLOC) |
160 | 161 |
def mocked_response(url, request): |
161 | 162 |
return httmock.response(201, 'not a JSON content') |
162 | 163 | |
163 | 164 |
with pytest.raises(OrangeError, match='Orange returned Invalid JSON content'): |
164 | 165 |
with httmock.HTTMock(mocked_response): |
165 |
orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message']) |
|
166 |
orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from']) |
|
167 | ||
168 |
# sender name not allowed |
|
169 |
@httmock.urlmatch(netloc=NETLOC) |
|
170 |
def mocked_response(url, request): |
|
171 |
request_body = json.loads(force_text(request.body)) |
|
172 |
assert request_body['smsParam']['senderName'] == 'john' |
|
173 |
error_response = [ |
|
174 |
{ |
|
175 |
'code': 'SenderNameNotAllowed', |
|
176 |
'field': 'smsParam.senderName', |
|
177 |
'message': 'The given sender name is not allowed.', |
|
178 |
} |
|
179 |
] |
|
180 |
return httmock.response(400, json.dumps(error_response)) |
|
181 | ||
182 |
orange.provide_sender = True |
|
183 |
orange.save() |
|
184 |
with pytest.raises(OrangeError, match='The given sender name is not allowed.'): |
|
185 |
with httmock.HTTMock(mocked_response): |
|
186 |
orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from']) |
|
166 | 187 | |
167 | 188 | |
168 | 189 |
def test_send_msg(app, connector): |
169 | 190 |
url = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug) |
170 | 191 |
assert Job.objects.count() == 0 |
171 | 192 |
resp = app.post_json(url, params=PAYLOAD, status=200) |
172 | 193 |
assert not resp.json['err'] |
173 | 194 |
assert Job.objects.count() == 1 |
174 |
- |