diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index 49ef6a968cbbced48ec4b78b1fbcb901795f6b87..e61b11ae9be744f392b80fd711bf2eb229bef333 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -1,6 +1,6 @@ from rest_framework import permissions from rest_framework import filters -from guardian.shortcuts import get_objects_for_user, get_user_perms +from guardian.shortcuts import get_objects_for_user """ Liste des actions passées dans views selon le protocole REST : @@ -26,10 +26,12 @@ class WACPermissions(permissions.DjangoObjectPermissions): 'PATCH': ['%(app_label)s.change_%(model_name)s'], 'DELETE': ['%(app_label)s.delete_%(model_name)s'], } + def has_permission(self, request, view): if request.method == 'OPTIONS': return True - return super().has_permission(request, view) + else: + return super().has_permission(request, view) class ObjectFilter(filters.BaseFilterBackend): @@ -41,15 +43,41 @@ 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 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 + else: + return super().has_permission(request, view) + + def has_object_permission(self, request, view, obj): + if view.action == "create": + return True + if hasattr(obj._meta, 'auto_author'): + if request.user == getattr(obj, obj._meta.auto_author): + return True + return super().has_object_permission(request, view) -class AnonymousReadOnly(permissions.DjangoObjectPermissions): +class AnonymousReadOnly(WACPermissions): """ 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 """ + + anonymous_perms = [{'mode': {'@type': 'view'}}] + authenticated_perms = [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'add'}}] + author_perms = [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'add'}}, {'mode': {'@type': 'change'}}] + def has_permission(self, request, view): if view.action in ['list', 'retrieve']: return True @@ -67,27 +95,4 @@ class AnonymousReadOnly(permissions.DjangoObjectPermissions): if author == request.user: return True else: - return super().has_object_permission(request, view, obj) - - -class InboxPermissions(permissions.DjangoObjectPermissions): - """ - 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 - else: - return super().has_permission(request, view) - - def has_object_permission(self, request, view, obj): - if view.action == "create": - return True - if hasattr(obj._meta, 'auto_author'): - if request.user == getattr(obj, obj._meta.auto_author): - return True - return super().has_object_permission(request, view) - + return super().has_object_permission(request, view, obj) \ No newline at end of file diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index adfc85b3eb77dbc94b5232b05abbc07069e74cc6..7107a004793b3dc8d3874ca0915e378ce353c553 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -19,6 +19,7 @@ from rest_framework.utils.serializer_helpers import ReturnDict from djangoldp.fields import LDPUrlField, IdURLField from djangoldp.models import Model +from djangoldp import permissions class LDListMixin: @@ -202,6 +203,18 @@ class LDPSerializer(HyperlinkedModelSerializer): data['@type'] = obj._meta.rdf_type data['permissions'] = [{'mode': {'@type': name.split('_')[0]}} for name in get_perms(self.context['request'].user, obj)] + + if self.context['request'].user.is_anonymous: + data['permissions'] += permissions.AnonymousReadOnly.anonymous_perms + elif self.context['request'].user.is_authenticated: + if hasattr(obj._meta, 'auto_author'): + data['permissions'] += permissions.AnonymousReadOnly.author_perms + else: + data['permissions'] += permissions.AnonymousReadOnly.authenticated_perms + + if hasattr(obj._meta, 'rdf_context'): + data['@context'] = obj._meta.rdf_context + return data def build_standard_field(self, field_name, model_field): diff --git a/djangoldp/tests/tests_anonymous_permissions.py b/djangoldp/tests/tests_anonymous_permissions.py index a8f4ee3f471f3d245c8f92fbd00ecfbd73d08fd8..0e7f59c28169dae87b15420eb1ebf39ce70e9f69 100644 --- a/djangoldp/tests/tests_anonymous_permissions.py +++ b/djangoldp/tests/tests_anonymous_permissions.py @@ -1,6 +1,8 @@ from django.contrib.auth.models import AnonymousUser from django.test import TestCase, RequestFactory +from guardian.shortcuts import get_anonymous_user + from djangoldp.permissions import AnonymousReadOnly from djangoldp.tests.models import JobOffer from djangoldp.views import LDPViewSet @@ -9,8 +11,8 @@ from djangoldp.views import LDPViewSet class TestAnonymousUserPermissions(TestCase): def setUp(self): self.factory = RequestFactory() - # self.c = Client() - self.user = AnonymousUser + self.user = get_anonymous_user() + self.job = JobOffer.objects.create(title="job") def test_get_request_with_anonymousUser(self): request = self.factory.get("/job-offers/") @@ -18,26 +20,36 @@ class TestAnonymousUserPermissions(TestCase): my_view = LDPViewSet.as_view({'get': 'list'}, model=JobOffer, nested_fields=["skills"], - permission_classes=[AnonymousReadOnly]) + 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/") + def test_post_request_with_anonymousUser(self): + request = self.factory.post("/job-offers/") request.user = self.user - my_view = LDPViewSet.as_view({'options': 'create'}, + my_view = LDPViewSet.as_view({'post': 'create'}, model=JobOffer, nested_fields=["skills"], - permission_classes=[AnonymousReadOnly]) + 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/") + def test_put_request_with_anonymousUser(self): + request = self.factory.put("/job-offers/") request.user = self.user - my_view = LDPViewSet.as_view({'options': 'update'}, + my_view = LDPViewSet.as_view({'put': 'update'}, model=JobOffer, nested_fields=["skills"], - permission_classes=[AnonymousReadOnly]) - response = my_view(request) + permission_classes=(AnonymousReadOnly,)) + response = my_view(request, pk=self.job.pk) self.assertEqual(response.status_code, 403) + + def test_patch_request_with_anonymousUser(self): + request = self.factory.patch("/job-offers/") + request.user = self.user + my_view = LDPViewSet.as_view({'patch': 'partial_update'}, + model=JobOffer, + nested_fields=["skills"], + permission_classes=(AnonymousReadOnly,)) + response = my_view(request, pk=self.job.pk) + self.assertEqual(response.status_code, 403) \ No newline at end of file diff --git a/djangoldp/tests/tests_user_permissions.py b/djangoldp/tests/tests_user_permissions.py index 93d2da07ff5d034f21a7f9d9a5c623933028ab6b..cbe38c43fb65b2c97c9f6f278b241ecd13a43953 100644 --- a/djangoldp/tests/tests_user_permissions.py +++ b/djangoldp/tests/tests_user_permissions.py @@ -9,7 +9,6 @@ from djangoldp.views import LDPViewSet 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') self.job = JobOffer.objects.create(title="job") @@ -24,24 +23,24 @@ class TestUserPermissions(TestCase): response = my_view(request) self.assertEqual(response.status_code, 200) - def test_request_options_create_with_user(self): + def test_post_request_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"], + my_view = LDPViewSet.as_view({'post': 'create'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) response = my_view(request) - self.assertEqual(response.status_code, 201) + self.assertEqual(response.status_code, 200) - def test_request_options_update_with_user(self): + def test_put_request_with_user(self): request = self.factory.options('/job-offers/' + str(self.job.pk) + "/") request.user = self.user - my_view = LDPViewSet.as_view({'options': 'update'}, model=JobOffer, nested_fields=["skills"], + my_view = LDPViewSet.as_view({'put': 'update'}, model=JobOffer, nested_fields=["skills"], permission_classes=[AnonymousReadOnly]) response = my_view(request, pk=self.job.pk) self.assertEqual(response.status_code, 200) def test_request_patch_with_user(self): - request = self.factory.patch('/job-offers/' + str(self.job.pk) + "/") + request = self.factory.options('/job-offers/' + str(self.job.pk) + "/") request.user = self.user my_view = LDPViewSet.as_view({'patch': 'partial_update'}, model=JobOffer, nested_fields=["skills"]) response = my_view(request, pk=self.job.pk)