Commits

Anonymous committed 25b68e0

Fixed #17194 -- Made sure the auth form tests work if a language other than English is activated by moving the error message translation strings into class level dictionaries. Many thanks to Claude Paroz, rabio and Bas Peschier for their initial work on this.

  • Participants
  • Parent commits 2061758

Comments (0)

Files changed (3)

File django/contrib/auth/forms.py

 
 mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0))
 
+
 class ReadOnlyPasswordHashWidget(forms.Widget):
     def render(self, name, value, attrs):
         if not value:
                     "masked": masked,
                 })
 
+
 class ReadOnlyPasswordHashField(forms.Field):
     widget = ReadOnlyPasswordHashWidget
 
         kwargs.setdefault("required", False)
         super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs)
 
+
 class UserCreationForm(forms.ModelForm):
     """
     A form that creates a user, with no privileges, from the given username and password.
     """
+    error_messages = {
+        'duplicate_username': _("A user with that username already exists."),
+        'password_mismatch': _("The two password fields didn't match."),
+    }
     username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$',
         help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
         error_messages = {'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")})
             User.objects.get(username=username)
         except User.DoesNotExist:
             return username
-        raise forms.ValidationError(_("A user with that username already exists."))
+        raise forms.ValidationError(self.error_messages['duplicate_username'])
 
     def clean_password2(self):
         password1 = self.cleaned_data.get("password1", "")
         password2 = self.cleaned_data["password2"]
         if password1 != password2:
-            raise forms.ValidationError(_("The two password fields didn't match."))
+            raise forms.ValidationError(self.error_messages['password_mismatch'])
         return password2
 
     def save(self, commit=True):
             user.save()
         return user
 
+
 class UserChangeForm(forms.ModelForm):
     username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$',
         help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
         if f is not None:
             f.queryset = f.queryset.select_related('content_type')
 
+
 class AuthenticationForm(forms.Form):
     """
     Base class for authenticating users. Extend this to get a form that accepts
     username = forms.CharField(label=_("Username"), max_length=30)
     password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
 
+    error_messages = {
+        'invalid_login': _("Please enter a correct username and password. "
+                           "Note that both fields are case-sensitive."),
+        'no_cookies': _("Your Web browser doesn't appear to have cookies "
+                        "enabled. Cookies are required for logging in."),
+        'inactive': _("This account is inactive."),
+    }
+
     def __init__(self, request=None, *args, **kwargs):
         """
         If request is passed in, the form will validate that cookies are
         if username and password:
             self.user_cache = authenticate(username=username, password=password)
             if self.user_cache is None:
-                raise forms.ValidationError(_("Please enter a correct username and password. Note that both fields are case-sensitive."))
+                raise forms.ValidationError(self.error_messages['invalid_login'])
             elif not self.user_cache.is_active:
-                raise forms.ValidationError(_("This account is inactive."))
+                raise forms.ValidationError(self.error_messages['inactive'])
         self.check_for_test_cookie()
         return self.cleaned_data
 
     def check_for_test_cookie(self):
         if self.request and not self.request.session.test_cookie_worked():
-            raise forms.ValidationError(
-                _("Your Web browser doesn't appear to have cookies enabled. "
-                  "Cookies are required for logging in."))
+            raise forms.ValidationError(self.error_messages['no_cookies'])
 
     def get_user_id(self):
         if self.user_cache:
     def get_user(self):
         return self.user_cache
 
+
 class PasswordResetForm(forms.Form):
+    error_messages = {
+        'unknown': _("That e-mail address doesn't have an associated "
+                     "user account. Are you sure you've registered?"),
+        'unusable': _("The user account associated with this e-mail "
+                      "address cannot reset the password."),
+    }
     email = forms.EmailField(label=_("E-mail"), max_length=75)
 
     def clean_email(self):
                                 email__iexact=email,
                                 is_active=True)
         if not len(self.users_cache):
