From 920cf5f5f65e1cf28cb9676f87616c79e1c84dd4 Mon Sep 17 00:00:00 2001 From: wxg0103 <727495428@qq.com> Date: Fri, 13 Nov 2026 10:57:38 +0800 Subject: [PATCH] fix: enhance folder permission checks by incorporating user group permissions --- apps/folders/serializers/folder.py | 27 +++++--- .../tests/test_folder_tree_permission.py | 67 +++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 apps/folders/tests/test_folder_tree_permission.py diff --git a/apps/folders/serializers/folder.py b/apps/folders/serializers/folder.py index 7b3b9477492..8fa1cdccfb6 100644 --- a/apps/folders/serializers/folder.py +++ b/apps/folders/serializers/folder.py @@ -19,7 +19,7 @@ from knowledge.models import KnowledgeFolder, Knowledge from knowledge.serializers.knowledge import KnowledgeSerializer from knowledge.serializers.knowledge_folder import KnowledgeFolderTreeSerializer -from system_manage.models import WorkspaceUserResourcePermission +from system_manage.models import WorkspaceUserGroupResourcePermission, WorkspaceUserResourcePermission from system_manage.serializers.user_resource_permission import UserResourcePermissionSerializer from tools.models import ToolFolder, Tool from tools.serializers.tool import ToolSerializer @@ -453,14 +453,23 @@ def get_folder_tree(self, current_user, name=None): if having_read_permission_by_role: permission_condition = ["VIEW", "ROLE"] - base_q &= Q( - id__in=WorkspaceUserResourcePermission.objects.filter( - user_id=current_user.id, - auth_target_type=self.data.get("source"), - workspace_id=self.data.get("workspace_id"), - permission_list__overlap=permission_condition, - ).values_list("target", flat=True) - ) | Q(id=self.data.get("workspace_id")) + user_authorized_folder_ids = WorkspaceUserResourcePermission.objects.filter( + user_id=current_user.id, + auth_target_type=self.data.get("source"), + workspace_id=self.data.get("workspace_id"), + permission_list__overlap=permission_condition, + ).values_list("target", flat=True) + group_authorized_folder_ids = WorkspaceUserGroupResourcePermission.objects.filter( + user_group__user_relations__user_id=current_user.id, + auth_target_type=self.data.get("source"), + workspace_id=self.data.get("workspace_id"), + permission_list__overlap=permission_condition, + ).values_list("target", flat=True) + base_q &= ( + Q(id__in=user_authorized_folder_ids) + | Q(id__in=group_authorized_folder_ids) + | Q(id=self.data.get("workspace_id")) + ) nodes = Folder.objects.filter(base_q).get_cached_trees() diff --git a/apps/folders/tests/test_folder_tree_permission.py b/apps/folders/tests/test_folder_tree_permission.py new file mode 100644 index 00000000000..640823a2ab5 --- /dev/null +++ b/apps/folders/tests/test_folder_tree_permission.py @@ -0,0 +1,67 @@ +"""Folder tree honors permissions granted through user groups.""" + +from types import SimpleNamespace +from unittest.mock import patch + +from application.models import ApplicationFolder +from django.test import TestCase +from knowledge.models import KnowledgeFolder +from system_manage.models import WorkspaceUserGroupResourcePermission +from tools.models import ToolFolder +from users.models import User +from users.models.user_group import SystemUserGroup, SystemUserGroupRelation + +from folders.serializers.folder import FolderTreeSerializer + + +class FolderTreeUserGroupPermissionTests(TestCase): + workspace_id = "00000000-0000-0000-0000-000000000010" + user_id = "00000000-0000-0000-0000-000000000011" + group_id = "00000000-0000-0000-0000-000000000012" + allowed_folder_id = "00000000-0000-0000-0000-000000000013" + other_folder_id = "00000000-0000-0000-0000-000000000014" + folder_types = ( + ("KNOWLEDGE", KnowledgeFolder), + ("APPLICATION", ApplicationFolder), + ("TOOL", ToolFolder), + ) + + def setUp(self): + self.user = User.objects.create( + id=self.user_id, + username="folder-tree-user", + nick_name="folder tree user", + password="x", + role="USER", + ) + group = SystemUserGroup.objects.create(id=self.group_id, name="group B", workspace_id=self.workspace_id) + SystemUserGroupRelation.objects.create(user=self.user, group=group) + + for source, folder_model in self.folder_types: + root = folder_model.objects.create(id=self.workspace_id, name="root", workspace_id=self.workspace_id) + folder_model.objects.create( + id=self.allowed_folder_id, name="111", workspace_id=self.workspace_id, parent=root + ) + folder_model.objects.create( + id=self.other_folder_id, name="other", workspace_id=self.workspace_id, parent=root + ) + WorkspaceUserGroupResourcePermission.objects.create( + workspace_id=self.workspace_id, + user_group=group, + auth_target_type=source, + target=self.allowed_folder_id, + permission_list=["VIEW"], + ) + + @patch("folders.serializers.folder.is_workspace_manage", return_value=False) + def test_group_granted_folder_appears_in_each_resource_tree(self, _is_workspace_manage): + for source, _folder_model in self.folder_types: + with self.subTest(source=source): + result = FolderTreeSerializer( + data={"workspace_id": self.workspace_id, "source": source} + ).get_folder_tree(SimpleNamespace(id=self.user_id), name=None) + + root = next(node for node in result if node["id"] == self.workspace_id) + child_ids = [child["id"] for child in root["children"]] + self.assertIn(self.allowed_folder_id, child_ids) + self.assertNotIn(self.other_folder_id, child_ids)