Projet

Général

Profil

0002-csv_import-adapt-user-csv-logic-to-new-phone_number-.patch

Paul Marillonnet, 22 septembre 2022 11:36

Télécharger (11,5 ko)

Voir les différences:

Subject: [PATCH 2/3] csv_import adapt user csv logic to new phone_number kind
 (#69365)

 src/authentic2/csv_import.py | 31 ++++++++++++++++++++++++++++++-
 tests/test_csv_import.py     | 30 ++++++++++++++++--------------
 tests/test_user_manager.py   | 14 ++++++--------
 3 files changed, 52 insertions(+), 23 deletions(-)
src/authentic2/csv_import.py
19 19
import io
20 20

  
21 21
import attr
22
import phonenumbers
22 23
from chardet.universaldetector import UniversalDetector
23 24
from django import forms
25
from django.conf import settings
24 26
from django.contrib.auth.hashers import identify_hasher
25 27
from django.core.exceptions import FieldDoesNotExist, ValidationError
26 28
from django.core.validators import RegexValidator
27 29
from django.db import IntegrityError, models
28 30
from django.db.transaction import atomic
29 31
from django.utils.encoding import force_bytes, force_text
32
from django.utils.timezone import now
30 33
from django.utils.translation import ugettext as _
31 34

  
32 35
from authentic2 import app_settings
......
467 470
                    header.key = True
468 471
            elif header.name not in SPECIAL_COLUMNS:
469 472
                try:
470
                    if header.name in ['email', 'first_name', 'last_name', 'username']:
473
                    if header.name in ['email', 'phone', 'first_name', 'last_name', 'username']:
471 474
                        User._meta.get_field(header.name)
472 475
                        header.field = True
473 476
                        if header.name == 'email':
......
547 550
            except IndexError:
548 551
                pass
549 552

  
553
        if 'phone' in data:
554
            # ensure E.164 international representation of phone numbers
555
            code = settings.PHONE_COUNTRY_CODES[settings.DEFAULT_COUNTRY_CODE]
556
            national_number = ''
557
            pn = None
558
            try:
559
                pn = phonenumbers.parse(data['phone'])
560
            except phonenumbers.NumberParseException:
561
                try:
562
                    # fallback on default local dial
563
                    pn = phonenumbers.parse(
564
                        data['phone'],
565
                        settings.PHONE_COUNTRY_CODES[settings.DEFAULT_COUNTRY_CODE],
566
                    )
567
                except phonenumbers.NumberParseException:
568
                    pass
569
            if pn:
570
                code = str(pn.country_code)
571
                national_number = '0' * (pn.number_of_leading_zeros or 0) + str(pn.national_number)
572
            data.pop('phone')
573
            # fill multi value field
574
            data['phone_0'] = code
575
            data['phone_1'] = national_number
576

  
550 577
        form = form_class(data=data)
551 578
        form.is_valid()
552 579

  
......
713 740
                    setattr(user, cell.header.name, cell.value)
714 741
                    if cell.header.name == 'email' and cell.header.verified:
715 742
                        user.set_email_verified(True)
743
                    if cell.header.name == 'phone' and cell.header.verified:
744
                        user.phone_verified_on = now()
716 745
                    cell.action = 'updated'
717 746
                    continue
718 747
            cell.action = 'nothing'
tests/test_csv_import.py
201 201
        CsvHeader(1, 'email', field=True, key=True, verified=True),
202 202
        CsvHeader(2, 'first_name', field=True),
203 203
        CsvHeader(3, 'last_name', field=True),
204
        CsvHeader(4, 'phone', attribute=True),
204
        CsvHeader(4, 'phone', field=True),
205 205
    ]
206 206
    assert importer.has_errors
207 207
    assert len(importer.rows) == 3
......
225 225
    assert thomas.attributes.first_name == 'Thomas'
226 226
    assert thomas.last_name == 'Noël'
227 227
    assert thomas.attributes.last_name == 'Noël'
