Skip to content

Commit

Permalink
Added external getter for delegated objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Mirek Simek committed Jun 1, 2018
1 parent 06edc77 commit 2eb5b98
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
37 changes: 30 additions & 7 deletions rest_delegated_permissions/permissions.py
Expand Up @@ -38,6 +38,13 @@ def has_object_permission(self, request, view, obj):
"""
return False

@abstractmethod
def has_permission(self, request, view):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return False

@abstractmethod
def filter(self, rest_permissions, filtered_queryset, user, action):
"""
Expand Down Expand Up @@ -86,13 +93,15 @@ def __init__(self, rest_permissions, model_class, request, action):
def get_queryset(self):
return self.rest_permissions.create_queryset_factory(self.model_class)(self.request.user, self.action)

def __init__(self, rest_permissions, *delegated_fields, mapping=None):
def __init__(self, rest_permissions, *delegated_fields, mapping=None, delegated_objects_getter=None):
self.rest_permissions = rest_permissions
self.delegated_fields = delegated_fields
self.mapping = mapping
self.delegated_objects_getter = delegated_objects_getter

def has_object_permission(self, request, view, obj):
for delegated_obj in DelegatedPermission.get_delegated_objects(obj, self.delegated_fields):
getter = self.delegated_objects_getter or DelegatedPermission.get_delegated_objects
for delegated_obj in getter(request, view, obj, self.delegated_fields):
if not delegated_obj:
continue
delegated_permissions = self.rest_permissions.permissions_for_model(delegated_obj)
Expand All @@ -105,6 +114,9 @@ def has_object_permission(self, request, view, obj):

return False

def has_permission(self, request, view):
return self.has_object_permission(request, view, None)

def _get_delegated_action(self, action):
if self.mapping:
if isinstance(self.mapping, str):
Expand All @@ -114,7 +126,10 @@ def _get_delegated_action(self, action):
return action

@staticmethod
def get_delegated_objects(obj, field_names):
def get_delegated_objects(request, view, obj, field_names):
if not obj:
return

for perm_field_name in field_names:
perm_field = obj._meta.get_field(perm_field_name)
delegated_objects = []
Expand All @@ -137,6 +152,17 @@ def get_queryset_filters(self, rest_permissions, qs, user, action):
yield filtered_qs


def kwargs_delegated_object_getter(field_name_to_kwarg_name_map,
instantiator=lambda clazz, value, fldname: clazz.objects.get(pk=value)):
def kwargs_delegated_object_getter_func(request, view, obj, delegated_fields):
model = view.get_queryset().model
for field_name, kwarg in field_name_to_kwarg_name_map.items():
kwarg_value = view.kwargs[kwarg]
related_model_class = model._meta.get_field(field_name).related_model
yield instantiator(related_model_class, kwarg_value, field_name)
pass
return kwargs_delegated_object_getter_func

class RestrictedViewDjangoModelPermissions(permissions.DjangoModelPermissions):
perms_map = {}
perms_map.update(permissions.DjangoModelPermissions.perms_map)
Expand Down Expand Up @@ -305,10 +331,7 @@ def has_object_permission(self, request, view, obj):
return condition.has_object_permission(request, view, obj)

def has_permission(self, request, view):
# everyone is allowed as the query set is filtered (for read) and
# has_object_permission is applied for update/delete
# create must be handled separately
return True
return condition.has_permission(request, view)

return _Permission

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -34,7 +34,7 @@ class InvoiceViewSet(ModelViewSet):

setup(
name='django-rest-delegated-permissions',
version='1.0.0',
version='1.1.0',
packages=[
'rest_delegated_permissions',
],
Expand Down

0 comments on commit 2eb5b98

Please sign in to comment.