fix: Application workspace restrictions (#3385)

This commit is contained in:
shaohuzhang1 2025-06-25 16:56:10 +08:00 committed by GitHub
parent d252a2546e
commit 4a90127a92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 153 additions and 33 deletions

View File

@ -325,7 +325,7 @@ class Query(serializers.Serializer):
auth_target_type="APPLICATION",
workspace_id=workspace_id,
user_id=user_id)} if (
not workspace_manage and is_x_pack_ee) else {
not workspace_manage) else {
'folder_query_set': folder_query_set,
'application_query_set': application_query_set,
'application_custom_sql': application_custom_sql_query_set
@ -551,7 +551,11 @@ class ApplicationOperateSerializer(serializers.Serializer):
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
if not QuerySet(Application).filter(id=self.data.get('application_id')).exists():
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def delete(self, with_valid=True):

View File

@ -7,16 +7,17 @@
@desc:
"""
import hashlib
import uuid_utils.compat as uuid
import uuid_utils.compat as uuid
from django.core.cache import cache
from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from application.models import ApplicationAccessToken
from application.models import ApplicationAccessToken, Application
from common.constants.cache_version import Cache_Version
from common.database_model_manage.database_model_manage import DatabaseModelManage
from common.exception.app_exception import AppApiException
class AccessTokenEditSerializer(serializers.Serializer):
@ -44,6 +45,16 @@ class AccessTokenEditSerializer(serializers.Serializer):
class AccessTokenSerializer(serializers.Serializer):
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def edit(self, instance):
self.is_valid(raise_exception=True)

View File

@ -30,15 +30,17 @@ class EditApplicationKeySerializer(serializers.Serializer):
class ApplicationKeySerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_('application id'))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
application_id = self.data.get("application_id")
application = QuerySet(Application).filter(id=application_id).first()
if application is None:
raise AppApiException(1001, _("Application does not exist"))
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def generate(self, with_valid=True):
if with_valid:
@ -61,10 +63,19 @@ class ApplicationKeySerializer(serializers.Serializer):
QuerySet(ApplicationApiKey).filter(application_id=application_id)]
class Operate(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_('application id'))
api_key_id = serializers.UUIDField(required=True, label=_('ApiKeyId'))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def delete(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)

View File

@ -22,8 +22,9 @@ from django.utils.translation import gettext_lazy as _, gettext
from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE
from rest_framework import serializers
from application.models import Chat
from application.models import Chat, Application
from common.db.search import get_dynamics_model, native_search, native_page_search
from common.exception.app_exception import AppApiException
from common.utils.common import get_file_content
from maxkb.conf import PROJECT_DIR
from maxkb.settings import TIME_ZONE
@ -48,6 +49,7 @@ class ApplicationChatRecordExportRequest(serializers.Serializer):
class ApplicationChatQuerySerializers(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
abstract = serializers.CharField(required=False, allow_blank=True, allow_null=True, label=_("summary"))
start_time = serializers.DateField(format='%Y-%m-%d', label=_("Start time"))
end_time = serializers.DateField(format='%Y-%m-%d', label=_("End time"))
@ -61,6 +63,15 @@ class ApplicationChatQuerySerializers(serializers.Serializer):
message=_("Only supports and|or"), code=500)
])
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def get_end_time(self):
return datetime.datetime.combine(
datetime.datetime.strptime(self.data.get('end_time'), '%Y-%m-%d'),

View File

@ -17,12 +17,12 @@ from django.utils.translation import gettext_lazy as _, gettext
from rest_framework import serializers
from rest_framework.utils.formatting import lazy_format
from application.models import ChatRecord, ApplicationAccessToken
from application.models import ChatRecord, ApplicationAccessToken, Application
from application.serializers.common import ChatInfo
from common.db.search import page_search
from common.exception.app_exception import AppApiException
from common.utils.common import post
from knowledge.models import Paragraph, Document, Problem, ProblemParagraphMapping
from knowledge.models import Paragraph, Document, Problem, ProblemParagraphMapping, Knowledge
from knowledge.serializers.common import get_embedding_model_id_by_knowledge_id, update_document_char_length
from knowledge.serializers.paragraph import ParagraphSerializers
from knowledge.task.embedding import embedding_by_paragraph, embedding_by_paragraph_list
@ -39,12 +39,18 @@ class ChatRecordSerializerModel(serializers.ModelSerializer):
class ChatRecordOperateSerializer(serializers.Serializer):
chat_id = serializers.UUIDField(required=True, label=_("Conversation ID"))
workspace_id = serializers.CharField(required=False, label=_("Workspace ID"))
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
chat_record_id = serializers.UUIDField(required=True, label=_("Conversation record id"))
def is_valid(self, *, debug=False, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
application_access_token = QuerySet(ApplicationAccessToken).filter(
application_id=self.data.get('application_id')).first()
if application_access_token is None:
@ -72,10 +78,20 @@ class ChatRecordOperateSerializer(serializers.Serializer):
class ApplicationChatRecordQuerySerializers(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
chat_id = serializers.UUIDField(required=True, label=_("Chat ID"))
order_asc = serializers.BooleanField(required=False, allow_null=True, label=_("Is it in order"))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def list(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
@ -137,11 +153,24 @@ class ParagraphModel(serializers.ModelSerializer):
class ChatRecordImproveSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
chat_id = serializers.UUIDField(required=True, label=_("Conversation ID"))
chat_record_id = serializers.UUIDField(required=True,
label=_("Conversation record id"))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def get(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
@ -173,6 +202,8 @@ class ApplicationChatRecordImproveInstanceSerializer(serializers.Serializer):
class ApplicationChatRecordAddKnowledgeSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
knowledge_id = serializers.UUIDField(required=True, label=_("Knowledge base id"))
document_id = serializers.UUIDField(required=True, label=_("Document id"))
chat_ids = serializers.ListSerializer(child=serializers.UUIDField(), required=True,
@ -180,6 +211,12 @@ class ApplicationChatRecordAddKnowledgeSerializer(serializers.Serializer):
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
if not Document.objects.filter(id=self.data['document_id'], knowledge_id=self.data['knowledge_id']).exists():
raise AppApiException(500, gettext("The document id is incorrect"))
@ -255,6 +292,19 @@ class ApplicationChatRecordImproveSerializer(serializers.Serializer):
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
query_set = QuerySet(Knowledge).filter(id=self.data.get('knowledge_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Knowledge id does not exist'))
if not QuerySet(Document).filter(id=self.data.get('document_id'),
knowledge_id=self.data.get('knowledge_id')).exists():
raise AppApiException(500, gettext("The document id is incorrect"))

View File

@ -1,7 +1,6 @@
from rest_framework import serializers
from application.models import ApplicationFolder
from knowledge.models import KnowledgeFolder
class ApplicationFolderTreeSerializer(serializers.ModelSerializer):

View File

@ -15,8 +15,9 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from application.models import ApplicationChatUserStats
from application.models import ApplicationChatUserStats, Application
from common.db.search import native_search, get_dynamics_model
from common.exception.app_exception import AppApiException
from common.utils.common import get_file_content
from maxkb.conf import PROJECT_DIR
@ -32,10 +33,20 @@ class ApplicationStatsSerializer(serializers.Serializer):
class ApplicationStatisticsSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
start_time = serializers.DateField(format='%Y-%m-%d', label=_("Start time"))
end_time = serializers.DateField(format='%Y-%m-%d', label=_("End time"))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def get_end_time(self):
return datetime.datetime.combine(
datetime.datetime.strptime(self.data.get('end_time'), '%Y-%m-%d'),

View File

@ -12,7 +12,7 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from application.models import WorkFlowVersion
from application.models import WorkFlowVersion, Application
from common.db.search import page_search
from common.exception.app_exception import AppApiException
@ -40,6 +40,7 @@ class ApplicationVersionSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, label=_("Workspace ID"))
class Query(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
def get_query_set(self, query):
query_set = QuerySet(WorkFlowVersion).filter(application_id=query.get('application_id'))
@ -64,10 +65,20 @@ class ApplicationVersionSerializer(serializers.Serializer):
post_records_handler=lambda v: ApplicationVersionModelSerializer(v).data)
class Operate(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
work_flow_version_id = serializers.UUIDField(required=True,
label=_("Workflow version id"))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get('workspace_id')
query_set = QuerySet(Application).filter(id=self.data.get('application_id'))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _('Application id does not exist'))
def one(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)

View File

@ -14,7 +14,7 @@ from (select application."id"::text,
from application left join "user" on user_id = "user".id
where application."id" in (select target
from workspace_user_resource_permission
where auth_target_type = 'APPLICATION'
${workspace_user_resource_permission_query_set}
and 'VIEW' = any (permission_list))
UNION
select application_folder."id",

View File

@ -37,7 +37,7 @@ class AccessToken(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def put(self, request: Request, workspace_id: str, application_id: str):
return result.success(
AccessTokenSerializer(data={'application_id': application_id}).edit(
AccessTokenSerializer(data={'workspace_id': workspace_id, 'application_id': application_id}).edit(
request.data))
@extend_schema(
@ -54,4 +54,5 @@ class AccessToken(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
)
def get(self, request: Request, workspace_id: str, application_id: str):
return result.success(AccessTokenSerializer(data={'application_id': application_id}).one())
return result.success(
AccessTokenSerializer(data={'workspace_id': workspace_id, 'application_id': application_id}).one())

View File

@ -46,7 +46,8 @@ class ApplicationChat(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str):
return result.success(ApplicationChatQuerySerializers(
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
data={**query_params_to_single_dict(request.query_params), 'workspace_id': workspace_id,
'application_id': application_id,
}).list())
class Page(APIView):
@ -68,7 +69,8 @@ class ApplicationChat(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str, current_page: int, page_size: int):
return result.success(ApplicationChatQuerySerializers(
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
data={**query_params_to_single_dict(request.query_params), 'workspace_id': workspace_id,
'application_id': application_id,
}).page(current_page=current_page,
page_size=page_size))
@ -91,7 +93,8 @@ class ApplicationChat(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def post(self, request: Request, workspace_id: str, application_id: str):
return ApplicationChatQuerySerializers(
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
data={**query_params_to_single_dict(request.query_params), 'workspace_id': workspace_id,
'application_id': application_id,
}).export(request.data)

View File

@ -42,7 +42,8 @@ class ApplicationChatRecord(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str, chat_id: str):
return result.success(ApplicationChatRecordQuerySerializers(
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
data={**query_params_to_single_dict(request.query_params), 'workspace_id': workspace_id,
'application_id': application_id,
'chat_id': chat_id
}).list())
@ -66,7 +67,8 @@ class ApplicationChatRecord(APIView):
def get(self, request: Request, workspace_id: str, application_id: str, chat_id: str, current_page: int,
page_size: int):
return result.success(ApplicationChatRecordQuerySerializers(
data={**query_params_to_single_dict(request.query_params), 'application_id': application_id,
data={**query_params_to_single_dict(request.query_params), 'workspace_id': workspace_id,
'application_id': application_id,
'chat_id': chat_id}).page(
current_page=current_page,
page_size=page_size))
@ -116,7 +118,8 @@ class ApplicationChatRecordAddKnowledge(APIView):
RoleConstants.USER.get_workspace_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def post(self, request: Request, workspace_id: str, application_id: str):
return result.success(ApplicationChatRecordAddKnowledgeSerializer().post_improve(request.data))
return result.success(ApplicationChatRecordAddKnowledgeSerializer(
data={'workspace_id': workspace_id, 'application_id': application_id}).post_improve(request.data))
class ApplicationChatRecordImprove(APIView):
@ -138,7 +141,8 @@ class ApplicationChatRecordImprove(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str, chat_id: str, chat_record_id: str):
return result.success(ChatRecordImproveSerializer(
data={'chat_id': chat_id, 'chat_record_id': chat_record_id}).get())
data={'workspace_id': workspace_id, 'application_id': application_id, 'chat_id': chat_id,
'chat_record_id': chat_record_id}).get())
class ApplicationChatRecordImproveParagraph(APIView):
@ -166,7 +170,8 @@ class ApplicationChatRecordImproveParagraph(APIView):
knowledge_id: str,
document_id: str):
return result.success(ApplicationChatRecordImproveSerializer(
data={'chat_id': chat_id, 'chat_record_id': chat_record_id,
data={'workspace_id': workspace_id, 'application_id': application_id, 'chat_id': chat_id,
'chat_record_id': chat_record_id,
'knowledge_id': knowledge_id, 'document_id': document_id}).improve(request.data))
class Operate(APIView):
@ -191,5 +196,6 @@ class ApplicationChatRecordImproveParagraph(APIView):
document_id: str, paragraph_id: str):
return result.success(ApplicationChatRecordImproveSerializer.Operate(
data={'chat_id': chat_id, 'chat_record_id': chat_record_id, 'workspace_id': workspace_id,
'application_id': application_id,
'knowledge_id': knowledge_id, 'document_id': document_id,
'paragraph_id': paragraph_id}).delete())

View File

@ -38,7 +38,7 @@ class ApplicationStats(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str):
return result.success(
ApplicationStatisticsSerializer(data={'application_id': application_id,
ApplicationStatisticsSerializer(data={'application_id': application_id, 'workspace_id': workspace_id,
'start_time': request.query_params.get(
'start_time'),
'end_time': request.query_params.get(

View File

@ -86,7 +86,7 @@ class ApplicationVersionView(APIView):
def get(self, request: Request, workspace_id: str, application_id: str, work_flow_version_id: str):
return result.success(
ApplicationVersionSerializer.Operate(
data={'user_id': request.user,
data={'user_id': request.user, 'workspace_id': workspace_id,
'application_id': application_id, 'work_flow_version_id': work_flow_version_id}).one())
@extend_schema(
@ -109,6 +109,7 @@ class ApplicationVersionView(APIView):
def put(self, request: Request, workspace_id: str, application_id: str, work_flow_version_id: str):
return result.success(
ApplicationVersionSerializer.Operate(
data={'application_id': application_id, 'work_flow_version_id': work_flow_version_id,
data={'application_id': application_id, 'workspace_id': workspace_id,
'work_flow_version_id': work_flow_version_id,
'user_id': request.user.id}).edit(
request.data))

View File

@ -296,8 +296,9 @@ const getWholeTree = async (user_id: string) => {
const folderTree = cloneDeep((parentRes as unknown as any).data)
if (Object.keys(childrenRes.data).indexOf(item.value) !== -1) {
item.isRole =
childrenRes.data[item.value].length > 0 &&
childrenRes.data[item.value][0].auth_type == 'ROLE'
childrenRes.data[item.value].length > 0 && hasPermission([EditionConst.IS_EE], 'OR')
? childrenRes.data[item.value][0].auth_type == 'ROLE'
: false
folderIdMap = getFolderIdMap(childrenRes.data[item.value])
dfsFolder(folderTree, folderIdMap)
const permissionHalf = {