generalize error_code
This commit is contained in:
parent
cc5ce2ffd4
commit
b703a78a5b
|
@ -186,6 +186,21 @@ class ErrorMessage:
|
|||
return ''.join(x.lower() if i == 0 else x.capitalize() for i, x in enumerate(self.code.split('_')))
|
||||
|
||||
|
||||
def widget_set_error(self, error=None, error_code=None):
|
||||
if error and error_code:
|
||||
self.error = error
|
||||
self.error_code = error_code
|
||||
elif error_code:
|
||||
self.error = getattr(self, 'get_%s_message' % error_code)()
|
||||
self.error_code = error_code
|
||||
else:
|
||||
self.error = error
|
||||
if self.error == Widget.REQUIRED_ERROR:
|
||||
self.error_code = 'value_missing'
|
||||
else:
|
||||
self.error_code = 'invalid_value'
|
||||
|
||||
|
||||
def widget_get_error_messages(self):
|
||||
for code in self.get_error_message_codes():
|
||||
yield ErrorMessage(code, getattr(self, 'get_%s_message' % code)())
|
||||
|
@ -207,6 +222,7 @@ Widget.get_error_messages = widget_get_error_messages
|
|||
Widget.get_error_message_codes = widget_get_error_message_codes
|
||||
Widget.get_value_missing_message = lambda x: Widget.REQUIRED_ERROR
|
||||
Widget.get_invalid_value_message = lambda x: _('Invalid value')
|
||||
Widget.set_error = widget_set_error
|
||||
|
||||
|
||||
def file_render_content(self):
|
||||
|
@ -601,12 +617,12 @@ class StringWidget(QuixoteStringWidget):
|
|||
if self.value:
|
||||
self.value = self.value.strip()
|
||||
if self.maxlength and len(self.value) > self.maxlength:
|
||||
self.error = self.get_too_long_message()
|
||||
self.set_error(error_code='too_long')
|
||||
elif self.validation_function:
|
||||
try:
|
||||
self.validation_function(self.value)
|
||||
except ValueError as e:
|
||||
self.error = str(e)
|
||||
self.set_error(str(e))
|
||||
|
||||
def get_too_long_message(self):
|
||||
return _('Too long, value must be at most %d characters.') % self.maxlength
|
||||
|
@ -661,12 +677,12 @@ class TextWidget(QuixoteTextWidget):
|
|||
if self.value is not None:
|
||||
if maxlength:
|
||||
if len(self.value) > maxlength:
|
||||
self.error = self.get_too_long_message()
|
||||
self.set_error('too_long')
|
||||
if use_validation_function and self.validation_function:
|
||||
try:
|
||||
self.validation_function(self.value)
|
||||
except ValueError as e:
|
||||
self.error = str(e)
|
||||
self.set_error(str(e))
|
||||
|
||||
def get_too_long_message(self):
|
||||
try:
|
||||
|
@ -677,7 +693,7 @@ class TextWidget(QuixoteTextWidget):
|
|||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
yield 'too-long'
|
||||
yield 'too_long'
|
||||
|
||||
def render_content(self):
|
||||
attrs = {'id': 'form_' + self.get_name_for_id()}
|
||||
|
@ -709,7 +725,7 @@ class CheckboxWidget(QuixoteCheckboxWidget):
|
|||
def _parse(self, request):
|
||||
self.value = self.name in request.form and not request.form[self.name] in (False, '', 'False')
|
||||
if self.required and not self.value:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
self.set_error(error_code='value_missing')
|
||||
|
||||
def set_value(self, value):
|
||||
if value in (None, False, '', 'False'):
|
||||
|
@ -912,7 +928,7 @@ class FileWithPreviewWidget(CompositeWidget):
|
|||
try:
|
||||
token = get_session().add_tempfile(self.get('file'), storage=self.storage)['token']
|
||||
except UploadStorageError:
|
||||
self.error = _('failed to store file (system error)')
|
||||
self.set_error(_('failed to store file (system error)'))
|
||||
return
|
||||
request.form[self.get_widget('token').get_name()] = token
|
||||
else:
|
||||
|
@ -931,7 +947,7 @@ class FileWithPreviewWidget(CompositeWidget):
|
|||
return
|
||||
|
||||
if self.storage and self.storage != self.storage:
|
||||
self.error = _('unknown storage system (system error)')
|
||||
self.set_error(_('unknown storage system (system error)'))
|
||||
return
|
||||
|
||||
# Don't trust the browser supplied MIME type, update the Upload object
|
||||
|
@ -967,7 +983,7 @@ class FileWithPreviewWidget(CompositeWidget):
|
|||
if self.max_file_size and hasattr(self.value, 'file_size'):
|
||||
# validate file size
|
||||
if self.value.file_size > self.max_file_size_bytes:
|
||||
self.error = _('over file size limit (%s)') % self.max_file_size
|
||||
self.set_error(_('over file size limit (%s)') % self.max_file_size)
|
||||
return
|
||||
|
||||
if self.file_type:
|
||||
|
@ -984,7 +1000,7 @@ class FileWithPreviewWidget(CompositeWidget):
|
|||
valid_file_type = True
|
||||
break
|
||||
if not valid_file_type:
|
||||
self.error = _('invalid file type')
|
||||
self.set_error(_('invalid file type'))
|
||||
|
||||
blacklisted_file_types = get_publisher().get_site_option('blacklisted-file-types')
|
||||
if blacklisted_file_types:
|
||||
|
@ -1004,7 +1020,7 @@ class FileWithPreviewWidget(CompositeWidget):
|
|||
os.path.splitext(self.value.base_filename)[-1].lower() in blacklisted_file_types
|
||||
or filetype in blacklisted_file_types
|
||||
):
|
||||
self.error = _('forbidden file type')
|
||||
self.set_error(_('forbidden file type'))
|
||||
|
||||
|
||||
class EmailWidget(StringWidget):
|
||||
|
@ -1038,37 +1054,37 @@ class EmailWidget(StringWidget):
|
|||
if self.value is not None:
|
||||
# basic tests first
|
||||
if '@' not in self.value[1:-1]:
|
||||
self.error = _('must be a valid email address')
|
||||
self.set_error(_('must be a valid email address'))
|
||||
return
|
||||
if self.value[0] != '"' and ' ' in self.value:
|
||||
self.error = _('must be a valid email address')
|
||||
self.set_error(_('must be a valid email address'))
|
||||
return
|
||||
if self.value[0] != '"' and self.value.count('@') != 1:
|
||||
self.error = _('must be a valid email address')
|
||||
self.set_error(_('must be a valid email address'))
|
||||
return
|
||||
user_part, domain = self.value.rsplit('@', 1)
|
||||
if not self.user_part_re.match(user_part):
|
||||
self.error = _('must be a valid email address')
|
||||
self.set_error(_('must be a valid email address'))
|
||||
return
|
||||
if get_cfg('emails', {}).get('check_domain_with_dns', True):
|
||||
# testing for domain existence
|
||||
if [x for x in domain.split('.') if not x]:
|
||||
# empty parts in domain, ex: @example..net, or
|
||||
# @.example.net
|
||||
self.error = _('invalid address domain')
|
||||
self.set_error(_('invalid address domain'))
|
||||
return
|
||||
domain = force_str(domain, 'utf-8', errors='ignore')
|
||||
try:
|
||||
domain = force_str(domain.encode('idna'))
|
||||
except UnicodeError:
|
||||
self.error = _('invalid address domain')
|
||||
self.set_error(_('invalid address domain'))
|
||||
return
|
||||
if domain == 'localhost':
|
||||
return
|
||||
try:
|
||||
dns.resolver.query(force_str(domain), 'MX')
|
||||
except dns.exception.DNSException:
|
||||
self.error = _('invalid address domain')
|
||||
self.set_error(_('invalid address domain'))
|
||||
|
||||
|
||||
class OptGroup:
|
||||
|
@ -1432,7 +1448,7 @@ class WcsExtraStringWidget(StringWidget):
|
|||
normalized_value = normalize(self.value)
|
||||
|
||||
if self.value and self.validation_function and not self.validation_function(normalized_value):
|
||||
self.error = self.validation_function_error_message or _('invalid value')
|
||||
self.set_error(self.validation_function_error_message or _('invalid value'))
|
||||
|
||||
if self.field and self.value and not self.error and self.field.validation:
|
||||
self.value = normalized_value
|
||||
|
@ -1496,19 +1512,21 @@ class DateWidget(StringWidget):
|
|||
value = misc.get_as_datetime(self.value).timetuple()
|
||||
self.value = strftime(self.get_format_string(), value)
|
||||
except ValueError:
|
||||
self.error = _('invalid date')
|
||||
self.set_error(_('invalid date'))
|
||||
self.value = None
|
||||
return
|
||||
if value[0] < 1500 or value[0] > 2099:
|
||||
self.error = _('invalid date')
|
||||
self.set_error(_('invalid date'))
|
||||
self.value = None
|
||||
elif self.minimum_date and value[:3] < self.minimum_date.timetuple()[:3]:
|
||||
self.error = _('invalid date: date must be on or after %s') % strftime(
|
||||
misc.date_format(), self.minimum_date
|
||||
self.set_error(
|
||||
_('invalid date: date must be on or after %s')
|
||||
% strftime(misc.date_format(), self.minimum_date)
|
||||
)
|
||||
elif self.maximum_date and value[:3] > self.maximum_date.timetuple()[:3]:
|
||||
self.error = _('invalid date; date must be on or before %s') % strftime(
|
||||
misc.date_format(), self.maximum_date
|
||||
self.set_error(
|
||||
_('invalid date; date must be on or before %s')
|
||||
% strftime(misc.date_format(), self.maximum_date)
|
||||
)
|
||||
|
||||
def add_media(self):
|
||||
|
@ -1567,7 +1585,7 @@ class TimeWidget(DateWidget):
|
|||
value = datetime.datetime.strptime(self.value, self.get_format_string())
|
||||
self.value = strftime(self.get_format_string(), value)
|
||||
except ValueError:
|
||||
self.error = _('invalid time')
|
||||
self.set_error(_('invalid time'))
|
||||
self.value = None
|
||||
return
|
||||
|
||||
|
@ -1603,7 +1621,7 @@ class DateTimeWidget(CompositeWidget):
|
|||
try:
|
||||
misc.get_as_datetime('%s %s' % (date, time))
|
||||
except ValueError:
|
||||
self.error = _('invalid value')
|
||||
self.set_error(_('invalid value'))
|
||||
self.value = '%s %s' % (date, time)
|
||||
return self.value
|
||||
|
||||
|
@ -1617,7 +1635,7 @@ class RegexStringWidget(StringWidget):
|
|||
try:
|
||||
re.compile(self.value)
|
||||
except Exception:
|
||||
self.error = _('invalid regular expression')
|
||||
self.set_error(_('invalid regular expression'))
|
||||
self.value = None
|
||||
|
||||
|
||||
|
@ -1670,11 +1688,11 @@ class CheckboxesWidget(Widget):
|
|||
values.append(option['value'])
|
||||
self.value = values
|
||||
if self.required and not self.value:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
self.set_error(error_code='value_missing')
|
||||
if self.value and self.min_choices and len(self.value) < self.min_choices:
|
||||
self.set_error(self.get_too_short_message())
|
||||
self.set_error(error_code='too_short')
|
||||
if self.value and self.max_choices and len(self.value) > self.max_choices:
|
||||
self.set_error(self.get_too_long_message())
|
||||
self.set_error(error_code='too_long')
|
||||
|
||||
def get_too_short_message(self):
|
||||
return _('You must select at least %d answers.') % self.min_choices
|
||||
|
@ -1708,7 +1726,7 @@ class ValidatedStringWidget(StringWidget):
|
|||
if self.regex and self.value is not None:
|
||||
match = re.match(self.regex, self.value)
|
||||
if not match or not match.group() == self.value:
|
||||
self.error = _('wrong format')
|
||||
self.set_error(_('wrong format'))
|
||||
|
||||
|
||||
class UrlWidget(ValidatedStringWidget):
|
||||
|
@ -1719,7 +1737,7 @@ class UrlWidget(ValidatedStringWidget):
|
|||
def _parse(self, request):
|
||||
ValidatedStringWidget._parse(self, request)
|
||||
if self.error:
|
||||
self.error = _('must start with http:// or https:// and have a domain name')
|
||||
self.set_error(_('must start with http:// or https:// and have a domain name'))
|
||||
|
||||
|
||||
class VarnameWidget(ValidatedStringWidget):
|
||||
|
@ -1731,7 +1749,7 @@ class VarnameWidget(ValidatedStringWidget):
|
|||
def _parse(self, request):
|
||||
ValidatedStringWidget._parse(self, request)
|
||||
if self.error:
|
||||
self.error = _('must only consist of letters, numbers, or underscore')
|
||||
self.set_error(_('must only consist of letters, numbers, or underscore'))
|
||||
# forbid id/text to be used as identifier, as they would clash against
|
||||
# "native" id/text keys in datasources; forbid "status" to avoid status
|
||||
# filtering being diverted to a form field.
|
||||
|
@ -1762,7 +1780,7 @@ class SlugWidget(ValidatedStringWidget):
|
|||
def _parse(self, request):
|
||||
super()._parse(request)
|
||||
if self.error:
|
||||
self.error = _('wrong format: must only consist of letters, numbers, dashes, or underscores')
|
||||
self.set_error(_('wrong format: must only consist of letters, numbers, dashes, or underscores'))
|
||||
|
||||
|
||||
class FileSizeWidget(ValidatedStringWidget):
|
||||
|
@ -1795,7 +1813,7 @@ class FileSizeWidget(ValidatedStringWidget):
|
|||
def _parse(self, request):
|
||||
ValidatedStringWidget._parse(self, request)
|
||||
if self.error:
|
||||
self.error = _('invalid file size')
|
||||
self.set_error(_('invalid file size'))
|
||||
|
||||
|
||||
class CaptchaWidget(CompositeWidget):
|
||||
|
@ -1845,7 +1863,7 @@ class CaptchaWidget(CompositeWidget):
|
|||
get_session().won_captcha = True
|
||||
self.value = v
|
||||
elif v['answer']:
|
||||
self.error = _('wrong answer')
|
||||
self.set_error(_('wrong answer'))
|
||||
|
||||
def get_title(self):
|
||||
return self.question
|
||||
|
@ -1936,7 +1954,7 @@ class WidgetList(quixote.form.widget.WidgetList):
|
|||
def _parse(self, request):
|
||||
super()._parse(request)
|
||||
if self.max_items and self.value and len(self.value) > self.max_items:
|
||||
self.set_error(self.get_too_many_message())
|
||||
self.set_error(error_code='too_many')
|
||||
|
||||
def get_too_many_message(self):
|
||||
return _('Too many elements (maximum: %s)') % self.max_items
|
||||
|
@ -2433,7 +2451,7 @@ class WysiwygTextWidget(TextWidget):
|
|||
try:
|
||||
self.validation_function(self.value)
|
||||
except ValueError as e:
|
||||
self.error = str(e)
|
||||
self.set_error(str(e))
|
||||
if self.value == '':
|
||||
self.value = None
|
||||
|
||||
|
@ -2525,7 +2543,7 @@ class TableWidget(CompositeWidget):
|
|||
request = get_request()
|
||||
if (request.form or request.get_method() == 'POST') and self.required:
|
||||
if not self.value:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
self.set_error(error_code='value_missing')
|
||||
else:
|
||||
for row in self.value:
|
||||
for column in row:
|
||||
|
@ -2535,7 +2553,7 @@ class TableWidget(CompositeWidget):
|
|||
continue
|
||||
break
|
||||
else:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
self.set_error(error_code='value_missing')
|
||||
return self.value
|
||||
|
||||
def _parse(self, request):
|
||||
|
@ -2681,9 +2699,9 @@ class MultiSelectWidget(MultipleSelectWidget):
|
|||
finally:
|
||||
self.name = orig_name
|
||||
if self.value and self.min_choices and len(self.value) < self.min_choices:
|
||||
self.set_error(self.get_too_short_message())
|
||||
self.set_error(error_code='too_short')
|
||||
if self.value and self.max_choices and len(self.value) > self.max_choices:
|
||||
self.set_error(self.get_too_long_message())
|
||||
self.set_error(error_code='too_long')
|
||||
|
||||
def get_too_short_message(self):
|
||||
return _('You must select at least %d choices.') % self.min_choices
|
||||
|
@ -2777,7 +2795,7 @@ class TableListRowsWidget(WidgetListAsTable):
|
|||
add_element_pushed = self.get_widget('add_element').parse()
|
||||
if (request.form or request.get_method() == 'POST') and self.required:
|
||||
if not self.value and not add_element_pushed:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
self.set_error(error_code='value_missing')
|
||||
for row in self.value or []:
|
||||
for column in row:
|
||||
if column:
|
||||
|
@ -2787,7 +2805,7 @@ class TableListRowsWidget(WidgetListAsTable):
|
|||
break
|
||||
else:
|
||||
if not add_element_pushed:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
self.set_error(error_code='value_missing')
|
||||
return self.value
|
||||
|
||||
def _parse(self, request):
|
||||
|
@ -2892,7 +2910,7 @@ class RankedItemsWidget(CompositeWidget):
|
|||
if value is not None:
|
||||
values[val] = value
|
||||
if value is not None and not isinstance(value, int):
|
||||
self.get_widget(key).set_error(self.get_type_mismatch_message())
|
||||
self.get_widget(key).set_error(error_code='type_mismatch')
|
||||
self.value = values or None
|
||||
|
||||
def get_type_mismatch_message(self):
|
||||
|
@ -3358,7 +3376,7 @@ class MapWidget(CompositeWidget):
|
|||
try:
|
||||
lat, lon = self.value.split(';')
|
||||
except ValueError:
|
||||
self.set_error(self.get_invalid_value_message())
|
||||
self.set_error(error_code='invalid_value')
|
||||
else:
|
||||
lat_lon = misc.normalize_geolocation({'lat': lat, 'lon': lon})
|
||||
self.value = '%s;%s' % (lat_lon['lat'], lat_lon['lon']) if lat_lon else None
|
||||
|
@ -3406,8 +3424,8 @@ class MapMarkerSelectionWidget(MapWidget):
|
|||
|
||||
|
||||
class HiddenErrorWidget(HiddenWidget):
|
||||
def set_error(self, error):
|
||||
Widget.set_error(self, error)
|
||||
def set_error(self, *args, **kwargs):
|
||||
Widget.set_error(self, *args, **kwargs)
|
||||
|
||||
|
||||
class SingleSelectWidgetWithOther(CompositeWidget):
|
||||
|
|
Loading…
Reference in New Issue