Ticket #8060: diff_v2_v3.diff

File diff_v2_v3.diff, 19.0 KB (added by Stephan Jaensch, 13 years ago)
  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index 96f5ede..ba806c4 100644
    a b class InlineModelAdmin(BaseModelAdmin):  
    14181418    def queryset(self, request):
    14191419        queryset = super(InlineModelAdmin, self).queryset(request)
    14201420        if request and not self.has_change_permission(request):
    1421             queryset = queryset.filter(pk__isnull=True)
     1421            queryset = queryset.none()
    14221422        return queryset
    14231423
    14241424    def get_permission_opts(self):
    class InlineModelAdmin(BaseModelAdmin):  
    14331433        return opts
    14341434
    14351435    def has_add_permission(self, request):
     1436        if self.opts.auto_created:
     1437            # We're checking the rights to an auto-created intermediate model. As per
     1438            # the discussion on ticket #8060, the user needs to have the change permission
     1439            # for the related model in order to be able to do anything with the
     1440            # intermediate model.
     1441            return self.has_change_permission(request)
    14361442        opts = self.get_permission_opts()
    14371443        return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
    14381444
    class InlineModelAdmin(BaseModelAdmin):  
    14411447        return request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
    14421448
    14431449    def has_delete_permission(self, request, obj=None):
     1450        if self.opts.auto_created:
     1451            # We're checking the rights to an auto-created intermediate model. As per
     1452            # the discussion on ticket #8060, the user needs to have the change permission
     1453            # for the related model in order to be able to do anything with the
     1454            # intermediate model.
     1455            return self.has_change_permission(request, obj)
    14441456        opts = self.get_permission_opts()
    14451457        return request.user.has_perm(opts.app_label + '.' + opts.get_delete_permission())
    14461458
  • tests/regressiontests/admin_inlines/tests.py

    diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
    index 7a12724..ebfe787 100644
    a b from django.test import TestCase  
    66# local test models
    77from models import (Holder, Inner, Holder2, Inner2, Holder3,
    88    Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child,
    9     Author, Book)
     9    Author, Book, TitleCollection, Title)
    1010from admin import InnerInline
    1111
    1212
    class TestInline(TestCase):  
    142142                '<input id="id_-2-0-name" type="text" class="vTextField" '
    143143                'name="-2-0-name" maxlength="100" />')
    144144
    145     def test_inline_permissions(self):
    146         """
    147         Make sure the admin respects permissions for objects that are edited
    148         inline. Ref #8060.
    149         """
    150         user = User.objects.get(username='super')
    151         user.is_superuser = False
    152         user.save()
    153 
    154         author_ct = ContentType.objects.get_for_model(Author)
    155         holder_ct = ContentType.objects.get_for_model(Holder)
    156         book_ct = ContentType.objects.get_for_model(Book)
    157         inner_ct = ContentType.objects.get_for_model(Inner)
    158 
    159         permission = Permission.objects.get(codename='add_author', content_type=author_ct)
    160         user.user_permissions.add(permission)
    161         permission = Permission.objects.get(codename='change_author', content_type=author_ct)
    162         user.user_permissions.add(permission)
    163         permission = Permission.objects.get(codename='add_holder', content_type=holder_ct)
    164         user.user_permissions.add(permission)
    165         permission = Permission.objects.get(codename='change_holder', content_type=holder_ct)
    166         user.user_permissions.add(permission)
    167 
    168         author = Author.objects.create(pk=1, name=u'The Author')
    169         author.books.create(name=u'The inline Book')
    170 
    171         # Make sure both ForeignKey as well as ManyToMany inlines are properly removed
    172         response = self.client.get('/admin/admin_inlines/author/add/')
    173         # This would be a TabularInline
    174         self.assertNotContains(response, '<h2>Author-book relationships</h2>')
    175         self.assertNotContains(response, 'Add another Author-Book Relationship')
    176         self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
    177         response = self.client.get('/admin/admin_inlines/author/1/')
    178         self.assertNotContains(response, '<h2>Author-book relationships</h2>')
    179         self.assertNotContains(response, 'Add another Author-Book Relationship')
    180         self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
    181 
    182         response = self.client.get('/admin/admin_inlines/holder/add/')
    183         # This would be a StackedInline
    184         self.assertNotContains(response, '<h2>Inners</h2>')
    185         self.assertNotContains(response, 'Add another Inner')
    186         self.assertNotContains(response, 'id="id_inner_set-TOTAL_FORMS"')
    187         response = self.client.get(self.change_url)
    188         self.assertNotContains(response, '<h2>Inners</h2>')
    189         self.assertNotContains(response, 'Add another Inner')
    190         self.assertNotContains(response, 'id="id_inner_set-TOTAL_FORMS"')
    191 
    192         # Now let's add the missing add permissions and make sure the inlines are shown
    193         permission = Permission.objects.get(codename='add_book', content_type=book_ct)
    194         user.user_permissions.add(permission)
    195         permission = Permission.objects.get(codename='add_inner', content_type=inner_ct)
    196         user.user_permissions.add(permission)
    197 
    198         response = self.client.get('/admin/admin_inlines/author/add/')
    199         self.assertContains(response, '<h2>Author-book relationships</h2>')
    200         self.assertContains(response, 'Add another Author-Book Relationship')
    201         self.assertContains(response, 'value="3" id="id_Author_books-TOTAL_FORMS"')
    202         response = self.client.get('/admin/admin_inlines/holder/add/')
    203         self.assertContains(response, '<h2>Inners</h2>')
    204         self.assertContains(response, 'Add another Inner')
    205         self.assertContains(response, 'value="3" id="id_inner_set-TOTAL_FORMS"')
    206 
    207         # The inlines should be in the change view as well, but existing data
    208         # should not be shown
    209         response = self.client.get('/admin/admin_inlines/author/1/')
    210         self.assertContains(response, '<h2>Author-book relationships</h2>')
    211         self.assertContains(response, 'Add another Author-Book Relationship')
    212         self.assertContains(response, 'value="3" id="id_Author_books-TOTAL_FORMS"')
    213         self.assertNotContains(response, '<input type="hidden" name="Author_books-0-id" value="1"')
    214         response = self.client.get(self.change_url)
    215         self.assertContains(response, '<h2>Inners</h2>')
    216         self.assertContains(response, 'Add another Inner')
    217         self.assertContains(response, 'value="3" id="id_inner_set-TOTAL_FORMS"')
    218         self.assertNotContains(response, '<input type="hidden" name="inner_set-0-id" value="1"')
    219 
    220         # Add the change permissions and check that existing data is shown.
    221         permission = Permission.objects.get(codename='change_book', content_type=book_ct)
    222         user.user_permissions.add(permission)
    223         permission = Permission.objects.get(codename='change_inner', content_type=inner_ct)
    224         user.user_permissions.add(permission)
    225         response = self.client.get('/admin/admin_inlines/author/1/')
    226         self.assertContains(response, '<input type="hidden" name="Author_books-0-id" value="1"')
    227         # Deletion should not be possible.
    228         self.assertNotContains(response, 'id="id_Author_books-0-DELETE"')
    229         response = self.client.get(self.change_url)
    230         self.assertContains(response, '<input type="hidden" name="inner_set-0-id" value="1"')
    231 
    232         # Remove the add permissions. inlines should still be there, but
    233         # no possibility to add data
    234         permission = Permission.objects.get(codename='add_book', content_type=book_ct)
    235         user.user_permissions.remove(permission)
    236         permission = Permission.objects.get(codename='add_inner', content_type=inner_ct)
    237         user.user_permissions.remove(permission)
    238         response = self.client.get('/admin/admin_inlines/author/1/')
    239         self.assertContains(response, '<h2>Author-book relationships</h2>')
    240         self.assertContains(response, '<input type="hidden" name="Author_books-0-id" value="1"')
    241         self.assertContains(response, 'value="1" id="id_Author_books-TOTAL_FORMS"')
    242         response = self.client.get(self.change_url)
    243         self.assertContains(response, '<h2>Inners</h2>')
    244         self.assertContains(response, '<input type="hidden" name="inner_set-0-id" value="1"')
    245         self.assertContains(response, 'value="1" id="id_inner_set-TOTAL_FORMS"')
    246 
    247         # Check that deletion is possible with the appropriate permissions.
    248         # Deletion is only possible for the Author-Book relationship since the
    249         # foreign key from Inner to Holder does not allow NULL values.
    250         permission = Permission.objects.get(codename='delete_book', content_type=book_ct)
    251         user.user_permissions.add(permission)
    252         response = self.client.get('/admin/admin_inlines/author/1/')
    253         self.assertContains(response, 'id="id_Author_books-0-DELETE"')
    254 
    255145class TestInlineMedia(TestCase):
    256146    urls = "regressiontests.admin_inlines.urls"
    257147    fixtures = ['admin-views-users.xml']
    class TestInlineAdminForm(TestCase):  
    306196        iaf = InlineAdminForm(None, None, {}, {}, joe)
    307197        parent_ct = ContentType.objects.get_for_model(Parent)
    308198        self.assertEqual(iaf.original.content_type, parent_ct)
     199
     200class TestInlinePermissions(TestCase):
     201    """
     202    Make sure the admin respects permissions for objects that are edited
     203    inline. Ref #8060.
     204    """
     205    urls = "regressiontests.admin_inlines.urls"
     206    fixtures = ['admin-views-users.xml']
     207
     208    def setUp(self):
     209        self.user = User.objects.get(username='super')
     210        self.user.is_superuser = False
     211        self.user.save()
     212
     213        self.author_ct = ContentType.objects.get_for_model(Author)
     214        self.holder_ct = ContentType.objects.get_for_model(Holder)
     215        self.book_ct = ContentType.objects.get_for_model(Book)
     216        self.inner_ct = ContentType.objects.get_for_model(Inner)
     217
     218        author = Author.objects.create(pk=1, name=u'The Author')
     219        author.books.create(name=u'The inline Book')
     220        holder = Holder(dummy=13)
     221        holder.save()
     222        Inner(dummy=42, holder=holder).save()
     223        self.change_url = '/admin/admin_inlines/holder/%i/' % holder.id
     224
     225        result = self.client.login(username='super', password='secret')
     226        self.assertEqual(result, True)
     227
     228    def tearDown(self):
     229        self.client.logout()
     230
     231    def test_inline_add_m2m_noperm(self):
     232        user = self.user
     233        permission = Permission.objects.get(codename='add_author', content_type=self.author_ct)
     234        user.user_permissions.add(permission)
     235        # Make sure the inline is removed
     236        response = self.client.get('/admin/admin_inlines/author/add/')
     237        # This would be a TabularInline
     238        self.assertNotContains(response, '<h2>Author-book relationships</h2>')
     239        self.assertNotContains(response, 'Add another Author-Book Relationship')
     240        self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
     241
     242    def test_inline_add_fk_noperm(self):
     243        user = self.user
     244        permission = Permission.objects.get(codename='add_holder', content_type=self.holder_ct)
     245        user.user_permissions.add(permission)
     246        response = self.client.get('/admin/admin_inlines/holder/add/')
     247        # This would be a StackedInline
     248        self.assertNotContains(response, '<h2>Inners</h2>')
     249        self.assertNotContains(response, 'Add another Inner')
     250        self.assertNotContains(response, 'id="id_inner_set-TOTAL_FORMS"')
     251
     252    def test_inline_change_m2m_noperm(self):
     253        user = self.user
     254        permission = Permission.objects.get(codename='change_author', content_type=self.author_ct)
     255        user.user_permissions.add(permission)
     256        response = self.client.get('/admin/admin_inlines/author/1/')
     257        self.assertNotContains(response, '<h2>Author-book relationships</h2>')
     258        self.assertNotContains(response, 'Add another Author-Book Relationship')
     259        self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
     260
     261    def test_inline_change_fk_noperm(self):
     262        user = self.user
     263        permission = Permission.objects.get(codename='change_holder', content_type=self.holder_ct)
     264        user.user_permissions.add(permission)
     265        response = self.client.get(self.change_url)
     266        self.assertNotContains(response, '<h2>Inners</h2>')
     267        self.assertNotContains(response, 'Add another Inner')
     268        self.assertNotContains(response, 'id="id_inner_set-TOTAL_FORMS"')
     269
     270    def test_inline_add_m2m_add_perm(self):
     271        user = self.user
     272        permission = Permission.objects.get(codename='add_author', content_type=self.author_ct)
     273        user.user_permissions.add(permission)
     274        permission = Permission.objects.get(codename='add_book', content_type=self.book_ct)
     275        user.user_permissions.add(permission)
     276        response = self.client.get('/admin/admin_inlines/author/add/')
     277        self.assertNotContains(response, '<h2>Author-book relationships</h2>')
     278        self.assertNotContains(response, 'Add another Author-Book Relationship')
     279        self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
     280
     281    def test_inline_add_fk_add_perm(self):
     282        user = self.user
     283        permission = Permission.objects.get(codename='add_holder', content_type=self.holder_ct)
     284        user.user_permissions.add(permission)
     285        permission = Permission.objects.get(codename='add_inner', content_type=self.inner_ct)
     286        user.user_permissions.add(permission)
     287        response = self.client.get('/admin/admin_inlines/holder/add/')
     288        self.assertContains(response, '<h2>Inners</h2>')
     289        self.assertContains(response, 'Add another Inner')
     290        self.assertContains(response, 'value="3" id="id_inner_set-TOTAL_FORMS"')
     291
     292    def test_inline_change_m2m_add_perm(self):
     293        # We need the change permission on the related model to make changes to the
     294        # intermediate model.
     295        user = self.user
     296        permission = Permission.objects.get(codename='change_author', content_type=self.author_ct)
     297        user.user_permissions.add(permission)
     298        permission = Permission.objects.get(codename='add_book', content_type=self.book_ct)
     299        user.user_permissions.add(permission)
     300        response = self.client.get('/admin/admin_inlines/author/1/')
     301        self.assertNotContains(response, '<h2>Author-book relationships</h2>')
     302        self.assertNotContains(response, 'Add another Author-Book Relationship')
     303        self.assertNotContains(response, 'id="id_Author_books-TOTAL_FORMS"')
     304        self.assertNotContains(response, 'id="id_Author_books-0-DELETE"')
     305
     306    def test_inline_change_m2m_change_perm(self):
     307        # Editing the preexisting m2m relation as well as adding additional
     308        # ones should be possible.
     309        user = self.user
     310        permission = Permission.objects.get(codename='change_author', content_type=self.author_ct)
     311        user.user_permissions.add(permission)
     312        permission = Permission.objects.get(codename='change_book', content_type=self.book_ct)
     313        user.user_permissions.add(permission)
     314        response = self.client.get('/admin/admin_inlines/author/1/')
     315        self.assertContains(response, '<h2>Author-book relationships</h2>')
     316        self.assertContains(response, 'Add another Author-Book Relationship')
     317        self.assertContains(response, 'value="4" id="id_Author_books-TOTAL_FORMS"')
     318        self.assertContains(response, '<input type="hidden" name="Author_books-0-id" value="1"')
     319        self.assertContains(response, 'id="id_Author_books-0-DELETE"')
     320
     321    def test_inline_change_fk_add_perm(self):
     322        user = self.user
     323        permission = Permission.objects.get(codename='change_holder', content_type=self.holder_ct)
     324        user.user_permissions.add(permission)
     325        permission = Permission.objects.get(codename='add_inner', content_type=self.inner_ct)
     326        user.user_permissions.add(permission)
     327        response = self.client.get(self.change_url)
     328        self.assertContains(response, '<h2>Inners</h2>')
     329        self.assertContains(response, 'Add another Inner')
     330        self.assertContains(response, 'value="3" id="id_inner_set-TOTAL_FORMS"')
     331        self.assertNotContains(response, '<input type="hidden" name="inner_set-0-id" value="1"')
     332
     333    def test_inline_change_fk_change_perm(self):
     334        user = self.user
     335        permission = Permission.objects.get(codename='change_holder', content_type=self.holder_ct)
     336        user.user_permissions.add(permission)
     337        permission = Permission.objects.get(codename='change_inner', content_type=self.inner_ct)
     338        user.user_permissions.add(permission)
     339        response = self.client.get(self.change_url)
     340        self.assertContains(response, '<h2>Inners</h2>')
     341        self.assertContains(response, 'value="1" id="id_inner_set-TOTAL_FORMS"')
     342        self.assertContains(response, '<input type="hidden" name="inner_set-0-id" value="1"')
     343
     344    def test_inline_change_fk_add_change_perm(self):
     345        user = self.user
     346        permission = Permission.objects.get(codename='change_holder', content_type=self.holder_ct)
     347        user.user_permissions.add(permission)
     348        permission = Permission.objects.get(codename='add_inner', content_type=self.inner_ct)
     349        user.user_permissions.add(permission)
     350        permission = Permission.objects.get(codename='change_inner', content_type=self.inner_ct)
     351        user.user_permissions.add(permission)
     352        response = self.client.get(self.change_url)
     353        self.assertContains(response, '<h2>Inners</h2>')
     354        self.assertContains(response, 'value="4" id="id_inner_set-TOTAL_FORMS"')
     355        self.assertContains(response, '<input type="hidden" name="inner_set-0-id" value="1"')
     356
     357    def test_inline_change_fk_del_perm(self):
     358        # The Author ForeignKey in the Book model does not allow NULL values,
     359        # so we use different models this time.
     360        user = self.user
     361        collection = TitleCollection.objects.create(pk=1)
     362        title = Title.objects.create(collection=collection, title1='foo', title2='foo')
     363        collection_ct = ContentType.objects.get_for_model(TitleCollection)
     364        title_ct = ContentType.objects.get_for_model(Title)
     365        permission = Permission.objects.get(codename='change_titlecollection', content_type=collection_ct)
     366        user.user_permissions.add(permission)
     367        permission = Permission.objects.get(codename='change_title', content_type=title_ct)
     368        user.user_permissions.add(permission)
     369        permission = Permission.objects.get(codename='delete_title', content_type=title_ct)
     370        user.user_permissions.add(permission)
     371        response = self.client.get('/admin/admin_inlines/titlecollection/1/')
     372        self.assertContains(response, '<h2>Titles</h2>')
     373        self.assertContains(response, 'id="id_title_set-0-DELETE"')
Back to Top