From 2136376219688ac60b8e72591b734c3651f783fd Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 24 Aug 2021 16:10:55 +0200
Subject: [PATCH] orange: add an option to pass sender name (#56345)

---
 .../0010_orangesmsgateway_provide_sender.py   | 22 ++++++++++++++
 passerelle/apps/orange/models.py              | 12 ++++++--
 tests/test_orange.py                          | 29 ++++++++++++++++---
 3 files changed, 57 insertions(+), 6 deletions(-)
 create mode 100644 passerelle/apps/orange/migrations/0010_orangesmsgateway_provide_sender.py

diff --git a/passerelle/apps/orange/migrations/0010_orangesmsgateway_provide_sender.py b/passerelle/apps/orange/migrations/0010_orangesmsgateway_provide_sender.py
new file mode 100644
index 00000000..8f64b763
--- /dev/null
+++ b/passerelle/apps/orange/migrations/0010_orangesmsgateway_provide_sender.py
@@ -0,0 +1,22 @@
+# Generated by Django 2.2.19 on 2021-08-24 14:30
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('orange', '0009_auto_20210202_1304'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='orangesmsgateway',
+            name='provide_sender',
+            field=models.BooleanField(
+                default=False,
+                help_text='Sender name must be allowed by orange',
+                verbose_name='Use sender configurated with Publik',
+            ),
+        ),
+    ]
diff --git a/passerelle/apps/orange/models.py b/passerelle/apps/orange/models.py
index 93f717a6..1d962597 100644
--- a/passerelle/apps/orange/models.py
+++ b/passerelle/apps/orange/models.py
@@ -44,16 +44,22 @@ def get_json(response):
 
 class OrangeSMSGateway(SMSResource):
     hide_description_fields = ['groupname']
 
     username = models.CharField(verbose_name=_('Identifier'), max_length=64)
     password = models.CharField(verbose_name=_('Password'), max_length=64)
     groupname = models.CharField(verbose_name=_('Group'), max_length=64)
 
+    provide_sender = models.BooleanField(
+        _('Use sender configurated with Publik'),
+        default=False,
+        help_text=_('Sender name must be allowed by orange'),
+    )
+
     class Meta:
         verbose_name = _('Orange')
         db_table = 'sms_orange'
 
     def get_access_token(self):
         headers = {'content-type': 'application/x-www-form-urlencoded'}
         params = {'username': self.username, 'password': self.password}
         response = self.requests.post(URL_TOKEN, data=params, headers=headers)
@@ -74,30 +80,32 @@ class OrangeSMSGateway(SMSResource):
         for group in response_json:
             if group['name'] == self.groupname:
                 group_id = group['id']
                 break
         if not group_id:
             raise APIError('Group name not found: ' + self.groupname)
         return group_id
 
-    def diffusion(self, access_token, group_id, destinations, message):
+    def diffusion(self, access_token, group_id, destinations, message, sender):
         headers = {
             'content-type': 'application/json',
             'authorization': 'Bearer %s' % access_token,
         }
         payload = {
             'name': 'Send a SMS from passerelle',
             'msisdns': destinations,
             'smsParam': {'encoding': 'GSM7', 'body': message},
         }
+        if self.provide_sender:
+            payload['smsParam']['senderName'] = sender
         response = self.requests.post(URL_DIFFUSION % group_id, json=payload, headers=headers)
         if response.status_code != 201:
             raise OrangeError('Orange fails to send SMS: %s, %s' % (response.status_code, response.text))
         return get_json(response)
 
     def send_msg(self, text, sender, destinations, **kwargs):
         '''Send a SMS using the Orange provider'''
 
         access_token = self.get_access_token()
         group_id = self.group_id_from_name(access_token)
-        response = self.diffusion(access_token, group_id, destinations, text)
+        response = self.diffusion(access_token, group_id, destinations, text, sender)
         return response
