0001-fields-custom-error-message-for-django-regex-validat.patch
tests/admin_pages/test_form.py | ||
---|---|---|
1501 | 1501 |
resp = resp.click('Edit', href='1/') |
1502 | 1502 |
resp.form['validation$type'] = 'Regular Expression' |
1503 | 1503 |
resp.form['validation$value_regex'] = r'\d+' |
1504 |
resp.form['validation$error_message'] = 'Foo Error' |
|
1504 | 1505 |
resp = resp.form.submit('submit').follow() |
1505 |
assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+'} |
|
1506 |
assert FormDef.get(formdef.id).fields[0].validation == { |
|
1507 |
'type': 'regex', |
|
1508 |
'value': r'\d+', |
|
1509 |
'error_message': 'Foo Error', |
|
1510 |
} |
|
1506 | 1511 | |
1507 | 1512 |
resp = resp.click('Edit', href='1/') |
1508 | 1513 |
resp.form['validation$type'] = 'None' |
... | ... | |
1512 | 1517 |
resp = resp.click('Edit', href='1/') |
1513 | 1518 |
resp.form['validation$type'] = 'Django Condition' |
1514 | 1519 |
resp.form['validation$value_django'] = 'value|decimal < 20' |
1520 |
resp.form['validation$error_message'] = 'Bar Error' |
|
1515 | 1521 |
resp = resp.form.submit('submit').follow() |
1516 |
assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20'} |
|
1522 |
assert FormDef.get(formdef.id).fields[0].validation == { |
|
1523 |
'type': 'django', |
|
1524 |
'value': 'value|decimal < 20', |
|
1525 |
'error_message': 'Bar Error', |
|
1526 |
} |
|
1517 | 1527 | |
1518 | 1528 |
resp = resp.click('Edit', href='1/') |
1519 | 1529 |
resp.form['validation$type'] = 'Django Condition' |
tests/test_widgets.py | ||
---|---|---|
743 | 743 |
widget.field = fakefield |
744 | 744 |
mock_form_submission(req, widget, {'test': '12,34'}) |
745 | 745 |
assert widget.has_error() |
746 |
assert widget.error == 'invalid value' |
|
747 | ||
748 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
749 |
fakefield.validation = { |
|
750 |
'type': 'regex', |
|
751 |
'value': r'\d+(\.\d{1,2})?', |
|
752 |
'error_message': 'Foo Bar Custom Error', |
|
753 |
} |
|
754 |
widget.field = fakefield |
|
755 |
mock_form_submission(req, widget, {'test': '12,34'}) |
|
756 |
assert widget.has_error() |
|
757 |
assert widget.error == 'Foo Bar Custom Error' |
|
746 | 758 | |
747 | 759 | |
748 | 760 |
def test_wcsextrastringwidget_builtin_validation(): |
... | ... | |
761 | 773 |
widget.field = fakefield |
762 | 774 |
mock_form_submission(req, widget, {'test': 'az'}) |
763 | 775 |
assert widget.has_error() |
776 |
assert widget.error == 'Only digits are allowed' |
|
764 | 777 | |
765 | 778 |
fakefield.validation = {'type': 'zipcode-fr'} |
766 | 779 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
... | ... | |
777 | 790 |
widget.field = fakefield |
778 | 791 |
mock_form_submission(req, widget, {'test': '1234'}) |
779 | 792 |
assert widget.has_error() |
793 |
assert widget.error == 'Invalid zip code' |
|
780 | 794 | |
781 | 795 | |
782 | 796 |
def test_wcsextrastringwidget_phone(): |
... | ... | |
798 | 812 |
widget.field = fakefield |
799 | 813 |
mock_form_submission(req, widget, {'test': invalid_case}) |
800 | 814 |
assert widget.has_error() |
815 |
assert widget.error == 'Invalid phone number' |
|
801 | 816 | |
802 | 817 |
# and check it gets a special HTML input type |
803 | 818 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
... | ... | |
827 | 842 |
widget.field = fakefield |
828 | 843 |
mock_form_submission(req, widget, {'test': 'az'}) |
829 | 844 |
assert widget.has_error() |
845 |
assert widget.error == 'Invalid phone number' |
|
830 | 846 | |
831 | 847 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
832 | 848 |
widget.field = fakefield |
... | ... | |
858 | 874 |
widget.field = fakefield |
859 | 875 |
mock_form_submission(req, widget, {'test': '443170130'}) |
860 | 876 |
assert widget.has_error() |
877 |
assert widget.error == 'Invalid SIREN code' |
|
861 | 878 | |
862 | 879 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
863 | 880 |
widget.field = fakefield |
... | ... | |
899 | 916 |
widget.field = fakefield |
900 | 917 |
mock_form_submission(req, widget, {'test': '44317013900037'}) |
901 | 918 |
assert widget.has_error() |
919 |
assert widget.error == 'Invalid SIRET code' |
|
902 | 920 | |
903 | 921 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
904 | 922 |
widget.field = fakefield |
... | ... | |
940 | 958 |
widget.field = fakefield |
941 | 959 |
mock_form_submission(req, widget, {'test': '42'}) |
942 | 960 |
assert widget.has_error() |
961 |
assert widget.error == 'Invalid NIR' |
|
943 | 962 | |
944 | 963 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
945 | 964 |
widget.field = fakefield |
... | ... | |
1016 | 1035 |
widget.field = fakefield |
1017 | 1036 |
mock_form_submission(req, widget, {'test': iban.replace(' ', '')}) |
1018 | 1037 |
assert widget.has_error() |
1038 |
assert widget.error == 'Invalid IBAN' |
|
1019 | 1039 | |
1020 | 1040 | |
1021 | 1041 |
def test_wcsextrastringwidget_django_validation(): |
... | ... | |
1039 | 1059 |
widget.field = fakefield |
1040 | 1060 |
mock_form_submission(req, widget, {'test': 'az'}) |
1041 | 1061 |
assert widget.has_error() |
1062 |
assert widget.error == 'invalid value' |
|
1063 | ||
1064 |
widget = WcsExtraStringWidget('test', value='foo', required=False) |
|
1065 |
fakefield.validation = { |
|
1066 |
'type': 'django', |
|
1067 |
'value': 'value|decimal and value|decimal < 20', |
|
1068 |
'error_message': 'Foo Bar Custom Error', |
|
1069 |
} |
|
1070 |
widget.field = fakefield |
|
1071 |
mock_form_submission(req, widget, {'test': 'az'}) |
|
1072 |
assert widget.has_error() |
|
1073 |
assert widget.error == 'Foo Bar Custom Error' |
|
1042 | 1074 | |
1043 | 1075 | |
1044 | 1076 |
def test_widgetdict_widget(): |
wcs/qommon/form.py | ||
---|---|---|
1051 | 1051 |
class ValidationWidget(CompositeWidget): |
1052 | 1052 |
validation_methods = collections.OrderedDict( |
1053 | 1053 |
[ |
1054 |
('digits', {'title': N_('Digits'), 'regex': r'\d+', 'html_inputmode': 'numeric'}), |
|
1054 |
( |
|
1055 |
'digits', |
|
1056 |
{ |
|
1057 |
'title': N_('Digits'), |
|
1058 |
'regex': r'\d+', |
|
1059 |
'error_message': N_('Only digits are allowed'), |
|
1060 |
'html_inputmode': 'numeric', |
|
1061 |
}, |
|
1062 |
), |
|
1055 | 1063 |
( |
1056 | 1064 |
'phone', |
1057 |
{'title': N_('Phone Number'), 'regex': r'\+?[-\(\)\d\.\s/]+', 'html_input_type': 'tel'}, |
|
1065 |
{ |
|
1066 |
'title': N_('Phone Number'), |
|
1067 |
'regex': r'\+?[-\(\)\d\.\s/]+', |
|
1068 |
'error_message': N_('Invalid phone number'), |
|
1069 |
'html_input_type': 'tel', |
|
1070 |
}, |
|
1058 | 1071 |
), |
1059 | 1072 |
( |
1060 | 1073 |
'phone-fr', |
1061 | 1074 |
{ |
1062 | 1075 |
'title': N_('Phone Number (France)'), |
1063 | 1076 |
'function': 'validate_phone_fr', |
1077 |
'error_message': N_('Invalid phone number'), |
|
1064 | 1078 |
'html_input_type': 'tel', |
1065 | 1079 |
}, |
1066 | 1080 |
), |
1067 | 1081 |
( |
1068 | 1082 |
'zipcode-fr', |
1069 |
{'title': N_('Zip Code (France)'), 'regex': r'\d{5}', 'html_inputmode': 'numeric'}, |
|
1083 |
{ |
|
1084 |
'title': N_('Zip Code (France)'), |
|
1085 |
'regex': r'\d{5}', |
|
1086 |
'error_message': N_('Invalid zip code'), |
|
1087 |
'html_inputmode': 'numeric', |
|
1088 |
}, |
|
1070 | 1089 |
), |
1071 | 1090 |
( |
1072 | 1091 |
'siren-fr', |
1073 | 1092 |
{ |
1074 | 1093 |
'title': N_('SIREN Code (France)'), |
1075 | 1094 |
'function': 'validate_siren', |
1095 |
'error_message': N_('Invalid SIREN code'), |
|
1076 | 1096 |
'html_inputmode': 'numeric', |
1077 | 1097 |
}, |
1078 | 1098 |
), |
... | ... | |
1081 | 1101 |
{ |
1082 | 1102 |
'title': N_('SIRET Code (France)'), |
1083 | 1103 |
'function': 'validate_siret', |
1104 |
'error_message': N_('Invalid SIRET code'), |
|
1084 | 1105 |
'html_inputmode': 'numeric', |
1085 | 1106 |
}, |
1086 | 1107 |
), |
1087 |
('nir-fr', {'title': N_('NIR (France)'), 'function': 'validate_nir'}), |
|
1088 |
('iban', {'title': N_('IBAN'), 'function': 'validate_iban'}), |
|
1108 |
( |
|
1109 |
'nir-fr', |
|
1110 |
{'title': N_('NIR (France)'), 'error_message': N_('Invalid NIR'), 'function': 'validate_nir'}, |
|
1111 |
), |
|
1112 |
('iban', {'title': N_('IBAN'), 'function': 'validate_iban', 'error_message': N_('Invalid IBAN')}), |
|
1089 | 1113 |
('regex', {'title': N_('Regular Expression')}), |
1090 | 1114 |
('django', {'title': N_('Django Condition')}), |
1091 | 1115 |
] |
... | ... | |
1130 | 1154 |
'data-dynamic-display-value': validation_labels.get('django'), |
1131 | 1155 |
}, |
1132 | 1156 |
) |
1157 |
self.add( |
|
1158 |
StringWidget, |
|
1159 |
'error_message', |
|
1160 |
size=80, |
|
1161 |
value=value.get('error_message') if value.get('type') in ['regex', 'django'] else None, |
|
1162 |
title=_('Custom error message'), |
|
1163 |
hint=_('This message will be be displayed if validation fails.'), |
|
1164 |
attrs={ |
|
1165 |
'data-dynamic-display-child-of': 'validation$type', |
|
1166 |
'data-dynamic-display-value-in': '|'.join( |
|
1167 |
[validation_labels.get('regex'), validation_labels.get('django')] |
|
1168 |
), |
|
1169 |
}, |
|
1170 |
) |
|
1133 | 1171 |
self._parsed = False |
1134 | 1172 | |
1135 | 1173 |
def _parse(self, request): |
... | ... | |
1140 | 1178 |
value = self.get('value_%s' % type_) |
1141 | 1179 |
if value: |
1142 | 1180 |
values['value'] = value |
1181 |
if type_ in ['regex', 'django']: |
|
1182 |
error_message = self.get('error_message') |
|
1183 |
if error_message: |
|
1184 |
values['error_message'] = error_message |
|
1143 | 1185 |
self.value = values or None |
1144 | 1186 | |
1145 | 1187 |
def render_content(self): |
1146 | 1188 |
r = TemplateIO(html=True) |
1147 |
for widget in self.get_widgets(): |
|
1189 |
inlines = ['type', 'value_regex', 'value_django'] |
|
1190 |
for name in inlines: |
|
1191 |
widget = self.get_widget(name) |
|
1148 | 1192 |
r += widget.render_error(widget.get_error()) |
1149 |
for widget in self.get_widgets(): |
|
1193 |
for name in inlines: |
|
1194 |
widget = self.get_widget(name) |
|
1150 | 1195 |
r += widget.render_content() |
1196 |
widget = self.get_widget('error_message') |
|
1197 |
r += widget.render() |
|
1151 | 1198 |
return r.getvalue() |
1152 | 1199 | |
1153 | 1200 |
@classmethod |
... | ... | |
1170 | 1217 |
if validation_method and 'function' in validation_method: |
1171 | 1218 |
return getattr(misc, validation_method['function']) |
1172 | 1219 | |
1220 |
@classmethod |
|
1221 |
def get_validation_error_message(cls, validation): |
|
1222 |
pattern = cls.get_validation_pattern(validation) |
|
1223 |
if validation['type'] == 'regex' and pattern: |
|
1224 |
return validation.get('error_message') |
|
1225 |
if validation['type'] == 'django' and validation.get('value'): |
|
1226 |
return validation.get('error_message') |
|
1227 |
validation_method = cls.validation_methods.get(validation['type']) |
|
1228 |
if validation_method and 'error_message' in validation_method: |
|
1229 |
return validation_method['error_message'] |
|
1230 | ||
1173 | 1231 |
@classmethod |
1174 | 1232 |
def get_validation_pattern(cls, validation): |
1175 | 1233 |
validation_method = cls.validation_methods.get(validation['type']) |
... | ... | |
1214 | 1272 |
StringWidget._parse(self, request) |
1215 | 1273 |
if self.field and self.field.validation and self.value is not None: |
1216 | 1274 |
self.validation_function = ValidationWidget.get_validation_function(self.field.validation) |
1275 |
self.validation_function_error_message = ValidationWidget.get_validation_error_message( |
|
1276 |
self.field.validation |
|
1277 |
) |
|
1217 | 1278 | |
1218 | 1279 |
if self.validation_function and not self.validation_function(self.value): |
1219 | 1280 |
self.error = self.validation_function_error_message or _('invalid value') |
1220 |
- |