0001-fields-add-Luhn-algorithm-to-string-field-validation.patch
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 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
649 |
widget.field = fakefield |
|
650 |
mock_form_submission(req, widget, {'test': '44317013900036'}) |
|
651 |
assert widget.has_error() |
|
652 | ||
653 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
654 |
widget.field = fakefield |
|
655 |
mock_form_submission(req, widget, {'test': 'XXX170130'}) |
|
656 |
assert widget.has_error() |
|
657 | ||
658 | ||
659 |
def test_wcsextrastringwidget_siret_validation(): |
|
660 |
class FakeField: pass |
|
661 |
fakefield = FakeField() |
|
662 |
fakefield.validation = {'type': 'siret-fr'} |
|
663 | ||
664 |
# regular case |
|
665 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
666 |
widget.field = fakefield |
|
667 |
mock_form_submission(req, widget, {'test': '44317013900036'}) |
|
668 |
assert not widget.has_error() |
|
669 | ||
670 |
# special case la poste |
|
671 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
672 |
widget.field = fakefield |
|
673 |
mock_form_submission(req, widget, {'test': '35600000000048'}) |
|
674 |
assert not widget.has_error() |
|
675 | ||
676 |
# failing cases |
|
677 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
678 |
widget.field = fakefield |
|
679 |
mock_form_submission(req, widget, {'test': '44317013900037'}) |
|
680 |
assert widget.has_error() |
|
681 | ||
682 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
683 |
widget.field = fakefield |
|
684 |
mock_form_submission(req, widget, {'test': 'ABC17013900037'}) |
|
685 |
assert widget.has_error() |
|
686 | ||
687 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
688 |
widget.field = fakefield |
|
689 |
mock_form_submission(req, widget, {'test': '443170139'}) |
|
690 |
assert widget.has_error() |
|
691 | ||
692 | ||
633 | 693 |
def test_wcsextrastringwidget_django_validation(): |
634 | 694 |
class FakeField: pass |
635 | 695 |
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 |
if not string_value.isdigit(): |
|
651 |
return False |
|
652 | ||
653 |
# take all digits counting from the right, double value for digits pair |
|
654 |
# index (counting from 1), if double has 2 digits take their sum |
|
655 |
checksum = 0 |
|
656 |
for i, x in enumerate(reversed(string_value)): |
|
657 |
if i % 2 == 0: |
|
658 |
checksum += int(x) |
|
659 |
else: |
|
660 |
checksum += sum(int(y) for y in str(2 * int(x))) |
|
661 |
if checksum % 10 != 0: |
|
662 |
return False |
|
663 |
return True |
|
664 | ||
665 | ||
666 |
def validate_siren(string_value): |
|
667 |
return validate_luhn(string_value, length=9) |
|
668 | ||
669 | ||
670 |
def validate_siret(string_value): |
|
671 |
# special case : La Poste |
|
672 |
if not string_value.isdigit(): |
|
673 |
return False |
|
674 |
if (string_value.startswith('356000000') |
|
675 |
and len(string_value) == 14 |
|
676 |
and sum(int(x) for x in string_value) % 5 == 0): |
|
677 |
return True |
|
678 |
return validate_luhn(string_value, length=14) |
|
642 |
- |