Projet

Général

Profil

0001-sms-add-endpoint-to-send-SMS-asynchronously-21465.patch

Nicolas Roche, 10 avril 2020 18:32

Télécharger (6,99 ko)

Voir les différences:

Subject: [PATCH] sms: add endpoint to send SMS asynchronously (#21465)

 passerelle/base/models.py | 33 +++++++++++++++++++++++++-------
 tests/test_sms.py         | 40 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 9 deletions(-)
passerelle/base/models.py
932 932
            elif number.startswith(default_trunk_prefix):
933 933
                number = '00' + default_country_code + number[len(default_trunk_prefix):]
934 934
            else:
935 935
                raise APIError('phone number %r is unsupported (no international prefix, '
936 936
                               'no local trunk prefix)' % number)
937 937
            numbers.append(number)
938 938
        return numbers
939 939

  
940
    @endpoint(perm='can_send_messages', methods=['post'])
941
    def send(self, request, *args, **kwargs):
940
    def get_parameters(self, request, *args, **kwargs):
942 941
        try:
943 942
            data = json_loads(request.body)
944 943
            assert isinstance(data, dict), 'JSON payload is not a dict'
945 944
            assert 'message' in data, 'missing "message" in JSON payload'
946 945
            assert 'from' in data, 'missing "from" in JSON payload'
947 946
            assert 'to' in data, 'missing "to" in JSON payload'
948 947
            assert isinstance(data['message'], six.text_type), 'message is not a string'
949 948
            assert isinstance(data['from'], six.text_type), 'from is not a string'
950 949
            assert all(map(lambda x: isinstance(x, six.text_type), data['to'])), \
951 950
                'to is not a list of strings'
952 951
        except (ValueError, AssertionError) as e:
953 952
            raise APIError('Payload error: %s' % e)
954
        data['message'] = data['message'][:self.max_message_length]
955
        logging.info('sending message %r to %r with sending number %r',
956
                     data['message'], data['to'], data['from'])
957
        stop = not bool('nostop' in request.GET)
958
        result = {'data': self.send_msg(data['message'], data['from'], data['to'], stop=stop)}
953
        parameters = {
954
            'text': data['message'][:self.max_message_length],
955
            'sender': data['from'],
956
            'destinations': data['to'],
957
            'stop': not bool('nostop' in request.GET)
958
        }
959
        logging.info(
960
            'sending message %r to %r with sending number %r',
961
            parameters['text'], parameters['destinations'], parameters['sender'])
962
        return parameters
963

  
964
    def call_send_msg(self, *args, **kwargs):
965
        resp = self.send_msg(**kwargs)
959 966
        SMSLog.objects.create(appname=self.get_connector_slug(), slug=self.slug)
967
        return resp
968

  
969
    @endpoint(perm='can_send_messages', methods=['post'])
970
    def send(self, request, *args, **kwargs):
971
        parameters = self.get_parameters(request, *args, **kwargs)
972
        result = {'data': self.call_send_msg(**parameters)}
960 973
        return result
961 974

  
975
    @endpoint(perm='can_send_messages', methods=['post'])
976
    def send_async(self, request, *args, **kwargs):
977
        parameters = self.get_parameters(request, *args, **kwargs)
978
        self.add_job('call_send_msg', **parameters)
979
        return {'err': 0, 'data': parameters}
980

  
962 981
    class Meta:
963 982
        abstract = True
964 983

  
965 984

  
966 985
@six.python_2_unicode_compatible
967 986
class SMSLog(models.Model):
968 987
    timestamp = models.DateTimeField(auto_now_add=True)
969 988
    appname = models.CharField(max_length=128, verbose_name='appname', null=True)
tests/test_sms.py
1 1
import mock
2 2
import pytest
3 3

  
4 4
from django.contrib.contenttypes.models import ContentType
5 5

  
6 6
from passerelle.apps.ovh.models import OVHSMSGateway
7
from passerelle.base.models import ApiUser, AccessRight, SMSResource, SMSLog
7
from passerelle.base.models import ApiUser, AccessRight, Job, SMSResource, SMSLog
8 8

  
9 9
from test_manager import login, admin_user
10 10

  
11 11
import utils
12 12

  
13 13
pytestmark = pytest.mark.django_db
14 14

  
15 15
klasses = SMSResource.__subclasses__()
......
61 61
                test_vector.get('response', ''),
62 62
                test_vector.get('status_code', 200)):
63 63

  
64 64
            result = app.post_json(path, params=payload)
65 65
            for key, value in test_vector['result'].items():
66 66
                assert key in result.json
67 67
                assert result.json[key] == value
68 68

  
69
def test_send_async(app, connector):
70
    path = '/%s/%s/send_async/' % (connector.get_connector_slug(), connector.slug)
71
    result = app.post_json(path, params={})
72
    assert result.json['err'] == 1
73
    assert result.json['err_desc'].startswith('Payload error: ')
74

  
75
    payload = {
76
        'message': 'hello',
77
        'from': '+33699999999',
78
        'to': ['+33688888888', '+33677777777'],
79
    }
80
    test_vectors = getattr(connector, 'TEST_DEFAULTS', {}).get('test_vectors', [])
81
    total = len(test_vectors)
82
    nb_failed = 0
83
    assert Job.objects.count() == 0
84
    for test_vector in test_vectors:
85

  
86
        # register job
87
        result = app.post_json(path, params=payload)
88
        job = Job.objects.get(status='registered')
89

  
90
        # perform job
91
        with utils.mock_url(
92
                connector.URL,
93
                test_vector.get('response', ''),
94
                test_vector.get('status_code', 200)):
95
            connector.jobs()
96
        job = Job.objects.get(id=job.id)
97
        if job.status == 'failed':
98
            assert test_vector['result']['err_desc'] in job.status_details['error_summary']
99
            nb_failed += 1
100
        else:
101
            assert job.status == 'completed'
102

  
103
    assert Job.objects.count() == total
104
    assert SMSLog.objects.count() == total - nb_failed
69 105

  
70 106
def test_manage_views(admin_user, app, connector):
71 107
    url = '/%s/%s/' % (connector.get_connector_slug(), connector.slug)
72 108
    resp = app.get(url)
73 109
    assert 'Endpoints' in resp.text
74 110
    assert not 'accessright/add' in resp.text
75 111
    app = login(app)
76 112
    resp = app.get(url)
......
86 122
    payload = {
87 123
        'message': message_above_limit,
88 124
        'from': '+33699999999',
89 125
        'to': ['+33688888888'],
90 126
    }
91 127
    with mock.patch.object(OVHSMSGateway, 'send_msg') as send_function:
92 128
        send_function.return_value = {}
93 129
        result = app.post_json(path, params=payload)
94
        assert send_function.call_args[0][0] == 'a' * connector.max_message_length
130
        assert send_function.call_args[1]['text'] == 'a' * connector.max_message_length
95 131

  
96 132

  
97 133
@pytest.mark.parametrize('connector', [OVHSMSGateway], indirect=True)
98 134
def test_sms_log(app, connector):
99 135
    path = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug)
100 136
    assert not SMSLog.objects.filter(appname=connector.get_connector_slug(), slug=connector.slug).exists()
101 137

  
102 138
    payload = {
103
-