From ee08ecad536e5de1e4493f9bdb1bd56283f6adf3 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Fri, 25 Jan 2019 15:48:00 +0100 Subject: [PATCH 1/7] Fix bug #74: Container include a @type": "ldp:Container" Changed the behavior of the serialization in LDListMixin tho that it includes @type: ldp:Container --- README.md | 33 ++++++++++----------------------- djangoldp/serializers.py | 4 +++- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index e8525f1c..a565c835 100644 --- a/README.md +++ b/README.md @@ -144,12 +144,14 @@ class MyModel(models.Model): ## permissions This allows you to add permissions for AnonymousUser, logged in user, author ... in the url: Currently, there are 3 choices : -* PublicPostPermissions -* PrivateProjectPermissions -* NotificationsPermissions +* ObjectPermission +* AnonymousReadOnly +* InboxPermissions Specific permissin classes can be developed to fit special needs. -PublicPostPermissions gives these permissions: +ObjectPermission give permissions assign in the administration + +AnonymousReadOnly gives these permissions: * Anonymous users: can read all posts * Logged in users: can read all posts + create new posts * Author: can read all posts + create new posts + update their own @@ -157,30 +159,15 @@ PublicPostPermissions gives these permissions: ``` from django.conf.urls import url from djangoldp.views import LDPViewSet -from djangoldp.permissions import PublicPostPermissions +from djangoldp.permissions import AnonymousReadOnly urlpatterns = [ - url(r'^projects/', ProjectViewSet.urls(permission_classes=(PublicPostPermissions,))), + url(r'^projects/', ProjectViewSet.urls(permission_classes=(AnonymousReadOnly,))), url(r'^customers/', LDPViewSet.urls(model=Customer)), ] ``` -PrivateProjectPermissions provides the following -* Anonymous users: no permissions -* Logged in users: can read projects if they're in the team -* Users of group Partners: can see all projects + update all projects - -``` -from django.conf.urls import url -from djangoldp.views import LDPViewSet -from djangoldp.permissions import PrivateProjectPermissions - -urlpatterns = [ - url(r'^projects/', ProjectViewSet.urls(permission_classes=(PrivateProjectPermissions,))), - url(r'^customers/', LDPViewSet.urls(model=Customer)), -] -``` -NotificationsPermissions is used for, well, notifications: +InboxPermissions is used for, well, notifications: * Anonymous users: can create notifications but can't read * Logged in users: can create notifications but can't read * Inbox owners: can read + update all notifications @@ -191,7 +178,7 @@ from djangoldp.views import LDPViewSet from djangoldp.permissions import NotificationsPermissions urlpatterns = [ - url(r'^projects/', ProjectViewSet.urls(permission_classes=(NotificationsPermissions,))), + url(r'^projects/', ProjectViewSet.urls(permission_classes=(InboxPermissions,))), url(r'^customers/', LDPViewSet.urls(model=Customer)), ] ``` diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 45336313..958851c8 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -15,7 +15,7 @@ class LDListMixin: data = [data] return [self.child_relation.to_internal_value(item['@id']) for item in data] def to_representation(self, value): - return {'@id': self.id, 'ldp:contains': super().to_representation(value)} + return {'@id': self.id, '@type': 'ldp:Container', 'ldp:contains': super().to_representation(value)} def get_attribute(self, instance): parent_id_field = self.parent.fields[self.parent.url_field_name] context = self.parent.context @@ -89,8 +89,10 @@ class LDPSerializer(HyperlinkedModelSerializer): def to_representation(self, obj): data = super().to_representation(obj) + if hasattr(obj._meta, 'rdf_type'): data['@type'] = obj._meta.rdf_type + data['permissions'] = [{'mode': {'@type': name.split('_')[0]}} for name in get_perms(self.context['request'].user, obj)] return data -- GitLab From 1f3ce706da82deaaedbdb1fd605c3e4586b1622b Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Thu, 31 Jan 2019 12:58:31 +0100 Subject: [PATCH 2/7] WIP: add test for permission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test for djangoldp-joboffer’s permissions --- djangoldp/tests.py | 76 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/djangoldp/tests.py b/djangoldp/tests.py index 7ce503c2..53644644 100644 --- a/djangoldp/tests.py +++ b/djangoldp/tests.py @@ -1,3 +1,75 @@ -from django.test import TestCase +from django.test import TestCase, Client, RequestFactory +from djangoldp.views import LDPViewSet +from djangoldp.permissions import AnonymousReadOnly + +from django.contrib.auth.models import AnonymousUser, User +from djangoldp_joboffer.models import JobOffer + + +class TestUserPermissions (TestCase): + def setUp(self): + self.factory = RequestFactory() +# self.c = Client() + self.user = User.objects.create_user(username='john', email='jlennon@beatles.com', password='glass onion') + + def tearDown(self): + self.user.delete() + + def test_get_with_user(self): + request = self.factory.get('/job-offers/') + request.user = self.user + my_view = LDPViewSet.as_view({'get': 'list'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 200) + + def test_request_options_create_with_user(self): + request = self.factory.options('/job-offers/') + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'create'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 201) + + def test_request_options_update_with_user(self): + request = self.factory.options('/job-offers/') + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'update'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 201) + +class TestAnonymousUserPermissions (TestCase): + def setUp(self): + self.factory = RequestFactory() +# self.c = Client() + self.user = AnonymousUser + + def test_get_request_with_anonymousUser(self): + request = self.factory.get("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'get': 'list'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 200) + + def test_request_options_create_with_anonymousUser(self): + request = self.factory.options("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'create'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 403) + + def test_request_options_update_with_anonymousUser(self): + request = self.factory.options("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'update'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 403) + -# Create your tests here. -- GitLab From 3f7896f3512f9ef618f245b70fa4d902d008e8fd Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Thu, 7 Feb 2019 10:10:39 +0100 Subject: [PATCH 3/7] Bug Fixes: Url ID field Fix bugs: URLField represents ids of resources --- djangoldp/models.py | 6 ++++ djangoldp/serializers.py | 6 +++- djangoldp/tests/tests.py | 77 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/djangoldp/models.py b/djangoldp/models.py index 50b31c6c..02503fb2 100644 --- a/djangoldp/models.py +++ b/djangoldp/models.py @@ -1,5 +1,11 @@ from django.conf import settings from django.db import models +from rest_framework import fields + +class LDPUrlField (fields.URLField): + def to_representation(self, value): + str = super(LDPUrlField, self).to_representation(value) + return {'@id': str} class LDPSource(models.Model): container = models.URLField() diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index dc167525..41bb34d4 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -4,10 +4,12 @@ from django.utils.datastructures import MultiValueDictKeyError from guardian.shortcuts import get_perms from rest_framework.fields import empty from rest_framework.relations import HyperlinkedRelatedField, ManyRelatedField, MANY_RELATION_KWARGS -from rest_framework.serializers import HyperlinkedModelSerializer, ListSerializer +from rest_framework.serializers import HyperlinkedModelSerializer, ListSerializer, ModelSerializer from rest_framework.utils.field_mapping import get_nested_relation_kwargs from rest_framework.utils.serializer_helpers import ReturnDict +from django.db import models as django_models +from djangoldp import models class LDListMixin: def to_internal_value(self, data): @@ -108,6 +110,8 @@ class LDPSerializer(HyperlinkedModelSerializer): serializer_related_field = JsonLdRelatedField serializer_url_field = JsonLdIdentityField + ModelSerializer.serializer_field_mapping [django_models.URLField] = models.LDPUrlField + def get_default_field_names(self, declared_fields, model_info): try: fields = list(self.Meta.model._meta.serializer_fields) diff --git a/djangoldp/tests/tests.py b/djangoldp/tests/tests.py index 647b26c3..fe5de882 100644 --- a/djangoldp/tests/tests.py +++ b/djangoldp/tests/tests.py @@ -43,3 +43,80 @@ class Serializer(TestCase): self.assertEquals(result.title, "job test") self.assertIs(result.skills.count(), 0) + +from django.test import TestCase, Client, RequestFactory +from djangoldp.views import LDPViewSet +from djangoldp.permissions import AnonymousReadOnly + +from django.contrib.auth.models import AnonymousUser, User +from djangoldp_joboffer.models import JobOffer + + +class TestUserPermissions (TestCase): + def setUp(self): + self.factory = RequestFactory() +# self.c = Client() + self.user = User.objects.create_user(username='john', email='jlennon@beatles.com', password='glass onion') + + def tearDown(self): + self.user.delete() + + def test_get_with_user(self): + request = self.factory.get('/job-offers/') + request.user = self.user + my_view = LDPViewSet.as_view({'get': 'list'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 200) + + def test_request_options_create_with_user(self): + request = self.factory.options('/job-offers/') + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'create'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 201) + + def test_request_options_update_with_user(self): + request = self.factory.options('/job-offers/') + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'update'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 201) + + +class TestAnonymousUserPermissions (TestCase): + def setUp(self): + self.factory = RequestFactory() +# self.c = Client() + self.user = AnonymousUser + + def test_get_request_with_anonymousUser(self): + request = self.factory.get("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'get': 'list'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 200) + + def test_request_options_create_with_anonymousUser(self): + request = self.factory.options("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'create'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 403) + + def test_request_options_update_with_anonymousUser(self): + request = self.factory.options("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'options': 'update'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=[AnonymousReadOnly]) + response = my_view(request) + self.assertEqual(response.status_code, 403) + + -- GitLab From 00cdaca814087ef260f2ca6a45d33c7bf176d1d2 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Tue, 12 Feb 2019 14:11:03 +0100 Subject: [PATCH 4/7] add LDPUrlField Bug Fixes: Url ID Field --- djangoldp/fields.py | 10 ++++++++++ djangoldp/models.py | 5 ----- djangoldp/permissions.py | 12 +++++++----- djangoldp/serializers.py | 3 ++- 4 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 djangoldp/fields.py diff --git a/djangoldp/fields.py b/djangoldp/fields.py new file mode 100644 index 00000000..fb4ba855 --- /dev/null +++ b/djangoldp/fields.py @@ -0,0 +1,10 @@ +from django.db import models +from rest_framework import fields + +class IdURLField (fields.URLField): + def to_representation(self, value): + str = super(IdURLField, self).to_representation(value) + return {'@id': str} + +class LDPUrlField (models.URLField): + pass diff --git a/djangoldp/models.py b/djangoldp/models.py index 02503fb2..4a71ef68 100644 --- a/djangoldp/models.py +++ b/djangoldp/models.py @@ -1,11 +1,6 @@ from django.conf import settings from django.db import models -from rest_framework import fields -class LDPUrlField (fields.URLField): - def to_representation(self, value): - str = super(LDPUrlField, self).to_representation(value) - return {'@id': str} class LDPSource(models.Model): container = models.URLField() diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index 90862a84..ed660fc6 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -29,6 +29,8 @@ class WACPermissions(permissions.DjangoObjectPermissions): def has_permission(self, request, view): if request.method == 'OPTIONS': return True + if request.method == 'PATCH': + return True return super().has_permission(request, view) @@ -41,10 +43,10 @@ class ObjectFilter(filters.BaseFilterBackend): objects = get_objects_for_user(request.user, perm, klass=queryset) return objects -class ObjectPermission(permissions.DjangoObjectPermissions): +class ObjectPermission(WACPermissions): filter_class = ObjectFilter -class AnonymousReadOnly(permissions.DjangoObjectPermissions): +class AnonymousReadOnly(WACPermissions): """ Anonymous users: can read all posts Logged in users: can read all posts + create new posts @@ -67,16 +69,15 @@ class AnonymousReadOnly(permissions.DjangoObjectPermissions): if author == request.user: return True else: - return super().has_object_permission(request, view) + return super().has_object_permission(request, view, obj) -class InboxPermissions(permissions.DjangoObjectPermissions): +class InboxPermissions(WACPermissions): """ Anonymous users: can create notifications but can't read Logged in users: can create notifications but can't read Inbox owners: can read + update all notifications """ - filter_class = ObjectFilter def has_permission(self, request, view): if view.action in ['create', 'retrieve', 'update', 'partial_update', 'destroy']: return True @@ -91,3 +92,4 @@ class InboxPermissions(permissions.DjangoObjectPermissions): return True return super().has_object_permission(request, view) +#droit de lecture pour le user connecté qui est le destinataire du message diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 41bb34d4..e9b3919f 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -10,6 +10,7 @@ from rest_framework.utils.serializer_helpers import ReturnDict from django.db import models as django_models from djangoldp import models +from djangoldp import fields class LDListMixin: def to_internal_value(self, data): @@ -110,7 +111,7 @@ class LDPSerializer(HyperlinkedModelSerializer): serializer_related_field = JsonLdRelatedField serializer_url_field = JsonLdIdentityField - ModelSerializer.serializer_field_mapping [django_models.URLField] = models.LDPUrlField + ModelSerializer.serializer_field_mapping [fields.LDPUrlField] = fields.IdURLField def get_default_field_names(self, declared_fields, model_info): try: -- GitLab From 1348706080bbdc97bcfad859f15ccd4582b307cf Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Wed, 13 Feb 2019 15:56:54 +0100 Subject: [PATCH 5/7] Features: add PATCH to Access-Control-Allow-Methods in views New behavior: PATCH is activated --- djangoldp/views.py | 113 ++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 62 deletions(-) diff --git a/djangoldp/views.py b/djangoldp/views.py index 9f38b079..7341a56e 100644 --- a/djangoldp/views.py +++ b/djangoldp/views.py @@ -1,3 +1,4 @@ +from pyld import jsonld from django.apps import apps from django.conf import settings from django.conf.urls import url, include @@ -6,38 +7,33 @@ from django.core.urlresolvers import get_resolver from django.db.utils import OperationalError from django.shortcuts import get_object_or_404 from django.utils.decorators import classonlymethod -from guardian.shortcuts import get_objects_for_user -from pyld import jsonld from rest_framework.authentication import SessionAuthentication -from rest_framework.parsers import JSONParser +from rest_framework.filters import BaseFilterBackend from rest_framework.renderers import JSONRenderer +from rest_framework.parsers import JSONParser +from rest_framework.permissions import DjangoObjectPermissions from rest_framework.viewsets import ModelViewSet - from .models import LDPSource from .serializers import LDPSerializer +from guardian.shortcuts import get_objects_for_user class JSONLDRenderer(JSONRenderer): media_type = 'application/ld+json' - def render(self, data, accepted_media_type=None, renderer_context=None): data["@context"] = settings.LDP_RDF_CONTEXT return super(JSONLDRenderer, self).render(data, accepted_media_type, renderer_context) - class JSONLDParser(JSONParser): media_type = 'application/ld+json' - def parse(self, stream, media_type=None, parser_context=None): data = super(JSONLDParser, self).parse(stream, media_type, parser_context) return jsonld.compact(data, ctx=settings.LDP_RDF_CONTEXT) - class NoCSRFAuthentication(SessionAuthentication): def enforce_csrf(self, request): return - class LDPViewSetGenerator(ModelViewSet): """An extension of ModelViewSet that generates automatically URLs for the model""" model = None @@ -45,7 +41,7 @@ class LDPViewSetGenerator(ModelViewSet): model_prefix = None list_actions = {'get': 'list', 'post': 'create'} detail_actions = {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'} - + @classonlymethod def get_model(cls, **kwargs): '''gets the model in the arguments or in the viewset definition''' @@ -53,18 +49,18 @@ class LDPViewSetGenerator(ModelViewSet): if isinstance(model, str): model = apps.get_model(model) return model - + @classonlymethod def get_lookup_arg(cls, **kwargs): return kwargs.get('lookup_url_kwarg') or cls.lookup_url_kwarg or kwargs.get('lookup_field') or cls.lookup_field - + @classonlymethod def get_detail_expr(cls, lookup_field=None, **kwargs): '''builds the detail url based on the lookup_field''' lookup_field = lookup_field or cls.get_lookup_arg(**kwargs) lookup_group = r'\d' if lookup_field == 'pk' else r'[\w\-\.]' return r'(?P<{}>{}+)/'.format(lookup_field, lookup_group) - + @classonlymethod def urls(cls, **kwargs): kwargs['model'] = cls.get_model(**kwargs) @@ -72,26 +68,23 @@ class LDPViewSetGenerator(ModelViewSet): if kwargs.get('model_prefix'): model_name = '{}-{}'.format(kwargs['model_prefix'], model_name) detail_expr = cls.get_detail_expr(**kwargs) - + urls = [ - url('^$', cls.as_view(cls.list_actions, **kwargs), name='{}-list'.format(model_name)), - url('^' + detail_expr + '$', cls.as_view(cls.detail_actions, **kwargs), - name='{}-detail'.format(model_name)), - ] - + url('^$', cls.as_view(cls.list_actions, **kwargs), name='{}-list'.format(model_name)), + url('^'+detail_expr+'$', cls.as_view(cls.detail_actions, **kwargs), name='{}-detail'.format(model_name)), + ] + for field in kwargs.get('nested_fields') or cls.nested_fields: - urls.append(url('^' + detail_expr + field + '/', LDPNestedViewSet.nested_urls(field, **kwargs))) - + urls.append(url('^'+detail_expr+field+'/', LDPNestedViewSet.nested_urls(field, **kwargs))) + return include(urls) - class LDPViewSet(LDPViewSetGenerator): """An automatically generated viewset that serves models following the Linked Data Platform convention""" fields = None exclude = None - depth = 0 - renderer_classes = (JSONLDRenderer,) - parser_classes =(JSONLDParser,) + renderer_classes = (JSONLDRenderer, ) + parser_classes = (JSONLDParser, ) authentication_classes = (NoCSRFAuthentication,) def __init__(self, **kwargs): @@ -102,45 +95,42 @@ class LDPViewSet(LDPViewSetGenerator): self.filter_backends = p.filter_class self.serializer_class = self.build_serializer() - + + def build_serializer(self): model_name = self.model._meta.object_name.lower() - lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0] - meta_args = {'model': self.model, 'extra_kwargs': {'@id': {'lookup_field': lookup_field}}, 'depth': self.depth, - 'extra_fields': self.nested_fields} + #associer chaque model à une url ---------- get_absolute_url + lookup_field = get_resolver().reverse_dict[model_name+'-detail'][0][0][1][0] + meta_args = {'model': self.model, 'extra_kwargs': {'@id': {'lookup_field': lookup_field}}, 'depth': 2, 'extra_fields': self.nested_fields} if self.fields: meta_args['fields'] = self.fields else: meta_args['exclude'] = self.exclude or () meta_class = type('Meta', (), meta_args) - return type(LDPSerializer)(model_name + 'Serializer', (LDPSerializer,), {'Meta': meta_class}) - + return type(LDPSerializer)(model_name+'Serializer', (LDPSerializer,), {'Meta': meta_class}) + def perform_create(self, serializer, **kwargs): if hasattr(self.model._meta, 'auto_author'): kwargs[self.model._meta.auto_author] = self.request.user serializer.save(**kwargs) - + def get_queryset(self, *args, **kwargs): if self.model: return self.model.objects.all() - perm = "view_{}".format(self.model._meta.model_name.lower()) + perm="view_{}".format(self.model._meta.model_name.lower()) return get_objects_for_user(self.request.user, perm, klass=self.model) else: return super(LDPView, self).get_queryset(*args, **kwargs) - + def dispatch(self, request, *args, **kwargs): response = super(LDPViewSet, self).dispatch(request, *args, **kwargs) response["Access-Control-Allow-Origin"] = request.META.get('HTTP_ORIGIN') - response["Access-Control-Allow-Methods"] = "POST,PUT" + response["Access-Control-Allow-Methods"] = "POST,PUT, PATCH" response["Access-Control-Allow-Headers"] = "Content-Type, if-match" response["Access-Control-Allow-Credentials"] = 'true' response["Accept-Post"] = "application/ld+json" return response - def update(self, request, *args, **kwargs): - response = super().update(request, *args, **kwargs) - return response - class LDPNestedViewSet(LDPViewSet): """A special case of LDPViewSet serving objects of a relation of a given object (e.g. members of a group, or skills of a user)""" parent_model = None @@ -148,24 +138,24 @@ class LDPNestedViewSet(LDPViewSet): related_field = None nested_field = None nested_related_name = None - + def get_parent(self): return get_object_or_404(self.parent_model, **{self.parent_lookup_field: self.kwargs[self.parent_lookup_field]}) - + def perform_create(self, serializer, **kwargs): kwargs[self.nested_related_name] = self.get_parent() super().perform_create(serializer, **kwargs) - + def get_queryset(self, *args, **kwargs): if self.related_field.many_to_many or self.related_field.one_to_many: return getattr(self.get_parent(), self.nested_field).all() if self.related_field.many_to_one or self.related_field.one_to_one: return [getattr(self.get_parent(), self.nested_field)] - + @classonlymethod def get_related_fields(cls, model): - return {field.get_accessor_name(): field for field in model._meta.fields_map.values()} - + return {field.get_accessor_name():field for field in model._meta.fields_map.values()} + @classonlymethod def nested_urls(cls, nested_field, **kwargs): try: @@ -176,31 +166,30 @@ class LDPNestedViewSet(LDPViewSet): nested_related_name = related_field.related_query_name() else: nested_related_name = related_field.remote_field.name - + return cls.urls( - model=related_field.related_model, - exclude=(nested_related_name,) if related_field.one_to_many else (), - parent_model=cls.get_model(**kwargs), - nested_field=nested_field, - nested_related_name=nested_related_name, - related_field=related_field, - parent_lookup_field=cls.get_lookup_arg(**kwargs), - model_prefix=cls.get_model(**kwargs)._meta.object_name.lower(), - permission_classes=kwargs.get('permission_classes', ()), - lookup_url_kwarg=related_field.related_model._meta.object_name.lower() + '_id') - + model = related_field.related_model, + exclude = (nested_related_name,) if related_field.one_to_many else (), + parent_model = cls.get_model(**kwargs), + nested_field = nested_field, + nested_related_name = nested_related_name, + related_field = related_field, + parent_lookup_field = cls.get_lookup_arg(**kwargs), + model_prefix = cls.get_model(**kwargs)._meta.object_name.lower(), + permission_classes = kwargs.get('permission_classes', ()), + lookup_url_kwarg = related_field.related_model._meta.object_name.lower()+'_id') class LDPSourceViewSet(LDPViewSet): model = LDPSource federation = None - + @classonlymethod def urls(cls, **kwargs): try: - return include([url(name + '/', super(LDPSourceViewSet, cls).urls(federation=name, **kwargs)) - for name in LDPSource.objects.order_by().values_list('federation', flat=True).distinct()]) - except OperationalError: # for the case where the table doesn't exist + return include([url(name+'/', super(LDPSourceViewSet, cls).urls(federation=name, **kwargs)) + for name in LDPSource.objects.order_by().values_list('federation', flat=True).distinct()]) + except OperationalError: #for the case where the table doesn't exist return include([]) - + def get_queryset(self, *args, **kwargs): return super().get_queryset(*args, **kwargs).filter(federation=self.federation) -- GitLab From 9ed86e1b8b4807d82fad7153193bda3fc2520429 Mon Sep 17 00:00:00 2001 From: Thibaud <thibaud@duquennoy.fr> Date: Wed, 13 Feb 2019 15:08:18 +0000 Subject: [PATCH 6/7] Update permissions.py --- djangoldp/permissions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index ed660fc6..aefed327 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -29,8 +29,6 @@ class WACPermissions(permissions.DjangoObjectPermissions): def has_permission(self, request, view): if request.method == 'OPTIONS': return True - if request.method == 'PATCH': - return True return super().has_permission(request, view) -- GitLab From baaa7da7c1ec2d04c7fda461a221b11c18b87751 Mon Sep 17 00:00:00 2001 From: Thibaud <thibaud@duquennoy.fr> Date: Wed, 13 Feb 2019 15:08:18 +0000 Subject: [PATCH 7/7] feature: Url ID field feature: Url ID field --- djangoldp/permissions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index ed660fc6..aefed327 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -29,8 +29,6 @@ class WACPermissions(permissions.DjangoObjectPermissions): def has_permission(self, request, view): if request.method == 'OPTIONS': return True - if request.method == 'PATCH': - return True return super().has_permission(request, view) -- GitLab