Add test to permission type

This commit is contained in:
Olivia Rodriguez Valdes 2019-01-07 08:25:19 -05:00
parent 56a4ae9194
commit 106d3e063d
4 changed files with 126 additions and 9 deletions

View File

@ -164,4 +164,4 @@ class DjangoPermissionField(Field):
def get_resolver(self, parent_resolver): def get_resolver(self, parent_resolver):
"""Intercept resolver to analyse permissions""" """Intercept resolver to analyse permissions"""
return partial(auth_resolver, self.resolver or parent_resolver, self.permissions, True) return partial(auth_resolver, self.resolver or parent_resolver, self.permissions, None, None, True)

View File

@ -1,10 +1,10 @@
from mock import patch from mock import patch
from graphene import Interface, ObjectType, Schema, Connection, String from graphene import Interface, ObjectType, Schema, Connection, String, Field
from graphene.relay import Node from graphene.relay import Node
from .. import registry from .. import registry
from ..types import DjangoObjectType, DjangoObjectTypeOptions from ..types import DjangoObjectType, DjangoObjectTypeOptions, DjangoPermissionObjectType
from .models import Article as ArticleModel from .models import Article as ArticleModel
from .models import Reporter as ReporterModel from .models import Reporter as ReporterModel
@ -224,3 +224,101 @@ def test_django_objecttype_exclude_fields():
fields = list(Reporter._meta.fields.keys()) fields = list(Reporter._meta.fields.keys())
assert "email" not in fields assert "email" not in fields
def extra_field_resolver(root, info, **kwargs):
return 'extra field'
class PermissionArticle(DjangoPermissionObjectType):
"""Basic Type to test"""
class Meta(object):
"""Meta Class"""
field_to_permission = {
'headline': ('content_type.permission1',),
'pub_date': ('content_type.permission2',)
}
permission_to_field = {
'content_type.permission3': ('headline', 'reporter', 'extra_field',)
}
model = ArticleModel
extra_field = Field(String, resolver=extra_field_resolver)
def resolve_headline(self, info, **kwargs):
return 'headline'
def test_django_permissions():
expected = {
'headline': ('content_type.permission1', 'content_type.permission3'),
'pub_date': ('content_type.permission2',),
'reporter': ('content_type.permission3',),
'extra_field': ('content_type.permission3',),
}
assert PermissionArticle._field_permissions == expected
def test_permission_resolver():
MyType = object()
class Viewer(object):
def has_perm(self, perm):
return perm == 'content_type.permission3'
class Info(object):
class Context(object):
user = Viewer()
context = Context()
resolved = PermissionArticle.resolve_headline(MyType, Info())
assert resolved == 'headline'
def test_resolver_without_permission():
MyType = object()
class Viewer(object):
def has_perm(self, perm):
return False
class Info(object):
class Context(object):
user = Viewer()
context = Context()
resolved = PermissionArticle.resolve_headline(MyType, Info())
assert resolved is None
def test_permission_resolver_to_field():
MyType = object()
class Viewer(object):
def has_perm(self, perm):
return perm == 'content_type.permission3'
class Info(object):
class Context(object):
user = Viewer()
context = Context()
resolved = PermissionArticle.resolve_extra_field(MyType, Info())
assert resolved == 'extra field'
def test_resolver_to_field_without_permission():
MyType = object()
class Viewer(object):
def has_perm(self, perm):
return perm != 'content_type.permission3'
class Info(object):
class Context(object):
user = Viewer()
context = Context()
resolved = PermissionArticle.resolve_extra_field(MyType, Info())
assert resolved is None

View File

