This commit is contained in:
lorin 2017-05-15 13:48:55 +00:00 committed by GitHub
commit c6fbc4e107
2 changed files with 77 additions and 0 deletions

View File

@ -4,6 +4,7 @@ Provides a set of pluggable permission policies.
from __future__ import unicode_literals
from django.http import Http404
from django.utils import six
from rest_framework import exceptions
from rest_framework.compat import is_authenticated
@ -11,6 +12,49 @@ from rest_framework.compat import is_authenticated
SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
class BasePermissionMetaClass(type):
"""
Metaclass for the base permission class.
"""
def __init__(cls, name, bases, dct):
super(BasePermissionMetaClass, cls).__init__(name, bases, dct)
def __or__(klass, perm_class):
"""
Returns a new permission class performing a logical OR between two
different permission classes.
"""
assert issubclass(perm_class, BasePermission), (
"%s is not a subclass of BasePermission" % perm_class
)
def has_permission(self, request, view):
perm = klass.has_permission(self, request, view)
otherwise = perm_class().has_permission(request, view)
return perm or otherwise
def has_object_permission(self, request, view, obj):
perm = klass.has_object_permission(self, request, view, obj)
otherwise = perm_class().has_object_permission(request, view, obj)
return perm or otherwise
t = type(
str('{0}Or{1}').format(klass.__name__, perm_class.__name__),
(klass,),
{}
)
t.has_permission = has_permission
t.has_object_permission = has_object_permission
return t
# Needed for performing logical operations between permission classes.
@six.add_metaclass(BasePermissionMetaClass)
class BasePermission(object):
"""
A base class from which all permission classes should inherit.

View File

@ -483,3 +483,36 @@ class CustomPermissionsTests(TestCase):
detail = response.data.get('detail')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(detail, self.custom_message)
class AllowPermission(permissions.BasePermission):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return True
class DenyPermission(permissions.BasePermission):
def has_permission(self, request, view):
return False
def has_object_permission(self, request, view, obj):
return False
class PermissionOperatorTests(TestCase):
def test_permission_logical_or(self):
# We evaluate all possible combinations.
# We pass None to the has_permission function, request and view aren't
# relevant to these classes.
self.assertFalse((DenyPermission | DenyPermission)().has_permission(None, None))
self.assertTrue((AllowPermission | DenyPermission)().has_permission(None, None))
self.assertTrue((DenyPermission | AllowPermission)().has_permission(None, None))
self.assertTrue((AllowPermission | AllowPermission)().has_permission(None, None))
self.assertFalse((DenyPermission | DenyPermission)().has_object_permission(None, None, None))
self.assertTrue((AllowPermission | DenyPermission)().has_object_permission(None, None, None))
self.assertTrue((DenyPermission | AllowPermission)().has_object_permission(None, None, None))
self.assertTrue((AllowPermission | AllowPermission)().has_object_permission(None, None, None))