Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #11513 -- Ensure that the redirect at the end of an object chan…

…ge won't redirect to a page for which the user doesn't have permission. Thanks to rlaager for the report and draft patch, and to Julien Phalip for the final patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15584 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 75a1aaa1f9341e558b6efe9227cf663d55704469 1 parent fe3c9ad
Russell Keith-Magee authored February 19, 2011
8  django/contrib/admin/options.py
@@ -766,7 +766,13 @@ def response_change(self, request, obj):
766 766
             return HttpResponseRedirect("../add/")
767 767
         else:
768 768
             self.message_user(request, msg)
769  
-            return HttpResponseRedirect("../")
  769
+            # Figure out where to redirect. If the user has change permission,
  770
+            # redirect to the change-list page for this object. Otherwise,
  771
+            # redirect to the admin index.
  772
+            if self.has_change_permission(request, None):
  773
+                return HttpResponseRedirect('../')
  774
+            else:
  775
+                return HttpResponseRedirect('../../../')
770 776
 
771 777
     def response_action(self, request, queryset):
772 778
         """
8  tests/regressiontests/admin_views/models.py
@@ -133,6 +133,13 @@ def save_model(self, request, obj, form, change=True):
133 133
         ).send()
134 134
         return super(ArticleAdmin, self).save_model(request, obj, form, change)
135 135
 
  136
+class RowLevelChangePermissionModel(models.Model):
  137
+    name = models.CharField(max_length=100, blank=True)
  138
+
  139
+class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
  140
+    def has_change_permission(self, request, obj=None):
  141
+        """ Only allow changing objects with even id number """
  142
+        return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
136 143
 
137 144
 class CustomArticle(models.Model):
138 145
     content = models.TextField()
@@ -735,6 +742,7 @@ class FoodDeliveryAdmin(admin.ModelAdmin):
735 742
 admin.site.register(WorkHour, WorkHourAdmin)
736 743
 admin.site.register(Reservation)
737 744
 admin.site.register(FoodDelivery, FoodDeliveryAdmin)
  745
+admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
738 746
 
739 747
 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
740 748
 # That way we cover all four cases:
37  tests/regressiontests/admin_views/tests.py
@@ -35,7 +35,8 @@
35 35
     Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
36 36
     Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
37 37
     Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
38  
-    Question, Answer, Inquisition, Actor, FoodDelivery)
  38
+    Question, Answer, Inquisition, Actor, FoodDelivery,
  39
+    RowLevelChangePermissionModel)
39 40
 
40 41
 
41 42
 class AdminViewBasicTest(TestCase):
@@ -792,6 +793,40 @@ def testChangeView(self):
792 793
                         'Plural error message not found in response to post with multiple errors.')
793 794
         self.client.get('/test_admin/admin/logout/')
794 795
 
  796
+        # Test redirection when using row-level change permissions. Refs #11513.
  797
+        RowLevelChangePermissionModel.objects.create(name="odd id")
  798
+        RowLevelChangePermissionModel.objects.create(name="even id")
  799
+        for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]:
  800
+            self.client.post('/test_admin/admin/', login_dict)
  801
+            request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
  802
+            self.assertEqual(request.status_code, 403)
  803
+            request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
  804
+            self.assertEquals(RowLevelChangePermissionModel.objects.get(id=1).name, 'odd id')
  805
+            self.assertEqual(request.status_code, 403)
  806
+            request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
  807
+            self.assertEqual(request.status_code, 200)
  808
+            request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed'})
  809
+            self.assertEquals(RowLevelChangePermissionModel.objects.get(id=2).name, 'changed')
  810
+            self.assertRedirects(request, '/test_admin/admin/')
  811
+            self.client.get('/test_admin/admin/logout/')
  812
+        for login_dict in [self.joepublic_login, self.no_username_login]:
  813
+            self.client.post('/test_admin/admin/', login_dict)
  814
+            request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
  815
+            self.assertEqual(request.status_code, 200)
  816
+            self.assertContains(request, 'login-form')
  817
+            request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
  818
+            self.assertEquals(RowLevelChangePermissionModel.objects.get(id=1).name, 'odd id')
  819
+            self.assertEqual(request.status_code, 200)
  820
+            self.assertContains(request, 'login-form')
  821
+            request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
  822
+            self.assertEqual(request.status_code, 200)
  823
+            self.assertContains(request, 'login-form')
  824
+            request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed again'})
  825
+            self.assertEquals(RowLevelChangePermissionModel.objects.get(id=2).name, 'changed')
  826
+            self.assertEqual(request.status_code, 200)
  827
+            self.assertContains(request, 'login-form')
  828
+            self.client.get('/test_admin/admin/logout/')
  829
+
795 830
     def testConditionallyShowAddSectionLink(self):
796 831
         """
797 832
         The foreign key widget should only show the "add related" button if the

0 notes on commit 75a1aaa

Please sign in to comment.
Something went wrong with that request. Please try again.