Projet

Général

Profil

0001-fields-custom-error-message-for-django-regex-validat.patch

Lauréline Guérin, 04 février 2021 09:48

Télécharger (11,4 ko)

Voir les différences:

Subject: [PATCH] fields: custom error message for django/regex validation
 (#50772)

 tests/admin_pages/test_form.py |  6 ++++--
 tests/test_widgets.py          | 30 +++++++++++++++++++++++++++
 wcs/qommon/form.py             | 37 +++++++++++++++++++++++++++++++---
 3 files changed, 68 insertions(+), 5 deletions(-)
tests/admin_pages/test_form.py
1492 1492
    resp = resp.click('Edit', href='1/')
1493 1493
    resp.form['validation$type'] = 'Regular Expression'
1494 1494
    resp.form['validation$value_regex'] = r'\d+'
1495
    resp.form['validation$error_message'] = 'Foo Error'
1495 1496
    resp = resp.form.submit('submit').follow()
1496
    assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+'}
1497
    assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+', 'error_message': 'Foo Error'}
1497 1498

  
1498 1499
    resp = resp.click('Edit', href='1/')
1499 1500
    resp.form['validation$type'] = 'None'
......
1503 1504
    resp = resp.click('Edit', href='1/')
1504 1505
    resp.form['validation$type'] = 'Django Condition'
1505 1506
    resp.form['validation$value_django'] = 'value|decimal < 20'
1507
    resp.form['validation$error_message'] = 'Bar Error'
1506 1508
    resp = resp.form.submit('submit').follow()
1507
    assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20'}
1509
    assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20', 'error_message': 'Bar Error'}
1508 1510

  
1509 1511
    resp = resp.click('Edit', href='1/')
1510 1512
    resp.form['validation$type'] = 'Django Condition'
tests/test_widgets.py
720 720
    widget.field = fakefield
721 721
    mock_form_submission(req, widget, {'test': '12,34'})
722 722
    assert widget.has_error()
723
    assert widget.error == 'invalid value'
724

  
725
    widget = WcsExtraStringWidget('test', value='foo', required=False)
726
    fakefield.validation = {
727
        'type': 'regex', 'value': r'\d+(\.\d{1,2})?',
728
        'error_message': 'Foo Bar Custom Error'
729
    }
730
    widget.field = fakefield
731
    mock_form_submission(req, widget, {'test': '12,34'})
732
    assert widget.has_error()
733
    assert widget.error == 'Foo Bar Custom Error'
723 734

  
724 735

  
725 736
def test_wcsextrastringwidget_builtin_validation():
......
736 747
    widget.field = fakefield
737 748
    mock_form_submission(req, widget, {'test': 'az'})
738 749
    assert widget.has_error()
750
    assert widget.error == 'Only digits are allowed'
739 751

  
740 752
    fakefield.validation = {'type': 'zipcode-fr'}
741 753
    widget = WcsExtraStringWidget('test', value='foo', required=False)
......
752 764
    widget.field = fakefield
753 765
    mock_form_submission(req, widget, {'test': '1234'})
754 766
    assert widget.has_error()
767
    assert widget.error == 'Invalid zip code (5 digits required)'
755 768

  
756 769

  
757 770
def test_wcsextrastringwidget_phone():
......
772 785
        widget.field = fakefield
773 786
        mock_form_submission(req, widget, {'test': invalid_case})
774 787
        assert widget.has_error()
788
        assert widget.error == 'Invalid phone number'
775 789

  
776 790
    # and check it gets a special HTML input type
777 791
    widget = WcsExtraStringWidget('test', value='foo', required=False)
......
800 814
    widget.field = fakefield
801 815
    mock_form_submission(req, widget, {'test': 'az'})
802 816
    assert widget.has_error()
817
    assert widget.error == 'Invalid phone number'
803 818

  
804 819
    widget = WcsExtraStringWidget('test', value='foo', required=False)
805 820
    widget.field = fakefield
......
829 844
    widget.field = fakefield
830 845
    mock_form_submission(req, widget, {'test': '443170130'})
831 846
    assert widget.has_error()
847
    assert widget.error == 'Invalid SIREN code'
832 848

  
833 849
    widget = WcsExtraStringWidget('test', value='foo', required=False)
834 850
    widget.field = fakefield
......
868 884
    widget.field = fakefield
869 885
    mock_form_submission(req, widget, {'test': '44317013900037'})
870 886
    assert widget.has_error()
887
    assert widget.error == 'Invalid SIRET code'
871 888

  
872 889
    widget = WcsExtraStringWidget('test', value='foo', required=False)
873 890
    widget.field = fakefield
......
907 924
    widget.field = fakefield
908 925
    mock_form_submission(req, widget, {'test': '42'})
909 926
    assert widget.has_error()
927
    assert widget.error == 'Invalid NIR'
910 928

  
911 929
    widget = WcsExtraStringWidget('test', value='foo', required=False)
912 930
    widget.field = fakefield
......
979 997
        widget.field = fakefield
980 998
        mock_form_submission(req, widget, {'test': iban.replace(' ', '')})
981 999
        assert widget.has_error()
1000
        assert widget.error == 'Invalid IBAN'
982 1001

  
983 1002

  
984 1003
def test_wcsextrastringwidget_django_validation():
......
1000 1019
    widget.field = fakefield
1001 1020
    mock_form_submission(req, widget, {'test': 'az'})
1002 1021
    assert widget.has_error()
1022
    assert widget.error == 'invalid value'
1023

  
1024
    widget = WcsExtraStringWidget('test', value='foo', required=False)
1025
    fakefield.validation = {
1026
        'type': 'django', 'value': 'value|decimal and value|decimal < 20',
1027
        'error_message': 'Foo Bar Custom Error'
1028
    }
1029
    widget.field = fakefield
1030
    mock_form_submission(req, widget, {'test': 'az'})
1031
    assert widget.has_error()
1032
    assert widget.error == 'Foo Bar Custom Error'
1003 1033

  
1004 1034

  
1005 1035
def test_widgetdict_widget():
wcs/qommon/form.py
1022 1022
        ('digits', {
1023 1023
            'title': N_('Digits'),
1024 1024
            'regex': r'\d+',
1025
            'error_message': N_('Only digits are allowed'),
1025 1026
            'html_inputmode': 'numeric'}
1026 1027
        ),
1027 1028
        ('phone', {
1028 1029
            'title': N_('Phone Number'),
1029 1030
            'regex': r'\+?[-\(\)\d\.\s/]+',
1031
            'error_message': N_('Invalid phone number'),
1030 1032
            'html_input_type': 'tel'}
1031 1033
        ),
1032 1034
        ('phone-fr', {
1033 1035
            'title': N_('Phone Number (France)'),
1034 1036
            'function': 'validate_phone_fr',
1037
            'error_message': N_('Invalid phone number'),
1035 1038
            'html_input_type': 'tel'}
1036 1039
        ),
1037 1040
        ('zipcode-fr', {
1038 1041
            'title': N_('Zip Code (France)'),
1039 1042
            'regex': r'\d{5}',
1043
            'error_message': N_('Invalid zip code (5 digits required)'),
1040 1044
            'html_inputmode': 'numeric'}
1041 1045
        ),
1042 1046
        ('siren-fr', {
1043 1047
            'title': N_('SIREN Code (France)'),
1044 1048
            'function': 'validate_siren',
1049
            'error_message': N_('Invalid SIREN code'),
1045 1050
            'html_inputmode': 'numeric'}
1046 1051
        ),
1047 1052
        ('siret-fr', {
1048 1053
            'title': N_('SIRET Code (France)'),
1049 1054
            'function': 'validate_siret',
1055
            'error_message': N_('Invalid SIRET code'),
1050 1056
            'html_inputmode': 'numeric'}
1051 1057
        ),
1052 1058
        ('nir-fr', {
1053 1059
            'title': N_('NIR (France)'),
1060
            'error_message': N_('Invalid NIR'),
1054 1061
            'function': 'validate_nir'}
1055 1062
        ),
1056 1063
        ('iban', {
1057 1064
            'title': N_('IBAN'),
1058
            'function': 'validate_iban'}
1065
            'function': 'validate_iban',
1066
            'error_message': N_('Invalid IBAN')}
1059 1067
        ),
