Skip to content

Commit 7e6e5de

Browse files
committed
feat: Batch delete and move tools
1 parent b57802e commit 7e6e5de

File tree

4 files changed

+175
-4
lines changed

4 files changed

+175
-4
lines changed

apps/tools/api/tool.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from common.mixins.api_mixin import APIMixin
66
from common.result import ResultSerializer, DefaultResultSerializer
7+
from knowledge.serializers.common import BatchSerializer, BatchMoveSerializer
78
from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest, ToolDebugRequest, ToolEditRequest, \
89
PylintInstance, AddInternalToolRequest
910

@@ -323,3 +324,25 @@ def get_parameters():
323324
),
324325
]
325326

327+
class ToolBatchOperateAPI(APIMixin):
328+
@staticmethod
329+
def get_parameters():
330+
return [
331+
OpenApiParameter(
332+
name="workspace_id",
333+
description="工作空间id",
334+
type=OpenApiTypes.STR,
335+
location='path',
336+
required=True,
337+
)
338+
]
339+
340+
@staticmethod
341+
def get_request():
342+
return BatchSerializer
343+
344+
@staticmethod
345+
def get_move_request():
346+
return BatchMoveSerializer
347+
348+

apps/tools/serializers/tool.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,65 @@ def process():
11731173

11741174
return to_stream_response_simple(process())
11751175

1176+
class ToolBatchOperateSerializer(serializers.Serializer):
1177+
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
1178+
1179+
def is_valid(self, *, raise_exception=False):
1180+
super().is_valid(raise_exception=True)
1181+
1182+
@transaction.atomic
1183+
def batch_delete(self, instance: Dict, with_valid=True):
1184+
from knowledge.serializers.common import BatchSerializer
1185+
from trigger.handler.simple_tools import deploy
1186+
from trigger.serializers.trigger import TriggerModelSerializer
1187+
1188+
if with_valid:
1189+
BatchSerializer(data=instance).is_valid(model=Tool, raise_exception=True)
1190+
self.is_valid(raise_exception=True)
1191+
id_list = instance.get('id_list')
1192+
workspace_id = self.data.get('workspace_id')
1193+
1194+
tool_query_set = QuerySet(Tool).filter(id__in=id_list, workspace_id=workspace_id)
1195+
1196+
for tool in tool_query_set:
1197+
if tool.template_id is None and tool.icon != '':
1198+
QuerySet(File).filter(id=tool.icon.split('/')[-1]).delete()
1199+
if tool.tool_type == ToolType.SKILL:
1200+
QuerySet(File).filter(id=tool.code).delete()
1201+
1202+
QuerySet(WorkspaceUserResourcePermission).filter(target__in=id_list).delete()
1203+
QuerySet(ResourceMapping).filter(target_id__in=id_list).delete()
1204+
QuerySet(ToolRecord).filter(tool_id__in=id_list).delete()
1205+
1206+
trigger_ids = list(
1207+
QuerySet(TriggerTask).filter(
1208+
source_type="TOOL", source_id__in=id_list
1209+
).values('trigger_id').distinct()
1210+
)
1211+
1212+
QuerySet(TriggerTask).filter(source_type="TOOL", source_id__in=id_list).delete()
1213+
for trigger_id in trigger_ids:
1214+
trigger = Trigger.objects.filter(id=trigger_id['trigger_id']).first()
1215+
if trigger and trigger.is_active:
1216+
deploy(TriggerModelSerializer(trigger).data, **{})
1217+
1218+
tool_query_set.delete()
1219+
return True
1220+
1221+
def batch_move(self, instance: Dict, with_valid=True):
1222+
from knowledge.serializers.common import BatchMoveSerializer
1223+
if with_valid:
1224+
BatchMoveSerializer(data=instance).is_valid(model=Tool, raise_exception=True)
1225+
self.is_valid(raise_exception=True)
1226+
id_list = instance.get('id_list')
1227+
folder_id = instance.get('folder_id')
1228+
workspace_id = self.data.get('workspace_id')
1229+
1230+
QuerySet(Tool).filter(id__in=id_list, workspace_id=workspace_id).update(folder_id=folder_id)
1231+
return True
1232+
1233+
1234+
11761235

11771236
class ToolTreeSerializer(serializers.Serializer):
11781237
class Query(serializers.Serializer):

apps/tools/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
path('workspace/<str:workspace_id>/tool/test_connection', views.ToolView.TestConnection.as_view()),
1717
path('workspace/<str:workspace_id>/tool/upload_skill_file', views.ToolView.UploadSkillFile.as_view()),
1818
path('workspace/<str:workspace_id>/tool/generate_code', views.ToolView.GenerateCode.as_view()),
19+
path('workspace/<str:workspace_id>/tool/batch_delete', views.ToolView.BatchDelete.as_view()),
20+
path('workspace/<str:workspace_id>/tool/batch_move', views.ToolView.BatchMove.as_view()),
1921
path('workspace/<str:workspace_id>/tool/<str:tool_id>', views.ToolView.Operate.as_view()),
2022
path('workspace/<str:workspace_id>/tool/<str:tool_id>/publish', views.ToolWorkflowView.Publish.as_view()),
2123
path('workspace/<str:workspace_id>/tool/<str:tool_id>/debug', views.ToolWorkflowDebugView.as_view()),

apps/tools/views/tool.py

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
from rest_framework.views import APIView
77

