Projet

Général

Profil

0001-fields-add-Luhn-algorithm-to-string-field-validation.patch

Benjamin Dauvergne, 10 août 2019 18:35

Télécharger (4,77 ko)

Voir les différences:

Subject: [PATCH] fields: add Luhn algorithm to string field validation
 (#35013)

 tests/test_widgets.py | 38 ++++++++++++++++++++++++++++++++++++++
 wcs/qommon/form.py    |  5 +++++
 wcs/qommon/misc.py    | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+)
tests/test_widgets.py
630 630
    mock_form_submission(req, widget, {'test': '1234'})
631 631
    assert widget.has_error()
632 632

  
633
def test_wcsextrastringwidget_siren_validation():
634
    class FakeField: pass
635
    fakefield = FakeField()
636
    fakefield.validation = {'type': 'siren-fr'}
637

  
638
    widget = WcsExtraStringWidget('test', value='foo', required=False)
639
    widget.field = fakefield
640
    mock_form_submission(req, widget, {'test': '443170139'})
641
    assert not widget.has_error()
642

  
643
    widget = WcsExtraStringWidget('test', value='foo', required=False)
644
    widget.field = fakefield
645
    mock_form_submission(req, widget, {'test': '443170130'})
646
    assert widget.has_error()
647

  
648
def test_wcsextrastringwidget_siret_validation():
649
    class FakeField: pass
650
    fakefield = FakeField()
651
    fakefield.validation = {'type': 'siret-fr'}
652

  
653
    # regular case
654
    widget = WcsExtraStringWidget('test', value='foo', required=False)
655
    widget.field = fakefield
656
    mock_form_submission(req, widget, {'test': '44317013900036'})
657
    assert not widget.has_error()
658

  
659
    # special case la poste
660
    widget = WcsExtraStringWidget('test', value='foo', required=False)
661
    widget.field = fakefield
662
    mock_form_submission(req, widget, {'test': '35600000000048'})
663
    assert not widget.has_error()
664

  
665
    # failing case
666
    widget = WcsExtraStringWidget('test', value='foo', required=False)
667
    widget.field = fakefield
668
    mock_form_submission(req, widget, {'test': '44317013900037'})
669
    assert widget.has_error()
670

  
633 671
def test_wcsextrastringwidget_django_validation():
634 672
    class FakeField: pass
635 673
    fakefield = FakeField()
wcs/qommon/form.py
906 906
        ('digits', {'title': N_('Digits'), 'regex': '\d+'}),
907 907
        ('phone-fr', {'title': N_('Phone Number (France)'), 'regex': '0[\d\.\s]{9}'}),
908 908
        ('zipcode-fr', {'title': N_('Zip Code (France)'), 'regex': '\d{5}'}),
909
        ('siren-fr', {'title': N_('SIREN Code (France)'), 'function': 'validate_siren'}),
910
        ('siret-fr', {'title': N_('SIRET Code (France)'), 'function': 'validate_siret'}),
909 911
        ('regex', {'title': N_('Regular Expression')}),
910 912
        ('django', {'title': N_('Django Condition')}),
911 913
    ])
......
965 967
                condition = ValidationCondition(validation['value'], value=value)
966 968
                return condition.evaluate()
967 969
            return django_validation
970
        validation_method = cls.validation_methods.get(validation['type'])
971
        if 'function' in validation_method:
972
            return getattr(misc, validation_method['function'])
968 973

  
969 974
    @classmethod
970 975
    def get_validation_pattern(cls, validation):
wcs/qommon/misc.py
639 639
    if isinstance(text, (htmltext, str)):
640 640
        text = unicode(str(text), get_publisher().site_charset)
641 641
    return site_encode(HTMLParser().unescape(strip_tags(text)))
642

  
643

  
644
def validate_luhn(string_value, length=None):
645
    '''Verify Luhn checksum on a string representing a number'''
646
    if not string_value:
647
        return False
648
    if length is not None and len(string_value) != length:
649
        return False
650

  
651
    # take all digits counting from the right, double value for digits pair
652
    # index (counting from 1), if double has 2 digits take their sum
653
    checksum = 0
654
    for i, x in enumerate(reversed(string_value)):
655
        if i % 2 == 0:
656
            checksum += int(x)
657
        else:
658
            checksum += sum(int(y) for y in str(2 * int(x)))
659
    if checksum % 10 != 0:
660
        return False
661
    return True
662

  
663

  
664
def validate_siren(string_value):
665
    return validate_luhn(string_value, length=9)
666

  
667

  
668
def validate_siret(string_value):
669
    # special case : La Poste
670
    if (string_value.startswith('356000000')
671
            and len(string_value) == 14
672
            and sum(int(x) for x in string_value) % 5 == 0):
673
        return True
674
    return validate_luhn(string_value, length=14)
642
-