fields: custom error message for django/regex validation (#50772)
This commit is contained in:
parent
08893a339c
commit
669b338187
|
@ -1501,8 +1501,13 @@ def test_form_edit_string_field_validation(pub):
|
|||
resp = resp.click('Edit', href='1/')
|
||||
resp.form['validation$type'] = 'Regular Expression'
|
||||
resp.form['validation$value_regex'] = r'\d+'
|
||||
resp.form['validation$error_message'] = 'Foo Error'
|
||||
resp = resp.form.submit('submit').follow()
|
||||
assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+'}
|
||||
assert FormDef.get(formdef.id).fields[0].validation == {
|
||||
'type': 'regex',
|
||||
'value': r'\d+',
|
||||
'error_message': 'Foo Error',
|
||||
}
|
||||
|
||||
resp = resp.click('Edit', href='1/')
|
||||
resp.form['validation$type'] = 'None'
|
||||
|
@ -1512,8 +1517,13 @@ def test_form_edit_string_field_validation(pub):
|
|||
resp = resp.click('Edit', href='1/')
|
||||
resp.form['validation$type'] = 'Django Condition'
|
||||
resp.form['validation$value_django'] = 'value|decimal < 20'
|
||||
resp.form['validation$error_message'] = 'Bar Error'
|
||||
resp = resp.form.submit('submit').follow()
|
||||
assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20'}
|
||||
assert FormDef.get(formdef.id).fields[0].validation == {
|
||||
'type': 'django',
|
||||
'value': 'value|decimal < 20',
|
||||
'error_message': 'Bar Error',
|
||||
}
|
||||
|
||||
resp = resp.click('Edit', href='1/')
|
||||
resp.form['validation$type'] = 'Django Condition'
|
||||
|
|
|
@ -743,6 +743,18 @@ def test_wcsextrastringwidget_regex_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': '12,34'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'invalid value'
|
||||
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
fakefield.validation = {
|
||||
'type': 'regex',
|
||||
'value': r'\d+(\.\d{1,2})?',
|
||||
'error_message': 'Foo Bar Custom Error',
|
||||
}
|
||||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': '12,34'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Foo Bar Custom Error'
|
||||
|
||||
|
||||
def test_wcsextrastringwidget_builtin_validation():
|
||||
|
@ -761,6 +773,7 @@ def test_wcsextrastringwidget_builtin_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': 'az'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Only digits are allowed'
|
||||
|
||||
fakefield.validation = {'type': 'zipcode-fr'}
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
|
@ -777,6 +790,7 @@ def test_wcsextrastringwidget_builtin_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': '1234'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid zip code'
|
||||
|
||||
|
||||
def test_wcsextrastringwidget_phone():
|
||||
|
@ -798,6 +812,7 @@ def test_wcsextrastringwidget_phone():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': invalid_case})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid phone number'
|
||||
|
||||
# and check it gets a special HTML input type
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
|
@ -827,6 +842,7 @@ def test_wcsextrastringwidget_phone_fr():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': 'az'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid phone number'
|
||||
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
widget.field = fakefield
|
||||
|
@ -858,6 +874,7 @@ def test_wcsextrastringwidget_siren_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': '443170130'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid SIREN code'
|
||||
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
widget.field = fakefield
|
||||
|
@ -899,6 +916,7 @@ def test_wcsextrastringwidget_siret_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': '44317013900037'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid SIRET code'
|
||||
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
widget.field = fakefield
|
||||
|
@ -940,6 +958,7 @@ def test_wcsextrastringwidget_nir_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': '42'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid NIR'
|
||||
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
widget.field = fakefield
|
||||
|
@ -1016,6 +1035,7 @@ def test_wcsextrastringwidget_iban_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': iban.replace(' ', '')})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Invalid IBAN'
|
||||
|
||||
|
||||
def test_wcsextrastringwidget_django_validation():
|
||||
|
@ -1039,6 +1059,18 @@ def test_wcsextrastringwidget_django_validation():
|
|||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': 'az'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'invalid value'
|
||||
|
||||
widget = WcsExtraStringWidget('test', value='foo', required=False)
|
||||
fakefield.validation = {
|
||||
'type': 'django',
|
||||
'value': 'value|decimal and value|decimal < 20',
|
||||
'error_message': 'Foo Bar Custom Error',
|
||||
}
|
||||
widget.field = fakefield
|
||||
mock_form_submission(req, widget, {'test': 'az'})
|
||||
assert widget.has_error()
|
||||
assert widget.error == 'Foo Bar Custom Error'
|
||||
|
||||
|
||||
def test_widgetdict_widget():
|
||||
|
|
|
@ -1051,28 +1051,48 @@ class ValidationCondition(Condition):
|
|||
class ValidationWidget(CompositeWidget):
|
||||
validation_methods = collections.OrderedDict(
|
||||
[
|
||||
('digits', {'title': N_('Digits'), 'regex': r'\d+', 'html_inputmode': 'numeric'}),
|
||||
(
|
||||
'digits',
|
||||
{
|
||||
'title': N_('Digits'),
|
||||
'regex': r'\d+',
|
||||
'error_message': N_('Only digits are allowed'),
|
||||
'html_inputmode': 'numeric',
|
||||
},
|
||||
),
|
||||
(
|
||||
'phone',
|
||||
{'title': N_('Phone Number'), 'regex': r'\+?[-\(\)\d\.\s/]+', 'html_input_type': 'tel'},
|
||||
{
|
||||
'title': N_('Phone Number'),
|
||||
'regex': r'\+?[-\(\)\d\.\s/]+',
|
||||
'error_message': N_('Invalid phone number'),
|
||||
'html_input_type': 'tel',
|
||||
},
|
||||
),
|
||||
(
|
||||
'phone-fr',
|
||||
{
|
||||
'title': N_('Phone Number (France)'),
|
||||
'function': 'validate_phone_fr',
|
||||
'error_message': N_('Invalid phone number'),
|
||||
'html_input_type': 'tel',
|
||||
},
|
||||
),
|
||||
(
|
||||
'zipcode-fr',
|
||||
{'title': N_('Zip Code (France)'), 'regex': r'\d{5}', 'html_inputmode': 'numeric'},
|
||||
{
|
||||
'title': N_('Zip Code (France)'),
|
||||
'regex': r'\d{5}',
|
||||
'error_message': N_('Invalid zip code'),
|
||||
'html_inputmode': 'numeric',
|
||||
},
|
||||
),
|
||||
(
|
||||
'siren-fr',
|
||||
{
|
||||
'title': N_('SIREN Code (France)'),
|
||||
'function': 'validate_siren',
|
||||
'error_message': N_('Invalid SIREN code'),
|
||||
'html_inputmode': 'numeric',
|
||||
},
|
||||
),
|
||||
|
@ -1081,11 +1101,15 @@ class ValidationWidget(CompositeWidget):
|
|||
{
|
||||
'title': N_('SIRET Code (France)'),
|
||||
'function': 'validate_siret',
|
||||
'error_message': N_('Invalid SIRET code'),
|
||||
'html_inputmode': 'numeric',
|
||||
},
|
||||
),
|
||||
('nir-fr', {'title': N_('NIR (France)'), 'function': 'validate_nir'}),
|
||||
('iban', {'title': N_('IBAN'), 'function': 'validate_iban'}),
|
||||
(
|
||||
'nir-fr',
|
||||
{'title': N_('NIR (France)'), 'error_message': N_('Invalid NIR'), 'function': 'validate_nir'},
|
||||
),
|
||||
('iban', {'title': N_('IBAN'), 'function': 'validate_iban', 'error_message': N_('Invalid IBAN')}),
|
||||
('regex', {'title': N_('Regular Expression')}),
|
||||
('django', {'title': N_('Django Condition')}),
|
||||
]
|
||||
|
@ -1130,6 +1154,20 @@ class ValidationWidget(CompositeWidget):
|
|||
'data-dynamic-display-value': validation_labels.get('django'),
|
||||
},
|
||||
)
|
||||
self.add(
|
||||
StringWidget,
|
||||
'error_message',
|
||||
size=80,
|
||||
value=value.get('error_message') if value.get('type') in ['regex', 'django'] else None,
|
||||
title=_('Custom error message'),
|
||||
hint=_('This message will be be displayed if validation fails.'),
|
||||
attrs={
|
||||
'data-dynamic-display-child-of': 'validation$type',
|
||||
'data-dynamic-display-value-in': '|'.join(
|
||||
[validation_labels.get('regex'), validation_labels.get('django')]
|
||||
),
|
||||
},
|
||||
)
|
||||
self._parsed = False
|
||||
|
||||
def _parse(self, request):
|
||||
|
@ -1140,14 +1178,23 @@ class ValidationWidget(CompositeWidget):
|
|||
value = self.get('value_%s' % type_)
|
||||
if value:
|
||||
values['value'] = value
|
||||
if type_ in ['regex', 'django']:
|
||||
error_message = self.get('error_message')
|
||||
if error_message:
|
||||
values['error_message'] = error_message
|
||||
self.value = values or None
|
||||
|
||||
def render_content(self):
|
||||
r = TemplateIO(html=True)
|
||||
for widget in self.get_widgets():
|
||||
inlines = ['type', 'value_regex', 'value_django']
|
||||
for name in inlines:
|
||||
widget = self.get_widget(name)
|
||||
r += widget.render_error(widget.get_error())
|
||||
for widget in self.get_widgets():
|
||||
for name in inlines:
|
||||
widget = self.get_widget(name)
|
||||
r += widget.render_content()
|
||||
widget = self.get_widget('error_message')
|
||||
r += widget.render()
|
||||
return r.getvalue()
|
||||
|
||||
@classmethod
|
||||
|
@ -1170,6 +1217,17 @@ class ValidationWidget(CompositeWidget):
|
|||
if validation_method and 'function' in validation_method:
|
||||
return getattr(misc, validation_method['function'])
|
||||
|
||||
@classmethod
|
||||
def get_validation_error_message(cls, validation):
|
||||
pattern = cls.get_validation_pattern(validation)
|
||||
if validation['type'] == 'regex' and pattern:
|
||||
return validation.get('error_message')
|
||||
if validation['type'] == 'django' and validation.get('value'):
|
||||
return validation.get('error_message')
|
||||
validation_method = cls.validation_methods.get(validation['type'])
|
||||
if validation_method and 'error_message' in validation_method:
|
||||
return validation_method['error_message']
|
||||
|
||||
@classmethod
|
||||
def get_validation_pattern(cls, validation):
|
||||
validation_method = cls.validation_methods.get(validation['type'])
|
||||
|
@ -1214,6 +1272,9 @@ class WcsExtraStringWidget(StringWidget):
|
|||
StringWidget._parse(self, request)
|
||||
if self.field and self.field.validation and self.value is not None:
|
||||
self.validation_function = ValidationWidget.get_validation_function(self.field.validation)
|
||||
self.validation_function_error_message = ValidationWidget.get_validation_error_message(
|
||||
self.field.validation
|
||||
)
|
||||
|
||||
if self.validation_function and not self.validation_function(self.value):
|
||||
self.error = self.validation_function_error_message or _('invalid value')
|
||||
|
|
Loading…
Reference in New Issue