feat: add import and export endpoints to ToolView for workspace tools

This commit is contained in:
CaptainB 2025-04-22 14:24:44 +08:00 committed by 刘瑞斌
parent 55705593a9
commit bbd7079166
7 changed files with 537 additions and 67 deletions

View File

@ -139,6 +139,12 @@ class PermissionConstants(Enum):
RoleConstants.USER]) RoleConstants.USER])
TOOL_DELETE = Permission(group=Group.TOOL, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN, TOOL_DELETE = Permission(group=Group.TOOL, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
RoleConstants.USER]) RoleConstants.USER])
TOOL_DEBUG = Permission(group=Group.TOOL, operate=Operate.USE, role_list=[RoleConstants.ADMIN,
RoleConstants.USER])
TOOL_IMPORT = Permission(group=Group.TOOL, operate=Operate.USE, role_list=[RoleConstants.ADMIN,
RoleConstants.USER])
TOOL_EXPORT = Permission(group=Group.TOOL, operate=Operate.USE, role_list=[RoleConstants.ADMIN,
RoleConstants.USER])
def get_workspace_application_permission(self): def get_workspace_application_permission(self):
return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate, return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate,

View File

@ -0,0 +1,93 @@
# coding=utf-8
import os
import subprocess
import sys
import uuid
from textwrap import dedent
from diskcache import Cache
from maxkb.const import BASE_DIR
from maxkb.const import PROJECT_DIR
python_directory = sys.executable
class ToolExecutor:
def __init__(self, sandbox=False):
self.sandbox = sandbox
if sandbox:
self.sandbox_path = '/opt/maxkb/app/sandbox'
self.user = 'sandbox'
else:
self.sandbox_path = os.path.join(PROJECT_DIR, 'data', 'sandbox')
self.user = None
self._createdir()
if self.sandbox:
os.system(f"chown -R {self.user}:root {self.sandbox_path}")
def _createdir(self):
old_mask = os.umask(0o077)
try:
os.makedirs(self.sandbox_path, 0o700, exist_ok=True)
finally:
os.umask(old_mask)
def exec_code(self, code_str, keywords):
_id = str(uuid.uuid1())
success = '{"code":200,"msg":"成功","data":exec_result}'
err = '{"code":500,"msg":str(e),"data":None}'
path = r'' + self.sandbox_path + ''
_exec_code = f"""
try:
import os
env = dict(os.environ)
for key in list(env.keys()):
if key in os.environ and (key.startswith('MAXKB') or key.startswith('POSTGRES') or key.startswith('PG')):
del os.environ[key]
locals_v={'{}'}
keywords={keywords}
globals_v=globals()
exec({dedent(code_str)!a}, globals_v, locals_v)
f_name, f = locals_v.popitem()
for local in locals_v:
globals_v[local] = locals_v[local]
exec_result=f(**keywords)
from diskcache import Cache
cache = Cache({path!a})
cache.set({_id!a},{success})
except Exception as e:
from diskcache import Cache
cache = Cache({path!a})
cache.set({_id!a},{err})
"""
if self.sandbox:
subprocess_result = self._exec_sandbox(_exec_code, _id)
else:
subprocess_result = self._exec(_exec_code)
if subprocess_result.returncode == 1:
raise Exception(subprocess_result.stderr)
cache = Cache(self.sandbox_path)
result = cache.get(_id)
cache.delete(_id)
if result.get('code') == 200:
return result.get('data')
raise Exception(result.get('msg'))
def _exec_sandbox(self, _code, _id):
exec_python_file = f'{self.sandbox_path}/{_id}.py'
with open(exec_python_file, 'w') as file:
file.write(_code)
os.system(f"chown {self.user}:{self.user} {exec_python_file}")
kwargs = {'cwd': BASE_DIR}
subprocess_result = subprocess.run(
['su', '-s', python_directory, '-c', "exec(open('" + exec_python_file + "').read())", self.user],
text=True,
capture_output=True, **kwargs)
os.remove(exec_python_file)
return subprocess_result
@staticmethod
def _exec(_code):
return subprocess.run([python_directory, '-c', _code], text=True, capture_output=True)

