Improve error messages for name-parts inputs (Z#23234440) (#6187)

* Improve error messages for name-parts inputs (Z#23234440)

* fix isort after flake8

* correct spelling of .med in user-provided title/name

* fix search instead of match
This commit is contained in:
Richard Schreiber
2026-05-19 15:23:30 +02:00
committed by GitHub
parent 6d293e544e
commit ce5af572cc

View File

@@ -35,6 +35,7 @@
import copy import copy
import json import json
import logging import logging
import re
from datetime import timedelta from datetime import timedelta
from decimal import Decimal from decimal import Decimal
from io import BytesIO from io import BytesIO
@@ -47,9 +48,7 @@ from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import ( from django.core.validators import MaxValueValidator, MinValueValidator
MaxValueValidator, MinValueValidator, RegexValidator,
)
from django.db.models import QuerySet from django.db.models import QuerySet
from django.forms import Select, widgets from django.forms import Select, widgets
from django.forms.widgets import FILE_INPUT_CONTRADICTION from django.forms.widgets import FILE_INPUT_CONTRADICTION
@@ -220,20 +219,6 @@ class NamePartsFormField(forms.MultiValueField):
defaults = { defaults = {
'widget': self.widget, 'widget': self.widget,
'max_length': kwargs.pop('max_length', None), 'max_length': kwargs.pop('max_length', None),
'validators': [
RegexValidator(
# The following characters should never appear in a name anywhere of
# the world. However, they commonly appear in inputs generated by spam
# bots.
r'^[^$€/%§{}<>~]*$',
message=_('Please do not use special characters in names.')
),
RegexValidator(
URL_RE,
inverse_match=True,
message=_('Please do not use special characters in names.')
)
]
} }
self.max_length = defaults['max_length'] self.max_length = defaults['max_length']
self.scheme_name = kwargs.pop('scheme') self.scheme_name = kwargs.pop('scheme')
@@ -255,7 +240,6 @@ class NamePartsFormField(forms.MultiValueField):
if fname == 'title' and self.scheme_titles: if fname == 'title' and self.scheme_titles:
d = dict(defaults) d = dict(defaults)
d.pop('max_length', None) d.pop('max_length', None)
d.pop('validators', None)
field = forms.ChoiceField( field = forms.ChoiceField(
**d, **d,
choices=[('', '')] + [(d, d) for d in self.scheme_titles[1]] choices=[('', '')] + [(d, d) for d in self.scheme_titles[1]]
@@ -264,7 +248,6 @@ class NamePartsFormField(forms.MultiValueField):
elif fname == 'salutation': elif fname == 'salutation':
d = dict(defaults) d = dict(defaults)
d.pop('max_length', None) d.pop('max_length', None)
d.pop('validators', None)
field = forms.ChoiceField( field = forms.ChoiceField(
**d, **d,
choices=[ choices=[
@@ -296,6 +279,37 @@ class NamePartsFormField(forms.MultiValueField):
if sum(len(v) for v in value.values() if v) > (self.max_length or 250): if sum(len(v) for v in value.values() if v) > (self.max_length or 250):
raise forms.ValidationError(_('Please enter a shorter name.'), code='max_length') raise forms.ValidationError(_('Please enter a shorter name.'), code='max_length')
for fname, label, size in self.scheme['fields']:
if fname == 'salutation' or (fname == 'title' and self.scheme_titles):
continue
v = value.get(fname)
if not v:
continue
special_chars = re.findall('[$€/%§{}<>~]', v)
if special_chars:
raise forms.ValidationError(
_('The field "%(label)s" may not contain special characters such as "%(chars)s".'),
code='name_special_chars',
params={
"label": label,
"chars": "".join(special_chars),
},
)
# URL_RE checks for valid domain names, including one special TLD med, which can be part of a title
if ".med" in v:
v = v.replace(".med", ". med")
value[fname] = v
url_matched = URL_RE.search(v)
if url_matched:
raise forms.ValidationError(
_('The field "%(label)s" may not contain an URL (%(url)s).'),
code='url_in_title',
params={
"label": label,
"url": url_matched.group(0),
}
)
if value.get("salutation") == "empty": if value.get("salutation") == "empty":
value["salutation"] = "" value["salutation"] = ""