mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-07-29 07:14:56 +00:00
perf: resolve permitted_document_ids once before email/share loops
Replaces per-document has_perms_owner_aware calls in the email-document action and bulk share-link-bundle creation with a single permitted_document_ids(request.user) resolution before the loop, reducing DB round-trips while preserving identical permission semantics (including the per-document error message on the bundle endpoint). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRp4kf1mdn9ruv81zWAmh2
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
09c60ea667
commit
6794d6e835
@@ -256,3 +256,27 @@ class TestPermittedDocumentIdsArbitraryPermission:
|
||||
expected_visible=[],
|
||||
expected_hidden=[doc.pk],
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestEmailDocumentPermissionBoundary:
|
||||
def test_email_action_rejects_document_without_view_permission(
|
||||
self,
|
||||
rest_api_client,
|
||||
):
|
||||
owner = User.objects.create_user(username="owner")
|
||||
requester = User.objects.create_user(username="requester")
|
||||
rest_api_client.force_authenticate(user=requester)
|
||||
hidden = DocumentFactory(owner=owner)
|
||||
|
||||
response = rest_api_client.post(
|
||||
"/api/documents/email/",
|
||||
{
|
||||
"documents": [hidden.pk],
|
||||
"addresses": "someone@example.com",
|
||||
"subject": "test",
|
||||
"message": "test",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
@@ -60,7 +60,7 @@ class ShareLinkBundleAPITests(DirectoriesMixin, APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertIn("document_ids", response.data)
|
||||
|
||||
@mock.patch("documents.views.has_perms_owner_aware", return_value=False)
|
||||
@mock.patch("documents.views.permitted_document_ids", return_value=set())
|
||||
def test_create_bundle_rejects_insufficient_permissions(self, perms_mock) -> None:
|
||||
payload = {
|
||||
"document_ids": [self.document.pk],
|
||||
|
||||
@@ -1925,12 +1925,9 @@ class DocumentViewSet(
|
||||
use_archive_version = validated_data.get("use_archive_version", True)
|
||||
|
||||
documents = Document.objects.select_related("owner").filter(pk__in=document_ids)
|
||||
for document in documents:
|
||||
if request.user is not None and not has_perms_owner_aware(
|
||||
request.user,
|
||||
"view_document",
|
||||
document,
|
||||
):
|
||||
if request.user is not None:
|
||||
permitted_ids = set(permitted_document_ids(request.user))
|
||||
if not all(document.pk in permitted_ids for document in documents):
|
||||
return HttpResponseForbidden("Insufficient permissions")
|
||||
|
||||
try:
|
||||
@@ -4505,8 +4502,9 @@ class ShareLinkBundleViewSet(PassUserMixin, ModelViewSet[ShareLinkBundle]):
|
||||
)
|
||||
|
||||
documents = list(documents_qs)
|
||||
permitted_ids = set(permitted_document_ids(request.user))
|
||||
for document in documents:
|
||||
if not has_perms_owner_aware(request.user, "view_document", document):
|
||||
if document.pk not in permitted_ids:
|
||||
raise ValidationError(
|
||||
{
|
||||
"document_ids": _(
|
||||
|
||||
Reference in New Issue
Block a user