View File

@ -14,13 +14,15 @@ from modules.serializers.module import ModuleSerializer, ModuleTreeSerializer
class ModuleView(APIView): class ModuleView(APIView):
authentication_classes = [TokenAuth] authentication_classes = [TokenAuth]
@extend_schema(methods=['POST'], @extend_schema(
methods=['POST'],
description=_('Create module'), description=_('Create module'),
operation_id=_('Create module'), operation_id=_('Create module'),
parameters=ModuleCreateAPI.get_parameters(), parameters=ModuleCreateAPI.get_parameters(),
request=ModuleCreateAPI.get_request(), request=ModuleCreateAPI.get_request(),
responses=ModuleCreateAPI.get_response(), responses=ModuleCreateAPI.get_response(),
tags=[_('Module')]) tags=[_('Module')]
)
@has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.CREATE, @has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.CREATE,
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}")) resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}"))
def post(self, request: Request, workspace_id: str, source: str): def post(self, request: Request, workspace_id: str, source: str):
@ -30,12 +32,14 @@ class ModuleView(APIView):
'workspace_id': workspace_id} 'workspace_id': workspace_id}
).insert(request.data)) ).insert(request.data))
@extend_schema(methods=['GET'], @extend_schema(
methods=['GET'],
description=_('Get module tree'), description=_('Get module tree'),
operation_id=_('Get module tree'), operation_id=_('Get module tree'),
parameters=ModuleTreeReadAPI.get_parameters(), parameters=ModuleTreeReadAPI.get_parameters(),
responses=ModuleTreeReadAPI.get_response(), responses=ModuleTreeReadAPI.get_response(),
tags=[_('Module')]) tags=[_('Module')]
)
@has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.READ, @has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.READ,
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}")) resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}"))
def get(self, request: Request, workspace_id: str, source: str): def get(self, request: Request, workspace_id: str, source: str):
@ -46,13 +50,15 @@ class ModuleView(APIView):
class Operate(APIView): class Operate(APIView):
authentication_classes = [TokenAuth] authentication_classes = [TokenAuth]
@extend_schema(methods=['PUT'], @extend_schema(
methods=['PUT'],
description=_('Update module'), description=_('Update module'),
operation_id=_('Update module'), operation_id=_('Update module'),
parameters=ModuleEditAPI.get_parameters(), parameters=ModuleEditAPI.get_parameters(),
request=ModuleEditAPI.get_request(), request=ModuleEditAPI.get_request(),
responses=ModuleEditAPI.get_response(), responses=ModuleEditAPI.get_response(),
tags=[_('Module')]) tags=[_('Module')]
)
@has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.EDIT, @has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.EDIT,
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}")) resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}"))
def put(self, request: Request, workspace_id: str, source: str, module_id: str): def put(self, request: Request, workspace_id: str, source: str, module_id: str):
@ -60,12 +66,14 @@ class ModuleView(APIView):
data={'id': module_id, 'workspace_id': workspace_id, 'source': source} data={'id': module_id, 'workspace_id': workspace_id, 'source': source}
).edit(request.data)) ).edit(request.data))
@extend_schema(methods=['GET'], @extend_schema(
methods=['GET'],
description=_('Get module'), description=_('Get module'),
operation_id=_('Get module'), operation_id=_('Get module'),
parameters=ModuleReadAPI.get_parameters(), parameters=ModuleReadAPI.get_parameters(),
responses=ModuleReadAPI.get_response(), responses=ModuleReadAPI.get_response(),
tags=[_('Module')]) tags=[_('Module')]
)
@has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.READ, @has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.READ,
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}")) resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}"))
def get(self, request: Request, workspace_id: str, source: str, module_id: str): def get(self, request: Request, workspace_id: str, source: str, module_id: str):
@ -73,12 +81,14 @@ class ModuleView(APIView):
data={'id': module_id, 'workspace_id': workspace_id, 'source': source} data={'id': module_id, 'workspace_id': workspace_id, 'source': source}
).one()) ).one())
@extend_schema(methods=['DELETE'], @extend_schema(
methods=['DELETE'],
description=_('Delete module'), description=_('Delete module'),
operation_id=_('Delete module'), operation_id=_('Delete module'),
parameters=ModuleDeleteAPI.get_parameters(), parameters=ModuleDeleteAPI.get_parameters(),
responses=ModuleDeleteAPI.get_response(), responses=ModuleDeleteAPI.get_response(),
tags=[_('Module')]) tags=[_('Module')]
)
@has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.DELETE, @has_permissions(lambda r, kwargs: Permission(group=Group(kwargs.get('source')), operate=Operate.DELETE,
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}")) resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}"))
def delete(self, request: Request, workspace_id: str, source: str, module_id: str): def delete(self, request: Request, workspace_id: str, source: str, module_id: str):

