Projet

Général

Profil

0002-sms-return-filtered-numbers-to-caller-39650.patch

Nicolas Roche, 02 février 2021 21:11

Télécharger (8,78 ko)

Voir les différences:

Subject: [PATCH 2/2] sms: return filtered numbers to caller (#39650)

 passerelle/sms/models.py | 27 +++++++++++++++++++--------
 passerelle/sms/views.py  |  2 +-
 tests/test_sms.py        | 37 ++++++++++++++++++++++++++++---------
 3 files changed, 48 insertions(+), 18 deletions(-)
passerelle/sms/models.py
142 142
            if SMSResource.BE_ in self.authorized:
143 143
                regexes.append(r'^00324[5-9]\d{7}$')  # Belgian
144 144
        country_regex = re.compile('|'.join(regexes))
145 145

  
146 146
        if not self.allow_premium_rate:
147 147
            premium_numbers = set(dest for dest in destinations if premium_regex.match(dest))
148 148
        if SMSResource.ALL not in self.authorized:
149 149
            foreign_numbers = set(dest for dest in destinations if not country_regex.match(dest))
150
        for number in list(premium_numbers):
151
            logging.warning('unauthorized premium rate phone number: %s', number)
152
        for number in list(foreign_numbers - premium_numbers):
153
            logging.warning('unauthorized foreign phone number: %s', number)
154
        authorized_numbers = list(set(destinations) - foreign_numbers - premium_numbers)
150

  
151
        authorized_numbers = sorted(
152
            set(destinations) - foreign_numbers - premium_numbers,
153
            key=int)
154
        premium_numbers_string = ", ".join(sorted(premium_numbers, key=int))
155
        foreign_numbers_string = ", ".join(sorted(foreign_numbers - premium_numbers, key=int))
156
        if premium_numbers_string:
157
            logging.warning('unauthorized premium rate phone number: %s',
158
                            premium_numbers_string)
159
        if foreign_numbers_string:
160
            logging.warning('unauthorized foreign phone number: %s',
161
                            foreign_numbers_string)
155 162
        if len(authorized_numbers) == 0:
156 163
            raise APIError('no phone number was authorized: %s' % ', '.join(destinations))
157
        return authorized_numbers
164
        warnings = {
165
            'deny premium rate phone numbers': premium_numbers_string,
166
            'deny foreign phone numbers': foreign_numbers_string,
167
        }
168
        return authorized_numbers, warnings
158 169

  
159 170
    @endpoint(perm='can_send_messages', methods=['post'],
160 171
              description=_('Send a SMS message'),
161 172
              parameters={'nostop': {'description': _('Do not send STOP instruction'), 'example_value': '1'}},
162 173
              post={'request_body': {'schema': {'application/json': SEND_SCHEMA}}})
163 174
    def send(self, request, post_data, nostop=None):
164 175
        post_data['message'] = post_data['message'][:self.max_message_length]
165 176
        post_data['to'] = self.clean_numbers(post_data['to'])
166
        post_data['to'] = self.authorize_numbers(post_data['to'])
177
        post_data['to'], warnings = self.authorize_numbers(post_data['to'])
167 178
        logging.info('sending SMS to %r from %r', post_data['to'], post_data['from'])
168 179
        stop = nostop is None  # ?nostop in not in query string
169 180
        self.add_job('send_job',
170 181
                     text=post_data['message'], sender=post_data['from'], destinations=post_data['to'],
171 182
                     stop=stop)
172
        return {'err': 0}
183
        return {'err': 0, 'warn': warnings}
173 184

  
174 185
    def send_job(self, *args, **kwargs):
175 186
        self.send_msg(**kwargs)
176 187
        SMSLog.objects.create(appname=self.get_connector_slug(), slug=self.slug)
177 188

  
178 189
    class Meta:
179 190
        abstract = True
180 191

  
passerelle/sms/views.py
24 24

  
25 25
    def form_valid(self, form):
26 26
        number = form.cleaned_data['number']
27 27
        sender = form.cleaned_data['sender']
28 28
        message = form.cleaned_data['message']
29 29
        connector = self.get_object()
30 30
        try:
31 31
            number = connector.clean_numbers([number])[0]
32
            number = connector.authorize_numbers([number])[0]
32
            number = connector.authorize_numbers([number])[0][0]
33 33
            connector.send_msg(
34 34
                text=message, sender=sender, destinations=[number], stop=False)
35 35
        except APIError as exc:
36 36
            messages.error(self.request, _('Sending SMS fails: %s' % exc))
37 37
        else:
38 38
            messages.success(self.request, _('An SMS was just sent'))
39 39
        return super(SmsTestSendView, self).form_valid(form)
tests/test_sms.py
57 57

  
58 58
def test_authorize_numbers():
59 59
    connector = OVHSMSGateway()
60 60

  
61 61
    # premium-rate
62 62
    assert connector.allow_premium_rate == False
63 63
    number = '0033' + '8' + '12345678'
64 64
    with pytest.raises(APIError, match='no phone number was authorized: %s' % number):
65
        assert connector.authorize_numbers([number])
65
        connector.authorize_numbers([number])
66 66
    connector.allow_premium_rate = True
67 67
    connector.save()
68
    assert connector.authorize_numbers([number])[0] == [number]
68 69

  
69 70
    # All country
70 71
    assert connector.authorized == [SMSResource.ALL]
71 72
    number = '0033' + '1' + '12345678'
72
    assert connector.authorize_numbers([number]) == [number]
73
    assert connector.authorize_numbers([number])[0] == [number]
73 74
    connector.authorized = [SMSResource.FR_METRO]
74 75
    connector.save()
75 76
    with pytest.raises(APIError, match='no phone number was authorized: %s' % number):
76 77
        connector.authorize_numbers([number])
77 78

  
78 79
    # France
79 80
    number = '0033' + '6' + '12345678'
80
    assert connector.authorize_numbers([number]) == [number]
81
    assert connector.authorize_numbers([number])[0] == [number]
81 82
    connector.authorized = [SMSResource.FR_DOMTOM]
82 83
    connector.save()
83 84
    with pytest.raises(APIError, match='no phone number was authorized: %s' % number):
84 85
        connector.authorize_numbers([number])
85 86

  
86 87
    # Dom-Tom
87 88
    number = '596596' + '123456'
88
    assert connector.authorize_numbers([number]) == [number]
89
    assert connector.authorize_numbers([number])[0] == [number]
89 90
    connector.authorized = [SMSResource.BE_]
90 91
    connector.save()
91 92
    with pytest.raises(APIError, match='no phone number was authorized: %s' % number):
92 93
        connector.authorize_numbers([number])
93 94

  
94 95
    # Belgian
95 96
    number = '0032' + '45' + '1234567'
96
    assert connector.authorize_numbers([number]) == [number]
97
    assert connector.authorize_numbers([number])[0] == [number]
97 98
    connector.authorized = [SMSResource.FR_METRO]
98 99
    connector.save()
99 100
    with pytest.raises(APIError, match='no phone number was authorized: %s' % number):
100 101
        connector.authorize_numbers([number])
101 102

  
102
    # Don't raise if filtered destination is not empty
103
    numbers = ['0033' + '6' + '12345678', '0032' + '45' + '1234567']
104
    assert len(connector.authorize_numbers(numbers)) == 1
103
    # Don't raise if authorized destinations are not empty
104
    connector.allow_premium_rate = False
105
    connector.authorized = [SMSResource.FR_METRO]
106
    connector.save()
107
    numbers = [
108
        '0033' + '8' + '12345678',
109
        '0033' + '1' + '12345678',
110
        '0033' + '6' + '12345678',
111
        '596596' + '123456',
112
        '0032' + '45' + '1234567',
113
    ]
114
    authorized_numbers, warnings = connector.authorize_numbers(numbers)
115
    assert authorized_numbers == ['0033612345678']
116
    assert warnings == {
117
        'deny premium rate phone numbers': '0033812345678',
118
        'deny foreign phone numbers': '0032451234567, 0033112345678, 596596123456',
119
    }
105 120

  
106 121

  
107 122
@pytest.fixture(params=klasses)
108 123
def connector(request, db):
109 124
    klass = request.param
110 125
    kwargs = getattr(klass, 'TEST_DEFAULTS', {}).get('create_kwargs', {})
111 126
    kwargs.update({
112 127
        'title': klass.__name__,
......
497 512
        if x.text.startswith(_('Authorized Countries'))][0]
498 513

  
499 514
    path = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug)
500 515
    payload = {
501 516
        'message': 'plop',
502 517
        'from': '+33699999999',
503 518
        'to': ['+33688888888'],
504 519
    }
505
    app.post_json(path, params=payload)
520
    resp = app.post_json(path, params=payload)
521
    assert resp.json['warn'] == {
522
        'deny premium rate phone numbers': '',
523
        'deny foreign phone numbers': '',
524
    }
506 525
    with mock.patch.object(type(connector), 'send_msg') as send_function:
507 526
        send_function.return_value = {}
508 527
        connector.jobs()
509 528
    assert SMSLog.objects.count() == 1
510 529

  
511 530
    payload['to'][0] = '+33188888888'
512 531
    SMSLog.objects.all().delete()
513 532
    app.post_json(path, params=payload)
514
-