@ -9,7 +9,7 @@ from graphene.types.utils import yank_fields_from_attrs
from .converter import convert_django_field_with_choices from .converter import convert_django_field_with_choices
from .registry import Registry, get_global_registry from .registry import Registry, get_global_registry
from .utils import DJANGO_FILTER_INSTALLED, get_model_fields, is_valid_django_model from .utils import DJANGO_FILTER_INSTALLED, get_model_fields, is_valid_django_model, auth_resolver
def construct_fields(model, registry, only_fields, exclude_fields): def construct_fields(model, registry, only_fields, exclude_fields):
@ -170,7 +170,7 @@ class DjangoPermissionObjectType(DjangoObjectType):
for field_name, field_permissions in cls._field_permissions.items(): for field_name, field_permissions in cls._field_permissions.items():
attr = 'resolve_{}'.format(field_name) attr = 'resolve_{}'.format(field_name)
resolver = getattr(cls, attr, None) resolver = getattr(cls._meta.fields[field_name], 'resolver', None) or getattr(cls, attr, None)
if not hasattr(field_permissions, '__iter__'): if not hasattr(field_permissions, '__iter__'):
field_permissions = tuple(field_permissions) field_permissions = tuple(field_permissions)
@ -188,7 +188,7 @@ class DjangoPermissionObjectType(DjangoObjectType):
_as=Field, _as=Field,
) )
for name, field in django_fields.items(): for name, field in django_fields.items():
if isinstance(field._type, NonNull): if hasattr(field, '_type') and isinstance(field._type, NonNull):
field._type = field._type._of_type field._type = field._type._of_type
setattr(cls, name, field) setattr(cls, name, field)
@ -211,7 +211,7 @@ class DjangoPermissionObjectType(DjangoObjectType):
cls._field_permissions[field] = cls._field_permissions.get(field, tuple()) + permissions cls._field_permissions[field] = cls._field_permissions.get(field, tuple()) + permissions
@classmethod @classmethod
def set_auth_resolver(cls, name, permissions, field, resolver=None): def set_auth_resolver(cls, name, permissions, resolver=None):
""" """
Set middleware resolver to handle field permissions Set middleware resolver to handle field permissions
:param name: Field name :param name: Field name
@ -220,4 +220,4 @@ class DjangoPermissionObjectType(DjangoObjectType):
:param resolver: Field resolver :param resolver: Field resolver
:return: Middleware resolver to check permissions :return: Middleware resolver to check permissions
""" """
field.resolver = partial(auth_resolver, field.resolver or resolver, name, permissions, None, False) return partial(auth_resolver, resolver, permissions, name, None, False)

View File

@ -6,6 +6,7 @@ from django.db.models.manager import Manager
# from graphene.utils import LazyList # from graphene.utils import LazyList
from graphene.types.resolver import get_default_resolver
from graphene.utils.get_unbound_function import get_unbound_function from graphene.utils.get_unbound_function import get_unbound_function
@ -110,11 +111,27 @@ def resolve_bound_resolver(resolver, root, info, **args):
return resolver(root, info, **args) return resolver(root, info, **args)
def auth_resolver(parent_resolver, permissions, raise_exception, root, info, **args): def resolve_default_resolver(attname, default_value, root, info, **args):
"""
Resolve field with default resolver
:param attname: Field name
:param default_value: Field default value
:param root: Schema root
:param info: Schema info
:param args: Schema args
:return: Resolved field
"""
resolver = get_default_resolver()
return resolver(attname, default_value, root, info, **args)
def auth_resolver(parent_resolver, permissions, attname, default_value, raise_exception, root, info, **args):
""" """
Middleware resolver to check viewer's permissions Middleware resolver to check viewer's permissions
:param parent_resolver: Field resolver :param parent_resolver: Field resolver
:param permissions: Field permissions :param permissions: Field permissions
:param attname: Field name
:param default_value: Default value to field if no resolver is provided
:param raise_exception: If True a PermissionDenied is raised :param raise_exception: If True a PermissionDenied is raised
:param root: Schema root :param root: Schema root
:param info: Schema info :param info: Schema info
@ -127,6 +144,8 @@ def auth_resolver(parent_resolver, permissions, raise_exception, root, info, **a
if parent_resolver: if parent_resolver:
# A resolver is provided in the class # A resolver is provided in the class
return resolve_bound_resolver(parent_resolver, root, info, **args) return resolve_bound_resolver(parent_resolver, root, info, **args)
# Get default resolver
return resolve_default_resolver(attname, default_value, root, info, **args)
elif raise_exception: elif raise_exception:
raise PermissionDenied() raise PermissionDenied()
return None return None