diff options
author | Arthur Koziel <arthur@arthurkoziel.com> | 2010-09-13 00:04:27 +0000 |
---|---|---|
committer | Arthur Koziel <arthur@arthurkoziel.com> | 2010-09-13 00:04:27 +0000 |
commit | dd49269c7db008b2567f50cb03c4d3d9b321daa1 (patch) | |
tree | 326dd25bb045ac016cda7966b43cbdfe1f67d699 /django/contrib/auth | |
parent | c9b188c4ec939abbe48dae5a371276742e64b6b8 (diff) | |
download | django-soc2010/app-loading.tar.gz |
[soc2010/app-loading] merged trunkarchive/soc2010/app-loadingsoc2010/app-loading
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/app-loading@13818 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/contrib/auth')
-rw-r--r-- | django/contrib/auth/decorators.py | 3 | ||||
-rw-r--r-- | django/contrib/auth/forms.py | 10 | ||||
-rw-r--r-- | django/contrib/auth/tests/__init__.py | 3 | ||||
-rw-r--r-- | django/contrib/auth/tests/decorators.py | 30 | ||||
-rw-r--r-- | django/contrib/auth/tests/forms.py | 483 | ||||
-rw-r--r-- | django/contrib/auth/tests/urls.py | 5 | ||||
-rw-r--r-- | django/contrib/auth/tests/views.py | 37 | ||||
-rw-r--r-- | django/contrib/auth/views.py | 3 |
8 files changed, 313 insertions, 261 deletions
diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py index 09dcf42e42..7d7a0cddb7 100644 --- a/django/contrib/auth/decorators.py +++ b/django/contrib/auth/decorators.py @@ -30,13 +30,14 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE return decorator -def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME): +def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None): """ Decorator for views that checks that the user is logged in, redirecting to the log-in page if necessary. """ actual_decorator = user_passes_test( lambda u: u.is_authenticated(), + login_url=login_url, redirect_field_name=redirect_field_name ) if function: diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 086acf3349..cc0f7071c3 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -52,6 +52,12 @@ class UserChangeForm(forms.ModelForm): class Meta: model = User + def __init__(self, *args, **kwargs): + super(UserChangeForm, self).__init__(*args, **kwargs) + f = self.fields.get('user_permissions', None) + 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 @@ -111,7 +117,7 @@ class PasswordResetForm(forms.Form): return email def save(self, domain_override=None, email_template_name='registration/password_reset_email.html', - use_https=False, token_generator=default_token_generator): + use_https=False, token_generator=default_token_generator, from_email=None): """ Generates a one-use only link for resetting password and sends to the user """ @@ -134,7 +140,7 @@ class PasswordResetForm(forms.Form): 'protocol': use_https and 'https' or 'http', } send_mail(_("Password reset on %s") % site_name, - t.render(Context(c)), None, [user.email]) + t.render(Context(c)), from_email, [user.email]) class SetPasswordForm(forms.Form): """ diff --git a/django/contrib/auth/tests/__init__.py b/django/contrib/auth/tests/__init__.py index 965ea2d6be..a1d02b6014 100644 --- a/django/contrib/auth/tests/__init__.py +++ b/django/contrib/auth/tests/__init__.py @@ -1,7 +1,7 @@ from django.contrib.auth.tests.auth_backends import BackendTest, RowlevelBackendTest, AnonymousUserBackendTest, NoAnonymousUserBackendTest from django.contrib.auth.tests.basic import BASIC_TESTS from django.contrib.auth.tests.decorators import LoginRequiredTestCase -from django.contrib.auth.tests.forms import FORM_TESTS +from django.contrib.auth.tests.forms import UserCreationFormTest, AuthenticationFormTest, SetPasswordFormTest, PasswordChangeFormTest, UserChangeFormTest, PasswordResetFormTest from django.contrib.auth.tests.remote_user \ import RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest from django.contrib.auth.tests.models import ProfileTestCase @@ -13,6 +13,5 @@ from django.contrib.auth.tests.views \ __test__ = { 'BASIC_TESTS': BASIC_TESTS, - 'FORM_TESTS': FORM_TESTS, 'TOKEN_GENERATOR_TESTS': TOKEN_GENERATOR_TESTS, } diff --git a/django/contrib/auth/tests/decorators.py b/django/contrib/auth/tests/decorators.py index 7efd9d8ccf..0240a76eb7 100644 --- a/django/contrib/auth/tests/decorators.py +++ b/django/contrib/auth/tests/decorators.py @@ -1,12 +1,12 @@ -from unittest import TestCase - from django.contrib.auth.decorators import login_required +from django.contrib.auth.tests.views import AuthViewsTestCase - -class LoginRequiredTestCase(TestCase): +class LoginRequiredTestCase(AuthViewsTestCase): """ Tests the login_required decorators """ + urls = 'django.contrib.auth.tests.urls' + def testCallable(self): """ Check that login_required is assignable to callable objects. @@ -22,4 +22,24 @@ class LoginRequiredTestCase(TestCase): """ def normal_view(request): pass - login_required(normal_view)
\ No newline at end of file + login_required(normal_view) + + def testLoginRequired(self, view_url='/login_required/', login_url='/login/'): + """ + Check that login_required works on a simple view wrapped in a + login_required decorator. + """ + response = self.client.get(view_url) + self.assertEqual(response.status_code, 302) + self.assert_(login_url in response['Location']) + self.login() + response = self.client.get(view_url) + self.assertEqual(response.status_code, 200) + + def testLoginRequiredNextUrl(self): + """ + Check that login_required works on a simple view wrapped in a + login_required decorator with a login_url set. + """ + self.testLoginRequired(view_url='/login_required_login_url/', + login_url='/somewhere/')
\ No newline at end of file diff --git a/django/contrib/auth/tests/forms.py b/django/contrib/auth/tests/forms.py index b691c560be..5aa49e09c3 100644 --- a/django/contrib/auth/tests/forms.py +++ b/django/contrib/auth/tests/forms.py @@ -1,231 +1,252 @@ - -FORM_TESTS = """ ->>> from django.contrib.auth.models import User ->>> from django.contrib.auth.forms import UserCreationForm, AuthenticationForm ->>> from django.contrib.auth.forms import PasswordChangeForm, SetPasswordForm - -# The user already exists. - ->>> user = User.objects.create_user("jsmith", "jsmith@example.com", "test123") ->>> data = { -... 'username': 'jsmith', -... 'password1': 'test123', -... 'password2': 'test123', -... } ->>> form = UserCreationForm(data) ->>> form.is_valid() -False ->>> form["username"].errors -[u'A user with that username already exists.'] - -# The username contains invalid data. - ->>> data = { -... 'username': 'jsmith!', -... 'password1': 'test123', -... 'password2': 'test123', -... } ->>> form = UserCreationForm(data) ->>> form.is_valid() -False ->>> form["username"].errors -[u'This value may contain only letters, numbers and @/./+/-/_ characters.'] - -# The verification password is incorrect. - ->>> data = { -... 'username': 'jsmith2', -... 'password1': 'test123', -... 'password2': 'test', -... } ->>> form = UserCreationForm(data) ->>> form.is_valid() -False ->>> form["password2"].errors -[u"The two password fields didn't match."] - -# One (or both) passwords weren't given - ->>> data = {'username': 'jsmith2'} ->>> form = UserCreationForm(data) ->>> form.is_valid() -False ->>> form['password1'].errors -[u'This field is required.'] ->>> form['password2'].errors -[u'This field is required.'] - ->>> data['password2'] = 'test123' ->>> form = UserCreationForm(data) ->>> form.is_valid() -False ->>> form['password1'].errors -[u'This field is required.'] - -# The success case. - ->>> data = { -... 'username': 'jsmith2@example.com', -... 'password1': 'test123', -... 'password2': 'test123', -... } ->>> form = UserCreationForm(data) ->>> form.is_valid() -True ->>> form.save() -<User: jsmith2@example.com> - -# The user submits an invalid username. - ->>> data = { -... 'username': 'jsmith_does_not_exist', -... 'password': 'test123', -... } - ->>> form = AuthenticationForm(None, data) ->>> form.is_valid() -False ->>> form.non_field_errors() -[u'Please enter a correct username and password. Note that both fields are case-sensitive.'] - -# The user is inactive. - ->>> data = { -... 'username': 'jsmith', -... 'password': 'test123', -... } ->>> user.is_active = False ->>> user.save() ->>> form = AuthenticationForm(None, data) ->>> form.is_valid() -False ->>> form.non_field_errors() -[u'This account is inactive.'] - ->>> user.is_active = True ->>> user.save() - -# The success case - ->>> form = AuthenticationForm(None, data) ->>> form.is_valid() -True ->>> form.non_field_errors() -[] - -### SetPasswordForm: - -# The two new passwords do not match. - ->>> data = { -... 'new_password1': 'abc123', -... 'new_password2': 'abc', -... } ->>> form = SetPasswordForm(user, data) ->>> form.is_valid() -False ->>> form["new_password2"].errors -[u"The two password fields didn't match."] - -# The success case. - ->>> data = { -... 'new_password1': 'abc123', -... 'new_password2': 'abc123', -... } ->>> form = SetPasswordForm(user, data) ->>> form.is_valid() -True - -### PasswordChangeForm: - -The old password is incorrect. - ->>> data = { -... 'old_password': 'test', -... 'new_password1': 'abc123', -... 'new_password2': 'abc123', -... } ->>> form = PasswordChangeForm(user, data) ->>> form.is_valid() -False ->>> form["old_password"].errors -[u'Your old password was entered incorrectly. Please enter it again.'] - -# The two new passwords do not match. - ->>> data = { -... 'old_password': 'test123', -... 'new_password1': 'abc123', -... 'new_password2': 'abc', -... } ->>> form = PasswordChangeForm(user, data) ->>> form.is_valid() -False ->>> form["new_password2"].errors -[u"The two password fields didn't match."] - -# The success case. - ->>> data = { -... 'old_password': 'test123', -... 'new_password1': 'abc123', -... 'new_password2': 'abc123', -... } ->>> form = PasswordChangeForm(user, data) ->>> form.is_valid() -True - -# Regression test - check the order of fields: - ->>> PasswordChangeForm(user, {}).fields.keys() -['old_password', 'new_password1', 'new_password2'] - -### UserChangeForm - ->>> from django.contrib.auth.forms import UserChangeForm ->>> data = {'username': 'not valid'} ->>> form = UserChangeForm(data, instance=user) ->>> form.is_valid() -False ->>> form['username'].errors -[u'This value may contain only letters, numbers and @/./+/-/_ characters.'] - - -### PasswordResetForm - ->>> from django.contrib.auth.forms import PasswordResetForm ->>> data = {'email':'not valid'} ->>> form = PasswordResetForm(data) ->>> form.is_valid() -False ->>> form['email'].errors -[u'Enter a valid e-mail address.'] - -# Test nonexistant email address ->>> data = {'email':'foo@bar.com'} ->>> form = PasswordResetForm(data) ->>> form.is_valid() -False ->>> form.errors -{'email': [u"That e-mail address doesn't have an associated user account. Are you sure you've registered?"]} - -# Test cleaned_data bug fix ->>> user = User.objects.create_user("jsmith3", "jsmith3@example.com", "test123") ->>> data = {'email':'jsmith3@example.com'} ->>> form = PasswordResetForm(data) ->>> form.is_valid() -True ->>> form.cleaned_data['email'] -u'jsmith3@example.com' - -# bug #5605, preserve the case of the user name (before the @ in the email address) -# when creating a user. ->>> user = User.objects.create_user('forms_test2', 'tesT@EXAMple.com', 'test') ->>> user.email -'tesT@example.com' ->>> user = User.objects.create_user('forms_test3', 'tesT', 'test') ->>> user.email -'tesT' - -""" +from django.contrib.auth.models import User +from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm +from django.test import TestCase + + +class UserCreationFormTest(TestCase): + + fixtures = ['authtestdata.json'] + + def test_user_already_exists(self): + data = { + 'username': 'testclient', + 'password1': 'test123', + 'password2': 'test123', + } + form = UserCreationForm(data) + self.assertFalse(form.is_valid()) + self.assertEqual(form["username"].errors, + [u'A user with that username already exists.']) + + def test_invalid_data(self): + data = { + 'username': 'jsmith!', + 'password1': 'test123', + 'password2': 'test123', + } + form = UserCreationForm(data) + self.assertFalse(form.is_valid()) + self.assertEqual(form["username"].errors, + [u'This value may contain only letters, numbers and @/./+/-/_ characters.']) + + + def test_password_verification(self): + # The verification password is incorrect. + data = { + 'username': 'jsmith', + 'password1': 'test123', + 'password2': 'test', + } + form = UserCreationForm(data) + self.assertFalse(form.is_valid()) + self.assertEqual(form["password2"].errors, + [u"The two password fields didn't match."]) + + + def test_both_passwords(self): + # One (or both) passwords weren't given + data = {'username': 'jsmith'} + form = UserCreationForm(data) + 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.']) + + + data['password2'] = 'test123' + form = UserCreationForm(data) + self.assertFalse(form.is_valid()) + self.assertEqual(form['password1'].errors, + [u'This field is required.']) + + def test_success(self): + # The success case. + + data = { + 'username': 'jsmith@example.com', + 'password1': 'test123', + 'password2': 'test123', + } + form = UserCreationForm(data) + self.assertTrue(form.is_valid()) + u = form.save() + self.assertEqual(repr(u), '<User: jsmith@example.com>') + + +class AuthenticationFormTest(TestCase): + + fixtures = ['authtestdata.json'] + + def test_invalid_username(self): + # The user submits an invalid username. + + data = { + 'username': 'jsmith_does_not_exist', + 'password': 'test123', + } + 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.']) + + def test_inactive_user(self): + # The user is inactive. + data = { + 'username': 'inactive', + 'password': 'password', + } + form = AuthenticationForm(None, data) + self.assertFalse(form.is_valid()) + self.assertEqual(form.non_field_errors(), + [u'This account is inactive.']) + + + def test_success(self): + # The success case + data = { + 'username': 'testclient', + 'password': 'password', + } + form = AuthenticationForm(None, data) + self.assertTrue(form.is_valid()) + self.assertEqual(form.non_field_errors(), []) + + +class SetPasswordFormTest(TestCase): + + fixtures = ['authtestdata.json'] + + def test_password_verification(self): + # The two new passwords do not match. + user = User.objects.get(username='testclient') + data = { + 'new_password1': 'abc123', + 'new_password2': 'abc', + } + form = SetPasswordForm(user, data) + self.assertFalse(form.is_valid()) + self.assertEqual(form["new_password2"].errors, + [u"The two password fields didn't match."]) + + def test_success(self): + user = User.objects.get(username='testclient') + data = { + 'new_password1': 'abc123', + 'new_password2': 'abc123', + } + form = SetPasswordForm(user, data) + self.assertTrue(form.is_valid()) + + +class PasswordChangeFormTest(TestCase): + + fixtures = ['authtestdata.json'] + + def test_incorrect_password(self): + user = User.objects.get(username='testclient') + data = { + 'old_password': 'test', + 'new_password1': 'abc123', + 'new_password2': 'abc123', + } + 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.']) + + + def test_password_verification(self): + # The two new passwords do not match. + user = User.objects.get(username='testclient') + data = { + 'old_password': 'password', + 'new_password1': 'abc123', + 'new_password2': 'abc', + } + form = PasswordChangeForm(user, data) + self.assertFalse(form.is_valid()) + self.assertEqual(form["new_password2"].errors, + [u"The two password fields didn't match."]) + + + def test_success(self): + # The success case. + user = User.objects.get(username='testclient') + data = { + 'old_password': 'password', + 'new_password1': 'abc123', + 'new_password2': 'abc123', + } + form = PasswordChangeForm(user, data) + self.assertTrue(form.is_valid()) + + def test_field_order(self): + # Regression test - check the order of fields: + user = User.objects.get(username='testclient') + self.assertEqual(PasswordChangeForm(user, {}).fields.keys(), + ['old_password', 'new_password1', 'new_password2']) + +class UserChangeFormTest(TestCase): + + fixtures = ['authtestdata.json'] + + def test_username_validity(self): + user = User.objects.get(username='testclient') + data = {'username': 'not valid'} + 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.']) + + def test_bug_14242(self): + # A regression test, introduce by adding an optimization for the + # UserChangeForm. + + class MyUserForm(UserChangeForm): + def __init__(self, *args, **kwargs): + super(MyUserForm, self).__init__(*args, **kwargs) + self.fields['groups'].help_text = 'These groups give users different permissions' + + class Meta(UserChangeForm.Meta): + fields = ('groups',) + + # Just check we can create it + form = MyUserForm({}) + + +class PasswordResetFormTest(TestCase): + + fixtures = ['authtestdata.json'] + + def test_invalid_email(self): + data = {'email':'not valid'} + form = PasswordResetForm(data) + self.assertFalse(form.is_valid()) + self.assertEqual(form['email'].errors, + [u'Enter a valid e-mail address.']) + + def test_nonexistant_email(self): + # Test nonexistant email address + 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?"]}) + + def test_cleaned_data(self): + # Regression test + user = User.objects.create_user("jsmith3", "jsmith3@example.com", "test123") + data = {'email':'jsmith3@example.com'} + form = PasswordResetForm(data) + self.assertTrue(form.is_valid()) + self.assertEqual(form.cleaned_data['email'], u'jsmith3@example.com') + + + def test_bug_5605(self): + # bug #5605, preserve the case of the user name (before the @ in the + # email address) when creating a user. + user = User.objects.create_user('forms_test2', 'tesT@EXAMple.com', 'test') + self.assertEqual(user.email, 'tesT@example.com') + user = User.objects.create_user('forms_test3', 'tesT', 'test') + self.assertEqual(user.email, 'tesT') diff --git a/django/contrib/auth/tests/urls.py b/django/contrib/auth/tests/urls.py index f94b8daa7f..bc2f7e705f 100644 --- a/django/contrib/auth/tests/urls.py +++ b/django/contrib/auth/tests/urls.py @@ -1,5 +1,7 @@ from django.conf.urls.defaults import patterns from django.contrib.auth.urls import urlpatterns +from django.contrib.auth.views import password_reset +from django.contrib.auth.decorators import login_required from django.http import HttpResponse from django.template import Template, RequestContext @@ -14,5 +16,8 @@ urlpatterns += patterns('', (r'^logout/custom_query/$', 'django.contrib.auth.views.logout', dict(redirect_field_name='follow')), (r'^logout/next_page/$', 'django.contrib.auth.views.logout', dict(next_page='/somewhere/')), (r'^remote_user/$', remote_user_auth_view), + (r'^password_reset_from_email/$', 'django.contrib.auth.views.password_reset', dict(from_email='staffmember@example.com')), + (r'^login_required/$', login_required(password_reset)), + (r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')), ) diff --git a/django/contrib/auth/tests/views.py b/django/contrib/auth/tests/views.py index d894e6dafd..e20afbc5b0 100644 --- a/django/contrib/auth/tests/views.py +++ b/django/contrib/auth/tests/views.py @@ -36,6 +36,16 @@ class AuthViewsTestCase(TestCase): settings.LANGUAGE_CODE = self.old_LANGUAGE_CODE settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS + def login(self, password='password'): + response = self.client.post('/login/', { + 'username': 'testclient', + 'password': password + } + ) + self.assertEquals(response.status_code, 302) + self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) + self.assert_(SESSION_KEY in self.client.session) + class PasswordResetTest(AuthViewsTestCase): def test_email_not_found(self): @@ -52,6 +62,14 @@ class PasswordResetTest(AuthViewsTestCase): self.assertEquals(response.status_code, 302) self.assertEquals(len(mail.outbox), 1) self.assert_("http://" in mail.outbox[0].body) + self.assertEquals(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email) + + def test_email_found_custom_from(self): + "Email is sent if a valid email address is provided for password reset when a custom from_email is provided." + response = self.client.post('/password_reset_from_email/', {'email': 'staffmember@example.com'}) + self.assertEquals(response.status_code, 302) + self.assertEquals(len(mail.outbox), 1) + self.assertEquals("staffmember@example.com", mail.outbox[0].from_email) def _test_confirm_start(self): # Start by creating the email @@ -118,15 +136,6 @@ class PasswordResetTest(AuthViewsTestCase): class ChangePasswordTest(AuthViewsTestCase): - def login(self, password='password'): - response = self.client.post('/login/', { - 'username': 'testclient', - 'password': password - } - ) - self.assertEquals(response.status_code, 302) - self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) - def fail_login(self, password='password'): response = self.client.post('/login/', { 'username': 'testclient', @@ -228,16 +237,6 @@ class LoginTest(AuthViewsTestCase): class LogoutTest(AuthViewsTestCase): urls = 'django.contrib.auth.tests.urls' - def login(self, password='password'): - response = self.client.post('/login/', { - 'username': 'testclient', - 'password': password - } - ) - self.assertEquals(response.status_code, 302) - self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) - self.assert_(SESSION_KEY in self.client.session) - def confirm_logged_out(self): self.assert_(SESSION_KEY not in self.client.session) diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index b2e875a869..eaa0dbeba2 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -105,7 +105,7 @@ def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_N def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html', email_template_name='registration/password_reset_email.html', password_reset_form=PasswordResetForm, token_generator=default_token_generator, - post_reset_redirect=None): + post_reset_redirect=None, from_email=None): if post_reset_redirect is None: post_reset_redirect = reverse('django.contrib.auth.views.password_reset_done') if request.method == "POST": @@ -114,6 +114,7 @@ def password_reset(request, is_admin_site=False, template_name='registration/pas opts = {} opts['use_https'] = request.is_secure() opts['token_generator'] = token_generator + opts['from_email'] = from_email if is_admin_site: opts['domain_override'] = request.META['HTTP_HOST'] else: |