0001-sms-improve-SMSGatewayMixin.clean_numbers-fixes-6867.patch
passerelle/apps/choosit/migrations/0005_choositsmsgateway_default_trunk_prefix.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('choosit', '0004_auto_20160407_0456'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AddField( |
|
15 |
model_name='choositsmsgateway', |
|
16 |
name='default_trunk_prefix', |
|
17 |
field=models.CharField(default='0', max_length=2), |
|
18 |
preserve_default=True, |
|
19 |
), |
|
20 |
] |
passerelle/apps/choosit/models.py | ||
---|---|---|
14 | 14 | |
15 | 15 | |
16 | 16 |
class ChoositSMSGateway(BaseResource, SMSGatewayMixin): |
17 |
key = models.CharField(max_length=64) |
|
18 |
default_country_code = models.CharField(max_length=3, default=u'33') |
|
17 |
key = models.CharField(verbose_name=_('key'), max_length=64) |
|
18 |
default_country_code = models.CharField(verbose_name=_('default country code'), max_length=3, |
|
19 |
default=u'33') |
|
20 |
default_trunk_prefix = models.CharField(verbose_name=_('default trunk prefix'), max_length=2, |
|
21 |
default=u'0') |
|
19 | 22 |
# FIXME: add regexp field, to check destination and from format |
20 | 23 | |
21 | 24 |
TEST_DEFAULTS = { |
... | ... | |
29 | 32 |
'err': 1, |
30 | 33 |
'err_desc': 'Choosit error: some destinations failed', |
31 | 34 |
'data': [ |
32 |
[u'33688888888', u'Choosit error: bad JSON response No JSON object ' |
|
35 |
[u'0033688888888', u'Choosit error: bad JSON response No JSON object '
|
|
33 | 36 |
'could be decoded'], |
34 |
[u'33677777777', u'Choosit error: bad JSON response No JSON object ' |
|
37 |
[u'0033677777777', u'Choosit error: bad JSON response No JSON object '
|
|
35 | 38 |
'could be decoded'], |
36 | 39 |
] |
37 | 40 |
} |
... | ... | |
44 | 47 |
'err': 1, |
45 | 48 |
'err_desc': 'Choosit error: some destinations failed', |
46 | 49 |
'data': [ |
47 |
[u'33688888888', u'Choosit error: not ok'], |
|
48 |
[u'33677777777', u'Choosit error: not ok'], |
|
50 |
[u'0033688888888', u'Choosit error: not ok'],
|
|
51 |
[u'0033677777777', u'Choosit error: not ok'],
|
|
49 | 52 |
], |
50 | 53 |
} |
51 | 54 |
}, |
... | ... | |
57 | 60 |
'result': { |
58 | 61 |
'err': 0, |
59 | 62 |
'data': [ |
60 |
[u'33688888888', {'result': u'Envoi terminé', 'sms_id': 1234}], |
|
61 |
[u'33677777777', {'result': u'Envoi terminé', 'sms_id': 1234}], |
|
63 |
[u'0033688888888', {'result': u'Envoi terminé', 'sms_id': 1234}],
|
|
64 |
[u'0033677777777', {'result': u'Envoi terminé', 'sms_id': 1234}],
|
|
62 | 65 |
], |
63 | 66 |
} |
64 | 67 |
} |
... | ... | |
83 | 86 |
"""Send a SMS using the Choosit provider""" |
84 | 87 |
# from http://sms.choosit.com/documentation_technique.html |
85 | 88 |
# unfortunately it lacks a batch API... |
86 |
destinations = self.clean_numbers(destinations, self.default_country_code, prefix='') |
|
89 |
destinations = self.clean_numbers(destinations, |
|
90 |
self.default_country_code, |
|
91 |
self.default_trunk_prefix) |
|
87 | 92 |
results = [] |
88 | 93 |
for dest in destinations: |
89 | 94 |
params = { |
passerelle/apps/mobyt/migrations/0005_mobytsmsgateway_default_trunk_prefix.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('mobyt', '0004_auto_20160407_0456'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AddField( |
|
15 |
model_name='mobytsmsgateway', |
|
16 |
name='default_trunk_prefix', |
|
17 |
field=models.CharField(default='0', max_length=2), |
|
18 |
preserve_default=True, |
|
19 |
), |
|
20 |
] |
passerelle/apps/mobyt/models.py | ||
---|---|---|
15 | 15 |
('ll', _('sms low-cost')), |
16 | 16 |
('n', _('sms top')), |
17 | 17 |
) |
18 |
username = models.CharField(max_length=64) |
|
19 |
password = models.CharField(max_length=64) |
|
18 |
username = models.CharField(verbose_name=_('username'), max_length=64)
|
|
19 |
password = models.CharField(verbose_name=_('password'), max_length=64)
|
|
20 | 20 |
quality = models.CharField(max_length=4, choices=MESSAGES_QUALITIES, default='l', |
21 | 21 |
verbose_name=_('message quality')) |
22 |
default_country_code = models.CharField(max_length=3, default=u'33') |
|
22 |
default_country_code = models.CharField(verbose_name=_('default contry code'), max_length=3, |
|
23 |
default=u'33') |
|
24 |
default_trunk_prefix = models.CharField(verbose_name=_('default trunk prefix'), max_length=2, |
|
25 |
default=u'0') |
|
23 | 26 |
# FIXME: add regexp field, to check destination and from format |
24 | 27 | |
25 | 28 |
manager_view_template_name = 'passerelle/manage/messages_service_view.html' |
... | ... | |
53 | 56 |
def send_msg(self, text, sender, destinations, **kwargs): |
54 | 57 |
"""Send a SMS using the Mobyt provider""" |
55 | 58 |
# unfortunately it lacks a batch API... |
56 |
destinations = self.clean_numbers(destinations, self.default_country_code) |
|
59 |
destinations = self.clean_numbers(destinations, |
|
60 |
self.default_country_code, |
|
61 |
self.default_trunk_prefix) |
|
57 | 62 |
rcpt = ','.join(destinations) |
58 | 63 |
params = { |
59 | 64 |
'user': self.username, |
passerelle/apps/ovh/migrations/0005_ovhsmsgateway_default_trunk_prefix.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('ovh', '0004_auto_20160407_0456'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AddField( |
|
15 |
model_name='ovhsmsgateway', |
|
16 |
name='default_trunk_prefix', |
|
17 |
field=models.CharField(default='0', max_length=2), |
|
18 |
preserve_default=True, |
|
19 |
), |
|
20 |
] |
passerelle/apps/ovh/models.py | ||
---|---|---|
21 | 21 |
(3, _('Messages are stored in external storage like a PDA or ' |
22 | 22 |
'a PC.')), |
23 | 23 |
) |
24 |
account = models.CharField(max_length=64) |
|
25 |
username = models.CharField(max_length=64) |
|
26 |
password = models.CharField(max_length=64) |
|
24 |
account = models.CharField(verbose_name=_('account'), max_length=64)
|
|
25 |
username = models.CharField(verbose_name=_('username'), max_length=64)
|
|
26 |
password = models.CharField(verbose_name=_('password'), max_length=64)
|
|
27 | 27 |
msg_class = models.IntegerField(choices=MESSAGES_CLASSES, default=1, |
28 | 28 |
verbose_name=_('message class')) |
29 |
credit_threshold_alert = models.PositiveIntegerField(default=100) |
|
30 |
default_country_code = models.CharField(max_length=3, default=u'33') |
|
31 |
credit_left = models.PositiveIntegerField(default=0) |
|
29 |
credit_threshold_alert = models.PositiveIntegerField(verbose_name=_('credit alert threshold'), |
|
30 |
default=100) |
|
31 |
default_country_code = models.CharField(verbose_name=_('default country code'), max_length=3, |
|
32 |
default=u'33') |
|
33 |
default_trunk_prefix = models.CharField(verbose_name=_('default trunk prefix'), max_length=2, |
|
34 |
default=u'0') |
|
35 |
credit_left = models.PositiveIntegerField(verbose_name=_('credit left'), default=0) |
|
32 | 36 |
# FIXME: add regexp field, to check destination and from format |
33 | 37 | |
34 | 38 |
manager_view_template_name = 'passerelle/manage/messages_service_view.html' |
... | ... | |
83 | 87 | |
84 | 88 |
def send_msg(self, text, sender, destinations, **kwargs): |
85 | 89 |
"""Send a SMS using the OVH provider""" |
86 |
# unfortunately it lacks a batch API... |
|
87 |
destinations = self.clean_numbers(destinations, self.default_country_code) |
|
90 |
destinations = self.clean_numbers(destinations, |
|
91 |
self.default_country_code, |
|
92 |
self.default_trunk_prefix) |
|
88 | 93 | |
89 | 94 |
text = unicode(text).encode('utf-8') |
90 | 95 |
to = ','.join(destinations) |
passerelle/apps/oxyd/migrations/0005_oxydsmsgateway_default_trunk_prefix.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('oxyd', '0004_auto_20160407_0456'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AddField( |
|
15 |
model_name='oxydsmsgateway', |
|
16 |
name='default_trunk_prefix', |
|
17 |
field=models.CharField(default='0', max_length=2), |
|
18 |
preserve_default=True, |
|
19 |
), |
|
20 |
] |
passerelle/apps/oxyd/models.py | ||
---|---|---|
5 | 5 |
from passerelle.utils.jsonresponse import APIError |
6 | 6 |
from passerelle.base.models import BaseResource |
7 | 7 |
from passerelle.sms import SMSGatewayMixin |
8 |
from django.utils.translation import ugettext_lazy as _ |
|
8 | 9 | |
9 | 10 | |
10 | 11 |
class OxydSMSGateway(BaseResource, SMSGatewayMixin): |
11 |
username = models.CharField(max_length=64) |
|
12 |
password = models.CharField(max_length=64) |
|
13 |
default_country_code = models.CharField(max_length=3, default=u'33') |
|
12 |
username = models.CharField(verbose_name=_('username'), max_length=64) |
|
13 |
password = models.CharField(verbose_name=_('password'), max_length=64) |
|
14 |
default_country_code = models.CharField(verbose_name=_('default country code'), max_length=3, |
|
15 |
default=u'33') |
|
16 |
default_trunk_prefix = models.CharField(verbose_name=_('default trunk prefix'), max_length=2, |
|
17 |
default=u'0') |
|
14 | 18 |
# FIXME: add regexp field, to check destination and from format |
15 | 19 | |
16 | 20 |
manager_view_template_name = 'passerelle/manage/messages_service_view.html' |
... | ... | |
27 | 31 |
'err': 1, |
28 | 32 |
'err_desc': 'OXYD error: some destinations failed', |
29 | 33 |
'data': [ |
30 |
['33688888888', "OXYD error: received content '' instead of 200"], |
|
31 |
['33677777777', "OXYD error: received content '' instead of 200"], |
|
34 |
['0033688888888', "OXYD error: received content '' instead of 200"],
|
|
35 |
['0033677777777', "OXYD error: received content '' instead of 200"],
|
|
32 | 36 |
], |
33 | 37 |
} |
34 | 38 |
}, |
... | ... | |
54 | 58 |
def send_msg(self, text, sender, destinations, **kwargs): |
55 | 59 |
"""Send a SMS using the Oxyd provider""" |
56 | 60 |
# unfortunately it lacks a batch API... |
57 |
destinations = self.clean_numbers(destinations, self.default_country_code, prefix='') |
|
61 |
destinations = self.clean_numbers(destinations, |
|
62 |
self.default_country_code, |
|
63 |
self.default_trunk_prefix) |
|
58 | 64 |
results = [] |
59 | 65 |
for dest in destinations: |
60 | 66 |
params = { |
passerelle/sms/__init__.py | ||
---|---|---|
11 | 11 |
category = _('SMS Providers') |
12 | 12 | |
13 | 13 |
@classmethod |
14 |
def clean_numbers(cls, destinations, default_country_code, prefix='+'): |
|
14 |
def clean_numbers(cls, destinations, default_country_code='33', |
|
15 |
default_trunk_prefix='0'): # Yeah France first ! |
|
15 | 16 |
numbers = [] |
16 | 17 |
for dest in destinations: |
17 | 18 |
# most gateways needs the number prefixed by the country code, this is |
18 | 19 |
# really unfortunate. |
20 |
dest = dest.strip() |
|
19 | 21 |
number = ''.join(re.findall('[0-9]', dest)) |
20 | 22 |
if dest.startswith('+'): |
21 |
pass # it already is fully qualified
|
|
23 |
number = '00' + number
|
|
22 | 24 |
elif number.startswith('00'): |
23 | 25 |
# assumes 00 is international access code, remove it |
24 |
number = number[2:] |
|
25 |
elif number.startswith('0'): |
|
26 |
# local prefix, remove 0 and add default country code |
|
27 |
number = default_country_code + number[1:] |
|
28 |
numbers.append(prefix + number) |
|
26 |
pass |
|
27 |
elif number.startswith(default_trunk_prefix): |
|
28 |
number = '00' + default_country_code + number[len(default_trunk_prefix):] |
|
29 |
else: |
|
30 |
raise NotImplementedError('phone number %r is unsupported (no ' |
|
31 |
'international prefix, no local ' |
|
32 |
'trunk prefix)' % number) |
|
33 |
numbers.append(number) |
|
29 | 34 |
return numbers |
30 | 35 | |
31 | 36 |
@endpoint('json-api', perm='can_send_messages', methods=['post']) |
tests/test_sms.py | ||
---|---|---|
15 | 15 | |
16 | 16 | |
17 | 17 |
def test_clean_numbers(): |
18 |
assert SMSGatewayMixin.clean_numbers(['+ 33 12'], '33') == ['+3312'] |
|
19 |
assert SMSGatewayMixin.clean_numbers(['0 0 33 12'], '33') == ['+3312'] |
|
20 |
assert SMSGatewayMixin.clean_numbers(['0 12'], '33') == ['+3312'] |
|
21 | ||
22 | ||
23 |
def test_clean_numbers_no_prefix(): |
|
24 |
assert SMSGatewayMixin.clean_numbers(['+ 33 12'], '33', prefix='') == ['3312'] |
|
25 |
assert SMSGatewayMixin.clean_numbers(['0 0 33 12'], '33', prefix='') == ['3312'] |
|
26 |
assert SMSGatewayMixin.clean_numbers(['0 12'], '33', prefix='') == ['3312'] |
|
18 |
assert SMSGatewayMixin.clean_numbers(['+ 33 12']) == ['003312'] |
|
19 |
assert SMSGatewayMixin.clean_numbers(['0 0 33 12']) == ['003312'] |
|
20 |
assert SMSGatewayMixin.clean_numbers(['0 12']) == ['003312'] |
|
21 |
assert SMSGatewayMixin.clean_numbers(['+ 33 12'], '32', '1') == ['003312'] |
|
22 |
assert SMSGatewayMixin.clean_numbers(['0 0 33 12'], '32', '1') == ['003312'] |
|
23 |
assert SMSGatewayMixin.clean_numbers(['1 12'], '32', '1') == ['003212'] |
|
27 | 24 | |
28 | 25 | |
29 | 26 |
@pytest.fixture(params=klasses) |
... | ... | |
60 | 57 |
for test_vector in getattr(connector, 'TEST_DEFAULTS', {}).get('test_vectors', []): |
61 | 58 |
with utils.mock_url(connector.URL, test_vector['response']): |
62 | 59 |
result = app.post_json(path, params=payload) |
63 |
print result.json |
|
64 | 60 |
for key, value in test_vector['result'].iteritems(): |
65 | 61 |
assert key in result.json |
66 | 62 |
assert result.json[key] == value |
67 | 63 | |
64 | ||
68 | 65 |
def test_manage_views(admin_user, app, connector): |
69 | 66 |
url = '/%s/%s/' % (connector.get_connector_slug(), connector.slug) |
70 | 67 |
resp = app.get(url) |
71 |
- |