228
    assert thomas.attributes.phone == '1234'
228
    # phonenumbers' e.164 representation from a settings.DEFAULT_COUNTRY_CODE dial:
229
    assert thomas.attributes.phone == '+331234'
229 230
    assert thomas.password
230 231

  
231 232
    fpeters = User.objects.get(email='fpeters@entrouvert.com')
......
235 236
    assert fpeters.attributes.first_name == 'Frédéric'
236 237
    assert fpeters.last_name == 'Péters'
237 238
    assert fpeters.attributes.last_name == 'Péters'
238
    assert fpeters.attributes.phone == '5678'
239
    # phonenumbers' e.164 representation from a settings.DEFAULT_COUNTRY_CODE dial:
240
    assert fpeters.attributes.phone == '+335678'
239 241

  
240 242

  
241 243
def test_simulate(profile, user_csv_importer_factory):
......
251 253
        CsvHeader(1, 'email', field=True, key=True, verified=True),
252 254
        CsvHeader(2, 'first_name', field=True),
253 255
        CsvHeader(3, 'last_name', field=True),
254
        CsvHeader(4, 'phone', attribute=True),
256
        CsvHeader(4, 'phone', field=True),
255 257
    ]
256 258
    assert importer.has_errors
257 259
    assert len(importer.rows) == 3
......
261 263
    assert all(error == Error('data-error') for error in importer.rows[2].cells[0].errors)
262 264
    assert not importer.rows[2].cells[1].errors
263 265
    assert not importer.rows[2].cells[2].errors
264
    assert importer.rows[2].cells[3].errors
266
    assert not importer.rows[2].cells[3].errors
265 267
    assert all(error == Error('data-error') for error in importer.rows[2].cells[3].errors)
266 268

  
267 269
    assert importer.updated == 0
......
277 279
    importer = user_csv_importer_factory(content)
278 280

  
279 281
    user = User.objects.create(ou=get_default_ou())
280
    user.attributes.phone = '1234'
282
    user.attributes.phone = '+331234'
281 283

  
282 284
    assert importer.run()
283 285

  
......
298 300
    importer = user_csv_importer_factory(content)
299 301

  
300 302
    user = User.objects.create()
301
    user.attributes.phone = '1234'
303
    user.attributes.phone = '+331234'
302 304

  
303 305
    assert importer.run()
304 306

  
......
318 320
    importer = user_csv_importer_factory(content)
319 321

  
320 322
    user = User.objects.create()
321
    user.attributes.phone = '1234'
323
    user.attributes.phone = '+331234'
322 324

  
323 325
    assert importer.run()
324 326

  
......
356 358
    importer = user_csv_importer_factory(content)
357 359

  
358 360
    user = User.objects.create(ou=get_default_ou())
359
    user.attributes.phone = '1234'
361
    user.attributes.phone = '+331234'
360 362

  
361 363
    user = User.objects.create(email='tnoel@entrouvert.com', ou=get_default_ou())
362 364

  
......
378 380
    importer = user_csv_importer_factory(content)
379 381

  
380 382
    user = User.objects.create()
381
    user.attributes.phone = '1234'
383
    user.attributes.phone = '+331234'
382 384

  
383 385
    User.objects.create(email='tnoel@entrouvert.com', ou=get_default_ou())
384 386

  
......
400 402
    importer = user_csv_importer_factory(content)
401 403

  
402 404
    user = User.objects.create()
403
    user.attributes.phone = '1234'
405
    user.attributes.phone = '+331234'
404 406

  
405 407
    thomas = User.objects.create(email='tnoel@entrouvert.com', ou=get_default_ou())
406 408

  
......
418 420
    thomas.refresh_from_db()
419 421
    assert not thomas.first_name
420 422
    assert not thomas.last_name
421
    assert thomas.attributes.phone == '1234'
423
    assert thomas.attributes.phone == '+331234'
