summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2011-10-07 00:41:25 +0000
committerCarl Meyer <carl@oddbird.net>2011-10-07 00:41:25 +0000
commitb1b1da1eac93297503c04b8394fb98e38f552f5f (patch)
tree774b258c552e330f98ee8f437e76b6159c8500b4 /tests
parente2f9c11736db9e23004733760303f605f1cfb924 (diff)
Fixed #8060 - Added permissions-checking for admin inlines. Thanks p.patruno for report and Stephan Jaensch for work on the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16934 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
-rw-r--r--tests/regressiontests/admin_inlines/tests.py183
-rw-r--r--tests/regressiontests/admin_ordering/tests.py22
-rw-r--r--tests/regressiontests/generic_inline_admin/tests.py22
-rw-r--r--tests/regressiontests/modeladmin/tests.py17
4 files changed, 224 insertions, 20 deletions
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
index 955d6208de..7ab5ba6478 100644
--- a/tests/regressiontests/admin_inlines/tests.py
+++ b/tests/regressiontests/admin_inlines/tests.py
@@ -1,11 +1,12 @@
from django.contrib.admin.helpers import InlineAdminForm
+from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
# local test models
from models import (Holder, Inner, Holder2, Inner2, Holder3,
Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child,
- CapoFamiglia, Consigliere, SottoCapo)
+ Author, Book)
from admin import InnerInline
@@ -141,7 +142,6 @@ class TestInline(TestCase):
'<input id="id_-2-0-name" type="text" class="vTextField" '
'name="-2-0-name" maxlength="100" />')
-
class TestInlineMedia(TestCase):
urls = "regressiontests.admin_inlines.urls"
fixtures = ['admin-views-users.xml']
@@ -196,3 +196,182 @@ class TestInlineAdminForm(TestCase):
iaf = InlineAdminForm(None, None, {}, {}, joe)
parent_ct = ContentType.objects.get_for_model(Parent)
self.assertEqual(iaf.original.content_type, parent_ct)
+
+class TestInlinePermissions(TestCase):
+ """
+ Make sure the admin respects permissions for objects that are edited
+ inline. Refs #8060.
+
+ """
+ urls = "regressiontests.admin_inlines.urls"
+
+ def setUp(self):
+ self.user = User(username='admin')
+ self.user.is_staff = True
+ self.user.is_active = True
+ self.user.set_password('secret')
+ self.user.save()
+
+ self.author_ct = ContentType.objects.get_for_model(Author)
+ self.holder_ct = ContentType.objects.get_for_model(Holder2)
+ self.book_ct = ContentType.objects.get_for_model(Book)
+ self.inner_ct = ContentType.objects.get_for_model(Inner2)
+
+ # User always has permissions to add and change Authors, and Holders,
+ # the main (parent) models of the inlines. Permissions on the inlines
+ # vary per test.
+ permission = Permission.objects.get(codename='add_author', content_type=self.author_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='change_author', content_type=self.author_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='add_holder2', content_type=self.holder_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='change_holder2', content_type=self.holder_ct)
+ self.user.user_permissions.add(permission)
+
+ author = Author.objects.create(pk=1, name=u'The Author')
+ author.books.create(name=u'The inline Book')
+ self.author_change_url = '/admin/admin_inlines/author/%i/' % author.id
+
+ holder = Holder2.objects.create(dummy=13)
+ Inner2.objects.create(dummy=42, holder=holder)
+ self.holder_change_url = '/admin/admin_inlines/holder2/%i/' % holder.id
+
+ self.assertEqual(
+ self.client.login(username='admin', password='secret'),
+ True)
+
+ def tearDown(self):
+ self.client.logout()
+
+ def test_inline_add_m2m_noperm(self):
+ response = self.client.get('/admin/admin_inlines/author/add/')
+ # No change permission on books, so no inline
+ self.assertNotContains(response, '<h2>Author-book relationships</h2>')
+ self.assertNotContains(response, 'Add another Author-Book Relationship')
+ self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
+
+ def test_inline_add_fk_noperm(self):
+ response = self.client.get('/admin/admin_inlines/holder2/add/')
+ # No permissions on Inner2s, so no inline
+ self.assertNotContains(response, '<h2>Inner2s</h2>')
+ self.assertNotContains(response, 'Add another Inner2')
+ self.assertNotContains(response, 'id="id_inner2_set-TOTAL_FORMS"')
+
+ def test_inline_change_m2m_noperm(self):
+ response = self.client.get(self.author_change_url)
+ # No change permission on books, so no inline
+ self.assertNotContains(response, '<h2>Author-book relationships</h2>')
+ self.assertNotContains(response, 'Add another Author-Book Relationship')
+ self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
+
+ def test_inline_change_fk_noperm(self):
+ response = self.client.get(self.holder_change_url)
+ # No permissions on Inner2s, so no inline
+ self.assertNotContains(response, '<h2>Inner2s</h2>')
+ self.assertNotContains(response, 'Add another Inner2')
+ self.assertNotContains(response, 'id="id_inner2_set-TOTAL_FORMS"')
+
+ def test_inline_add_m2m_add_perm(self):
+ permission = Permission.objects.get(codename='add_book', content_type=self.book_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get('/admin/admin_inlines/author/add/')
+ # No change permission on Books, so no inline
+ self.assertNotContains(response, '<h2>Author-book relationships</h2>')
+ self.assertNotContains(response, 'Add another Author-Book Relationship')
+ self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
+
+ def test_inline_add_fk_add_perm(self):
+ permission = Permission.objects.get(codename='add_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get('/admin/admin_inlines/holder2/add/')
+ # Add permission on inner2s, so we get the inline
+ self.assertContains(response, '<h2>Inner2s</h2>')
+ self.assertContains(response, 'Add another Inner2')
+ self.assertContains(response, 'value="3" id="id_inner2_set-TOTAL_FORMS"')
+
+ def test_inline_change_m2m_add_perm(self):
+ permission = Permission.objects.get(codename='add_book', content_type=self.book_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.author_change_url)
+ # No change permission on books, so no inline
+ self.assertNotContains(response, '<h2>Author-book relationships</h2>')
+ self.assertNotContains(response, 'Add another Author-Book Relationship')
+ self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
+ self.assertNotContains(response, 'id="id_Author_books-0-DELETE"')
+
+ def test_inline_change_m2m_change_perm(self):
+ permission = Permission.objects.get(codename='change_book', content_type=self.book_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.author_change_url)
+ # We have change perm on books, so we can add/change/delete inlines
+ self.assertContains(response, '<h2>Author-book relationships</h2>')
+ self.assertContains(response, 'Add another Author-Book Relationship')
+ self.assertContains(response, 'value="4" id="id_Author_books-TOTAL_FORMS"')
+ self.assertContains(response, '<input type="hidden" name="Author_books-0-id" value="1"')
+ self.assertContains(response, 'id="id_Author_books-0-DELETE"')
+
+ def test_inline_change_fk_add_perm(self):
+ permission = Permission.objects.get(codename='add_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.holder_change_url)
+ # Add permission on inner2s, so we can add but not modify existing
+ self.assertContains(response, '<h2>Inner2s</h2>')
+ self.assertContains(response, 'Add another Inner2')
+ # 3 extra forms only, not the existing instance form
+ self.assertContains(response, 'value="3" id="id_inner2_set-TOTAL_FORMS"')
+ self.assertNotContains(response, '<input type="hidden" name="inner2_set-0-id" value="1"')
+
+ def test_inline_change_fk_change_perm(self):
+ permission = Permission.objects.get(codename='change_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.holder_change_url)
+ # Change permission on inner2s, so we can change existing but not add new
+ self.assertContains(response, '<h2>Inner2s</h2>')
+ # Just the one form for existing instances
+ self.assertContains(response, 'value="1" id="id_inner2_set-TOTAL_FORMS"')
+ self.assertContains(response, '<input type="hidden" name="inner2_set-0-id" value="1"')
+ # max-num 0 means we can't add new ones
+ self.assertContains(response, 'value="0" id="id_inner2_set-MAX_NUM_FORMS"')
+
+ def test_inline_change_fk_add_change_perm(self):
+ permission = Permission.objects.get(codename='add_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='change_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.holder_change_url)
+ # Add/change perm, so we can add new and change existing
+ self.assertContains(response, '<h2>Inner2s</h2>')
+ # One form for existing instance and three extra for new
+ self.assertContains(response, 'value="4" id="id_inner2_set-TOTAL_FORMS"')
+ self.assertContains(response, '<input type="hidden" name="inner2_set-0-id" value="1"')
+
+
+ def test_inline_change_fk_change_del_perm(self):
+ permission = Permission.objects.get(codename='change_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='delete_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.holder_change_url)
+ # Change/delete perm on inner2s, so we can change/delete existing
+ self.assertContains(response, '<h2>Inner2s</h2>')
+ # One form for existing instance only, no new
+ self.assertContains(response, 'value="1" id="id_inner2_set-TOTAL_FORMS"')
+ self.assertContains(response, '<input type="hidden" name="inner2_set-0-id" value="1"')
+ self.assertContains(response, 'id="id_inner2_set-0-DELETE"')
+
+
+ def test_inline_change_fk_all_perms(self):
+ permission = Permission.objects.get(codename='add_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='change_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ permission = Permission.objects.get(codename='delete_inner2', content_type=self.inner_ct)
+ self.user.user_permissions.add(permission)
+ response = self.client.get(self.holder_change_url)
+ # All perms on inner2s, so we can add/change/delete
+ self.assertContains(response, '<h2>Inner2s</h2>')
+ # One form for existing instance only, three for new
+ self.assertContains(response, 'value="4" id="id_inner2_set-TOTAL_FORMS"')
+ self.assertContains(response, '<input type="hidden" name="inner2_set-0-id" value="1"')
+ self.assertContains(response, 'id="id_inner2_set-0-DELETE"')
diff --git a/tests/regressiontests/admin_ordering/tests.py b/tests/regressiontests/admin_ordering/tests.py
index 70eca5f771..9c14706aa5 100644
--- a/tests/regressiontests/admin_ordering/tests.py
+++ b/tests/regressiontests/admin_ordering/tests.py
@@ -4,6 +4,18 @@ from django.contrib.admin.options import ModelAdmin
from models import Band, Song, SongInlineDefaultOrdering, SongInlineNewOrdering, DynOrderingBandAdmin
+
+class MockRequest(object):
+ pass
+
+class MockSuperUser(object):
+ def has_perm(self, perm):
+ return True
+
+request = MockRequest()
+request.user = MockSuperUser()
+
+
class TestAdminOrdering(TestCase):
"""
Let's make sure that ModelAdmin.queryset uses the ordering we define in
@@ -26,7 +38,7 @@ class TestAdminOrdering(TestCase):
class.
"""
ma = ModelAdmin(Band, None)
- names = [b.name for b in ma.queryset(None)]
+ names = [b.name for b in ma.queryset(request)]
self.assertEqual([u'Aerosmith', u'Radiohead', u'Van Halen'], names)
def test_specified_ordering(self):
@@ -37,7 +49,7 @@ class TestAdminOrdering(TestCase):
class BandAdmin(ModelAdmin):
ordering = ('rank',) # default ordering is ('name',)
ma = BandAdmin(Band, None)
- names = [b.name for b in ma.queryset(None)]
+ names = [b.name for b in ma.queryset(request)]
self.assertEqual([u'Radiohead', u'Van Halen', u'Aerosmith'], names)
def test_dynamic_ordering(self):
@@ -79,7 +91,7 @@ class TestInlineModelAdminOrdering(TestCase):
class.
"""
inline = SongInlineDefaultOrdering(self.b, None)
- names = [s.name for s in inline.queryset(None)]
+ names = [s.name for s in inline.queryset(request)]
self.assertEqual([u'Dude (Looks Like a Lady)', u'Jaded', u'Pink'], names)
def test_specified_ordering(self):
@@ -87,5 +99,5 @@ class TestInlineModelAdminOrdering(TestCase):
Let's check with ordering set to something different than the default.
"""
inline = SongInlineNewOrdering(self.b, None)
- names = [s.name for s in inline.queryset(None)]
- self.assertEqual([u'Jaded', u'Pink', u'Dude (Looks Like a Lady)'], names) \ No newline at end of file
+ names = [s.name for s in inline.queryset(request)]
+ self.assertEqual([u'Jaded', u'Pink', u'Dude (Looks Like a Lady)'], names)
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
index 858d6a5f3b..baea85717b 100644
--- a/tests/regressiontests/generic_inline_admin/tests.py
+++ b/tests/regressiontests/generic_inline_admin/tests.py
@@ -216,6 +216,18 @@ class NoInlineDeletionTest(TestCase):
formset = inline.get_formset(fake_request)
self.assertFalse(formset.can_delete)
+
+class MockRequest(object):
+ pass
+
+class MockSuperUser(object):
+ def has_perm(self, perm):
+ return True
+
+request = MockRequest()
+request.user = MockSuperUser()
+
+
class GenericInlineModelAdminTest(TestCase):
urls = "regressiontests.generic_inline_admin.urls"
@@ -226,12 +238,12 @@ class GenericInlineModelAdminTest(TestCase):
media_inline = MediaInline(Media, AdminSite())
# Create a formset with default arguments
- formset = media_inline.get_formset(None)
+ formset = media_inline.get_formset(request)
self.assertEqual(formset.max_num, None)
self.assertEqual(formset.can_order, False)
# Create a formset with custom keyword arguments
- formset = media_inline.get_formset(None, max_num=100, can_order=True)
+ formset = media_inline.get_formset(request, max_num=100, can_order=True)
self.assertEqual(formset.max_num, 100)
self.assertEqual(formset.can_order, True)
@@ -241,9 +253,6 @@ class GenericInlineModelAdminTest(TestCase):
used in conjunction with `GenericInlineModelAdmin.readonly_fields`
and when no `ModelAdmin.exclude` is defined.
"""
-
- request = None
-
class MediaForm(ModelForm):
class Meta:
@@ -272,9 +281,6 @@ class GenericInlineModelAdminTest(TestCase):
`ModelAdmin.exclude` or `GenericInlineModelAdmin.exclude` are defined.
Refs #15907.
"""
-
- request = None
-
# First with `GenericInlineModelAdmin` -----------------
class MediaForm(ModelForm):
diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py
index 872fb0c3fe..1e8c12e5bc 100644
--- a/tests/regressiontests/modeladmin/tests.py
+++ b/tests/regressiontests/modeladmin/tests.py
@@ -19,9 +19,15 @@ from models import (Band, Concert, ValidationTestModel,
ValidationTestInlineModel)
-# None of the following tests really depend on the content of the request,
-# so we'll just pass in None.
-request = None
+class MockRequest(object):
+ pass
+
+class MockSuperUser(object):
+ def has_perm(self, perm):
+ return True
+
+request = MockRequest()
+request.user = MockSuperUser()
class ModelAdminTests(TestCase):
@@ -357,9 +363,10 @@ class ModelAdminTests(TestCase):
concert = Concert.objects.create(main_band=self.band, opening_band=self.band, day=1)
ma = BandAdmin(Band, self.site)
- fieldsets = list(ma.inline_instances[0].get_fieldsets(request))
+ inline_instances = ma.get_inline_instances(request)
+ fieldsets = list(inline_instances[0].get_fieldsets(request))
self.assertEqual(fieldsets[0][1]['fields'], ['main_band', 'opening_band', 'day', 'transport'])
- fieldsets = list(ma.inline_instances[0].get_fieldsets(request, ma.inline_instances[0].model))
+ fieldsets = list(inline_instances[0].get_fieldsets(request, inline_instances[0].model))
self.assertEqual(fieldsets[0][1]['fields'], ['day'])
# radio_fields behavior ###########################################