From bfe8213b78ea3bda3b942d6474112e13edbde273 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 1 Sep 2026 07:45:47 -0700 Subject: [PATCH] Fix: re-use permitted_object_ids --- src/documents/serialisers.py | 3 +++ src/documents/tests/test_tag_hierarchy.py | 31 +++++++++++++++++++++++ src/documents/views.py | 4 ++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index dcb84b527..4193bed72 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -81,6 +81,7 @@ from documents.permissions import get_document_count_filter_for_user from documents.permissions import get_groups_with_only_permission from documents.permissions import has_perms_owner_aware from documents.permissions import permitted_document_ids +from documents.permissions import restrict_queryset_to_visible from documents.permissions import set_permissions_for_object from documents.regex import validate_regex_pattern from documents.templating.filepath import validate_filepath_template_and_render @@ -661,6 +662,8 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer): .select_related("owner") .annotate(document_count=Count("documents", filter=filter_q)) ) + user = getattr(request, "user", None) if request else self.user + children = restrict_queryset_to_visible(children, user, "view_tag") view = self.context.get("view") ordering = ( diff --git a/src/documents/tests/test_tag_hierarchy.py b/src/documents/tests/test_tag_hierarchy.py index 0bb4c75c5..c50812edc 100644 --- a/src/documents/tests/test_tag_hierarchy.py +++ b/src/documents/tests/test_tag_hierarchy.py @@ -1,5 +1,6 @@ from unittest import mock +from django.contrib.auth.models import Permission from django.contrib.auth.models import User from rest_framework.test import APITestCase @@ -14,6 +15,36 @@ from documents.signals.handlers import run_workflows from documents.tests.utils import DirectoriesMixin +class TestTagHierarchyPermissions(APITestCase): + def test_children_only_include_visible_tags(self) -> None: + owner = User.objects.create_user(username="owner") + requester = User.objects.create_user(username="requester") + requester.user_permissions.add( + Permission.objects.get(codename="view_tag"), + ) + parent = Tag.objects.create(name="Visible parent", owner=requester) + hidden_child = Tag.objects.create( + name="Hidden child", + owner=owner, + tn_parent=parent, + ) + self.client.force_authenticate(user=requester) + + response = self.client.get("/api/tags/") + + assert response.status_code == 200 + parent_result = next( + tag for tag in response.data["results"] if tag["id"] == parent.pk + ) + assert parent_result["children"] == [] + assert hidden_child.pk not in response.data.get("all", []) + + response = self.client.get(f"/api/tags/{parent.pk}/") + + assert response.status_code == 200 + assert response.data["children"] == [] + + class TestTagHierarchy(DirectoriesMixin, APITestCase): def setUp(self) -> None: super().setUp() diff --git a/src/documents/views.py b/src/documents/views.py index c6f0aeb15..4bca07f20 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -635,7 +635,9 @@ class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Tag]): annotate_document_count_for_related_queryset( Tag.objects.filter( pk__in=descendant_pks | {t.pk for t in all_tags}, - ).select_related("owner"), + ) + .filter(pk__in=permitted_object_ids(user, Tag, "view_tag")) + .select_related("owner"), through_model=self.document_count_through, related_object_field=self._get_document_count_source_field(), user=user,