From d70894fadd7997a893b772c8f957a2c7d138b34a Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Thu, 26 Apr 2018 16:11:19 +0200 Subject: [PATCH] standardize phonenumber format (#23443) --- corbo/migrations/0011_auto_20180426_1334.py | 26 +++++++++++++++++ corbo/models.py | 10 ++++++- corbo/utils.py | 14 +++++++++ tests/conftest.py | 6 ++++ tests/test_api.py | 10 +++++-- tests/test_data_migrations.py | 32 +++++++++++++++++++++ 6 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 corbo/migrations/0011_auto_20180426_1334.py create mode 100644 tests/test_data_migrations.py diff --git a/corbo/migrations/0011_auto_20180426_1334.py b/corbo/migrations/0011_auto_20180426_1334.py new file mode 100644 index 0000000..2de01d2 --- /dev/null +++ b/corbo/migrations/0011_auto_20180426_1334.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + +from corbo.utils import format_phonenumber + + +def format_sms_identifiers(apps, schema_editor): + Subscription = apps.get_model('corbo', 'Subscription') + uri = 'sms:' + for subscription in Subscription.objects.filter(identifier__startswith=uri): + _, phonenumber = subscription.identifier.split(':', 1) + subscription.identifier = uri + format_phonenumber(phonenumber) + subscription.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('corbo', '0010_broadcast_delivery_count'), + ] + + operations = [ + migrations.RunPython(format_sms_identifiers, format_sms_identifiers), + ] diff --git a/corbo/models.py b/corbo/models.py index 0a28f50..7d6f5fa 100644 --- a/corbo/models.py +++ b/corbo/models.py @@ -177,7 +177,6 @@ class Broadcast(models.Model): self.deliver_time = timezone.now() self.save() - class Meta: verbose_name = _('sent') ordering = ('-deliver_time',) @@ -198,3 +197,12 @@ class Subscription(models.Model): class Meta: unique_together = ('category', 'identifier', 'uuid') + + def clean(self): + if 'sms:' in self.identifier: + uri, phonenumber = self.identifier.split(':', 1) + self.identifier = '%s:%s' % (uri, utils.format_phonenumber(phonenumber)) + + def save(self, *args, **kwargs): + self.clean() + return super(Subscription, self).save(*args, **kwargs) diff --git a/corbo/utils.py b/corbo/utils.py index 5e5f0d0..3c626b7 100644 --- a/corbo/utils.py +++ b/corbo/utils.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import os +import re import logging import requests import urlparse @@ -103,3 +104,16 @@ def send_sms(content, destinations): else: logger.error('SMS send requested but no SMS gateway defined.') return sent + + +def format_phonenumber(phonenumber): + '''formats a given string into a phone number by removing: + 1. parenthesis and their content + 2. every characters but numbers and plus signs + 3. all plus signs after the first character. + ''' + phonenumber = re.sub('\(.*?\)', '', phonenumber) + phonenumber = re.sub('[^\d+]', '', phonenumber) + if phonenumber: + phonenumber = phonenumber[0] + re.sub('[\+]', '', phonenumber[1:]) + return phonenumber diff --git a/tests/conftest.py b/tests/conftest.py index 05669b6..bfe6106 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -131,3 +131,9 @@ def tenant(transactional_db, request, tenant_base): return Tenant(domain_url=name, schema_name=name.replace('-', '_').replace('.', '_')) return make_tenant('corbo.example.net') + + +@pytest.fixture(params=['06 10 20 30 40', '+33 6 10 20 30 40', + '0033610203040', '+33 (0) 6 10 20 30 40', '0033+610203040+']) +def phonenumber(request): + return request.param diff --git a/tests/test_api.py b/tests/test_api.py index b56db02..a24a23f 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,4 +1,6 @@ import pytest + +import urllib from uuid import uuid4 @@ -70,7 +72,7 @@ def test_get_subscriptions(app, categories, announces, user): for identifier, name in channel_choices: for category in categories: - uri = '%s:%s' % (identifier, uuid) + uri = '%s:%s' % (identifier, '00339988776655') Subscription.objects.create(identifier=uri, uuid=uuid, category=category) resp = app.get(reverse('subscriptions'), params={'uuid': uuid}) assert len(resp.json['data']) == 2 @@ -141,12 +143,14 @@ def test_simple_email_subscription(app, categories, user): assert transport['id'] == 'mailto' assert transport['text'] == 'mailto' -def test_simple_sms_subscription(app, categories, user): +def test_simple_sms_subscription(app, categories, user, phonenumber): payload = {'category_id': 'alerts', 'transports': ['sms']} uuid = uuid4() - url = '/api/subscribe/?uuid=%s&mobile=0607080900' % uuid + url_params = urllib.urlencode({'uuid': uuid, 'mobile': phonenumber}) + url = '/api/subscribe/?' + url_params app.authorization = ('Basic', ('john.doe', 'password')) resp = app.post_json(url, params=payload, status=200) + assert Subscription.objects.get(uuid=uuid).identifier in ['sms:0610203040', 'sms:+33610203040', 'sms:0033610203040'] resp = app.get('/api/subscriptions/?uuid=%s' % uuid) data = resp.json['data'] print resp.json diff --git a/tests/test_data_migrations.py b/tests/test_data_migrations.py new file mode 100644 index 0000000..f9f5801 --- /dev/null +++ b/tests/test_data_migrations.py @@ -0,0 +1,32 @@ +import uuid + +import pytest + +from django.db import connection +from django.db.migrations.executor import MigrationExecutor + +pytestmark = pytest.mark.django_db + + +def test_subscription_sms_identifier_format_migration(): + executor = MigrationExecutor(connection) + app = 'corbo' + migrate_from = [(app, '0009_auto_20170120_1533')] + migrate_to = [(app, '0011_auto_20180426_1334')] + executor.migrate(migrate_from) + executor.loader.build_graph() + old_apps = executor.loader.project_state(migrate_from).apps + Category = old_apps.get_model('corbo', 'Category') + Subscription = old_apps.get_model('corbo', 'Subscription') + category = Category.objects.create(name='Science', slug='science') + for identifier in ('sms:06 10 20 30 40', 'sms:+33 6 10 20 30 40', 'sms:0033610203040', + 'mailto:john@doe.com', 'sms:+33 (0) 6 10 20 30 40', 'sms:06.10.20:30.40.'): + Subscription.objects.create(uuid=uuid.uuid4().hex, category=category, identifier=identifier) + executor.migrate(migrate_to) + executor.loader.build_graph() + apps = executor.loader.project_state(migrate_from).apps + Subscription = apps.get_model('corbo', 'Subscription') + assert Subscription.objects.count() == 6 + valid_sms_identifier = ['sms:0610203040', 'sms:+33610203040', 'sms:0033610203040'] + for subscription in Subscription.objects.filter(identifier__startswith='sms:'): + assert subscription.identifier in valid_sms_identifier