mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: add TestConnection API endpoint and corresponding frontend functionality
This commit is contained in:
parent
2735540dd6
commit
fc05d26eaf
|
|
@ -5,11 +5,11 @@ import json
|
|||
import os
|
||||
import pickle
|
||||
import re
|
||||
import requests
|
||||
import tempfile
|
||||
import zipfile
|
||||
from typing import Dict
|
||||
|
||||
import requests
|
||||
import uuid_utils.compat as uuid
|
||||
from django.core import validators
|
||||
from django.db import transaction
|
||||
|
|
@ -356,9 +356,6 @@ class ToolSerializer(serializers.Serializer):
|
|||
ToolCreateRequest(data=instance).is_valid(raise_exception=True)
|
||||
# 校验代码是否包括禁止的关键字
|
||||
ToolExecutor().validate_banned_keywords(instance.get('code', ''))
|
||||
# 校验mcp json
|
||||
if instance.get('tool_type') == ToolType.MCP.value:
|
||||
validate_mcp_config(json.loads(instance.get('code')))
|
||||
|
||||
tool_id = uuid.uuid7()
|
||||
Tool(
|
||||
|
|
@ -386,6 +383,18 @@ class ToolSerializer(serializers.Serializer):
|
|||
'id': tool_id, 'workspace_id': self.data.get('workspace_id')
|
||||
}).one()
|
||||
|
||||
class TestConnection(serializers.Serializer):
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
code = serializers.CharField(required=True, label=_('tool content'))
|
||||
|
||||
def test_connection(self):
|
||||
self.is_valid(raise_exception=True)
|
||||
# 校验代码是否包括禁止的关键字
|
||||
ToolExecutor().validate_banned_keywords(self.data.get('code', ''))
|
||||
# 校验mcp json
|
||||
validate_mcp_config(json.loads(self.data.get('code')))
|
||||
return True
|
||||
|
||||
class Debug(serializers.Serializer):
|
||||
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
|
|
@ -475,9 +484,7 @@ class ToolSerializer(serializers.Serializer):
|
|||
ToolEditRequest(data=instance).is_valid(raise_exception=True)
|
||||
# 校验代码是否包括禁止的关键字
|
||||
ToolExecutor().validate_banned_keywords(instance.get('code', ''))
|
||||
# 校验mcp json
|
||||
if instance.get('tool_type') == ToolType.MCP.value:
|
||||
validate_mcp_config(json.loads(instance.get('code')))
|
||||
|
||||
|
||||
if not QuerySet(Tool).filter(id=self.data.get('id')).exists():
|
||||
raise serializers.ValidationError(_('Tool not found'))
|
||||
|
|
@ -755,7 +762,8 @@ class ToolSerializer(serializers.Serializer):
|
|||
versions = tool.get('versions', [])
|
||||
tool['label'] = tag_dict[tool.get('tags')[0]] if tool.get('tags') else ''
|
||||
tool['version'] = next(
|
||||
(version.get('name') for version in versions if version.get('downloadUrl') == tool['downloadUrl']),
|
||||
(version.get('name') for version in versions if
|
||||
version.get('downloadUrl') == tool['downloadUrl']),
|
||||
)
|
||||
filter_apps.append(tool)
|
||||
|
||||
|
|
@ -836,7 +844,8 @@ class ToolSerializer(serializers.Serializer):
|
|||
raise AppApiException(500, _('Tool does not exist'))
|
||||
# 查找匹配的版本名称
|
||||
version_name = next(
|
||||
(version.get('name') for version in self.data.get('versions') if version.get('downloadUrl') == self.data.get('download_url')),
|
||||
(version.get('name') for version in self.data.get('versions') if
|
||||
version.get('downloadUrl') == self.data.get('download_url')),
|
||||
)
|
||||
res = requests.get(self.data.get('download_url'), timeout=5)
|
||||
tool_data = RestrictedUnpickler(io.BytesIO(res.content)).load().tool
|
||||
|
|
@ -855,7 +864,6 @@ class ToolSerializer(serializers.Serializer):
|
|||
return ToolModelSerializer(tool).data
|
||||
|
||||
|
||||
|
||||
class ToolTreeSerializer(serializers.Serializer):
|
||||
class Query(serializers.Serializer):
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ urlpatterns = [
|
|||
path('workspace/<str:workspace_id>/tool/pylint', views.ToolView.Pylint.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/debug', views.ToolView.Debug.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/tool_list', views.ToolView.Query.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/test_connection', views.ToolView.TestConnection.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>', views.ToolView.Operate.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>/edit_icon', views.ToolView.EditIcon.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>/export', views.ToolView.Export.as_view()),
|
||||
|
|
|
|||
|
|
@ -360,6 +360,31 @@ class ToolView(APIView):
|
|||
'image': request.FILES.get('file')
|
||||
}).edit(request.data))
|
||||
|
||||
class TestConnection(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
@extend_schema(
|
||||
methods=['POST'],
|
||||
description=_("Test tool connection"),
|
||||
summary=_("Test tool connection"),
|
||||
operation_id=_("Test tool connection"), # type: ignore
|
||||
request=ToolReadAPI.get_request(),
|
||||
responses=ToolReadAPI.get_response(),
|
||||
tags=[_("Tool")] # type: ignore
|
||||
)
|
||||
@has_permissions(
|
||||
PermissionConstants.TOOL_CREATE.get_workspace_permission(),
|
||||
PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
|
||||
PermissionConstants.TOOL_EDIT.get_workspace_permission(),
|
||||
PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
|
||||
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
|
||||
)
|
||||
def post(self, request: Request, workspace_id: str):
|
||||
return result.success(ToolSerializer.TestConnection(data={
|
||||
'workspace_id': workspace_id,
|
||||
'code': request.data.get('code'),
|
||||
}).test_connection())
|
||||
|
||||
class InternalTool(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,17 @@ const putTool: (tool_id: string, data: toolData, loading?: Ref<boolean>) => Prom
|
|||
return put(`${prefix}/${tool_id}`, data, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param 参数
|
||||
*/
|
||||
const postToolTestConnection: (data: toolData, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||
data,
|
||||
loading,
|
||||
) => {
|
||||
return post(`${prefix}/test_connection`, data, undefined, loading)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取工具详情
|
||||
* @param tool_id 工具id
|
||||
|
|
@ -176,5 +187,6 @@ export default {
|
|||
delTool,
|
||||
addInternalTool,
|
||||
addStoreTool,
|
||||
updateStoreTool
|
||||
updateStoreTool,
|
||||
postToolTestConnection
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,17 @@ const putTool: (tool_id: string, data: toolData, loading?: Ref<boolean>) => Prom
|
|||
return put(`${prefix.value}/${tool_id}`, data, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param 参数
|
||||
*/
|
||||
const postToolTestConnection: (data: toolData, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||
data,
|
||||
loading,
|
||||
) => {
|
||||
return post(`${prefix.value}/test_connection`, data, undefined, loading)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取工具详情
|
||||
* @param tool_id 工具id
|
||||
|
|
@ -184,5 +195,6 @@ export default {
|
|||
delTool,
|
||||
addInternalTool,
|
||||
addStoreTool,
|
||||
updateStoreTool
|
||||
updateStoreTool,
|
||||
postToolTestConnection
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@
|
|||
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button :loading="loading" @click="testConnection">{{ $t('views.system.test') }}</el-button>
|
||||
<el-button :loading="loading" @click="visible = false">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
|
|
@ -275,6 +276,21 @@ const submit = async (formEl: FormInstance | undefined) => {
|
|||
})
|
||||
}
|
||||
|
||||
function testConnection() {
|
||||
if (!form.value.code) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
loadSharedApi({ type: 'tool', systemType: apiType.value })
|
||||
.postToolTestConnection({ code: form.value.code }, loading)
|
||||
.then(() => {
|
||||
MsgSuccess(t('views.system.testSuccess'))
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const open = (data: any) => {
|
||||
if (data) {
|
||||
isEdit.value = data?.id ? true : false
|
||||
|
|
|
|||
Loading…
Reference in New Issue