View File

@ -4,7 +4,7 @@ from drf_spectacular.utils import OpenApiParameter
from common.mixins.api_mixin import APIMixin from common.mixins.api_mixin import APIMixin
from common.result import ResultSerializer, DefaultResultSerializer from common.result import ResultSerializer, DefaultResultSerializer
from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest, ToolDebugRequest
class ToolCreateResponse(ResultSerializer): class ToolCreateResponse(ResultSerializer):
@ -91,3 +91,104 @@ class ToolTreeReadAPI(APIMixin):
required=False, required=False,
) )
] ]
class ToolDebugApi(APIMixin):
@staticmethod
def get_request():
return ToolDebugRequest
@staticmethod
def get_response():
return DefaultResultSerializer
class ToolExportAPI(APIMixin):
@staticmethod
def get_parameters():
return [
OpenApiParameter(
name="workspace_id",
description="工作空间id",
type=OpenApiTypes.STR,
location='path',
required=True,
),
OpenApiParameter(
name="tool_id",
description="工具id",
type=OpenApiTypes.STR,
location='path',
required=True,
)
]
@staticmethod
def get_response():
return DefaultResultSerializer
class ToolImportAPI(APIMixin):
@staticmethod
def get_parameters():
return [
OpenApiParameter(
name="workspace_id",
description="工作空间id",
type=OpenApiTypes.STR,
location='path',
required=True,
),
OpenApiParameter(
name='file',
type=OpenApiTypes.BINARY,
description='工具文件',
required=True
),
]
@staticmethod
def get_response():
return DefaultResultSerializer
class ToolPageAPI(ToolReadAPI):
@staticmethod
def get_parameters():
return [
OpenApiParameter(
name="workspace_id",
description="工作空间id",
type=OpenApiTypes.STR,
location='path',
required=True,
),
OpenApiParameter(
name="tool_id",
description="工具id",
type=OpenApiTypes.STR,
location='path',
required=True,
),
OpenApiParameter(
name="current_page",
description="当前页码",
type=OpenApiTypes.INT,
location='path',
required=True,
),
OpenApiParameter(
name="page_size",
description="每页大小",
type=OpenApiTypes.INT,
location='path',
required=True,
),
OpenApiParameter(
name="name",
description="工具名称",
type=OpenApiTypes.STR,
location='query',
required=False,
),
]

View File

