fix: Application import (#3566)

This commit is contained in:
shaohuzhang1 2025-07-11 21:45:08 +08:00 committed by GitHub
parent 109e8507f1
commit 592ae54e82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 233 additions and 99 deletions

View File

@ -34,7 +34,7 @@ from common.database_model_manage.database_model_manage import DatabaseModelMana
from common.db.search import native_search, native_page_search
from common.exception.app_exception import AppApiException
from common.field.common import UploadedFileField
from common.utils.common import get_file_content, valid_license, restricted_loads, generate_uuid
from common.utils.common import get_file_content, restricted_loads, generate_uuid
from knowledge.models import Knowledge, KnowledgeScope
from knowledge.serializers.knowledge import KnowledgeSerializer, KnowledgeModelSerializer
from maxkb.conf import PROJECT_DIR
@ -377,6 +377,7 @@ class Query(serializers.Serializer):
class ApplicationImportRequest(serializers.Serializer):
file = UploadedFileField(required=True, label=_("file"))
folder_id = serializers.CharField(required=True, label=_("Folder ID"))
class ApplicationEditSerializer(serializers.Serializer):
@ -478,16 +479,14 @@ class ApplicationSerializer(serializers.Serializer):
QuerySet(ApplicationKnowledgeMapping).bulk_create(application_knowledge_mapping_model_list)
return ApplicationCreateSerializer.ApplicationResponse(application_model).data
@valid_license(model=Application, count=5,
message=_(
'The community version supports up to 5 applications. If you need more applications, please contact us (https://fit2cloud.com/).'))
@transaction.atomic
def import_(self, instance: dict, with_valid=True):
def import_(self, instance: dict, is_import_tool, with_valid=True):
if with_valid:
self.is_valid()
ApplicationImportRequest(data=instance).is_valid(raise_exception=True)
user_id = self.data.get('user_id')
workspace_id = self.data.get("workspace_id")
folder_id = instance.get('folder_id')
mk_instance_bytes = instance.get('file').read()
try:
mk_instance = restricted_loads(mk_instance_bytes)
@ -498,7 +497,7 @@ class ApplicationSerializer(serializers.Serializer):
update_tool_map = {}
if len(tool_list) > 0:
tool_id_list = reduce(lambda x, y: [*x, *y],
[[tool.get('id'), generate_uuid((tool.get('id') + tool.get('workspace_id') or ''))]
[[tool.get('id'), generate_uuid((tool.get('id') + workspace_id or ''))]
for tool
in
tool_list], [])
@ -506,7 +505,7 @@ class ApplicationSerializer(serializers.Serializer):
exits_tool_id_list = [str(tool.id) for tool in
QuerySet(Tool).filter(id__in=tool_id_list, workspace_id=workspace_id)]
# 需要更新的工具集合
update_tool_map = {tool.get('id'): generate_uuid((tool.get('id') + tool.get('workspace_id') or '')) for tool
update_tool_map = {tool.get('id'): generate_uuid((tool.get('id') + workspace_id or '')) for tool
in
tool_list if
not exits_tool_id_list.__contains__(
@ -515,8 +514,8 @@ class ApplicationSerializer(serializers.Serializer):
tool_list = [{**tool, 'id': update_tool_map.get(tool.get('id'))} for tool in tool_list if
not exits_tool_id_list.__contains__(
tool.get('id')) and not exits_tool_id_list.__contains__(
generate_uuid((tool.get('id') + tool.get('workspace_id') or '')))]
application_model = self.to_application(application, workspace_id, user_id, update_tool_map)
generate_uuid((tool.get('id') + workspace_id or '')))]
application_model = self.to_application(application, workspace_id, user_id, update_tool_map, folder_id)
tool_model_list = [self.to_tool(f, workspace_id, user_id) for f in tool_list]
application_model.save()
# 插入授权数据
@ -528,7 +527,14 @@ class ApplicationSerializer(serializers.Serializer):
# 插入认证信息
ApplicationAccessToken(application_id=application_model.id,
access_token=hashlib.md5(str(uuid.uuid7()).encode()).hexdigest()[8:24]).save()
QuerySet(Tool).bulk_create(tool_model_list) if len(tool_model_list) > 0 else None
if is_import_tool:
if len(tool_model_list) > 0:
QuerySet(Tool).bulk_create(tool_model_list)
UserResourcePermissionSerializer(data={
'workspace_id': self.data.get('workspace_id'),
'user_id': self.data.get('user_id'),
'auth_target_type': AuthTargetType.APPLICATION.value
}).auth_resource_batch([t.id for t in tool_model_list])
return True
@staticmethod
@ -550,7 +556,7 @@ class ApplicationSerializer(serializers.Serializer):
workspace_id=workspace_id)
@staticmethod
def to_application(application, workspace_id, user_id, update_tool_map):
def to_application(application, workspace_id, user_id, update_tool_map, folder_id):
work_flow = application.get('work_flow')
for node in work_flow.get('nodes', []):
if node.get('type') == 'tool-lib-node':
@ -563,7 +569,7 @@ class ApplicationSerializer(serializers.Serializer):
user_id=user_id,
name=application.get('name'),
workspace_id=workspace_id,
folder_id=workspace_id,
folder_id=folder_id,
desc=application.get('desc'),
prologue=application.get('prologue'), dialogue_number=application.get('dialogue_number'),
knowledge_setting=application.get('knowledge_setting'),

View File

@ -7,7 +7,7 @@ app_name = 'application'
urlpatterns = [
path('workspace/<str:workspace_id>/application', views.ApplicationAPI.as_view(), name='application'),
path('workspace/<str:workspace_id>/application/import', views.ApplicationAPI.Import.as_view()),
path('workspace/<str:workspace_id>/application/folder/<str:folder_id>/import', views.ApplicationAPI.Import.as_view()),
path('workspace/<str:workspace_id>/application/<int:current_page>/<int:page_size>', views.ApplicationAPI.Page.as_view(), name='application_page'),
path('workspace/<str:workspace_id>/application/<str:application_id>', views.ApplicationAPI.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/publish', views.ApplicationAPI.Publish.as_view()),

View File

@ -21,7 +21,7 @@ from application.models import Application
from application.serializers.application import ApplicationSerializer, Query, ApplicationOperateSerializer
from common import result
from common.auth import TokenAuth
from common.auth.authentication import has_permissions
from common.auth.authentication import has_permissions, get_is_permissions
from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants
from common.log.log import log
@ -112,10 +112,15 @@ class ApplicationAPI(APIView):
RoleConstants.USER.get_workspace_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
@log(menu='Application', operate="Import Application", )
def post(self, request: Request, workspace_id: str):
def post(self, request: Request, workspace_id: str, folder_id: str):
is_import_tool = get_is_permissions(request, workspace_id=workspace_id, folder_id=folder_id)(
PermissionConstants.TOOL_IMPORT.get_workspace_permission(),
PermissionConstants.TOOL_IMPORT.get_workspace_permission_workspace_manage_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
)
return result.success(ApplicationSerializer(
data={'user_id': request.user.id, 'workspace_id': workspace_id,
}).import_({'file': request.FILES.get('file')}))
}).import_({'file': request.FILES.get('file'), 'folder_id': folder_id}, is_import_tool))
class Export(APIView):
authentication_classes = [TokenAuth]

View File

@ -83,6 +83,16 @@ def exist(user_role: List[RoleConstants], user_permission: List[PermissionConsta
return exist_permissions(user_role, user_permission, permission, request, **kwargs)
def get_is_permissions(request, **kwargs):
def is_permissions(*permission, compare=CompareConstants.OR):
exit_list = list(
map(lambda p: exist(request.auth.role_list, request.auth.permission_list, p, request, **kwargs),
permission))
return any(exit_list) if compare == CompareConstants.OR else all(exit_list)
return is_permissions
def has_permissions(*permission, compare=CompareConstants.OR):
"""
权限 role or permission

View File

@ -130,6 +130,32 @@ class UserResourcePermissionSerializer(serializers.Serializer):
else:
return wurp.permission_list.__contains__(ResourcePermission.VIEW.value)
def auth_resource_batch(self, resource_id_list: list):
self.is_valid(raise_exception=True)
auth_target_type = self.data.get('auth_target_type')
workspace_id = self.data.get('workspace_id')
user_id = self.data.get('user_id')
wurp = QuerySet(WorkspaceUserResourcePermission).filter(auth_target_type=auth_target_type,
workspace_id=workspace_id, user_id=user_id).first()
auth_type = wurp.auth_type if wurp else (
ResourceAuthType.RESOURCE_PERMISSION_GROUP if edition == 'CE' else ResourceAuthType.ROLE)
workspace_user_resource_permission = [WorkspaceUserResourcePermission(
target=resource_id,
auth_target_type=auth_target_type,
permission_list=[ResourcePermission.VIEW,
ResourcePermission.MANAGE] if auth_type == ResourceAuthType.RESOURCE_PERMISSION_GROUP else [
ResourcePermissionRole.ROLE],
workspace_id=workspace_id,
user_id=user_id,
auth_type=auth_type
) for resource_id in resource_id_list]
QuerySet(WorkspaceUserResourcePermission).bulk_create(workspace_user_resource_permission)
# 刷新缓存
version = Cache_Version.PERMISSION_LIST.get_version()
key = Cache_Version.PERMISSION_LIST.get_key(user_id=user_id)
cache.delete(key, version=version)
return True
def auth_resource(self, resource_id: str):
self.is_valid(raise_exception=True)
auth_target_type = self.data.get('auth_target_type')

View File

@ -140,7 +140,6 @@ const putXpackAccessToken: (
return put(`${prefix.value}/${application_id}/setting`, data, undefined, loading)
}
/**
*
*/
@ -161,11 +160,12 @@ const exportApplication = (
/**
*
*/
const importApplication: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading,
) => {
return post(`${prefix.value}/import`, data, undefined, loading)
const importApplication: (
folder_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (folder_id, data, loading) => {
return post(`${prefix.value}/folder/${folder_id}/import`, data, undefined, loading)
}
/**

View File

@ -225,9 +225,7 @@
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
@click.stop="getAccessToken(item.id)"
>
<el-dropdown-item @click.stop="getAccessToken(item.id)">
<AppIcon iconName="app-create-chat"></AppIcon>
{{ $t('views.application.operation.toChat') }}
</el-dropdown-item>
@ -268,8 +266,7 @@
@click.stop="deleteApplication(item)"
v-if="permissionPrecise.delete(item.id)"
>{{ $t('common.delete') }}
</el-dropdown-item
>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@ -366,33 +363,124 @@ const goApp = (item: any) => {
router.push({ path: get_route(item) })
}
const get_route = (item: any) => {
if (hasPermission([new ComplexPermission([RoleConst.USER], [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)], [], 'AND'),
if (
hasPermission(
[
new ComplexPermission(
[RoleConst.USER],
[PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
[],
'AND',
),
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
PermissionConst.APPLICATION_OVERVIEW_READ.getWorkspacePermissionWorkspaceManageRole,
PermissionConst.APPLICATION_OVERVIEW_READ.getApplicationWorkspaceResourcePermission(item.id)], 'OR')) {
PermissionConst.APPLICATION_OVERVIEW_READ.getApplicationWorkspaceResourcePermission(
item.id,
),
],
'OR',
)
) {
return `/application/${item.id}/${item.type}/overview`
} else if (hasPermission([new ComplexPermission([RoleConst.USER], [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)], [], 'AND'),
} else if (
hasPermission(
[
new ComplexPermission(
[RoleConst.USER],
[PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
[],
'AND',
),
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
PermissionConst.APPLICATION_EDIT.getWorkspacePermissionWorkspaceManageRole,
PermissionConst.APPLICATION_EDIT.getApplicationWorkspaceResourcePermission(item.id)], 'OR')) {
PermissionConst.APPLICATION_EDIT.getApplicationWorkspaceResourcePermission(item.id),
],
'OR',
)
) {
if (item.type == 'WORK_FLOW') {
return `/application/${item.id}/workflow`
} else {
return `/application/${item.id}/${item.type}/setting`
}
} else if (hasPermission([new ComplexPermission([RoleConst.USER], [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)], [EditionConst.IS_EE, EditionConst.IS_PE], 'AND'),
new ComplexPermission([RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,], [PermissionConst.APPLICATION_ACCESS_READ.getWorkspacePermissionWorkspaceManageRole], [EditionConst.IS_EE, EditionConst.IS_PE], 'OR'),
new ComplexPermission([], [PermissionConst.APPLICATION_ACCESS_READ.getApplicationWorkspaceResourcePermission(item.id)], [EditionConst.IS_EE, EditionConst.IS_PE], 'OR'),], 'OR')) {
} else if (
hasPermission(
[
new ComplexPermission(
[RoleConst.USER],
[PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
[EditionConst.IS_EE, EditionConst.IS_PE],
'AND',
),
new ComplexPermission(
[RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
[PermissionConst.APPLICATION_ACCESS_READ.getWorkspacePermissionWorkspaceManageRole],
[EditionConst.IS_EE, EditionConst.IS_PE],
'OR',
),
new ComplexPermission(
[],
[
PermissionConst.APPLICATION_ACCESS_READ.getApplicationWorkspaceResourcePermission(
item.id,
),
],
[EditionConst.IS_EE, EditionConst.IS_PE],
'OR',
),
],
'OR',
)
) {
return `/application/${item.id}/${item.type}/access`
} else if (hasPermission([new ComplexPermission([RoleConst.USER], [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)], [EditionConst.IS_EE, EditionConst.IS_PE], 'AND'),
new ComplexPermission([RoleConst.WORKSPACE_MANAGE.getWorkspaceRole], [PermissionConst.APPLICATION_CHAT_USER_READ.getWorkspacePermissionWorkspaceManageRole], [EditionConst.IS_EE, EditionConst.IS_PE], 'OR'),
new ComplexPermission([], [PermissionConst.APPLICATION_CHAT_USER_READ.getApplicationWorkspaceResourcePermission(item.id)], [EditionConst.IS_EE, EditionConst.IS_PE], 'OR'),], 'OR')) {
} else if (
hasPermission(
[
new ComplexPermission(
[RoleConst.USER],
[PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
[EditionConst.IS_EE, EditionConst.IS_PE],
'AND',
),
new ComplexPermission(
[RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
[PermissionConst.APPLICATION_CHAT_USER_READ.getWorkspacePermissionWorkspaceManageRole],
[EditionConst.IS_EE, EditionConst.IS_PE],
'OR',
),
new ComplexPermission(
[],
[
PermissionConst.APPLICATION_CHAT_USER_READ.getApplicationWorkspaceResourcePermission(
item.id,
),
],
[EditionConst.IS_EE, EditionConst.IS_PE],
'OR',
),
],
'OR',
)
) {
return `/application/${item.id}/${item.type}/chat-user`
} else if (hasPermission([new ComplexPermission([RoleConst.USER], [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)], [], 'AND'),
} else if (
hasPermission(
[
new ComplexPermission(
[RoleConst.USER],
[PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
[],
'AND',
),
PermissionConst.APPLICATION_CHAT_LOG_READ.getWorkspacePermissionWorkspaceManageRole,
PermissionConst.APPLICATION_CHAT_LOG_READ.getApplicationWorkspaceResourcePermission(item.id)], 'OR')) {
PermissionConst.APPLICATION_CHAT_LOG_READ.getApplicationWorkspaceResourcePermission(
item.id,
),
],
'OR',
)
) {
return `/application/${item.id}/${item.type}/chat-log`
} else return `/application/`
}
@ -487,8 +575,7 @@ function deleteApplication(row: any) {
MsgSuccess(t('common.deleteSuccess'))
})
})
.catch(() => {
})
.catch(() => {})
}
const exportApplication = (application: any) => {
@ -506,7 +593,7 @@ const importApplication = (file: any) => {
const formData = new FormData()
formData.append('file', file.raw, file.name)
elUploadRef.value.clearFiles()
ApplicationApi.importApplication(formData, loading)
ApplicationApi.importApplication(folder.currentFolder.id, formData, loading)
.then(async (res: any) => {
if (res?.data) {
applicationList.value = []