Commit 8ab9cd8f authored by Jean-Baptiste's avatar Jean-Baptiste

update: filter container by object permissions

parent 54fdc333
Pipeline #4925 passed with stage
in 1 minute and 22 seconds
......@@ -74,6 +74,12 @@ class Model(models.Model):
view, args, kwargs = get_resolver().resolve(id)
return view.initkwargs['model'].objects.get(**kwargs)
@classonlymethod
def resolve_parent(cls, path):
split = path.strip('/').split('/')
parent_path = "/".join(split[0:len(split) - 1])
return Model.resolve_id(parent_path)
@classonlymethod
def resolve_container(cls, path):
path = cls.__clean_path(path)
......
from rest_framework.permissions import BasePermission
from django.core.exceptions import PermissionDenied
from django.db.models.base import ModelBase
from django.urls import Resolver404
from rest_framework.permissions import BasePermission
class LDPPermissions(BasePermission):
......@@ -14,10 +15,18 @@ class LDPPermissions(BasePermission):
authenticated_perms = ['inherit']
owner_perms = ['inherit']
def user_permissions(self, user, model, obj=None):
def user_permissions(self, user, obj_or_model, obj=None):
"""
Filter user permissions for a model class
"""
# sorted out param mess
if isinstance(obj_or_model, ModelBase):
model = obj_or_model
else:
obj = obj_or_model
model = obj_or_model.__class__
# Get Anonymous permissions from Model's Meta. If not found use default
anonymous_perms = getattr(model._meta, 'anonymous_perms', self.anonymous_perms)
......@@ -37,7 +46,9 @@ class LDPPermissions(BasePermission):
return anonymous_perms
else:
if obj and hasattr(model._meta, 'owner_field') and (getattr(obj, getattr(model._meta, 'owner_field')) == user or getattr(obj, getattr(model._meta, 'owner_field')) == user.id):
if obj and hasattr(model._meta, 'owner_field') and (
getattr(obj, getattr(model._meta, 'owner_field')) == user or getattr(obj, getattr(model._meta,
'owner_field')) == user.id):
return owner_perms
else:
......@@ -45,14 +56,7 @@ class LDPPermissions(BasePermission):
def filter_user_perms(self, user, obj_or_model, permissions):
# Only used on Model.get_permissions to translate permissions to LDP
if isinstance(obj_or_model, ModelBase):
model = obj_or_model
obj = None
else:
obj = obj_or_model
model = obj_or_model.__class__
return [perm for perm in permissions if perm in self.user_permissions(user, model, obj)]
return [perm for perm in permissions if perm in self.user_permissions(user, obj_or_model)]
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
......@@ -83,14 +87,20 @@ class LDPPermissions(BasePermission):
"""
Access to containers
"""
model = view.model
perms = self.get_permissions(request.method, model)
from djangoldp.models import Model
if self.is_a_container(request._request.path):
try:
obj = Model.resolve_parent(request.path)
model = view.parent_model
except Resolver404:
obj = None
model = view.model
else:
obj = Model.resolve_id(request._request.path)
model = view.model
try:
obj = view.model.resolve_id(request._request.path)
except:
obj = None
perms = self.get_permissions(request.method, model)
for perm in perms:
if not perm.split('.')[1].split('_')[0] in self.user_permissions(request.user, model, obj):
......@@ -98,6 +108,11 @@ class LDPPermissions(BasePermission):
return True
def is_a_container(self, path):
from djangoldp.models import Model
container, id = Model.resolve(path)
return id is None
def has_object_permission(self, request, view, obj):
"""
Access to objects
......@@ -111,4 +126,4 @@ class LDPPermissions(BasePermission):
if not perm.split('.')[1].split('_')[0] in self.user_permissions(request.user, model, obj):
return False
return True
\ No newline at end of file
return True
from collections import OrderedDict, Mapping
from collections import OrderedDict, Mapping, Iterable
from typing import Any
from urllib import parse
......@@ -40,14 +40,39 @@ class LDListMixin:
return [getattr(self, self.child_attr).to_internal_value(item) for item in data]
def to_representation(self, value):
'''
Permission on container :
- Can Add if add permission on contained object's type
- Can view the container is view permission on container model : container obj are filtered by view permission
'''
try:
model = getattr(self, self.child_attr).Meta.model
child_model = getattr(self, self.child_attr).Meta.model
except AttributeError:
model = value.model
child_model = value.model
parent_model = None
if isinstance(value, QuerySet):
value = list(value)
if not isinstance(value, Iterable):
filtered_values = value
container_permissions = Model.get_permissions(child_model, self.context['request'].user, ['view', 'add'])
else:
try:
parent_model = Model.resolve_parent(self.context['request'].path)
except:
parent_model = child_model
filtered_values = list(
filter(lambda v: Model.get_permission_classes(v, [LDPPermissions])[0]().has_object_permission(
self.context['request'], self.context['view'], v), value))
container_permissions = Model.get_permissions(child_model, self.context['request'].user, ['add'])
container_permissions.extend(
Model.get_permissions(parent_model, self.context['request'].user,
['view']))
return {'@id': self.id,
'@type': 'ldp:Container',
'ldp:contains': super().to_representation(value),
'permissions': Model.get_permissions(model, self.context['request'].user, ['view', 'add'])
'ldp:contains': super().to_representation(filtered_values),
'permissions': container_permissions
}
def get_attribute(self, instance):
......@@ -225,7 +250,7 @@ class LDPSerializer(HyperlinkedModelSerializer):
data = super().to_representation(obj)
slug_field = Model.slug_field(obj)
for field in data:
if isinstance(data[field], dict) and'@id' in data[field]:
if isinstance(data[field], dict) and '@id' in data[field]:
data[field]['@id'] = data[field]['@id'].format(Model.container_id(obj), str(getattr(obj, slug_field)))
rdf_type = Model.get_meta(obj, 'rdf_type', None)
rdf_context = Model.get_meta(obj, 'rdf_context', None)
......@@ -252,7 +277,8 @@ class LDPSerializer(HyperlinkedModelSerializer):
serializer_generator = LDPViewSet(model=model_class,
lookup_field=Model.get_meta(model_class, 'lookup_field', 'pk'),
permission_classes=Model.get_meta(model_class,
'permission_classes', [LDPPermissions]),
'permission_classes',
[LDPPermissions]),
fields=Model.get_meta(model_class, 'serializer_fields', []),
nested_fields=Model.get_meta(model_class, 'nested_fields', []))
parent_depth = max(getattr(self.parent.Meta, "depth", 0) - 1, 0)
......@@ -388,7 +414,6 @@ class LDPSerializer(HyperlinkedModelSerializer):
kwargs['required'] = False
return NestedLDPSerializer, kwargs
@classmethod
def many_init(cls, *args, **kwargs):
kwargs['child'] = cls(**kwargs)
......
......@@ -4,7 +4,7 @@ from django.contrib.auth.models import User
from django.test import TestCase
from rest_framework.test import APIRequestFactory, APIClient
from djangoldp.tests.models import Skill, JobOffer
from djangoldp.tests.models import Skill, JobOffer, Post
class TestTemp(TestCase):
......@@ -18,3 +18,4 @@ class TestTemp(TestCase):
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment