diff --git a/djangoldp/models.py b/djangoldp/models.py index b9c8c3da681e38eca12bb54307e3c1f08645ecad..f5d3d1a784fb4db0e6fd1118f35dbf0b4ac6d1f1 100644 --- a/djangoldp/models.py +++ b/djangoldp/models.py @@ -326,9 +326,22 @@ class Model(models.Model): if owner_field is None: return False - return (getattr(obj, owner_field) == user - or (hasattr(user, 'urlid') and getattr(obj, owner_field) == user.urlid) - or getattr(obj, owner_field) == user.id) + # owner fields might be nested (e.g. "collection__author") + owner_field_nesting = owner_field.split("__") + if len(owner_field_nesting) > 1: + obj_copy = obj + + for level in owner_field_nesting: + owner_value = getattr(obj_copy, level) + obj_copy = owner_value + + # or they might not be (e.g. "author") + else: + owner_value = getattr(obj, owner_field) + + return (owner_value == user + or (hasattr(user, 'urlid') and owner_value == user.urlid) + or owner_value == user.id) @classmethod def is_external(cls, value): diff --git a/djangoldp/tests/models.py b/djangoldp/tests/models.py index b5acbf26d7b04fd86e4a67d3090e25e306953402..a5fe54eb0babd78393e1d551c2c0e57f85b004b8 100644 --- a/djangoldp/tests/models.py +++ b/djangoldp/tests/models.py @@ -114,6 +114,20 @@ class OwnedResourceVariant(Model): depth = 1 +class OwnedResourceNestedOwnership(Model): + description = models.CharField(max_length=255, blank=True, null=True) + parent = models.ForeignKey(OwnedResource, blank=True, null=True, related_name="owned_resources", + on_delete=models.CASCADE) + + class Meta(Model.Meta): + anonymous_perms = [] + authenticated_perms = [] + owner_perms = ['view', 'delete', 'add', 'change', 'control'] + owner_field = 'parent__user__urlid' + serializer_fields = ['@id', 'description', 'parent'] + depth = 1 + + class UserProfile(Model): description = models.CharField(max_length=255, blank=True, null=True) user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='userprofile', on_delete=models.CASCADE) diff --git a/djangoldp/tests/tests_user_permissions.py b/djangoldp/tests/tests_user_permissions.py index 78cef0f77a0d3a495e430e1e73c7e7838c7b7154..ed1b2c569c0677acc25a793402c383c12a6d3929 100644 --- a/djangoldp/tests/tests_user_permissions.py +++ b/djangoldp/tests/tests_user_permissions.py @@ -4,7 +4,7 @@ from django.conf import settings from django.test import override_settings from rest_framework.test import APIClient, APITestCase from djangoldp.tests.models import JobOffer, LDPDummy, PermissionlessDummy, UserProfile, OwnedResource, \ - NoSuperUsersAllowedModel, ComplexPermissionClassesModel + NoSuperUsersAllowedModel, ComplexPermissionClassesModel, OwnedResourceNestedOwnership import json @@ -229,6 +229,25 @@ class TestUserPermissions(APITestCase): self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data['ldp:contains']), 1) self.assertEqual(response.data['ldp:contains'][0]['@id'], my_resource.urlid) + + # a repeat of the previous test but using a model where the owner_field is nested + def test_list_owned_resources_nested(self): + my_resource = OwnedResource.objects.create(description='test', user=self.user) + my_second_resource = OwnedResource.objects.create(description='test', user=self.user) + another_user = get_user_model().objects.create_user(username='test', email='test@test.com', password='test') + their_resource = OwnedResource.objects.create(description='another test', user=another_user) + + my_nested = OwnedResourceNestedOwnership.objects.create(description="test", parent=my_resource) + my_second_nested = OwnedResourceNestedOwnership.objects.create(description="test", parent=my_second_resource) + their_nested = OwnedResourceNestedOwnership.objects.create(description="test", parent=their_resource) + + response = self.client.get('/ownedresourcenestedownerships/') + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data['ldp:contains']), 2) + ids = [r['@id'] for r in response.data['ldp:contains']] + self.assertIn(my_nested.urlid, ids) + self.assertIn(my_second_nested.urlid, ids) + self.assertNotIn(their_nested.urlid, ids) # I do not have model permissions as an authenticated user, but I am the resources' owner def test_get_owned_resource(self): diff --git a/docs/create_model.md b/docs/create_model.md index 08035c771af9accac76b311e3febca8aa59fcd5e..7c01d381c94a8e5e5158937284befe16b0544ca2 100644 --- a/docs/create_model.md +++ b/docs/create_model.md @@ -354,7 +354,7 @@ class Todo(Model): authenticated_perms = ['inherit', 'add'] # inherits from anonymous owner_perms = ['inherit', 'change', 'control', 'delete'] # inherits from authenticated superuser_perms = ['inherit'] # inherits from owner - owner_field = 'user' + owner_field = 'user' # can be nested, e.g. user__parent ```