mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-08-20 17:53:20 +00:00
perf: migrate single-call Document permission sites to permitted_document_ids (#13507)
* perf: migrate 5 single-call Document permission sites to permitted_document_ids Swaps get_objects_for_user_owner_aware(user, "view_document", Document) for Document.objects.filter(id__in=permitted_document_ids(user)) at 5 read-only, single-call sites: AI chat "ask all documents", bulk-edit _resolve_document_ids all:true branch, SelectionDataView permission check, global search docs bucket, and the statistics endpoint's Document branch. Confirmed all 3 callers of _resolve_document_ids always use the default "view_document" codename before swapping. Added a regression test pinning the AI-chat owner/permission boundary through the real API client, and updated 2 existing mocked tests in test_views.py that asserted on get_objects_for_user_owner_aware for the chat endpoint. * perf: migrate 3 serialisers.py Document permission sites to permitted_document_ids Migrates _get_viewable_duplicates(), PaperlessTaskSerializer.get_duplicate_documents(), and the ShareLinkBundle document field queryset to use permitted_document_ids() instead of get_objects_for_user_owner_aware()/get_objects_for_user(), consolidating onto the shared permission-filtering helper. The is_staff gate in get_duplicate_documents() is preserved as-is. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRp4kf1mdn9ruv81zWAmh2 * refactor: remove dead permission_codename param from _resolve_document_ids The keyword param was unused in the method body since an earlier commit switched it to call permitted_document_ids(user) internally. None of the 3 call sites passed it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs: drop internal task-number reference from AI chat migration test docstring Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5e54259db9
commit
c6cecd3c4e
+10
-22
@@ -177,6 +177,7 @@ from documents.permissions import get_objects_for_user_owner_aware
|
||||
from documents.permissions import has_global_statistics_permission
|
||||
from documents.permissions import has_perms_owner_aware
|
||||
from documents.permissions import has_system_status_permission
|
||||
from documents.permissions import permitted_document_ids
|
||||
from documents.permissions import set_permissions_for_object
|
||||
from documents.plugins.date_parsing import get_date_parser
|
||||
from documents.schema import generate_object_with_permissions_schema
|
||||
@@ -2270,10 +2271,8 @@ class ChatStreamingView(GenericAPIView[Any]):
|
||||
|
||||
documents = [document]
|
||||
else:
|
||||
documents = get_objects_for_user_owner_aware(
|
||||
request.user,
|
||||
"view_document",
|
||||
Document,
|
||||
documents = Document.objects.filter(
|
||||
id__in=permitted_document_ids(request.user),
|
||||
)
|
||||
|
||||
output_language = _get_llm_output_language(ai_config=ai_config, request=request)
|
||||
@@ -2728,7 +2727,6 @@ class DocumentSelectionMixin:
|
||||
*,
|
||||
user: User,
|
||||
validated_data: dict[str, Any],
|
||||
permission_codename: str = "view_document",
|
||||
) -> list[int]:
|
||||
if not validated_data.get("all", False):
|
||||
# if all is not true, just pass through the provided document ids
|
||||
@@ -2741,10 +2739,8 @@ class DocumentSelectionMixin:
|
||||
for key, value in filters.items()
|
||||
if key not in _TANTIVY_SEARCH_PARAM_NAMES
|
||||
}
|
||||
permitted_documents = get_objects_for_user_owner_aware(
|
||||
user,
|
||||
permission_codename,
|
||||
Document,
|
||||
permitted_documents = Document.objects.filter(
|
||||
id__in=permitted_document_ids(user),
|
||||
)
|
||||
# orm-filtered docs
|
||||
filtered_documents = DocumentFilterSet(
|
||||
@@ -3352,10 +3348,8 @@ class SelectionDataView(GenericAPIView[Any]):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
ids = serializer.validated_data.get("documents")
|
||||
permitted_documents = get_objects_for_user_owner_aware(
|
||||
request.user,
|
||||
"documents.view_document",
|
||||
Document,
|
||||
permitted_documents = Document.objects.filter(
|
||||
id__in=permitted_document_ids(request.user),
|
||||
)
|
||||
if permitted_documents.filter(pk__in=ids).count() != len(ids):
|
||||
return HttpResponseForbidden("Insufficient permissions")
|
||||
@@ -3527,10 +3521,8 @@ class GlobalSearchView(PassUserMixin):
|
||||
OBJECT_LIMIT = 3
|
||||
docs = []
|
||||
if request.user.has_perm("documents.view_document"):
|
||||
all_docs = get_objects_for_user_owner_aware(
|
||||
request.user,
|
||||
"view_document",
|
||||
Document,
|
||||
all_docs = Document.objects.filter(
|
||||
id__in=permitted_document_ids(request.user),
|
||||
)
|
||||
if db_only:
|
||||
docs = all_docs.filter(title__icontains=query)[:OBJECT_LIMIT]
|
||||
@@ -3734,11 +3726,7 @@ class StatisticsView(GenericAPIView[Any]):
|
||||
documents = (
|
||||
Document.objects.all()
|
||||
if can_view_global_stats
|
||||
else get_objects_for_user_owner_aware(
|
||||
user,
|
||||
"documents.view_document",
|
||||
Document,
|
||||
)
|
||||
else Document.objects.filter(id__in=permitted_document_ids(user))
|
||||
).filter(root_document__isnull=True)
|
||||
tags = (
|
||||
Tag.objects.all()
|
||||
|
||||
Reference in New Issue
Block a user