Projet

Général

Profil

0004-fields-add-a-PhoneField-70486.patch

Paul Marillonnet, 19 octobre 2022 17:30

Télécharger (3,92 ko)

Voir les différences:

Subject: [PATCH 4/4] fields: add a PhoneField (#70486)

 src/authentic2/forms/fields.py | 31 ++++++++++++++++++++++++++++++-
 tests/test_fields.py           | 25 +++++++++++++++++++------
 2 files changed, 49 insertions(+), 7 deletions(-)
src/authentic2/forms/fields.py
17 17
import io
18 18
import warnings
19 19

  
20
import phonenumbers
20 21
import PIL.Image
21 22
from django import forms
23
from django.conf import settings
22 24
from django.core import validators
23 25
from django.core.files import File
24
from django.forms import CharField, EmailField, FileField, ModelChoiceField, ValidationError
26
from django.forms import CharField, EmailField, FileField, ModelChoiceField, MultiValueField, ValidationError
25 27
from django.forms.fields import FILE_INPUT_CONTRADICTION
26 28
from django.utils.translation import gettext_lazy as _
27 29

  
......
32 34
    EmailInput,
33 35
    NewPasswordInput,
34 36
    PasswordInput,
37
    PhoneWidget,
35 38
    ProfileImageInput,
36 39
)
37 40
from authentic2.manager.utils import label_from_role
......
209 212
        self.validate(value)
210 213
        self.run_validators(value)
211 214
        return value
215

  
216

  
217
class PhoneField(MultiValueField):
218
    widget = PhoneWidget
219

  
220
    def __init__(self, **kwargs):
221
        fields = (
222
            CharField(max_length=8, initial=settings.DEFAULT_COUNTRY_CODE),
223
            CharField(max_length=16, required=False),
224
        )
225
        super().__init__(error_messages=None, fields=fields, require_all_fields=False, **kwargs)
226

  
227
    def compress(self, data_list):
228
        from authentic2.attribute_kinds import clean_number
229

  
230
        if data_list and data_list[1]:
231
            country_code = data_list[0]
232
            data_list[0] = '+%s' % data_list[0]
233
            data_list[1] = clean_number(data_list[1])
234
            dial = settings.PHONE_COUNTRY_CODES.get(country_code, settings.DEFAULT_COUNTRY_CODE).get('lang')
235
            try:
236
                pn = phonenumbers.parse(''.join(data_list), dial)
237
            except phonenumbers.NumberParseException:
238
                raise ValidationError(_('Invalid phone number.'))
239
            return phonenumbers.format_number(pn, phonenumbers.PhoneNumberFormat.E164)
240
        return ''
tests/test_fields.py
18 18
import pytest
19 19
from django.core.exceptions import ValidationError
20 20

  
21
from authentic2.attribute_kinds import PhoneNumberField
22 21
from authentic2.forms.passwords import NewPasswordField
22
from authentic2.forms.fields import PhoneField
23 23

  
24 24

  
25
def test_phonenumber_field():
26
    field = PhoneNumberField()
25
def test_phonenumber_field(settings):
26
    settings.DEFAULT_COUNTRY_CODE = '33'
27
    field = PhoneField()
27 28

  
29
    positive = [
30
        {'input': ['33', '01 01 01 01 01'], 'output': '+33101010101'},
31
        # undialable numbers are still parsed and usable as identifiers
32
        {'input': ['33', '01 01 01'], 'output': '+33010101'},
33
        {'input': ['33', '01 01 01 010101'], 'output': '+3310101010101'},
34
    ]
28 35
    # positive
29
    for value in ['01 01 01 01 01', '+01 01 01 01 01', ' + 01/01.01-01.01', '+01/01.01-01.01']:
30
        field.clean(value)
36
    for value in positive:
37
        output = field.clean(value['input'])
38
        assert output == value['output']
31 39

  
32 40
    # negative
33
    for value in ['01a01']:
41
    for value in [
42
        ['33', '01a01'],
43
        ['33', '+01 01 01 01 01'],
44
        ['33', ' + 01/01.01-01.01'],
45
        ['33', '+01/01.01-01.01'],
46
    ]:
34 47
        with pytest.raises(ValidationError):
35 48
            field.clean(value)
36 49

  
37
-