@ -1,14 +1,57 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import json
import pickle
import re import re
import uuid_utils.compat as uuid import uuid_utils.compat as uuid
from django.core import validators from django.core import validators
from django.db import transaction
from django.db.models import QuerySet from django.db.models import QuerySet
from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers, status
from common.exception.app_exception import AppApiException
from common.result import result
from common.utils.tool_code import ToolExecutor
from maxkb.const import CONFIG
from tools.models import Tool, ToolScope, ToolModule from tools.models import Tool, ToolScope, ToolModule
tool_executor = ToolExecutor(CONFIG.get('SANDBOX'))
class ToolInstance:
def __init__(self, tool: dict, version: str):
self.tool = tool
self.version = version
def encryption(message: str):
"""
加密敏感字段数据 加密方式是 如果密码是 1234567890 那么给前端则是 123******890
:param message:
:return:
"""
if type(message) != str:
return message
if message == "":
return ""
max_pre_len = 8
max_post_len = 4
message_len = len(message)
pre_len = int(message_len / 5 * 2)
post_len = int(message_len / 5 * 1)
pre_str = "".join([message[index] for index in
range(0,
max_pre_len if pre_len > max_pre_len else 1 if pre_len <= 0 else int(
pre_len))])
end_str = "".join(
[message[index] for index in
range(message_len - (int(post_len) if pre_len < max_post_len else max_post_len),
message_len)])
content = "***************"
return pre_str + content + end_str
class ToolModelSerializer(serializers.ModelSerializer): class ToolModelSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@ -18,6 +61,14 @@ class ToolModelSerializer(serializers.ModelSerializer):
'create_time', 'update_time'] 'create_time', 'update_time']
class UploadedFileField(serializers.FileField):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def to_representation(self, value):
return value
class ToolInputField(serializers.Serializer): class ToolInputField(serializers.Serializer):
name = serializers.CharField(required=True, label=_('variable name')) name = serializers.CharField(required=True, label=_('variable name'))
is_required = serializers.BooleanField(required=True, label=_('required')) is_required = serializers.BooleanField(required=True, label=_('required'))
@ -60,6 +111,20 @@ class ToolCreateRequest(serializers.Serializer):
module_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, default='root') module_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, default='root')
class DebugField(serializers.Serializer):
name = serializers.CharField(required=True, label=_('variable name'))
value = serializers.CharField(required=False, allow_blank=True, allow_null=True, label=_('variable value'))
class ToolDebugRequest(serializers.Serializer):
code = serializers.CharField(required=True, label=_('tool content'))
input_field_list = serializers.ListField(child=ToolInputField(), required=False, default=list,
label=_('input field list'))
init_field_list = serializers.ListField(child=InitField(), required=False, default=list, label=_('init field list'))
init_params = serializers.DictField(required=False, default=dict, label=_('init params'))
debug_field_list = DebugField(required=True, many=True)
class ToolSerializer(serializers.Serializer): class ToolSerializer(serializers.Serializer):
class Create(serializers.Serializer): class Create(serializers.Serializer):
user_id = serializers.UUIDField(required=True, label=_('user id')) user_id = serializers.UUIDField(required=True, label=_('user id'))
@ -82,6 +147,64 @@ class ToolSerializer(serializers.Serializer):
tool.save() tool.save()
return ToolModelSerializer(tool).data return ToolModelSerializer(tool).data
class Debug(serializers.Serializer):
user_id = serializers.UUIDField(required=True, label=_('user id'))
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
def debug(self, debug_instance):
self.is_valid(raise_exception=True)
ToolDebugRequest(data=debug_instance).is_valid(raise_exception=True)
input_field_list = debug_instance.get('input_field_list')
code = debug_instance.get('code')
debug_field_list = debug_instance.get('debug_field_list')
init_params = debug_instance.get('init_params')
params = {field.get('name'): self.convert_value(field.get('name'), field.get('value'), field.get('type'),
field.get('is_required'))
for field in
[{'value': self.get_field_value(debug_field_list, field.get('name'), field.get('is_required')),
**field} for field in
input_field_list]}
# 合并初始化参数
if init_params is not None:
all_params = init_params | params
else:
all_params = params
return tool_executor.exec_code(code, all_params)
@staticmethod
def get_field_value(debug_field_list, name, is_required):
result = [field for field in debug_field_list if field.get('name') == name]
if len(result) > 0:
return result[-1].get('value')
if is_required:
raise AppApiException(500, f"{name}" + _('field has no value set'))
return None
@staticmethod
def convert_value(name: str, value: str, _type: str, is_required: bool):
if not is_required and value is None:
return None
try:
if _type == 'int':
return int(value)
if _type == 'float':
return float(value)
if _type == 'dict':
v = json.loads(value)
if isinstance(v, dict):
return v
raise Exception(_('type error'))
if _type == 'array':
v = json.loads(value)
if isinstance(v, list):
return v
raise Exception(_('type error'))
return value
except Exception as e:
raise AppApiException(500, _('Field: {name} Type: {_type} Value: {value} Type conversion error').format(
name=name, type=_type, value=value
))
class Operate(serializers.Serializer): class Operate(serializers.Serializer):
id = serializers.UUIDField(required=True, label=_('tool id')) id = serializers.UUIDField(required=True, label=_('tool id'))
workspace_id = serializers.CharField(required=True, label=_('workspace id')) workspace_id = serializers.CharField(required=True, label=_('workspace id'))
@ -111,6 +234,52 @@ class ToolSerializer(serializers.Serializer):
tool = QuerySet(Tool).filter(id=self.data.get('id')).first() tool = QuerySet(Tool).filter(id=self.data.get('id')).first()
return ToolModelSerializer(tool).data return ToolModelSerializer(tool).data
def export(self):
try:
self.is_valid()
id = self.data.get('id')
tool = QuerySet(Tool).filter(id=id).first()
tool_dict = ToolModelSerializer(tool).data
mk_instance = ToolInstance(tool_dict, 'v2')
tool_pickle = pickle.dumps(mk_instance)
response = HttpResponse(content_type='text/plain', content=tool_pickle)
response['Content-Disposition'] = f'attachment; filename="{tool.name}.fx"'
return response
except Exception as e:
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class Import(serializers.Serializer):
file = UploadedFileField(required=True, label=_("file"))
user_id = serializers.UUIDField(required=True, label=_("User ID"))
workspace_id = serializers.CharField(required=True, label=_("workspace id"))
#
@transaction.atomic
def import_(self):
self.is_valid()
# user_id = self.data.get('user_id')
# flib_instance_bytes = self.data.get('file').read()
# try:
# RestrictedUnpickler(io.BytesIO(s)).load()
# flib_instance = restricted_loads(flib_instance_bytes)
# except Exception as e:
# raise AppApiException(1001, _("Unsupported file format"))
# tool = flib_instance.tool
# tool_model = Tool(
# id=uuid.uuid7(),
# name=tool.get('name'),
# desc=tool.get('desc'),
# code=tool.get('code'),
# user_id=user_id,
# input_field_list=tool.get('input_field_list'),
# init_field_list=tool.get('init_field_list', []),
# scope=ToolScope.WORKSPACE,
# is_active=False
# )
# tool_model.save()
return True
class ToolTreeSerializer(serializers.Serializer): class ToolTreeSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_('workspace id')) workspace_id = serializers.CharField(required=True, label=_('workspace id'))