88
from common.auth import TokenAuth
9-
from common.auth.authentication import has_permissions
9+
from common.auth.authentication import has_permissions, check_batch_permissions
1010
from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants
1111
from common.log.log import log
12-
from common.result import result
12+
from common import result
1313
from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI, ToolDebugApi, \
14-
ToolExportAPI, ToolImportAPI, ToolPageAPI, PylintAPI, EditIconAPI, GetInternalToolAPI, AddInternalToolAPI
14+
ToolExportAPI, ToolImportAPI, ToolPageAPI, PylintAPI, EditIconAPI, GetInternalToolAPI, AddInternalToolAPI, \
15+
ToolBatchOperateAPI
1516
from tools.models import ToolScope, Tool
16-
from tools.serializers.tool import ToolSerializer, ToolTreeSerializer
17+
from tools.serializers.tool import ToolSerializer, ToolTreeSerializer, ToolBatchOperateSerializer
1718

1819

1920
def get_tool_operation_object(tool_id):
@@ -24,6 +25,15 @@ def get_tool_operation_object(tool_id):
2425
}
2526
return {}
2627

28+
def get_tool_operation_object_batch(tool_id_list):
29+
tool_model_list = QuerySet(model=Tool).filter(id__in=tool_id_list)
30+
if tool_model_list is not None:
31+
return {
32+
"name": f'[{",".join([t.name for t in tool_model_list])}]',
33+
'tool_list': [{'name': t.name} for t in tool_model_list]
34+
}
35+
return {}
36+
2737

2838
class ToolView(APIView):
2939
authentication_classes = [TokenAuth]
@@ -186,6 +196,83 @@ def delete(self, request: Request, workspace_id: str, tool_id: str):
186196
data={'id': tool_id, 'workspace_id': workspace_id}
187197
).delete())
188198

199+
class BatchDelete(APIView):
200+
authentication_classes = [TokenAuth]
201+
202+
@extend_schema(
203+
methods=['PUT'],
204+
description=_("Batch delete tools"),
205+
summary=_("Batch delete tools"),
206+
operation_id=_("Batch delete tools"),
207+
parameters=ToolBatchOperateAPI.get_parameters(),
208+
request=ToolBatchOperateAPI.get_request(),
209+
responses=result.DefaultResultSerializer,
210+
tags=[_('Tool')]
211+
)
212+
@has_permissions(PermissionConstants.TOOL_BATCH_DELETE.get_workspace_permission(),
213+
RoleConstants.USER.get_workspace_role(),
214+
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
215+
)
216+
def put(self, request: Request, workspace_id: str):
217+
id_list = request.data.get('id_list', [])
218+
permitted_ids = check_batch_permissions(
219+
request, id_list, 'tool_id',
220+
(PermissionConstants.TOOL_DELETE.get_workspace_tool_permission(),
221+
PermissionConstants.TOOL_DELETE.get_workspace_permission_workspace_manage_role(),
222+
ViewPermission([RoleConstants.USER.get_workspace_role()],
223+
[PermissionConstants.TOOL.get_workspace_tool_permission()],
224+
CompareConstants.AND),
225+
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()), workspace_id=workspace_id
226+
)
227+
228+
@log(menu='Tool', operate='Batch delete tools',
229+
get_operation_object=lambda r, k: get_tool_operation_object_batch(permitted_ids))
230+
def inner(view, r, **kwargs):
231+
return ToolBatchOperateSerializer(
232+
data={'workspace_id': workspace_id}
233+
).batch_delete({'id_list': permitted_ids})
234+
235+
return result.success(inner(self, request, workspace_id=workspace_id))
236+
237+
class BatchMove(APIView):
238+
authentication_classes = [TokenAuth]
239+
240+
@extend_schema(
241+
methods=['PUT'],
242+
description=_("Batch move tools"),
243+
summary=_("Batch move tools"),
244+
operation_id=_("Batch move tools"),
245+
parameters=ToolBatchOperateAPI.get_parameters(),
246+
request=ToolBatchOperateAPI.get_move_request(),
247+
responses=result.DefaultResultSerializer,
248+
tags=[_('Tool')]
249+
)
250+
@has_permissions(PermissionConstants.TOOL_BATCH_MOVE.get_workspace_permission(),
251+
RoleConstants.USER.get_workspace_role(),
252+
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
253+
)
254+
def put(self, request: Request, workspace_id: str):
255+
id_list = request.data.get('id_list', [])
256+
permitted_ids = check_batch_permissions(
257+
request, id_list, 'tool_id',
258+
(PermissionConstants.TOOL_EDIT.get_workspace_tool_permission(),
259+
PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
260+
ViewPermission([RoleConstants.USER.get_workspace_role()],
261+
[PermissionConstants.TOOL.get_workspace_tool_permission()],
262+
CompareConstants.AND),
263+
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()),
264+
workspace_id=workspace_id
265+
)
266+
267+
@log(menu='Tool', operate='Batch move tools',
268+
get_operation_object=lambda r, k: get_tool_operation_object_batch(permitted_ids))
269+
def inner(view, r, **kwargs):
270+
return ToolBatchOperateSerializer(
271+
data={'workspace_id': workspace_id}
272+
).batch_move({'id_list': permitted_ids, 'folder_id': request.data.get('folder_id')})
273+
274+
return result.success(inner(self, request, workspace_id=workspace_id))
275+
189276
class Page(APIView):
190277
authentication_classes = [TokenAuth]
191278

0 commit comments

Comments
 (0)