diff --git a/tests/test_orange.py b/tests/test_orange.py
index 7dabd9c1..bcb78a4c 100644
--- a/tests/test_orange.py
+++ b/tests/test_orange.py
@@ -25,17 +25,17 @@ from django.utils.encoding import force_text
 from passerelle.apps.orange.models import OrangeError, OrangeSMSGateway
 from passerelle.base.models import AccessRight, ApiUser, Job
 from passerelle.utils.jsonresponse import APIError
 
 NETLOC = 'contact-everyone.orange-business.com'
 JSON_HEADERS = {'content-type': 'application/json'}
 PAYLOAD = {
     'message': 'hello',
-    'from': '+33699999999',
+    'from': 'john',
     'to': ['+33688888888', '+33677777777'],
 }
 
 
 @httmock.urlmatch(netloc=NETLOC, path='/api/v1.2/oauth/token', method='POST')
 def response_token_ok(url, request):
     assert 'username=jdoe' in request.body
     assert 'password=secret' in request.body
@@ -54,16 +54,17 @@ def response_group_ok(url, request):
     return httmock.response(200, content, JSON_HEADERS)
 
 
 @httmock.urlmatch(netloc=NETLOC, path='/api/v1.2/groups/gid2/diffusion-requests', method='POST')
 def response_diffusion_ok(url, request):
     assert request.headers['authorization'] == 'Bearer my_token'
     request_body = json.loads(force_text(request.body))
     assert request_body['smsParam']['body'] == PAYLOAD['message']
+    assert 'senderName' not in request_body['smsParam'].keys()
     '33688888888' in request_body['msisdns'][0]
     '33677777777' in request_body['msisdns'][1]
     content = json.dumps({'status': "I'm ok"})
     return httmock.response(201, content, JSON_HEADERS)
 
 
 @httmock.urlmatch(netloc=NETLOC)
 def response_500(url, request):
@@ -142,32 +143,52 @@ def test_group_id_from_name(app, connector):
     with pytest.raises(OrangeError, match='Orange returned Invalid JSON content'):
         with httmock.HTTMock(response_invalid_json):
             orange.group_id_from_name('my_token')
 
 
 def test_diffusion(app, connector):
     orange = OrangeSMSGateway()
     with httmock.HTTMock(response_diffusion_ok):
-        resp = orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'])
+        resp = orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from'])
     assert resp['status'] == "I'm ok"
 
     # not 201
     with pytest.raises(OrangeError, match='Orange fails to send SMS'):
         with httmock.HTTMock(response_500):
-            orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'])
+            orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from'])
 
     # not json
     @httmock.urlmatch(netloc=NETLOC)
     def mocked_response(url, request):
         return httmock.response(201, 'not a JSON content')
 
     with pytest.raises(OrangeError, match='Orange returned Invalid JSON content'):
         with httmock.HTTMock(mocked_response):
-            orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'])
+            orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from'])
+
+    # sender name not allowed
+    @httmock.urlmatch(netloc=NETLOC)
+    def mocked_response(url, request):
+        request_body = json.loads(force_text(request.body))
+        assert request_body['smsParam']['senderName'] == 'john'
+        error_response = [
+            {
+                'code': 'SenderNameNotAllowed',
+                'field': 'smsParam.senderName',
+                'message': 'The given sender name is not allowed.',
+            }
+        ]
+        return httmock.response(400, json.dumps(error_response))
+
+    orange.provide_sender = True
+    orange.save()
+    with pytest.raises(OrangeError, match='The given sender name is not allowed.'):
+        with httmock.HTTMock(mocked_response):
+            orange.diffusion('my_token', 'gid2', PAYLOAD['to'], PAYLOAD['message'], PAYLOAD['from'])
 
 
 def test_send_msg(app, connector):
     url = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug)
     assert Job.objects.count() == 0
     resp = app.post_json(url, params=PAYLOAD, status=200)
     assert not resp.json['err']
     assert Job.objects.count() == 1
-- 
2.30.2

