attribute_kinds: normalize local phone numbers prefix (#48546)
This commit is contained in:
parent
0c705e7922
commit
3d1fbb6af2
|
@ -348,6 +348,9 @@ default_settings = dict(
|
|||
A2_DUPLICATES_BIRTHDATE_BONUS=Setting(
|
||||
default=0.3,
|
||||
definition='Bonus in case of birthdate match (no bonus is 0, max is 1).'),
|
||||
A2_LOCAL_PHONE_PREFIXES=Setting(
|
||||
default=['+33', '0033', '0'],
|
||||
definition='List of known prefix for local numbers, they will be normalized to the last one'),
|
||||
)
|
||||
|
||||
app_settings = AppSettings(default_settings)
|
||||
|
|
|
@ -145,9 +145,16 @@ validate_phone_number = RegexValidator(
|
|||
message=_('Phone number can start with a + and must contain only digits.'))
|
||||
|
||||
|
||||
def clean_number(number):
|
||||
def clean_phone_number(number):
|
||||
cleaned_number = re.sub(r'[-.\s/]', '', number)
|
||||
validate_phone_number(cleaned_number)
|
||||
# normalize local prefixes
|
||||
local_phone_prefixes = app_settings.A2_LOCAL_PHONE_PREFIXES
|
||||
if local_phone_prefixes:
|
||||
for prefix in local_phone_prefixes[:-1]:
|
||||
if cleaned_number.startswith(prefix):
|
||||
cleaned_number = local_phone_prefixes[-1] + cleaned_number[len(prefix):]
|
||||
break
|
||||
return cleaned_number
|
||||
|
||||
|
||||
|
@ -161,7 +168,7 @@ class PhoneNumberField(forms.CharField):
|
|||
|
||||
def clean(self, value):
|
||||
if value not in self.empty_values:
|
||||
value = clean_number(value)
|
||||
value = clean_phone_number(value)
|
||||
return value
|
||||
|
||||
|
||||
|
@ -169,7 +176,7 @@ class PhoneNumberDRFField(serializers.CharField):
|
|||
default_validators = [validate_phone_number]
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return clean_number(super().to_internal_value(data))
|
||||
return clean_phone_number(super().to_internal_value(data))
|
||||
|
||||
|
||||
validate_fr_postcode = RegexValidator(
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-11-13 21:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
from django.core.exceptions import ValidationError
|
||||
from authentic2.attribute_kinds import clean_phone_number
|
||||
|
||||
|
||||
def noop(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
def clean_phone_numbers(apps, schema_editor):
|
||||
Attribute = apps.get_model('authentic2', 'Attribute')
|
||||
AttributeValue = apps.get_model('authentic2', 'AttributeValue')
|
||||
at_ids = Attribute.all_objects.filter(kind='phone_number').values_list('id')
|
||||
for atv in AttributeValue.all_objects.filter(attribute__id__in=at_ids):
|
||||
try:
|
||||
new_content = clean_phone_number(atv.content)
|
||||
except ValidationError:
|
||||
pass
|
||||
else:
|
||||
if atv.content != new_content:
|
||||
atv.content = new_content
|
||||
atv.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('custom_user', '0021_set_unusable_password'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(clean_phone_numbers, noop),
|
||||
]
|
|
@ -1945,8 +1945,22 @@ def test_phone_normalization_ok(settings, app, admin):
|
|||
'last_name': 'Doe',
|
||||
}
|
||||
resp = app.post_json('/api/users/', headers=headers, params=payload, status=201)
|
||||
assert resp.json['phone'] == '+33499985643'
|
||||
assert User.objects.get(username='janedoe').attributes.phone == '+33499985643'
|
||||
assert resp.json['phone'] == '0499985643'
|
||||
assert User.objects.get(username='janedoe').attributes.phone == '0499985643'
|
||||
|
||||
|
||||
def test_phone_normalization_ok_other_prefix(settings, app, admin):
|
||||
headers = basic_authorization_header(admin)
|
||||
Attribute.objects.create(name='phone', label='phone', kind='phone_number')
|
||||
payload = {
|
||||
'username': 'janedoe',
|
||||
'phone': ' 00334-99 98.56/43',
|
||||
'first_name': 'Jane',
|
||||
'last_name': 'Doe',
|
||||
}
|
||||
resp = app.post_json('/api/users/', headers=headers, params=payload, status=201)
|
||||
assert resp.json['phone'] == '0499985643'
|
||||
assert User.objects.get(username='janedoe').attributes.phone == '0499985643'
|
||||
|
||||
|
||||
def test_phone_normalization_nok(settings, app, admin):
|
||||
|
|
|
@ -222,11 +222,11 @@ def test_phone_number(db, app, admin, mailoutbox, settings):
|
|||
assert response.pyquery.find('.form-field-error #id_phone_number')
|
||||
|
||||
form = response.form
|
||||
form.set('phone_number', '12345')
|
||||
form.set('phone_number', '+33499999999')
|
||||
form.set('password1', '12345abcdA')
|
||||
form.set('password2', '12345abcdA')
|
||||
response = form.submit().follow()
|
||||
assert qs.get().attributes.phone_number == '12345'
|
||||
assert qs.get().attributes.phone_number == '0499999999'
|
||||
qs.delete()
|
||||
|
||||
url = register_john()
|
||||
|
@ -234,11 +234,11 @@ def test_phone_number(db, app, admin, mailoutbox, settings):
|
|||
form = response.form
|
||||
form.set('first_name', 'John')
|
||||
form.set('last_name', 'Doe')
|
||||
form.set('phone_number', '+12345')
|
||||
form.set('phone_number', '0033499999999')
|
||||
form.set('password1', '12345abcdA')
|
||||
form.set('password2', '12345abcdA')
|
||||
response = form.submit().follow()
|
||||
assert qs.get().attributes.phone_number == '+12345'
|
||||
assert qs.get().attributes.phone_number == '0499999999'
|
||||
qs.delete()
|
||||
|
||||
url = register_john()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import itertools
|
||||
import mock
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
|
@ -63,3 +64,32 @@ def test_migration_custom_user_0021_set_unusable_password(transactional_db, migr
|
|||
User = new_apps.get_model('custom_user', 'User')
|
||||
user = User.objects.get()
|
||||
assert not AbstractUser.has_usable_password(user)
|
||||
|
||||
|
||||
def test_migration_custom_user_0022_clean_phone_numbers(transactional_db, migration):
|
||||
from authentic2.models import Attribute, AttributeValue
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
migration.before([('custom_user', '0021_set_unusable_password')])
|
||||
|
||||
Attribute.objects.create(name='phone', label='phone', kind='phone_number')
|
||||
Attribute.objects.create(name='mobile', label='mobile', kind='phone_number')
|
||||
|
||||
numbers1, numbers2 = itertools.tee(itertools.cycle(['+33699999999', '0033999999999', '0199999999']))
|
||||
next(numbers2)
|
||||
|
||||
for i, number1, number2 in zip(range(3), numbers1, numbers2):
|
||||
user = User.objects.create()
|
||||
user.attributes.phone = number1
|
||||
user.attributes.mobile = number2
|
||||
|
||||
migration.apply([('custom_user', '0022_clean_phone_numbers')])
|
||||
|
||||
assert (
|
||||
list(AttributeValue.objects.filter(attribute__name='phone').order_by('id').values_list('content', flat=True))
|
||||
== ['0699999999', '0999999999', '0199999999']
|
||||
)
|
||||
assert (
|
||||
list(AttributeValue.objects.filter(attribute__name='mobile').order_by('id').values_list('content', flat=True))
|
||||
== ['0999999999', '0199999999', '0699999999']
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue