See #230: can now use "or" operator to check permissions
This commit is contained in:
parent
ed6c1a9a5b
commit
dfb4f5f62a
|
@ -72,9 +72,12 @@ class User(AbstractUser):
|
||||||
perms[p] = v
|
perms[p] = v
|
||||||
return perms
|
return perms
|
||||||
|
|
||||||
def has_permissions(self, *perms):
|
def has_permissions(self, *perms, operator='and'):
|
||||||
|
if operator not in ['and', 'or']:
|
||||||
|
raise ValueError('Invalid operator {}'.format(operator))
|
||||||
permissions = self.get_permissions()
|
permissions = self.get_permissions()
|
||||||
return all([permissions[p] for p in perms])
|
checker = all if operator == 'and' else any
|
||||||
|
return checker([permissions[p] for p in perms])
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('users:detail', kwargs={'username': self.username})
|
return reverse('users:detail', kwargs={'username': self.username})
|
||||||
|
|
|
@ -16,4 +16,6 @@ class HasUserPermission(BasePermission):
|
||||||
return False
|
return False
|
||||||
if request.user.is_anonymous:
|
if request.user.is_anonymous:
|
||||||
return False
|
return False
|
||||||
return request.user.has_permissions(*view.required_permissions)
|
operator = getattr(view, 'permission_operator', 'and')
|
||||||
|
return request.user.has_permissions(
|
||||||
|
*view.required_permissions, operator=operator)
|
||||||
|
|
|
@ -231,8 +231,9 @@ def authenticated_actor(factories, mocker):
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def assert_user_permission():
|
def assert_user_permission():
|
||||||
def inner(view, permissions):
|
def inner(view, permissions, operator='and'):
|
||||||
assert HasUserPermission in view.permission_classes
|
assert HasUserPermission in view.permission_classes
|
||||||
|
assert getattr(view, 'permission_operator', 'and') == operator
|
||||||
assert set(view.required_permissions) == set(permissions)
|
assert set(view.required_permissions) == set(permissions)
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,17 @@ def test_get_permissions_regular(factories):
|
||||||
({'permission_library': True}, ['library'], True),
|
({'permission_library': True}, ['library'], True),
|
||||||
({'permission_library': True}, ['library', 'federation'], False),
|
({'permission_library': True}, ['library', 'federation'], False),
|
||||||
])
|
])
|
||||||
def test_has_permissions(args, perms, expected, factories):
|
def test_has_permissions_and(args, perms, expected, factories):
|
||||||
user = factories['users.User'](**args)
|
user = factories['users.User'](**args)
|
||||||
assert user.has_permissions(*perms) is expected
|
assert user.has_permissions(*perms, operator='and') is expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('args,perms,expected', [
|
||||||
|
({'is_superuser': True}, ['federation', 'library'], True),
|
||||||
|
({'is_superuser': False}, ['federation'], False),
|
||||||
|
({'permission_library': True}, ['library', 'federation'], True),
|
||||||
|
({'permission_library': True}, ['federation'], False),
|
||||||
|
])
|
||||||
|
def test_has_permissions_or(args, perms, expected, factories):
|
||||||
|
user = factories['users.User'](**args)
|
||||||
|
assert user.has_permissions(*perms, operator='or') is expected
|
||||||
|
|
|
@ -39,7 +39,7 @@ def test_has_user_permission_logged_in_single(value, factories, api_request):
|
||||||
(False, False, False),
|
(False, False, False),
|
||||||
(True, True, True),
|
(True, True, True),
|
||||||
])
|
])
|
||||||
def test_has_user_permission_logged_in_single(
|
def test_has_user_permission_logged_in_multiple_and(
|
||||||
federation, library, expected, factories, api_request):
|
federation, library, expected, factories, api_request):
|
||||||
user = factories['users.User'](
|
user = factories['users.User'](
|
||||||
permission_federation=federation,
|
permission_federation=federation,
|
||||||
|
@ -48,9 +48,35 @@ def test_has_user_permission_logged_in_single(
|
||||||
|
|
||||||
class View(APIView):
|
class View(APIView):
|
||||||
required_permissions = ['federation', 'library']
|
required_permissions = ['federation', 'library']
|
||||||
|
permission_operator = 'and'
|
||||||
view = View()
|
view = View()
|
||||||
permission = permissions.HasUserPermission()
|
permission = permissions.HasUserPermission()
|
||||||
request = api_request.get('/')
|
request = api_request.get('/')
|
||||||
setattr(request, 'user', user)
|
setattr(request, 'user', user)
|
||||||
result = permission.has_permission(request, view)
|
result = permission.has_permission(request, view)
|
||||||
assert result == user.has_permissions('federation', 'library') == expected
|
assert result == user.has_permissions('federation', 'library') == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('federation,library,expected', [
|
||||||
|
(True, False, True),
|
||||||
|
(False, True, True),
|
||||||
|
(False, False, False),
|
||||||
|
(True, True, True),
|
||||||
|
])
|
||||||
|
def test_has_user_permission_logged_in_multiple_or(
|
||||||
|
federation, library, expected, factories, api_request):
|
||||||
|
user = factories['users.User'](
|
||||||
|
permission_federation=federation,
|
||||||
|
permission_library=library,
|
||||||
|
)
|
||||||
|
|
||||||
|
class View(APIView):
|
||||||
|
required_permissions = ['federation', 'library']
|
||||||
|
permission_operator = 'or'
|
||||||
|
view = View()
|
||||||
|
permission = permissions.HasUserPermission()
|
||||||
|
request = api_request.get('/')
|
||||||
|
setattr(request, 'user', user)
|
||||||
|
result = permission.has_permission(request, view)
|
||||||
|
assert result == user.has_permissions(
|
||||||
|
'federation', 'library', operator='or') == expected
|
||||||
|
|
Loading…
Reference in New Issue