Commit 00d23a13 authored by ersran9's avatar ersran9 Committed by Tim Graham
Browse files

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

Thanks Giggaflop for the suggestion.
parent 5737c57d
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -64,8 +64,12 @@ def permission_required(perm, login_url=None, raise_exception=False):
    is raised.
    """
    def check_perms(user):
        if not isinstance(perm, (list, tuple)):
            perms = (perm, )
        else:
            perms = perm
        # First check if the user has the permission (even anon users)
        if user.has_perm(perm):
        if user.has_perms(perms):
            return True
        # In case the 403 handler should be called raise the exception
        if raise_exception:
+57 −1
Original line number Diff line number Diff line
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth import models
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.tests.test_views import AuthViewsTestCase
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.test import TestCase
from django.test.client import RequestFactory


@skipIfCustomUser
@@ -49,3 +54,54 @@ class LoginRequiredTestCase(AuthViewsTestCase):
        """
        self.testLoginRequired(view_url='/login_required_login_url/',
            login_url='/somewhere/')


class PermissionsRequiredDecoratorTest(TestCase):
    """
    Tests for the permission_required decorator
    """
    def setUp(self):
        self.user = models.User.objects.create(username='joe', password='qwerty')
        self.factory = RequestFactory()
        # Add permissions auth.add_customuser and auth.change_customuser
        perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser'))
        self.user.user_permissions.add(*perms)

    def test_many_permissions_pass(self):

        @permission_required(['auth.add_customuser', 'auth.change_customuser'])
        def a_view(request):
            return HttpResponse()
        request = self.factory.get('/rand')
        request.user = self.user
        resp = a_view(request)
        self.assertEqual(resp.status_code, 200)

    def test_single_permission_pass(self):

        @permission_required('auth.add_customuser')
        def a_view(request):
            return HttpResponse()
        request = self.factory.get('/rand')
        request.user = self.user
        resp = a_view(request)
        self.assertEqual(resp.status_code, 200)

    def test_permissioned_denied_redirect(self):

        @permission_required(['auth.add_customuser', 'auth.change_customuser', 'non-existant-permission'])
        def a_view(request):
            return HttpResponse()
        request = self.factory.get('/rand')
        request.user = self.user
        resp = a_view(request)
        self.assertEqual(resp.status_code, 302)

    def test_permissioned_denied_exception_raised(self):

        @permission_required(['auth.add_customuser', 'auth.change_customuser', 'non-existant-permission'], raise_exception=True)
        def a_view(request):
            return HttpResponse()
        request = self.factory.get('/rand')
        request.user = self.user
        self.assertRaises(PermissionDenied, a_view, request)
+3 −0
Original line number Diff line number Diff line
@@ -135,6 +135,9 @@ Minor features
  ``Meta`` option allows you to customize (or disable) creation of the default
  add, change, and delete permissions.

* The :func:`~django.contrib.auth.decorators.permission_required` decorator can
  take a list of permissions as well as a single permission.

Backwards incompatible changes in 1.7
=====================================

+5 −0
Original line number Diff line number Diff line
@@ -528,6 +528,11 @@ The permission_required decorator
    (HTTP Forbidden) view<http_forbidden_view>` instead of redirecting to the
    login page.

    .. versionchanged:: 1.7

        The :func:`~django.contrib.auth.decorators.permission_required`
        decorator can take a list of permissions as well as a single permission.

Applying permissions to generic views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~