-            raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
+            raise forms.ValidationError(self.error_messages['unknown'])
         if any((user.password == UNUSABLE_PASSWORD) for user in self.users_cache):
-            raise forms.ValidationError(_("The user account associated with this e-mail address cannot reset the password."))
+            raise forms.ValidationError(self.error_messages['unusable'])
         return email
 
     def save(self, domain_override=None,
             email = loader.render_to_string(email_template_name, c)
             send_mail(subject, email, from_email, [user.email])
 
+
 class SetPasswordForm(forms.Form):
     """
     A form that lets a user change set his/her password without
     entering the old password
     """
+    error_messages = {
+        'password_mismatch': _("The two password fields didn't match."),
+    }
     new_password1 = forms.CharField(label=_("New password"), widget=forms.PasswordInput)
     new_password2 = forms.CharField(label=_("New password confirmation"), widget=forms.PasswordInput)
 
         password2 = self.cleaned_data.get('new_password2')
         if password1 and password2:
             if password1 != password2:
-                raise forms.ValidationError(_("The two password fields didn't match."))
+                raise forms.ValidationError(self.error_messages['password_mismatch'])
         return password2
 
     def save(self, commit=True):
             self.user.save()
         return self.user
 
+
 class PasswordChangeForm(SetPasswordForm):
     """
     A form that lets a user change his/her password by entering
     their old password.
     """
+    error_messages = dict(SetPasswordForm.error_messages, **{
+        'password_incorrect': _("Your old password was entered incorrectly. Please enter it again."),
+    })
     old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput)
 
     def clean_old_password(self):
         """
         old_password = self.cleaned_data["old_password"]
         if not self.user.check_password(old_password):
-            raise forms.ValidationError(_("Your old password was entered incorrectly. Please enter it again."))
+            raise forms.ValidationError(self.error_messages['password_incorrect'])
         return old_password
 PasswordChangeForm.base_fields.keyOrder = ['old_password', 'new_password1', 'new_password2']
 
+
 class AdminPasswordChangeForm(forms.Form):
     """
     A form used to change the password of a user in the admin interface.
     """
+    error_messages = {
+        'password_mismatch': _("The two password fields didn't match."),
+    }
     password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
     password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)
 
         password2 = self.cleaned_data.get('password2')
         if password1 and password2:
             if password1 != password2:
-                raise forms.ValidationError(_("The two password fields didn't match."))
+                raise forms.ValidationError(self.error_messages['password_mismatch'])
         return password2
 
     def save(self, commit=True):

File django/contrib/auth/tests/forms.py

 from __future__ import with_statement
 import os
 from django.core import mail
+from django.forms.fields import Field, EmailField
 from django.contrib.auth.models import User
 from django.contrib.auth.forms import UserCreationForm, AuthenticationForm,  PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm
 from django.test import TestCase
+from django.utils.encoding import force_unicode
+from django.utils import translation
 
 
 class UserCreationFormTest(TestCase):
         form = UserCreationForm(data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form["username"].errors,
-                         [u'A user with that username already exists.'])
+                         [force_unicode(form.error_messages['duplicate_username'])])
 
     def test_invalid_data(self):
         data = {
         form = UserCreationForm(data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form["username"].errors,
-                         [u'This value may contain only letters, numbers and @/./+/-/_ characters.'])
-
+                         [force_unicode(form.fields['username'].error_messages['invalid'])])
 
     def test_password_verification(self):
         # The verification password is incorrect.
         form = UserCreationForm(data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form["password2"].errors,
-                         [u"The two password fields didn't match."])
-
+                         [force_unicode(form.error_messages['password_mismatch'])])
 
     def test_both_passwords(self):
         # One (or both) passwords weren't given
         data = {'username': 'jsmith'}
         form = UserCreationForm(data)
+        required_error = [force_unicode(Field.default_error_messages['required'])]
         self.assertFalse(form.is_valid())
-        self.assertEqual(form['password1'].errors,
-                         [u'This field is required.'])
-        self.assertEqual(form['password2'].errors,
-                         [u'This field is required.'])
-
+        self.assertEqual(form['password1'].errors, required_error)
+        self.assertEqual(form['password2'].errors, required_error)
 
         data['password2'] = 'test123'
         form = UserCreationForm(data)
         self.assertFalse(form.is_valid())
-        self.assertEqual(form['password1'].errors,
-                         [u'This field is required.'])
+        self.assertEqual(form['password1'].errors, required_error)
 
     def test_success(self):
         # The success case.
         form = AuthenticationForm(None, data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form.non_field_errors(),
-                         [u'Please enter a correct username and password. Note that both fields are case-sensitive.'])
+                         [force_unicode(form.error_messages['invalid_login'])])
 
     def test_inactive_user(self):
         # The user is inactive.
         form = AuthenticationForm(None, data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form.non_field_errors(),
-                         [u'This account is inactive.'])
+                         [force_unicode(form.error_messages['inactive'])])
 
+    def test_inactive_user_i18n(self):
+        with self.settings(USE_I18N=True):
+            with translation.override('pt-br', deactivate=True):
+                # The user is inactive.
+                data = {
+                    'username': 'inactive',
+                    'password': 'password',
+                    }
+                form = AuthenticationForm(None, data)
+                self.assertFalse(form.is_valid())
+                self.assertEqual(form.non_field_errors(),
+                                 [force_unicode(form.error_messages['inactive'])])
 
     def test_success(self):
         # The success case
         form = SetPasswordForm(user, data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form["new_password2"].errors,
-                         [u"The two password fields didn't match."])
+                         [force_unicode(form.error_messages['password_mismatch'])])
 
     def test_success(self):
         user = User.objects.get(username='testclient')
         form = PasswordChangeForm(user, data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form["old_password"].errors,
-                         [u'Your old password was entered incorrectly. Please enter it again.'])
-
+                         [force_unicode(form.error_messages['password_incorrect'])])
 
     def test_password_verification(self):
         # The two new passwords do not match.
         form = PasswordChangeForm(user, data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form["new_password2"].errors,
-                         [u"The two password fields didn't match."])
-
+                         [force_unicode(form.error_messages['password_mismatch'])])
 
     def test_success(self):
         # The success case.
         self.assertEqual(PasswordChangeForm(user, {}).fields.keys(),
                          ['old_password', 'new_password1', 'new_password2'])
 
+
 class UserChangeFormTest(TestCase):
 
     fixtures = ['authtestdata.json']
         form = UserChangeForm(data, instance=user)
         self.assertFalse(form.is_valid())
         self.assertEqual(form['username'].errors,
-                         [u'This value may contain only letters, numbers and @/./+/-/_ characters.'])
+                         [force_unicode(form.fields['username'].error_messages['invalid'])])
 
     def test_bug_14242(self):
         # A regression test, introduce by adding an optimization for the
         return (user, username, email)
 
     def test_invalid_email(self):
-        data = {'email':'not valid'}
+        data = {'email': 'not valid'}
         form = PasswordResetForm(data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form['email'].errors,
-                         [u'Enter a valid e-mail address.'])
+                         [force_unicode(EmailField.default_error_messages['invalid'])])
 
     def test_nonexistant_email(self):
         # Test nonexistant email address
-        data = {'email':'foo@bar.com'}
+        data = {'email': 'foo@bar.com'}
         form = PasswordResetForm(data)
         self.assertFalse(form.is_valid())
         self.assertEqual(form.errors,
-                         {'email': [u"That e-mail address doesn't have an associated user account. Are you sure you've registered?"]})
+                         {'email': [force_unicode(form.error_messages['unknown'])]})
 
     def test_cleaned_data(self):
         # Regression test
         form = PasswordResetForm({'email': email})
         self.assertFalse(form.is_valid())
 
-
     def test_unusable_password(self):
         user = User.objects.create_user('testuser', 'test@example.com', 'test')
         data = {"email": "test@example.com"}

File django/contrib/auth/tests/views.py

 import urllib
 
 from django.conf import settings
-from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
-from django.contrib.auth.forms import AuthenticationForm
 from django.contrib.sites.models import Site, RequestSite
 from django.contrib.auth.models import User
-from django.core.urlresolvers import NoReverseMatch
+from django.core import mail
+from django.core.urlresolvers import reverse, NoReverseMatch
+from django.http import QueryDict
+from django.utils.encoding import force_unicode
+from django.utils.html import escape
 from django.test import TestCase
-from django.core import mail
-from django.core.urlresolvers import reverse
-from django.http import QueryDict
+
+from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
+from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm,
+                SetPasswordForm, PasswordResetForm)
 
 
 class AuthViewsTestCase(TestCase):
     def login(self, password='password'):
         response = self.client.post('/login/', {
             'username': 'testclient',
-            'password': password
-            }
-        )
+            'password': password,
+            })
         self.assertEqual(response.status_code, 302)
         self.assertTrue(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
         self.assertTrue(SESSION_KEY in self.client.session)
 
+    def assertContainsEscaped(self, response, text, **kwargs):
+        return self.assertContains(response, escape(force_unicode(text)), **kwargs)
+
 
 class AuthViewNamedURLTests(AuthViewsTestCase):
     urls = 'django.contrib.auth.urls'
         response = self.client.get('/password_reset/')
         self.assertEqual(response.status_code, 200)
         response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
-        self.assertContains(response, "That e-mail address doesn't have an associated user account")
+        self.assertContainsEscaped(response, PasswordResetForm.error_messages['unknown'])
         self.assertEqual(len(mail.outbox), 0)
 
     def test_email_found(self):
         url, path = self._test_confirm_start()
         # Let's munge the token in the path, but keep the same length,
         # in case the URLconf will reject a different length.
-        path = path[:-5] + ("0"*4) + path[-1]
+        path = path[:-5] + ("0" * 4) + path[-1]
 
         response = self.client.get(path)
         self.assertEqual(response.status_code, 200)
         # Same as test_confirm_invalid, but trying
         # to do a POST instead.
         url, path = self._test_confirm_start()
-        path = path[:-5] + ("0"*4) + path[-1]
+        path = path[:-5] + ("0" * 4) + path[-1]
 
-        response = self.client.post(path, {'new_password1': 'anewpassword',
-                                           'new_password2':' anewpassword'})
+        self.client.post(path, {
+            'new_password1': 'anewpassword',
+            'new_password2': ' anewpassword',
+        })
         # Check the password has not been changed
         u = User.objects.get(email='staffmember@example.com')
         self.assertTrue(not u.check_password("anewpassword"))
     def test_confirm_different_passwords(self):
         url, path = self._test_confirm_start()
         response = self.client.post(path, {'new_password1': 'anewpassword',
-                                           'new_password2':' x'})
+                                           'new_password2': 'x'})
         self.assertEqual(response.status_code, 200)
-        self.assertTrue("The two password fields didn't match" in response.content)
+        self.assertContainsEscaped(response, SetPasswordForm.error_messages['password_mismatch'])
+
 
 class ChangePasswordTest(AuthViewsTestCase):
 
     def fail_login(self, password='password'):
         response = self.client.post('/login/', {
             'username': 'testclient',
-            'password': password
-            }
-        )
+            'password': password,
+        })
         self.assertEqual(response.status_code, 200)
-        self.assertTrue("Please enter a correct username and password. Note that both fields are case-sensitive." in response.content)
+        self.assertContainsEscaped(response, AuthenticationForm.error_messages['invalid_login'])
 
     def logout(self):
         response = self.client.get('/logout/')
             'old_password': 'donuts',
             'new_password1': 'password1',
             'new_password2': 'password1',
-            }
-        )
+        })
         self.assertEqual(response.status_code, 200)
-        self.assertTrue("Your old password was entered incorrectly. Please enter it again." in response.content)
+        self.assertContainsEscaped(response, PasswordChangeForm.error_messages['password_incorrect'])
 
     def test_password_change_fails_with_mismatched_passwords(self):
         self.login()
             'old_password': 'password',
             'new_password1': 'password1',
             'new_password2': 'donuts',
-            }
-        )
+        })
         self.assertEqual(response.status_code, 200)
-        self.assertTrue("The two password fields didn't match." in response.content)
+        self.assertContainsEscaped(response, SetPasswordForm.error_messages['password_mismatch'])
 
     def test_password_change_succeeds(self):
         self.login()
             'old_password': 'password',
             'new_password1': 'password1',
             'new_password2': 'password1',
-            }
-        )
+        })
         self.assertEqual(response.status_code, 302)
         self.assertTrue(response['Location'].endswith('/password_change/done/'))
         self.fail_login()
             'old_password': 'password',
             'new_password1': 'password1',
             'new_password2': 'password1',
-            }
-        )
+        })
         self.assertEqual(response.status_code, 302)
         self.assertTrue(response['Location'].endswith('/password_change/done/'))
 
             nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
                 'url': login_url,
                 'next': REDIRECT_FIELD_NAME,
-                'bad_url': urllib.quote(bad_url)
+                'bad_url': urllib.quote(bad_url),
             }
             response = self.client.post(nasty_url, {
                 'username': 'testclient',
                 'password': password,
-                }
-            )
+            })
             self.assertEqual(response.status_code, 302)
             self.assertFalse(bad_url in response['Location'],
                              "%s should be blocked" % bad_url)
                          'view/?param=//example.com',
                          'https:///',
                          '//testserver/',
-                         '/url%20with%20spaces/', # see ticket #12534
-                         ):
+                         '/url%20with%20spaces/'):  # see ticket #12534
             safe_url = '%(url)s?%(next)s=%(good_url)s' % {
                 'url': login_url,
                 'next': REDIRECT_FIELD_NAME,
-                'good_url': urllib.quote(good_url)
+                'good_url': urllib.quote(good_url),
             }
             response = self.client.post(safe_url, {
                     'username': 'testclient',
                     'password': password,
-                }
-            )
+            })
             self.assertEqual(response.status_code, 302)
             self.assertTrue(good_url in response['Location'],
                             "%s should be allowed" % good_url)
         login_required_url = self.get_login_required_url(login_url)
         querystring = QueryDict('', mutable=True)
         querystring['next'] = '/login_required/'
-        self.assertEqual(login_required_url,
-             'http://testserver%s?%s' % (login_url, querystring.urlencode('/')))
+        self.assertEqual(login_required_url, 'http://testserver%s?%s' %
+                         (login_url, querystring.urlencode('/')))
 
     def test_remote_login_url(self):
         login_url = 'http://remote.example.com/login'
         for bad_url in ('http://example.com',
                         'https://example.com',
                         'ftp://exampel.com',
-                        '//example.com'
-                        ):
+                        '//example.com'):
             nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
                 'url': logout_url,
                 'next': REDIRECT_FIELD_NAME,
-                'bad_url': urllib.quote(bad_url)
+                'bad_url': urllib.quote(bad_url),
             }
             self.login()
             response = self.client.get(nasty_url)
                          'view/?param=//example.com',
                          'https:///',
                          '//testserver/',
-                         '/url%20with%20spaces/', # see ticket #12534
-                         ):
+                         '/url%20with%20spaces/'):  # see ticket #12534
             safe_url = '%(url)s?%(next)s=%(good_url)s' % {
                 'url': logout_url,
                 'next': REDIRECT_FIELD_NAME,
-                'good_url': urllib.quote(good_url)
+                'good_url': urllib.quote(good_url),
             }
             self.login()
             response = self.client.get(safe_url)