Not bad catches from Copilot, if a little extra secure

This commit is contained in:
stumpylog
2026-08-27 11:37:07 -07:00
parent 8f008a8bf4
commit 16f1427b7a
2 changed files with 25 additions and 8 deletions
+23 -7
View File
@@ -6,6 +6,8 @@ from django.contrib.auth.models import User
from documents.models import Document
from documents.permissions import permitted_object_ids
from documents.permissions import restrict_queryset_to_visible
from documents.permissions import user_is_unrestricted
from paperless.config import AIConfig
from paperless_ai.base_model import ClassificationSuggestions
from paperless_ai.base_model import TaxonomyChoiceDict
@@ -50,19 +52,32 @@ def _fulltext_similar_documents(
similarity - cruder, but far better than no candidates at all.
more_like_this_ids returns only a ranked ID list, no scores, so weight is
synthesized from rank (descending from top_k) rather than claiming a
similarity magnitude that doesn't exist. A superuser is normalized to
``None`` before calling, since the backend's permission filter has no
superuser short-circuit of its own.
similarity magnitude that doesn't exist. An unrestricted user (none, or an
active superuser - see user_is_unrestricted) is normalized to ``None``
before calling, since the backend's permission filter has no superuser
short-circuit of its own. Results are re-checked with
restrict_queryset_to_visible() since Tantivy's indexed permission fields
lag the DB via async reindexing.
"""
from documents.search import get_backend
search_user = None if user is not None and user.is_superuser else user
unrestricted = user_is_unrestricted(user)
search_user = None if unrestricted else user
backend = get_backend()
similar_ids = backend.more_like_this_ids(
document.pk,
user=search_user,
limit=top_k,
)
if not unrestricted:
allowed_ids = set(
restrict_queryset_to_visible(
Document.objects.filter(pk__in=similar_ids),
user,
"view_document",
).values_list("pk", flat=True),
)
similar_ids = [doc_id for doc_id in similar_ids if doc_id in allowed_ids]
return [
SimilarDocument(document_id=doc_id, weight=float(top_k - rank))
for rank, doc_id in enumerate(similar_ids)
@@ -221,9 +236,10 @@ def get_taxonomy_context(
candidates = build_taxonomy_candidates(similar_documents, user)
similar_doc_ids = [s["document_id"] for s in similar_documents]
similar_docs = list(
Document.objects.filter(pk__in=similar_doc_ids)[:max_docs],
)
docs_by_id = Document.objects.in_bulk(similar_doc_ids)
similar_docs = [
docs_by_id[doc_id] for doc_id in similar_doc_ids if doc_id in docs_by_id
][:max_docs]
context_blocks = []
for similar in similar_docs:
text = similar.content[:1000] or ""
+2 -1
View File
@@ -634,6 +634,7 @@ class TestFulltextSimilarDocuments:
- At most 2 results are returned
"""
source = DocumentFactory.create(content="shared overlapping keyword text")
fulltext_backend.add_or_update(source)
for _ in range(4):
fulltext_backend.add_or_update(
DocumentFactory.create(content="shared overlapping keyword text"),
@@ -641,7 +642,7 @@ class TestFulltextSimilarDocuments:
result = _fulltext_similar_documents(source, user=None, top_k=2)
assert len(result) <= 2
assert len(result) == 2
def test_result_shape_is_similar_document(
self,