diff --git a/apps/models_provider/serializers/model_serializer.py b/apps/models_provider/serializers/model_serializer.py index e4720266a63..6f9abf1d6df 100644 --- a/apps/models_provider/serializers/model_serializer.py +++ b/apps/models_provider/serializers/model_serializer.py @@ -316,9 +316,11 @@ class Create(serializers.Serializer): credential = serializers.DictField(required=True, label=_("certification information")) workspace_id = serializers.CharField(required=False, label=_("workspace id"), max_length=128) - def is_valid(self, *, raise_exception=False): + def is_valid(self, *, raise_exception=False, workspace_id=None): if not super().is_valid(raise_exception=raise_exception): return False + if workspace_id is None: + workspace_id = self.data.get("workspace_id", "None") provider = self.data.get("provider") try: provider_handler = ModelProvideConstants[provider] @@ -342,11 +344,7 @@ def is_valid(self, *, raise_exception=False): 400, _("The field and default_value fields are required for the {index}th item").format(index=index), ) - if ( - QuerySet(Model) - .filter(name=self.data.get("name"), workspace_id=self.data.get("workspace_id", "None")) - .exists() - ): + if QuerySet(Model).filter(name=self.data.get("name"), workspace_id=workspace_id).exists(): raise AppApiException( 500, _("base model【{model_name}】already exists").format(model_name=self.data.get("name")) ) @@ -364,7 +362,7 @@ def insert(self, workspace_id, with_valid=True): status = Status.SUCCESS if with_valid: try: - self.is_valid(raise_exception=True) + self.is_valid(raise_exception=True, workspace_id=workspace_id) except AppApiException as e: if e.code == ValidCode.model_not_fount: status = Status.DOWNLOAD diff --git a/apps/oss/serializers/file.py b/apps/oss/serializers/file.py index 5d126af842f..bafdfe74cfa 100644 --- a/apps/oss/serializers/file.py +++ b/apps/oss/serializers/file.py @@ -40,7 +40,7 @@ from knowledge.services import validate_knowledge_file_size from maxkb.const import CONFIG from rest_framework import serializers -from system_manage.models import ChatUserApiKey, WorkspaceUserResourcePermission +from system_manage.models import ChatUserApiKey, WorkspaceUserGroupResourcePermission, WorkspaceUserResourcePermission from system_manage.models.resource_mapping import ResourceMapping, ResourceType from tools.serializers.tool import UploadedFileField from users.models import User @@ -417,7 +417,7 @@ def _check_workspace_resource_permission( else ["VIEW", "MANAGE"] ) if ( - not QuerySet(WorkspaceUserResourcePermission) + QuerySet(WorkspaceUserResourcePermission) .filter( target=target_id, workspace_id=workspace_id, @@ -427,7 +427,20 @@ def _check_workspace_resource_permission( ) .exists() ): - _deny() + return + if ( + QuerySet(WorkspaceUserGroupResourcePermission) + .filter( + target=target_id, + workspace_id=workspace_id, + user_group__user_relations__user_id=user_id, + auth_target_type=auth_target_type, + permission_list__overlap=permission_list, + ) + .exists() + ): + return + _deny() class FileSerializer(serializers.Serializer): diff --git a/apps/oss/tests/test_file_permissions.py b/apps/oss/tests/test_file_permissions.py index 7fe46bb8d38..a78ba0eb5a4 100644 --- a/apps/oss/tests/test_file_permissions.py +++ b/apps/oss/tests/test_file_permissions.py @@ -9,7 +9,7 @@ from common.exception.app_exception import AppUnauthorizedFailed from knowledge.models import Document, File, FileSourceType, Knowledge, Paragraph from oss.serializers.file import FileSerializer, _auth_system, _check_workspace_resource_permission -from system_manage.models import WorkspaceUserResourcePermission +from system_manage.models import WorkspaceUserGroupResourcePermission, WorkspaceUserResourcePermission from users.models import User @@ -19,6 +19,9 @@ def setUp(self): self.grants = MagicMock() self.grants.filter.return_value = self.grants self.grants.exists.return_value = False + self.group_grants = MagicMock() + self.group_grants.filter.return_value = self.group_grants + self.group_grants.exists.return_value = False self.user_query = MagicMock() self.user_query.filter.return_value.first.return_value = SimpleNamespace(id="user") self.document_query = MagicMock() @@ -32,6 +35,7 @@ def setUp(self): Paragraph: self.document_query, Knowledge: self.knowledge_query, WorkspaceUserResourcePermission: self.grants, + WorkspaceUserGroupResourcePermission: self.group_grants, }[model] self.enterContext(patch("oss.serializers.file.get_auth", return_value=self.auth)) self.file = File(source_type=FileSourceType.DOCUMENT, source_id="document") @@ -73,6 +77,17 @@ def test_explicit_view_and_manage_grants_allow_source_file_reads(self): permission_list__overlap=["VIEW", "MANAGE"], ) + def test_user_group_view_and_manage_grants_allow_source_file_reads(self): + self.group_grants.exists.return_value = True + _auth_system(self.file, "user") + self.group_grants.filter.assert_called_once_with( + target="knowledge", + workspace_id="ws", + user_group__user_relations__user_id="user", + auth_target_type="KNOWLEDGE", + permission_list__overlap=["VIEW", "MANAGE"], + ) + def test_custom_workspace_manager_uses_the_permission_object(self): self.auth.roles = {"EXTENDS_WORKSPACE_MANAGE:w:ws"} self.auth.permissions = {"KNOWLEDGE_WORKSPACE_MANAGE:w:ws": PermissionConstants.KNOWLEDGE_READ.value.bit()}