diff --git a/ietf/ietfauth/forms.py b/ietf/ietfauth/forms.py index 179c0fe65..9779fd218 100644 --- a/ietf/ietfauth/forms.py +++ b/ietf/ietfauth/forms.py @@ -9,6 +9,8 @@ from django.contrib.auth.models import User from django.utils.html import mark_safe from django.core.urlresolvers import reverse as urlreverse +from unidecode import unidecode + import debug # pyflakes:ignore from ietf.person.models import Person, Email @@ -45,9 +47,18 @@ class PasswordForm(forms.Form): def ascii_cleaner(supposedly_ascii): outside_printable_ascii_pattern = r'[^\x20-\x7F]' if re.search(outside_printable_ascii_pattern, supposedly_ascii): - raise forms.ValidationError("Please only enter ASCII characters.") + raise forms.ValidationError("Only unaccented Latin characters are allowed.") return supposedly_ascii +def prevent_at_symbol(name): + if "@" in name: + raise forms.ValidationError("Please fill in name - this looks like an email address (@ is not allowed in names).") + +def prevent_system_name(name): + name_without_spaces = name.replace(" ", "").replace("\t", "") + if "(system)" in name_without_spaces.lower(): + raise forms.ValidationError("Please pick another name - this name is reserved.") + def get_person_form(*args, **kwargs): exclude_list = ['time', 'user', 'photo_thumb', 'photo', ] @@ -65,11 +76,42 @@ def get_person_form(*args, **kwargs): def __init__(self, *args, **kwargs): super(ModelForm, self).__init__(*args, **kwargs) + # blank ascii if it's the same as name + self.fields["ascii"].required = self.fields["ascii"].widget.is_required = False + self.fields["ascii"].help_text += " " + "Leave blank to use auto-reconstructed Latin version of name." + + if self.initial.get("ascii") == self.initial.get("name"): + self.initial["ascii"] = "" + + self.unidecoded_ascii = False + + if self.data and not self.data.get("ascii", "").strip(): + self.data = self.data.copy() + name = self.data["name"] + reconstructed_name = unidecode(name) + self.data["ascii"] = reconstructed_name + self.unidecoded_ascii = name != reconstructed_name + + def clean_name(self): + name = self.cleaned_data.get("name") or u"" + prevent_at_symbol(name) + prevent_system_name(name) + return name + def clean_ascii(self): - return ascii_cleaner(self.cleaned_data.get("ascii") or u"") + if self.unidecoded_ascii: + raise forms.ValidationError("Name contained non-ASCII characters, and was automatically reconstructed using only Latin characters. Check the result - if you are happy, just hit Submit again.") + + name = self.cleaned_data.get("ascii") or u"" + prevent_at_symbol(name) + prevent_system_name(name) + return ascii_cleaner(name) def clean_ascii_short(self): - return ascii_cleaner(self.cleaned_data.get("ascii_short") or u"") + name = self.cleaned_data.get("ascii_short") or u"" + prevent_at_symbol(name) + prevent_system_name(name) + return ascii_cleaner(name) return PersonForm(*args, **kwargs) diff --git a/ietf/ietfauth/tests.py b/ietf/ietfauth/tests.py index 39927426f..335a5f489 100644 --- a/ietf/ietfauth/tests.py +++ b/ietf/ietfauth/tests.py @@ -213,6 +213,15 @@ class IetfAuthTests(TestCase): q = PyQuery(r.content) self.assertTrue(len(q("form .has-error")) > 0) + # edit details - blank ASCII + blank_ascii = base_data.copy() + blank_ascii["ascii"] = u"" + r = self.client.post(url, blank_ascii) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertTrue(len(q("form .has-error")) > 0) # we get a warning about reconstructed name + self.assertEqual(q("input[name=ascii]").val(), base_data["ascii"]) + # edit details r = self.client.post(url, base_data) self.assertEqual(r.status_code, 200)