mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-13 17:52:19 +03:00
fix #79 add decorator has_perms for nodes
This commit is contained in:
parent
5d6c7f2dc3
commit
320d95333f
|
@ -108,3 +108,28 @@ method to your ``DjangoObjectType``.
|
||||||
if post.published or context.user == post.owner:
|
if post.published or context.user == post.owner:
|
||||||
return post
|
return post
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
Permission node access
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
For restrict access using permissions, use the `has_perm` decorator in node.
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from graphene_django.types import DjangoObjectType
|
||||||
|
from graphene_django.decorator import has_perms
|
||||||
|
from .models import Post
|
||||||
|
|
||||||
|
class PostNode(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = Post
|
||||||
|
only_fields = ('title', 'content')
|
||||||
|
interfaces = (relay.Node, )
|
||||||
|
|
||||||
|
@has_perms(["django_app.django_can_see_content_permission"])
|
||||||
|
def resolve_content(self, id, context, info):
|
||||||
|
return self.content
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
51
graphene_django/decorators.py
Normal file
51
graphene_django/decorators.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# coding: utf-8
|
||||||
|
from functools import wraps
|
||||||
|
from django.http import HttpResponseForbidden
|
||||||
|
|
||||||
|
|
||||||
|
def has_perms(permissions):
|
||||||
|
"""
|
||||||
|
Check if have user logged and permissions to see some value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
class CityNode(DjangoObjectType):
|
||||||
|
class Meta(object):
|
||||||
|
interfaces = (relay.Node,)
|
||||||
|
model = City
|
||||||
|
only_fields = (
|
||||||
|
'name', 'locality', 'slug', 'state', 'active',
|
||||||
|
)
|
||||||
|
|
||||||
|
@has_perms(["django_city_app.can_see_location"])
|
||||||
|
def resolve_location(self, args, context, info):
|
||||||
|
return self.locality.pos
|
||||||
|
|
||||||
|
Args:
|
||||||
|
permissions: ["django_app.permission_codename",]
|
||||||
|
"""
|
||||||
|
def decorator(method):
|
||||||
|
if callable(permissions):
|
||||||
|
method.permissions = []
|
||||||
|
else:
|
||||||
|
method.permissions = permissions
|
||||||
|
|
||||||
|
@wraps(method)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
context = kwargs.get('context', dict(zip(method.func_code.co_varnames,
|
||||||
|
args)).get('context', None))
|
||||||
|
if not context:
|
||||||
|
return HttpResponseForbidden('Forbidden. No context, no access.')
|
||||||
|
try:
|
||||||
|
user = context.user
|
||||||
|
except AttributeError:
|
||||||
|
return HttpResponseForbidden('Forbidden. No request.')
|
||||||
|
|
||||||
|
if method.permissions and not user.has_perms(method.permissions):
|
||||||
|
return HttpResponseForbidden('Forbidden. User without access')
|
||||||
|
return method(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
if callable(permissions):
|
||||||
|
return decorator(permissions)
|
||||||
|
|
||||||
|
return decorator
|
80
graphene_django/tests/test_decorators.py
Normal file
80
graphene_django/tests/test_decorators.py
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
from django.utils.unittest import TestCase
|
||||||
|
from ..decorators import has_perms
|
||||||
|
|
||||||
|
|
||||||
|
class MockContext(object):
|
||||||
|
def __init__(self, authenticated=True, is_staff=False, superuser=False, perms=[]):
|
||||||
|
self.user = self
|
||||||
|
self.authenticated = authenticated
|
||||||
|
self.is_staff = is_staff
|
||||||
|
self.is_superuser = superuser
|
||||||
|
self.perms = perms
|
||||||
|
self.status_code = 200
|
||||||
|
|
||||||
|
def is_authenticated(self):
|
||||||
|
return self.authenticated
|
||||||
|
|
||||||
|
def has_perms(self, check_perms):
|
||||||
|
for perm in check_perms:
|
||||||
|
if perm not in self.perms:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class TestHasPermsDecorator(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@has_perms(['django_app.dummy_permission'])
|
||||||
|
def check_user_perms_func(cls, input, context, info=None):
|
||||||
|
cls.status_code = 200
|
||||||
|
cls.content = True
|
||||||
|
return cls
|
||||||
|
|
||||||
|
def test_get_content_without_permission(self):
|
||||||
|
context = MockContext(
|
||||||
|
authenticated=True
|
||||||
|
)
|
||||||
|
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||||
|
self.assertEqual(request.status_code, 403)
|
||||||
|
self.assertEqual(request.content, 'Forbidden. User without access')
|
||||||
|
|
||||||
|
def test_get_content_without_authentication(self):
|
||||||
|
context = MockContext(
|
||||||
|
authenticated=False
|
||||||
|
)
|
||||||
|
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||||
|
self.assertEqual(request.status_code, 403)
|
||||||
|
self.assertEqual(request.content, 'Forbidden. User is not authenticated.')
|
||||||
|
|
||||||
|
def test_get_context_with_permission(self):
|
||||||
|
context = MockContext(
|
||||||
|
authenticated=True,
|
||||||
|
perms=['django_app.dummy_permission']
|
||||||
|
|
||||||
|
)
|
||||||
|
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||||
|
self.assertEqual(request.status_code, 200)
|
||||||
|
self.assertEqual(request.content, True)
|
||||||
|
|
||||||
|
def test_get_context_with_diffent_and_valid_permission(self):
|
||||||
|
context = MockContext(
|
||||||
|
authenticated=True,
|
||||||
|
perms=['another_app.dummy_permission',
|
||||||
|
'django_app.dummy_permission']
|
||||||
|
|
||||||
|
)
|
||||||
|
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||||
|
self.assertEqual(request.status_code, 200)
|
||||||
|
self.assertEqual(request.content, True)
|
||||||
|
|
||||||
|
def test_get_context_with_diffent_and_invalid_permission(self):
|
||||||
|
context = MockContext(
|
||||||
|
authenticated=True,
|
||||||
|
perms=['another_app.dummy_permission',
|
||||||
|
'another_app.dummy_permission2']
|
||||||
|
|
||||||
|
)
|
||||||
|
request = TestHasPermsDecorator.check_user_perms_func(None, context=context)
|
||||||
|
self.assertEqual(request.status_code, 403)
|
||||||
|
self.assertEqual(request.content, 'Forbidden. User without access')
|
Loading…
Reference in New Issue
Block a user