diff --git a/src/documents/permissions.py b/src/documents/permissions.py index 43b620b02..96151ae0a 100644 --- a/src/documents/permissions.py +++ b/src/documents/permissions.py @@ -19,10 +19,13 @@ class PaperlessObjectPermissions(DjangoObjectPermissions): } def has_object_permission(self, request, view, obj): - if hasattr(obj, "owner") and request.user == obj.owner: - return True + if hasattr(obj, "owner") and obj.owner is not None: + if request.user == obj.owner: + return True + else: + return super().has_object_permission(request, view, obj) else: - return super().has_object_permission(request, view, obj) + return True # no owner class PaperlessAdminPermissions(BasePermission): diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index 08f9f604d..234ef21da 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -88,8 +88,8 @@ class OwnedObjectSerializer(serializers.ModelSerializer): user_object_perms = UserObjectPermission.objects.filter( object_pk=obj.pk, content_type=content_type, - ).values("user", "permission__codename") - return user_object_perms + ).values_list("user", "permission__codename") + return list(user_object_perms) permissions = SerializerMethodField() @@ -164,7 +164,9 @@ class OwnedObjectSerializer(serializers.ModelSerializer): ) def create(self, validated_data): - if self.user and validated_data["owner"] is None: + if self.user and ( + "owner" not in validated_data or validated_data["owner"] is None + ): validated_data["owner"] = self.user instance = super().create(validated_data) if "grant_permissions" in validated_data: @@ -306,10 +308,6 @@ class TagSerializerVersion1(MatchingModelSerializer): "is_insensitive", "is_inbox_tag", "document_count", - "owner", - "permissions", - "grant_permissions", - "revoke_permissions", ) @@ -342,6 +340,10 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer): "is_insensitive", "is_inbox_tag", "document_count", + "owner", + "permissions", + "grant_permissions", + "revoke_permissions", ) def validate_color(self, color): @@ -461,6 +463,9 @@ class SavedViewSerializer(OwnedObjectSerializer): rules_data = validated_data.pop("filter_rules") else: rules_data = None + if "user" in validated_data: + # backwards compatibility + validated_data["owner"] = validated_data.pop("user") super().update(instance, validated_data) if rules_data is not None: SavedViewFilterRule.objects.filter(saved_view=instance).delete() @@ -470,6 +475,9 @@ class SavedViewSerializer(OwnedObjectSerializer): def create(self, validated_data): rules_data = validated_data.pop("filter_rules") + if "user" in validated_data: + # backwards compatibility + validated_data["owner"] = validated_data.pop("user") saved_view = SavedView.objects.create(**validated_data) for rule_data in rules_data: SavedViewFilterRule.objects.create(saved_view=saved_view, **rule_data) diff --git a/src/documents/tests/test_api.py b/src/documents/tests/test_api.py index b6b52cd68..2b937867c 100644 --- a/src/documents/tests/test_api.py +++ b/src/documents/tests/test_api.py @@ -1158,21 +1158,21 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): u2 = User.objects.create_superuser("user2") v1 = SavedView.objects.create( - user=u1, + owner=u1, name="test1", sort_field="", show_on_dashboard=False, show_in_sidebar=False, ) v2 = SavedView.objects.create( - user=u2, + owner=u2, name="test2", sort_field="", show_on_dashboard=False, show_in_sidebar=False, ) v3 = SavedView.objects.create( - user=u2, + owner=u2, name="test3", sort_field="", show_on_dashboard=False, @@ -1219,7 +1219,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): v1 = SavedView.objects.get(name="test") self.assertEqual(v1.sort_field, "created2") self.assertEqual(v1.filter_rules.count(), 1) - self.assertEqual(v1.user, self.user) + self.assertEqual(v1.owner, self.user) response = self.client.patch( f"/api/saved_views/{v1.id}/", @@ -3015,17 +3015,13 @@ class TestApiUser(APITestCase): response = self.client.get(self.ENDPOINT) self.assertEqual(response.status_code, 200) - self.assertEqual(response.data["count"], 2) - returned_user1 = response.data["results"][1] + self.assertEqual(response.data["count"], 3) # AnonymousUser + returned_user2 = response.data["results"][2] - from pprint import pprint - - pprint(returned_user1) - - self.assertEqual(returned_user1["username"], user1.username) - self.assertEqual(returned_user1["password"], "**********") - self.assertEqual(returned_user1["first_name"], user1.first_name) - self.assertEqual(returned_user1["last_name"], user1.last_name) + self.assertEqual(returned_user2["username"], user1.username) + self.assertEqual(returned_user2["password"], "**********") + self.assertEqual(returned_user2["first_name"], user1.first_name) + self.assertEqual(returned_user2["last_name"], user1.last_name) def test_create_user(self): """ diff --git a/src/documents/tests/test_management_exporter.py b/src/documents/tests/test_management_exporter.py index fa7567f05..7114e7f76 100644 --- a/src/documents/tests/test_management_exporter.py +++ b/src/documents/tests/test_management_exporter.py @@ -124,7 +124,7 @@ class TestExportImport(DirectoriesMixin, TestCase): manifest = self._do_export(use_filename_format=use_filename_format) - self.assertEqual(len(manifest), 11) + self.assertEqual(len(manifest), 12) self.assertEqual( len(list(filter(lambda e: e["model"] == "documents.document", manifest))), 4, diff --git a/src/documents/tests/test_management_superuser.py b/src/documents/tests/test_management_superuser.py index d5fa86ce3..b79a9f9a6 100644 --- a/src/documents/tests/test_management_superuser.py +++ b/src/documents/tests/test_management_superuser.py @@ -31,8 +31,8 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): out = self.call_command(environ={}) # just the consumer user which is created - # during migration - self.assertEqual(User.objects.count(), 1) + # during migration, and AnonymousUser + self.assertEqual(User.objects.count(), 2) self.assertTrue(User.objects.filter(username="consumer").exists()) self.assertEqual(User.objects.filter(is_superuser=True).count(), 0) self.assertEqual( @@ -50,10 +50,10 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) - # count is 2 as there's the consumer - # user already created during migration + # count is 3 as there's the consumer + # user already created during migration, and AnonymousUser user: User = User.objects.get_by_natural_key("admin") - self.assertEqual(User.objects.count(), 2) + self.assertEqual(User.objects.count(), 3) self.assertTrue(user.is_superuser) self.assertEqual(user.email, "root@localhost") self.assertEqual(out, 'Created superuser "admin" with provided password.\n') @@ -70,7 +70,7 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) - self.assertEqual(User.objects.count(), 2) + self.assertEqual(User.objects.count(), 3) with self.assertRaises(User.DoesNotExist): User.objects.get_by_natural_key("admin") self.assertEqual( @@ -91,7 +91,7 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) - self.assertEqual(User.objects.count(), 2) + self.assertEqual(User.objects.count(), 3) user: User = User.objects.get_by_natural_key("admin") self.assertTrue(user.check_password("password")) self.assertEqual(out, "Did not create superuser, a user admin already exists\n") @@ -110,7 +110,7 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): out = self.call_command(environ={"PAPERLESS_ADMIN_PASSWORD": "123456"}) - self.assertEqual(User.objects.count(), 2) + self.assertEqual(User.objects.count(), 3) user: User = User.objects.get_by_natural_key("admin") self.assertTrue(user.check_password("password")) self.assertFalse(user.is_superuser) @@ -149,7 +149,7 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): ) user: User = User.objects.get_by_natural_key("admin") - self.assertEqual(User.objects.count(), 2) + self.assertEqual(User.objects.count(), 3) self.assertTrue(user.is_superuser) self.assertEqual(user.email, "hello@world.com") self.assertEqual(user.username, "admin") @@ -173,7 +173,7 @@ class TestManageSuperUser(DirectoriesMixin, TestCase): ) user: User = User.objects.get_by_natural_key("super") - self.assertEqual(User.objects.count(), 2) + self.assertEqual(User.objects.count(), 3) self.assertTrue(user.is_superuser) self.assertEqual(user.email, "hello@world.com") self.assertEqual(user.username, "super") diff --git a/src/documents/views.py b/src/documents/views.py index 8b01f0be1..8af4e1477 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -174,14 +174,16 @@ class CorrespondentViewSet(ModelViewSet, PassUserMixin): ) -class TagViewSet(ModelViewSet, PassUserMixin): +class TagViewSet(ModelViewSet): model = Tag queryset = Tag.objects.annotate(document_count=Count("documents")).order_by( Lower("name"), ) - def get_serializer_class(self): + def get_serializer_class(self, *args, **kwargs): + # from UserPassMixin + kwargs.setdefault("user", self.request.user) if int(self.request.version) == 1: return TagSerializerVersion1 else: @@ -189,7 +191,11 @@ class TagViewSet(ModelViewSet, PassUserMixin): pagination_class = StandardPagination permission_classes = (IsAuthenticated, PaperlessObjectPermissions) - filter_backends = (DjangoFilterBackend, OrderingFilter) + filter_backends = ( + DjangoFilterBackend, + OrderingFilter, + ObjectOwnedOrGrandtedPermissionsFilter, + ) filterset_class = TagFilterSet ordering_fields = ("name", "matching_algorithm", "match", "document_count") @@ -204,7 +210,11 @@ class DocumentTypeViewSet(ModelViewSet, PassUserMixin): serializer_class = DocumentTypeSerializer pagination_class = StandardPagination permission_classes = (IsAuthenticated, PaperlessObjectPermissions) - filter_backends = (DjangoFilterBackend, OrderingFilter) + filter_backends = ( + DjangoFilterBackend, + OrderingFilter, + ObjectOwnedOrGrandtedPermissionsFilter, + ) filterset_class = DocumentTypeFilterSet ordering_fields = ("name", "matching_algorithm", "match", "document_count")