Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #20828 -- Allowed @permission_required to take a list of permis…

…sions

Thanks Giggaflop for the suggestion.
  • Loading branch information...
commit 00d23a13ebaf6057d1428e798bfb6cf47bb5ef7c 1 parent 5737c57
ersran9 authored timgraham committed
6  django/contrib/auth/decorators.py
@@ -64,8 +64,12 @@ def permission_required(perm, login_url=None, raise_exception=False):
64 64
     is raised.
65 65
     """
66 66
     def check_perms(user):
  67
+        if not isinstance(perm, (list, tuple)):
  68
+            perms = (perm, )
  69
+        else:
  70
+            perms = perm
67 71
         # First check if the user has the permission (even anon users)
68  
-        if user.has_perm(perm):
  72
+        if user.has_perms(perms):
69 73
             return True
70 74
         # In case the 403 handler should be called raise the exception
71 75
         if raise_exception:
58  django/contrib/auth/tests/test_decorators.py
... ...
@@ -1,7 +1,12 @@
1 1
 from django.conf import settings
2  
-from django.contrib.auth.decorators import login_required
  2
+from django.contrib.auth import models
  3
+from django.contrib.auth.decorators import login_required, permission_required
3 4
 from django.contrib.auth.tests.test_views import AuthViewsTestCase
4 5
 from django.contrib.auth.tests.utils import skipIfCustomUser
  6
+from django.core.exceptions import PermissionDenied
  7
+from django.http import HttpResponse
  8
+from django.test import TestCase
  9
+from django.test.client import RequestFactory
5 10
 
6 11
 
7 12
 @skipIfCustomUser
@@ -49,3 +54,54 @@ def testLoginRequiredNextUrl(self):
49 54
         """
50 55
         self.testLoginRequired(view_url='/login_required_login_url/',
51 56
             login_url='/somewhere/')
  57
+
  58
+
  59
+class PermissionsRequiredDecoratorTest(TestCase):
  60
+    """
  61
+    Tests for the permission_required decorator
  62
+    """
  63
+    def setUp(self):
  64
+        self.user = models.User.objects.create(username='joe', password='qwerty')
  65
+        self.factory = RequestFactory()
  66
+        # Add permissions auth.add_customuser and auth.change_customuser
  67
+        perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser'))
  68
+        self.user.user_permissions.add(*perms)
  69
+
  70
+    def test_many_permissions_pass(self):
  71
+
  72
+        @permission_required(['auth.add_customuser', 'auth.change_customuser'])
  73
+        def a_view(request):
  74
+            return HttpResponse()
  75
+        request = self.factory.get('/rand')
  76
+        request.user = self.user
  77
+        resp = a_view(request)
  78
+        self.assertEqual(resp.status_code, 200)
  79
+
  80
+    def test_single_permission_pass(self):
  81
+
  82
+        @permission_required('auth.add_customuser')
  83
+        def a_view(request):
  84
+            return HttpResponse()
  85
+        request = self.factory.get('/rand')
  86
+        request.user = self.user
  87
+        resp = a_view(request)
  88
+        self.assertEqual(resp.status_code, 200)
  89
+
  90
+    def test_permissioned_denied_redirect(self):
  91
+
  92
+        @permission_required(['auth.add_customuser', 'auth.change_customuser', 'non-existant-permission'])
  93
+        def a_view(request):
  94
+            return HttpResponse()
  95
+        request = self.factory.get('/rand')
  96
+        request.user = self.user
  97
+        resp = a_view(request)
  98
+        self.assertEqual(resp.status_code, 302)
  99
+
  100
+    def test_permissioned_denied_exception_raised(self):
  101
+
  102
+        @permission_required(['auth.add_customuser', 'auth.change_customuser', 'non-existant-permission'], raise_exception=True)
  103
+        def a_view(request):
  104
+            return HttpResponse()
  105
+        request = self.factory.get('/rand')
  106
+        request.user = self.user
  107
+        self.assertRaises(PermissionDenied, a_view, request)
3  docs/releases/1.7.txt
@@ -135,6 +135,9 @@ Minor features
135 135
   ``Meta`` option allows you to customize (or disable) creation of the default
136 136
   add, change, and delete permissions.
137 137
 
  138
+* The :func:`~django.contrib.auth.decorators.permission_required` decorator can
  139
+  take a list of permissions as well as a single permission.
  140
+
138 141
 Backwards incompatible changes in 1.7
139 142
 =====================================
140 143
 
5  docs/topics/auth/default.txt
@@ -528,6 +528,11 @@ The permission_required decorator
528 528
     (HTTP Forbidden) view<http_forbidden_view>` instead of redirecting to the
529 529
     login page.
530 530
 
  531
+    .. versionchanged:: 1.7
  532
+
  533
+        The :func:`~django.contrib.auth.decorators.permission_required`
  534
+        decorator can take a list of permissions as well as a single permission.
  535
+
531 536
 Applying permissions to generic views
532 537
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
533 538
 

0 notes on commit 00d23a1

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