diff --git a/tests/regressiontests/admin_views/__init__.py b/tests/regressiontests/admin_views/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/regressiontests/admin_views/fixtures/admin-views-users.xml b/tests/regressiontests/admin_views/fixtures/admin-views-users.xml new file mode 100644 index 0000000000..89da93dbd7 --- /dev/null +++ b/tests/regressiontests/admin_views/fixtures/admin-views-users.xml @@ -0,0 +1,77 @@ + + + + super + Super + User + super@example.com + sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 + True + True + True + 2007-05-30 13:20:10 + 2007-05-30 13:20:10 + + + + + adduser + Add + User + auser@example.com + sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 + True + True + False + 2007-05-30 13:20:10 + 2007-05-30 13:20:10 + + + + + changeuser + Change + User + cuser@example.com + sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 + True + True + False + 2007-05-30 13:20:10 + 2007-05-30 13:20:10 + + + + + deleteuser + Delete + User + duser@example.com + sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 + True + True + False + 2007-05-30 13:20:10 + 2007-05-30 13:20:10 + + + + + joepublic + Joe + Public + joepublic@example.com + sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 + False + True + False + 2007-05-30 13:20:10 + 2007-05-30 13:20:10 + + + + + <p>test content</p> + 2008-03-18 11:54:58 + + \ No newline at end of file diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py new file mode 100644 index 0000000000..8df0a34f2d --- /dev/null +++ b/tests/regressiontests/admin_views/models.py @@ -0,0 +1,17 @@ +from django.db import models +from django.contrib import admin + + +class Article(models.Model): + """ + A simple article to test admin views. Test backwards compabilty. + """ + content = models.TextField() + date = models.DateTimeField() + + +class ArticleAdmin(admin.ModelAdmin): + list_display = ('content', 'date') + list_filter = ('date',) + +admin.site.register(Article, ArticleAdmin) \ No newline at end of file diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py new file mode 100644 index 0000000000..f3c2b1f2fc --- /dev/null +++ b/tests/regressiontests/admin_views/tests.py @@ -0,0 +1,202 @@ + +from django.test import TestCase +from django.contrib.auth.models import User, Permission +from django.contrib.contenttypes.models import ContentType +from django.contrib.admin.sites import LOGIN_FORM_KEY, _encode_post_data + +# local test models +from models import Article + +def get_perm(Model, perm): + """Return the permission object, for the Model""" + ct = ContentType.objects.get_for_model(Model) + return Permission.objects.get(content_type=ct,codename=perm) + + +class AdminViewPermissionsTest(TestCase): + """Tests for Admin Views Permissions.""" + + fixtures = ['admin-views-users.xml'] + + def setUp(self): + """Test setup.""" + # Setup permissions, for our users who can add, change, and delete. + # We can't put this into the fixture, because the content type id + # and the permission id could be different on each run of the test. + + opts = Article._meta + + # User who can add Articles + add_user = User.objects.get(username='adduser') + add_user.user_permissions.add(get_perm(Article, + opts.get_add_permission())) + + # User who can change Articles + change_user = User.objects.get(username='changeuser') + change_user.user_permissions.add(get_perm(Article, + opts.get_change_permission())) + + # User who can delete Articles + delete_user = User.objects.get(username='deleteuser') + delete_user.user_permissions.add(get_perm(Article, + opts.get_delete_permission())) + + # login POST dicts + self.super_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'super', + 'password': 'secret'} + self.adduser_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'adduser', + 'password': 'secret'} + self.changeuser_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'changeuser', + 'password': 'secret'} + self.deleteuser_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'deleteuser', + 'password': 'secret'} + self.joepublic_login = {'post_data': _encode_post_data({}), + LOGIN_FORM_KEY: 1, + 'username': 'joepublic', + 'password': 'secret'} + + + def testLogin(self): + """ + Make sure only staff members can log in. + + Successful posts to the login page will redirect to the orignal url. + Unsuccessfull attempts will continue to render the login page with + a 200 status code. + """ + # Super User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.super_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Add User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.adduser_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Change User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.changeuser_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Delete User + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.deleteuser_login) + self.assertRedirects(login, '/test_admin/admin/') + self.assertFalse(login.context) + self.client.get('/test_admin/admin/logout/') + + # Regular User should not be able to login. + request = self.client.get('/test_admin/admin/') + self.failUnlessEqual(request.status_code, 200) + login = self.client.post('/test_admin/admin/', self.joepublic_login) + self.failUnlessEqual(login.status_code, 200) + # Login.context is a list of context dicts we just need to check the first one. + self.assert_(login.context[0].get('error_message')) + + def testAddView(self): + """Test add view restricts access and actually adds items.""" + + add_dict = {'content': '