422 424

  
423 425

  
424 426
def test_external_id(profile, user_csv_importer_factory):
......
436 438
        CsvHeader(3, 'email', field=True, verified=True),
437 439
        CsvHeader(4, 'first_name', field=True),
438 440
        CsvHeader(5, 'last_name', field=True),
439
        CsvHeader(6, 'phone', attribute=True),
441
        CsvHeader(6, 'phone', field=True),
440 442
    ]
441 443
    assert not importer.has_errors
442 444
    assert len(importer.rows) == 2
......
449 451
        assert thomas.attributes.first_name == 'Thomas'
450 452
        assert thomas.last_name == 'Noël'
451 453
        assert thomas.attributes.last_name == 'Noël'
452
        assert thomas.attributes.phone == '1234'
454
        assert thomas.attributes.phone == '+331234'
453 455

  
454 456
    importer = user_csv_importer_factory(content)
455 457
    assert importer.run(), importer.errors
tests/test_user_manager.py
468 468
            'users.csv',
469 469
            '''email key verified,first_name,last_name,phone
470 470
tnoel@entrouvert.com,Thomas,Noël,1234
471
fpeters@entrouvert.com,Frédéric,Péters,5678
471
fpeters@entrouvert.com,Frédéric,Péters,+325678
472 472
john.doe@entrouvert.com,John,Doe,9101112
473 473
x,x,x,x'''.encode(
474 474
                encoding
......
528 528

  
529 529
    assert len(response.pyquery('tr.row-errors')) == 0
530 530
    assert len(response.pyquery('tr.row-cells-errors')) == 1
531
    assert sum(bool(response.pyquery(td).text()) for td in response.pyquery('tr.row-cells-errors td li')) == 2
531
    assert sum(bool(response.pyquery(td).text()) for td in response.pyquery('tr.row-cells-errors td li')) == 1
532 532
    assert 'Enter a valid email address' in response.pyquery('tr.row-cells-errors td.cell-email li').text()
533
    assert 'Phone number can start with' in response.pyquery('tr.row-cells-errors td.cell-phone li').text()
534 533

  
535 534
    assert User.objects.count() == user_count
536 535

  
......
549 548
            email='tnoel@entrouvert.com',
550 549
            first_name='Thomas',
551 550
            last_name='Noël',
552
            attribute_values__content='1234',
551
            attribute_values__content='+331234',
553 552
        ).count()
554 553
        == 1
555 554
    )
......
558 557
            email='fpeters@entrouvert.com',
559 558
            first_name='Frédéric',
560 559
            last_name='Péters',
561
            attribute_values__content='5678',
560
            attribute_values__content='+325678',
562 561
        ).count()
563 562
        == 1
564 563
    )
......
567 566
            email='john.doe@entrouvert.com',
568 567
            first_name='John',
569 568
            last_name='Doe',
570
            attribute_values__content='9101112',
569
            attribute_values__content='+339101112',
571 570
        ).count()
572 571
        == 1
573 572
    )
......
697 696
    assert 'Enter a valid date.' in response.text
698 697
    assert 'birthdate must be in the past and greater or equal than 1900-01-01.' in response.text
699 698
    assert 'The value must be a valid french postcode' in response.text
700
    assert 'Phone number can start with a + and must contain only digits' in response.text
701 699

  
702 700
    assert User.objects.count() == user_count + 1
703 701
    elliot = User.objects.filter(email='elliot@universalpictures.com')[0]
......
707 705
    assert elliot.attributes.values['saintsday'].content == '2019-07-20'
708 706
    assert elliot.attributes.values['birthdate'].content == '1972-05-26'
709 707
    assert elliot.attributes.values['zip'].content == '75014'
710
    assert elliot.attributes.values['phone'].content == '1234'
708
    assert elliot.attributes.values['phone'].content == '+331234'
711 709

  
712 710
    csv_lines[2] = "et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+888 5678"
713 711
    response = import_csv('\n'.join(csv_lines), app)
714
-