]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Support owner and object permissions for advanced queries
authorMichael Shamoon <4887959+shamoon@users.noreply.github.com>
Tue, 13 Dec 2022 06:34:38 +0000 (22:34 -0800)
committerMichael Shamoon <4887959+shamoon@users.noreply.github.com>
Tue, 13 Dec 2022 06:40:31 +0000 (22:40 -0800)
src/documents/index.py
src/documents/serialisers.py
src/documents/views.py

index fe40dc1a83fdf93bf6d563f96533e78961aaa2c1..8a3435e3d6055e2ba4688d041d2f09fc6d487df5 100644 (file)
@@ -6,6 +6,7 @@ from contextlib import contextmanager
 from dateutil.parser import isoparse
 from django.conf import settings
 from documents.models import Document
+from guardian.shortcuts import get_users_with_perms
 from whoosh import classify
 from whoosh import highlight
 from whoosh import query
@@ -49,6 +50,10 @@ def get_schema():
         path=TEXT(sortable=True),
         path_id=NUMERIC(),
         has_path=BOOLEAN(),
+        owner=TEXT(),
+        owner_id=NUMERIC(),
+        has_owner=BOOLEAN(),
+        viewer_id=KEYWORD(commas=True),
     )
 
 
@@ -90,6 +95,11 @@ def open_index_searcher():
 def update_document(writer, doc):
     tags = ",".join([t.name for t in doc.tags.all()])
     tags_ids = ",".join([str(t.id) for t in doc.tags.all()])
+    users_with_perms = get_users_with_perms(
+        doc,
+        only_with_perms_in=["view_document"],
+    )
+    viewer_ids = ",".join([str(u.id) for u in users_with_perms])
     writer.update_document(
         id=doc.pk,
         title=doc.title,
@@ -110,6 +120,10 @@ def update_document(writer, doc):
         path=doc.storage_path.name if doc.storage_path else None,
         path_id=doc.storage_path.id if doc.storage_path else None,
         has_path=doc.storage_path is not None,
+        owner=doc.owner.username if doc.owner else None,
+        owner_id=doc.owner.id if doc.owner else None,
+        has_owner=doc.owner is not None,
+        viewer_id=viewer_ids if viewer_ids else None,
     )
 
 
@@ -168,10 +182,17 @@ class DelayedQuery:
             elif k == "storage_path__isnull":
                 criterias.append(query.Term("has_path", v == "false"))
 
+        user_criterias = [query.Term("has_owner", False)]
+        if "user" in self.query_params:
+            user_criterias.append(query.Term("owner_id", self.query_params["user"]))
+            user_criterias.append(
+                query.Term("viewer_id", str(self.query_params["user"])),
+            )
         if len(criterias) > 0:
+            criterias.append(query.Or(user_criterias))
             return query.And(criterias)
         else:
-            return None
+            return query.Or(user_criterias)
 
     def _get_query_sortedby(self):
         if "ordering" not in self.query_params:
index ab7efe6de72850e810f88480a3f9fc240e8a74eb..6f4dc1ec90dff394b9aa2ab21f66f3b095a7fb07 100644 (file)
@@ -341,7 +341,7 @@ class StoragePathField(serializers.PrimaryKeyRelatedField):
         return StoragePath.objects.all()
 
 
-class DocumentSerializer(DynamicFieldsModelSerializer, OwnedObjectSerializer):
+class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
 
     correspondent = CorrespondentField(allow_null=True)
     tags = TagsField(many=True)
index 86d6075741ea699711e1840ca0d3bc99d36c2b90..ac6f19c19c159e47ef749628a3c190db8b657a4d 100644 (file)
@@ -221,12 +221,12 @@ class DocumentTypeViewSet(ModelViewSet, PassUserMixin):
 
 
 class DocumentViewSet(
+    PassUserMixin,
     RetrieveModelMixin,
     UpdateModelMixin,
     DestroyModelMixin,
     ListModelMixin,
     GenericViewSet,
-    PassUserMixin,
 ):
     model = Document
     queryset = Document.objects.all()
@@ -256,6 +256,7 @@ class DocumentViewSet(
         return Document.objects.distinct()
 
     def get_serializer(self, *args, **kwargs):
+        super().get_serializer(*args, **kwargs)
         fields_param = self.request.query_params.get("fields", None)
         if fields_param:
             fields = fields_param.split(",")
@@ -263,7 +264,6 @@ class DocumentViewSet(
             fields = None
         truncate_content = self.request.query_params.get("truncate_content", "False")
         serializer_class = self.get_serializer_class()
-        kwargs.setdefault("user", self.request.user)  # PassUserMixin
         kwargs.setdefault("context", self.get_serializer_context())
         kwargs.setdefault("fields", fields)
         kwargs.setdefault("truncate_content", truncate_content.lower() in ["true", "1"])
@@ -491,7 +491,7 @@ class DocumentViewSet(
         )
 
 
-class SearchResultSerializer(DocumentSerializer):
+class SearchResultSerializer(DocumentSerializer, PassUserMixin):
     def to_representation(self, instance):
         doc = Document.objects.get(id=instance["id"])
         r = super().to_representation(doc)
@@ -527,6 +527,12 @@ class UnifiedSearchViewSet(DocumentViewSet):
         if self._is_search_request():
             from documents import index
 
+            if hasattr(self.request, "user"):
+                # pass user to query for perms
+                self.request.query_params._mutable = True
+                self.request.query_params["user"] = self.request.user.id
+                self.request.query_params._mutable = False
+
             if "query" in self.request.query_params:
                 query_class = index.DelayedFullTextQuery
             elif "more_like_id" in self.request.query_params: