0001-api-update-phone-drf-field-to-handle-E164-format-694.patch
src/authentic2/attribute_kinds.py | ||
---|---|---|
24 | 24 |
import uuid |
25 | 25 |
from itertools import chain |
26 | 26 | |
27 |
import phonenumbers |
|
27 | 28 |
from django import forms |
28 | 29 |
from django.conf import settings |
29 | 30 |
from django.core.exceptions import ValidationError |
... | ... | |
146 | 147 |
return app_settings.A2_ATTRIBUTE_KIND_TITLE_CHOICES or DEFAULT_TITLE_CHOICES |
147 | 148 | |
148 | 149 | |
149 |
validate_phone_number = RegexValidator( |
|
150 |
r'^\+?\d{,20}$', message=_('Phone number can start with a + and must contain only digits.') |
|
151 |
) |
|
150 |
def validate_phone_number(value): |
|
151 |
default_country = settings.PHONE_COUNTRY_CODES[settings.DEFAULT_COUNTRY_CODE] |
|
152 |
try: |
|
153 |
phonenumbers.parse(value) |
|
154 |
except phonenumbers.NumberParseException: |
|
155 |
try: |
|
156 |
phonenumbers.parse( |
|
157 |
value, |
|
158 |
default_country, |
|
159 |
) |
|
160 |
except phonenumbers.NumberParseException: |
|
161 |
raise ValidationError( |
|
162 |
_( |
|
163 |
f'Phone number must be either in E.164 globally unique format or dialable from' |
|
164 |
' {settings.DEFAULT_COUNTRY_CODE} country code ({default_country}).' |
|
165 |
) |
|
166 |
) |
|
167 | ||
152 | 168 | |
153 | 169 |
french_validate_phone_number = RegexValidator( |
154 | 170 |
r'^[0][0-9]{9}$', message=_('A french phone number must start with a zero then another nine digits.') |
... | ... | |
180 | 196 |
default_validators = [validate_phone_number] |
181 | 197 | |
182 | 198 |
def to_internal_value(self, data): |
183 |
return clean_number(super().to_internal_value(data)) |
|
199 |
if isinstance(data, (list, tuple)): |
|
200 |
data = data[0] |
|
201 |
data = super().to_internal_value(clean_number(data)) |
|
202 |
default_country = settings.PHONE_COUNTRY_CODES[settings.DEFAULT_COUNTRY_CODE] |
|
203 |
try: |
|
204 |
pn = phonenumbers.parse(data) |
|
205 |
except phonenumbers.NumberParseException: |
|
206 |
pn = phonenumbers.parse(data, default_country) |
|
207 |
return phonenumbers.format_number(pn, phonenumbers.PhoneNumberFormat.E164) |
|
184 | 208 | |
185 | 209 | |
186 |
class FrenchPhoneNumberDRFField(PhoneNumberDRFField):
|
|
210 |
class FrenchPhoneNumberDRFField(serializers.CharField):
|
|
187 | 211 |
default_validators = [french_validate_phone_number] |
188 | 212 | |
213 |
def to_internal_value(self, data): |
|
214 |
return super().to_internal_value(clean_number(data)) |
|
215 | ||
189 | 216 | |
190 | 217 |
validate_fr_postcode = RegexValidator(r'^\d{5}$', message=_('The value must be a valid french postcode')) |
191 | 218 |
tests/api/test_all.py | ||
---|---|---|
2402 | 2402 |
} |
2403 | 2403 |
resp = app.post_json('/api/users/', headers=headers, params=payload, status=201) |
2404 | 2404 |
assert resp.json['extra_phone'] == '+33499985643' |
2405 |
assert User.objects.get(username='janedoe').attributes.extra_phone == '+33499985643' |
|
2405 |
user = User.objects.get(username='janedoe') |
|
2406 |
assert user.attributes.extra_phone == '+33499985643' |
|
2407 | ||
2408 |
user.delete() |
|
2409 |
payload['extra_phone'] = ' + 334-99 98.56/433 ' |
|
2410 |
resp = app.post_json('/api/users/', headers=headers, params=payload, status=201) |
|
2411 |
assert resp.json['extra_phone'] == '+334999856433' |
|
2412 |
user = User.objects.get(username='janedoe') |
|
2413 |
assert user.attributes.extra_phone == '+334999856433' |
|
2414 | ||
2415 |
user.delete() |
|
2416 |
payload['extra_phone'] = ' 04-99 98.56/433 ' |
|
2417 |
resp = app.post_json('/api/users/', headers=headers, params=payload, status=201) |
|
2418 |
assert resp.json['extra_phone'] == '+334999856433' |
|
2419 |
user = User.objects.get(username='janedoe') |
|
2420 |
assert user.attributes.extra_phone == '+334999856433' |
|
2421 | ||
2422 |
user.delete() |
|
2423 |
payload['extra_phone'] = '' |
|
2424 |
resp = app.post_json('/api/users/', headers=headers, params=payload, status=201) |
|
2425 |
assert resp.json['extra_phone'] == '' |
|
2426 |
user = User.objects.get(username='janedoe') |
|
2427 |
assert user.attributes.extra_phone == '' |
|
2406 | 2428 | |
2407 | 2429 | |
2408 | 2430 |
def test_phone_normalization_nok(settings, app, admin): |
... | ... | |
2419 | 2441 |
payload['extra_phone'] = '1#2' |
2420 | 2442 |
app.post_json('/api/users/', headers=headers, params=payload, status=400) |
2421 | 2443 | |
2444 |
payload['extra_phone'] = '+33499985643343434343' |
|
2445 |
app.post_json('/api/users/', headers=headers, params=payload, status=400) |
|
2446 | ||
2447 |
payload['extra_phone'] = '+334-99 98\\56/43' |
|
2448 |
app.post_json('/api/users/', headers=headers, params=payload, status=400) |
|
2449 | ||
2450 |
payload['extra_phone'] = '+334' |
|
2451 |
app.post_json('/api/users/', headers=headers, params=payload, status=400) |
|
2452 | ||
2422 | 2453 | |
2423 | 2454 |
def test_fr_phone_normalization_ok(settings, app, admin): |
2424 | 2455 |
headers = basic_authorization_header(admin) |
2425 |
- |