great article

', + 'date_0': '2008-03-18', 'date_1': '10:54:39'} + + # Change User should not have access to add articles + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.changeuser_login) + request = self.client.get('/test_admin/admin/admin_views/article/add/') + self.failUnlessEqual(request.status_code, 403) + # Try POST just to make sure + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.failUnlessEqual(post.status_code, 403) + self.failUnlessEqual(Article.objects.all().count(), 1) + self.client.get('/test_admin/admin/logout/') + + # Add user may login and POST to add view, then redirect to admin root + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.adduser_login) + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.assertRedirects(post, '/test_admin/admin/') + self.failUnlessEqual(Article.objects.all().count(), 2) + self.client.get('/test_admin/admin/logout/') + + # Super can add too, but is redirected to the change list view + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.super_login) + post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) + self.assertRedirects(post, '/test_admin/admin/admin_views/article/') + self.failUnlessEqual(Article.objects.all().count(), 3) + self.client.get('/test_admin/admin/logout/') + + def testChangeView(self): + """Change view should restrict access and allow users to edit items.""" + + change_dict = {'content': '

edited article

', + 'date_0': '2008-03-18', 'date_1': '10:54:39'} + + # add user shoud not be able to view the list of article or change any of them + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.adduser_login) + request = self.client.get('/test_admin/admin/admin_views/article/') + self.failUnlessEqual(request.status_code, 403) + request = self.client.get('/test_admin/admin/admin_views/article/1/') + self.failUnlessEqual(request.status_code, 403) + post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict) + self.failUnlessEqual(post.status_code, 403) + self.client.get('/test_admin/admin/logout/') + + # change user can view all items and edit them + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.changeuser_login) + request = self.client.get('/test_admin/admin/admin_views/article/') + self.failUnlessEqual(request.status_code, 200) + request = self.client.get('/test_admin/admin/admin_views/article/1/') + self.failUnlessEqual(request.status_code, 200) + post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict) + self.assertRedirects(post, '/test_admin/admin/admin_views/article/') + self.failUnlessEqual(Article.objects.get(pk=1).content, '

edited article

') + self.client.get('/test_admin/admin/logout/') + + def testDeleteView(self): + """Delete view should restrict access and actually delete items.""" + + delete_dict = {'post': 'yes'} + + # add user shoud not be able to delete articles + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.adduser_login) + request = self.client.get('/test_admin/admin/admin_views/article/1/delete/') + self.failUnlessEqual(request.status_code, 403) + post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict) + self.failUnlessEqual(post.status_code, 403) + self.failUnlessEqual(Article.objects.all().count(), 1) + self.client.get('/test_admin/admin/logout/') + + # Delete user can delete + self.client.get('/test_admin/admin/') + self.client.post('/test_admin/admin/', self.deleteuser_login) + request = self.client.get('/test_admin/admin/admin_views/article/1/delete/') + self.failUnlessEqual(request.status_code, 200) + post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict) + # TODO: http://code.djangoproject.com/ticket/6819 or the next line fails + self.assertRedirects(post, '/test_admin/admin/') + self.failUnlessEqual(Article.objects.all().count(), 0) + self.client.get('/test_admin/admin/logout/') + \ No newline at end of file diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py new file mode 100644 index 0000000000..13ccf1325b --- /dev/null +++ b/tests/regressiontests/admin_views/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls.defaults import * +from django.contrib import admin + +urlpatterns = patterns('', + (r'^admin/doc/', include('django.contrib.admindocs.urls')), + (r'^admin/(.*)', admin.site.root), +) \ No newline at end of file diff --git a/tests/urls.py b/tests/urls.py index dbdf9a8064..8ca7492fb7 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -17,6 +17,9 @@ urlpatterns = patterns('', # test urlconf for middleware tests (r'^middleware/', include('regressiontests.middleware.urls')), + + # admin view tests + (r'^test_admin/', include('regressiontests.admin_views.urls')), (r'^utils/', include('regressiontests.utils.urls')),