View File

@ -5,5 +5,9 @@ from . import views
app_name = "tool" app_name = "tool"
urlpatterns = [ urlpatterns = [
path('workspace/<str:workspace_id>/tool', views.ToolView.as_view()), path('workspace/<str:workspace_id>/tool', views.ToolView.as_view()),
path('workspace/<str:workspace_id>/tool/import', views.ToolView.Import.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>', views.ToolView.Operate.as_view()),
path('workspace/<str:workspace_id>/tool/<str:tool_id>/debug', views.ToolView.Debug.as_view()),
path('workspace/<str:workspace_id>/tool/<str:tool_id>/export', views.ToolView.Export.as_view()),
path('workspace/<str:workspace_id>/tool/<int:current_page>/<int:page_size>', views.ToolView.Page.as_view()),
] ]

View File

@ -1,5 +1,6 @@
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.views import APIView from rest_framework.views import APIView
@ -7,76 +8,162 @@ from common.auth import TokenAuth
from common.auth.authentication import has_permissions from common.auth.authentication import has_permissions
from common.constants.permission_constants import PermissionConstants from common.constants.permission_constants import PermissionConstants
from common.result import result from common.result import result
from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI, ToolDebugApi, \
ToolExportAPI, ToolImportAPI, ToolPageAPI
from tools.serializers.tool import ToolSerializer, ToolTreeSerializer from tools.serializers.tool import ToolSerializer, ToolTreeSerializer
class ToolView(APIView): class ToolView(APIView):
authentication_classes = [TokenAuth] authentication_classes = [TokenAuth]
@extend_schema(methods=['POST'], @extend_schema(
methods=['POST'],
description=_('Create tool'), description=_('Create tool'),
operation_id=_('Create tool'), operation_id=_('Create tool'),
parameters=ToolCreateAPI.get_parameters(), parameters=ToolCreateAPI.get_parameters(),
request=ToolCreateAPI.get_request(), request=ToolCreateAPI.get_request(),
responses=ToolCreateAPI.get_response(), responses=ToolCreateAPI.get_response(),
tags=[_('Tool')]) tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_CREATE.get_workspace_permission()) @has_permissions(PermissionConstants.TOOL_CREATE.get_workspace_permission())
def post(self, request: Request, workspace_id: str): def post(self, request: Request, workspace_id: str):
return result.success(ToolSerializer.Create( return result.success(ToolSerializer.Create(
data={'user_id': request.user.id, 'workspace_id': workspace_id} data={'user_id': request.user.id, 'workspace_id': workspace_id}
).insert(request.data)) ).insert(request.data))
@extend_schema(methods=['GET'], @extend_schema(
methods=['GET'],
description=_('Get tool by module'), description=_('Get tool by module'),
operation_id=_('Get tool by module'), operation_id=_('Get tool by module'),
parameters=ToolTreeReadAPI.get_parameters(), parameters=ToolTreeReadAPI.get_parameters(),
responses=ToolTreeReadAPI.get_response(), responses=ToolTreeReadAPI.get_response(),
tags=[_('Tool')]) tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_READ.get_workspace_permission()) @has_permissions(PermissionConstants.TOOL_READ.get_workspace_permission())
def get(self, request: Request, workspace_id: str): def get(self, request: Request, workspace_id: str):
return result.success(ToolTreeSerializer( return result.success(ToolTreeSerializer(
data={'workspace_id': workspace_id} data={'workspace_id': workspace_id}
).get_tools(request.query_params.get('module_id'))) ).get_tools(request.query_params.get('module_id')))
class Debug(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['POST'],
description=_('Debug Tool'),
operation_id=_('Debug Tool'),
request=ToolDebugApi.get_request(),
responses=ToolDebugApi.get_response(),
tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_DEBUG.get_workspace_permission())
def post(self, request: Request, workspace_id: str, tool_id: str):
return result.success(ToolSerializer.Debug(
data={'tool_id': tool_id, 'workspace_id': workspace_id}
).debug(request.data))
class Operate(APIView): class Operate(APIView):
authentication_classes = [TokenAuth] authentication_classes = [TokenAuth]
@extend_schema(methods=['PUT'], @extend_schema(
methods=['PUT'],
description=_('Update tool'), description=_('Update tool'),
operation_id=_('Update tool'), operation_id=_('Update tool'),
parameters=ToolEditAPI.get_parameters(), parameters=ToolEditAPI.get_parameters(),
request=ToolEditAPI.get_request(), request=ToolEditAPI.get_request(),
responses=ToolEditAPI.get_response(), responses=ToolEditAPI.get_response(),
tags=[_('Tool')]) tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_EDIT.get_workspace_permission()) @has_permissions(PermissionConstants.TOOL_EDIT.get_workspace_permission())
def put(self, request: Request, workspace_id: str, tool_id: str): def put(self, request: Request, workspace_id: str, tool_id: str):
return result.success(ToolSerializer.Operate( return result.success(ToolSerializer.Operate(
data={'id': tool_id, 'workspace_id': workspace_id} data={'id': tool_id, 'workspace_id': workspace_id}
).edit(request.data)) ).edit(request.data))
@extend_schema(methods=['GET'], @extend_schema(
methods=['GET'],
description=_('Get tool'), description=_('Get tool'),
operation_id=_('Get tool'), operation_id=_('Get tool'),
parameters=ToolReadAPI.get_parameters(), parameters=ToolReadAPI.get_parameters(),
responses=ToolReadAPI.get_response(), responses=ToolReadAPI.get_response(),
tags=[_('Tool')]) tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_READ.get_workspace_permission()) @has_permissions(PermissionConstants.TOOL_READ.get_workspace_permission())
def get(self, request: Request, workspace_id: str, tool_id: str): def get(self, request: Request, workspace_id: str, tool_id: str):
return result.success(ToolSerializer.Operate( return result.success(ToolSerializer.Operate(
data={'id': tool_id, 'workspace_id': workspace_id} data={'id': tool_id, 'workspace_id': workspace_id}
).one()) ).one())
@extend_schema(methods=['DELETE'], @extend_schema(
methods=['DELETE'],
description=_('Delete tool'), description=_('Delete tool'),
operation_id=_('Delete tool'), operation_id=_('Delete tool'),
parameters=ToolDeleteAPI.get_parameters(), parameters=ToolDeleteAPI.get_parameters(),
responses=ToolDeleteAPI.get_response(), responses=ToolDeleteAPI.get_response(),
tags=[_('Tool')]) tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_DELETE.get_workspace_permission()) @has_permissions(PermissionConstants.TOOL_DELETE.get_workspace_permission())
def delete(self, request: Request, workspace_id: str, tool_id: str): def delete(self, request: Request, workspace_id: str, tool_id: str):
return result.success(ToolSerializer.Operate( return result.success(ToolSerializer.Operate(
data={'id': tool_id, 'workspace_id': workspace_id} data={'id': tool_id, 'workspace_id': workspace_id}
).delete()) ).delete())
class Page(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['GET'],
description=_('Get tool list by pagination'),
operation_id=_('Get tool list by pagination'),
parameters=ToolPageAPI.get_parameters(),
responses=ToolPageAPI.get_response(),
tags=[_('Tool')]
)
@has_permissions(PermissionConstants.TOOL_READ.get_workspace_permission())
def get(self, request: Request, current_page: int, page_size: int):
return result.success(
ToolSerializer.Query(
data={
'name': request.query_params.get('name'),
'desc': request.query_params.get('desc'),
'function_type': request.query_params.get('function_type'),
'user_id': request.user.id,
'select_user_id': request.query_params.get('select_user_id')
}
).page(current_page, page_size))
class Import(APIView):
authentication_classes = [TokenAuth]
parser_classes = [MultiPartParser]
@extend_schema(
methods=['POST'],
description=_("Import tool"),
operation_id=_("Import tool"),
parameters=ToolImportAPI.get_parameters(),
request=ToolImportAPI.get_request(),
responses=ToolImportAPI.get_response(),
tags=[_("Tool")]
)
@has_permissions(PermissionConstants.TOOL_IMPORT.get_workspace_permission())
def post(self, request: Request, workspace_id: str):
return result.success(ToolSerializer.Import(
data={'workspace_id': workspace_id, 'file': request.FILES.get('file'), 'user_id': request.user.id}
).import_())
class Export(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['GET'],
description=_("Export tool"),
operation_id=_("Export tool"),
parameters=ToolExportAPI.get_parameters(),
responses=ToolExportAPI.get_response(),
tags=[_("Tool")]
)
@has_permissions(PermissionConstants.TOOL_EXPORT.get_workspace_permission())
def get(self, request: Request, tool_id: str, workspace_id: str):
return ToolSerializer.Operate(
data={'id': tool_id, 'workspace_id': workspace_id}
).export()