diff options
| author | Carl Meyer <carl@oddbird.net> | 2011-10-07 00:41:25 +0000 |
|---|---|---|
| committer | Carl Meyer <carl@oddbird.net> | 2011-10-07 00:41:25 +0000 |
| commit | b1b1da1eac93297503c04b8394fb98e38f552f5f (patch) | |
| tree | 774b258c552e330f98ee8f437e76b6159c8500b4 /tests | |
| parent | e2f9c11736db9e23004733760303f605f1cfb924 (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.py | 183 | ||||
| -rw-r--r-- | tests/regressiontests/admin_ordering/tests.py | 22 | ||||
| -rw-r--r-- | tests/regressiontests/generic_inline_admin/tests.py | 22 | ||||
| -rw-r--r-- | tests/regressiontests/modeladmin/tests.py | 17 |
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 ########################################### |