1060 1068
        ('regex', {'title': N_('Regular Expression')}),
1061 1069
        ('django', {'title': N_('Django Condition')}),
......
1075 1083
            self.value = {}
1076 1084

  
1077 1085
        validation_labels = collections.OrderedDict(options)
1078
        self.add(RegexStringWidget, 'value_regex', size=80,
1086
        self.add(RegexStringWidget, 'value_regex', size=40,
1079 1087
                 value=value.get('value') if value.get('type') == 'regex' else None,
1080 1088
                 attrs={'data-dynamic-display-child-of': 'validation$type',
1081 1089
                        'data-dynamic-display-value': validation_labels.get('regex')})
1082
        self.add(DjangoConditionWidget, 'value_django', size=80,
1090
        self.add(DjangoConditionWidget, 'value_django', size=40,
1083 1091
                 value=value.get('value') if value.get('type') == 'django' else None,
1084 1092
                 attrs={'data-dynamic-display-child-of': 'validation$type',
1085 1093
                        'data-dynamic-display-value': validation_labels.get('django')})
1094
        self.add(StringWidget, 'error_message', size=60,
1095
                 value=value.get('error_message') if value.get('type') in ['regex', 'django'] else None,
1096
                 placeholder=_('Custom error message.'),
1097
                 attrs={'data-dynamic-display-child-of': 'validation$type',
1098
                        'data-dynamic-display-value-in': '|'.join([
1099
                            validation_labels.get('regex'),
1100
                            validation_labels.get('django')])})
1086 1101
        self._parsed = False
1087 1102

  
1088 1103
    def _parse(self, request):
......
1093 1108
            value = self.get('value_%s' % type_)
1094 1109
            if value:
1095 1110
                values['value'] = value
1111
            if type_ in ['regex', 'django']:
1112
                error_message = self.get('error_message')
1113
                if error_message:
1114
                    values['error_message'] = error_message
1096 1115
        self.value = values or None
1097 1116

  
1098 1117
    def render_content(self):
......
1119 1138
        if validation_method and 'function' in validation_method:
1120 1139
            return getattr(misc, validation_method['function'])
1121 1140

  
1141
    @classmethod
1142
    def get_validation_error_message(cls, validation):
1143
        pattern = cls.get_validation_pattern(validation)
1144
        if validation['type'] == 'regex' and pattern:
1145
            return validation.get('error_message')
1146
        if validation['type'] == 'django' and validation.get('value'):
1147
            return validation.get('error_message')
1148
        validation_method = cls.validation_methods.get(validation['type'])
1149
        if validation_method and 'error_message' in validation_method:
1150
            return validation_method['error_message']
1151

  
1122 1152
    @classmethod
1123 1153
    def get_validation_pattern(cls, validation):
1124 1154
        validation_method = cls.validation_methods.get(validation['type'])
......
1163 1193
        StringWidget._parse(self, request)
1164 1194
        if self.field and self.field.validation and self.value is not None:
1165 1195
            self.validation_function = ValidationWidget.get_validation_function(self.field.validation)
1196
            self.validation_function_error_message = ValidationWidget.get_validation_error_message(self.field.validation)
1166 1197

  
1167 1198
        if self.validation_function and not self.validation_function(self.value):
1168 1199
            self.error = self.validation_function_error_message or _('invalid value')
1169
-