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