tool.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. from django.db.models import QuerySet, Count, Avg, Min, Max, Q
  2. from django.utils.translation import gettext_lazy as _
  3. from drf_spectacular.utils import extend_schema
  4. from rest_framework.parsers import MultiPartParser
  5. from rest_framework.request import Request
  6. from rest_framework.views import APIView
  7. from common import result
  8. from common.auth import TokenAuth
  9. from common.auth.authentication import has_permissions, check_batch_permissions
  10. from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants
  11. from common.log.log import log
  12. from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI, ToolDebugApi, \
  13. ToolExportAPI, ToolImportAPI, ToolPageAPI, PylintAPI, EditIconAPI, GetInternalToolAPI, AddInternalToolAPI, \
  14. ToolBatchOperateAPI
  15. from tools.models import ToolScope, Tool, ToolRecord
  16. from tools.serializers.tool import ToolSerializer, ToolTreeSerializer, ToolBatchOperateSerializer
  17. def get_tool_operation_object(tool_id):
  18. tool_model = QuerySet(model=Tool).filter(id=tool_id).first()
  19. if tool_model is not None:
  20. return {
  21. "name": tool_model.name
  22. }
  23. return {}
  24. def get_tool_operation_object_batch(tool_id_list):
  25. tool_model_list = QuerySet(model=Tool).filter(id__in=tool_id_list)
  26. if tool_model_list is not None:
  27. return {
  28. "name": f'[{",".join([t.name for t in tool_model_list])}]',
  29. 'tool_list': [{'name': t.name} for t in tool_model_list]
  30. }
  31. return {}
  32. class ToolView(APIView):
  33. authentication_classes = [TokenAuth]
  34. @extend_schema(
  35. methods=['POST'],
  36. description=_('Create tool'),
  37. summary=_('Create tool'),
  38. operation_id=_('Create tool'), # type: ignore
  39. parameters=ToolCreateAPI.get_parameters(),
  40. request=ToolCreateAPI.get_request(),
  41. responses=ToolCreateAPI.get_response(),
  42. tags=[_('Tool')] # type: ignore
  43. )
  44. @has_permissions(
  45. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  46. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  47. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  48. )
  49. @log(
  50. menu="Tool", operate="Create tool",
  51. get_operation_object=lambda r, k: r.data.get('name'),
  52. )
  53. def post(self, request: Request, workspace_id: str):
  54. return result.success(ToolSerializer.Create(
  55. data={'user_id': request.user.id, 'workspace_id': workspace_id}
  56. ).insert({**request.data, 'scope': ToolScope.WORKSPACE}))
  57. @extend_schema(
  58. methods=['GET'],
  59. description=_('Get tool by folder'),
  60. summary=_('Get tool by folder'),
  61. operation_id=_('Get tool by folder'), # type: ignore
  62. parameters=ToolTreeReadAPI.get_parameters(),
  63. responses=ToolTreeReadAPI.get_response(),
  64. tags=[_('Tool')] # type: ignore
  65. )
  66. @has_permissions(
  67. PermissionConstants.TOOL_READ.get_workspace_permission(),
  68. PermissionConstants.TOOL_READ.get_workspace_permission_workspace_manage_role(),
  69. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  70. )
  71. def get(self, request: Request, workspace_id: str):
  72. return result.success(ToolTreeSerializer.Query(
  73. data={
  74. 'workspace_id': workspace_id,
  75. 'folder_id': request.query_params.get('folder_id'),
  76. 'name': request.query_params.get('name'),
  77. 'scope': request.query_params.get('scope', ToolScope.WORKSPACE),
  78. 'tool_type': request.query_params.get('tool_type'),
  79. 'tool_type_list': request.query_params.getlist('tool_type_list[]'),
  80. 'user_id': request.user.id,
  81. 'create_user': request.query_params.get('create_user'),
  82. }
  83. ).get_tools())
  84. class Debug(APIView):
  85. authentication_classes = [TokenAuth]
  86. @extend_schema(
  87. methods=['POST'],
  88. description=_('Debug Tool'),
  89. summary=_('Debug Tool'),
  90. operation_id=_('Debug Tool'), # type: ignore
  91. request=ToolDebugApi.get_request(),
  92. responses=ToolDebugApi.get_response(),
  93. tags=[_('Tool')] # type: ignore
  94. )
  95. @has_permissions(
  96. PermissionConstants.TOOL_EDIT.get_workspace_permission(),
  97. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  98. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  99. )
  100. def post(self, request: Request, workspace_id: str):
  101. return result.success(ToolSerializer.Debug(
  102. data={'workspace_id': workspace_id, 'user_id': request.user.id}
  103. ).debug(request.data))
  104. class Operate(APIView):
  105. authentication_classes = [TokenAuth]
  106. @extend_schema(
  107. methods=['PUT'],
  108. description=_('Update tool'),
  109. summary=_('Update tool'),
  110. operation_id=_('Update tool'), # type: ignore
  111. parameters=ToolEditAPI.get_parameters(),
  112. request=ToolEditAPI.get_request(),
  113. responses=ToolEditAPI.get_response(),
  114. tags=[_('Tool')] # type: ignore
  115. )
  116. @has_permissions(
  117. PermissionConstants.TOOL_EDIT.get_workspace_tool_permission(),
  118. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  119. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  120. ViewPermission([RoleConstants.USER.get_workspace_role()],
  121. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  122. CompareConstants.AND),
  123. )
  124. @log(
  125. menu='Tool', operate='Update tool',
  126. get_operation_object=lambda r, k: get_tool_operation_object(k.get('tool_id')),
  127. )
  128. def put(self, request: Request, workspace_id: str, tool_id: str):
  129. return result.success(ToolSerializer.Operate(
  130. data={'id': tool_id, 'workspace_id': workspace_id}
  131. ).edit(request.data))
  132. @extend_schema(
  133. methods=['GET'],
  134. description=_('Get tool'),
  135. summary=_('Get tool'),
  136. operation_id=_('Get tool'), # type: ignore
  137. parameters=ToolReadAPI.get_parameters(),
  138. responses=ToolReadAPI.get_response(),
  139. tags=[_('Tool')] # type: ignore
  140. )
  141. @has_permissions(
  142. PermissionConstants.TOOL_READ.get_workspace_tool_permission(),
  143. PermissionConstants.TOOL_READ.get_workspace_permission_workspace_manage_role(),
  144. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  145. PermissionConstants.APPLICATION_READ.get_workspace_permission(),
  146. PermissionConstants.APPLICATION_READ.get_workspace_permission_workspace_manage_role(),
  147. RoleConstants.USER.get_workspace_role(),
  148. ViewPermission([RoleConstants.USER.get_workspace_role()],
  149. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  150. CompareConstants.AND),
  151. )
  152. @log(menu='Tool', operate='Get tool')
  153. def get(self, request: Request, workspace_id: str, tool_id: str):
  154. return result.success(ToolSerializer.Operate(
  155. data={'id': tool_id, 'workspace_id': workspace_id}
  156. ).one())
  157. @extend_schema(
  158. methods=['DELETE'],
  159. description=_('Delete tool'),
  160. summary=_('Delete tool'),
  161. operation_id=_('Delete tool'), # type: ignore
  162. parameters=ToolDeleteAPI.get_parameters(),
  163. responses=ToolDeleteAPI.get_response(),
  164. tags=[_('Tool')] # type: ignore
  165. )
  166. @has_permissions(
  167. PermissionConstants.TOOL_DELETE.get_workspace_tool_permission(),
  168. PermissionConstants.TOOL_DELETE.get_workspace_permission_workspace_manage_role(),
  169. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  170. ViewPermission([RoleConstants.USER.get_workspace_role()],
  171. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  172. CompareConstants.AND),
  173. )
  174. @log(
  175. menu='Tool', operate="Delete tool",
  176. get_operation_object=lambda r, k: get_tool_operation_object(k.get('tool_id')),
  177. )
  178. def delete(self, request: Request, workspace_id: str, tool_id: str):
  179. return result.success(ToolSerializer.Operate(
  180. data={'id': tool_id, 'workspace_id': workspace_id}
  181. ).delete())
  182. class BatchDelete(APIView):
  183. authentication_classes = [TokenAuth]
  184. @extend_schema(
  185. methods=['PUT'],
  186. description=_("Batch delete tools"),
  187. summary=_("Batch delete tools"),
  188. operation_id=_("Batch delete tools"),
  189. parameters=ToolBatchOperateAPI.get_parameters(),
  190. request=ToolBatchOperateAPI.get_request(),
  191. responses=result.DefaultResultSerializer,
  192. tags=[_('Tool')]
  193. )
  194. @has_permissions(PermissionConstants.TOOL_BATCH_DELETE.get_workspace_permission(),
  195. RoleConstants.USER.get_workspace_role(),
  196. RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
  197. )
  198. def put(self, request: Request, workspace_id: str):
  199. id_list = request.data.get('id_list', [])
  200. permitted_ids = check_batch_permissions(
  201. request, id_list, 'tool_id',
  202. (PermissionConstants.TOOL_DELETE.get_workspace_tool_permission(),
  203. PermissionConstants.TOOL_DELETE.get_workspace_permission_workspace_manage_role(),
  204. ViewPermission([RoleConstants.USER.get_workspace_role()],
  205. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  206. CompareConstants.AND),
  207. RoleConstants.WORKSPACE_MANAGE.get_workspace_role()), workspace_id=workspace_id
  208. )
  209. @log(menu='Tool', operate='Batch delete tools',
  210. get_operation_object=lambda r, k: get_tool_operation_object_batch(permitted_ids))
  211. def inner(view, r, **kwargs):
  212. return ToolBatchOperateSerializer(
  213. data={'workspace_id': workspace_id}
  214. ).batch_delete({'id_list': permitted_ids})
  215. return result.success(inner(self, request, workspace_id=workspace_id))
  216. class BatchMove(APIView):
  217. authentication_classes = [TokenAuth]
  218. @extend_schema(
  219. methods=['PUT'],
  220. description=_("Batch move tools"),
  221. summary=_("Batch move tools"),
  222. operation_id=_("Batch move tools"),
  223. parameters=ToolBatchOperateAPI.get_parameters(),
  224. request=ToolBatchOperateAPI.get_move_request(),
  225. responses=result.DefaultResultSerializer,
  226. tags=[_('Tool')]
  227. )
  228. @has_permissions(PermissionConstants.TOOL_BATCH_MOVE.get_workspace_permission(),
  229. RoleConstants.USER.get_workspace_role(),
  230. RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
  231. )
  232. def put(self, request: Request, workspace_id: str):
  233. id_list = request.data.get('id_list', [])
  234. permitted_ids = check_batch_permissions(
  235. request, id_list, 'tool_id',
  236. (PermissionConstants.TOOL_EDIT.get_workspace_tool_permission(),
  237. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  238. ViewPermission([RoleConstants.USER.get_workspace_role()],
  239. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  240. CompareConstants.AND),
  241. RoleConstants.WORKSPACE_MANAGE.get_workspace_role()),
  242. workspace_id=workspace_id
  243. )
  244. @log(menu='Tool', operate='Batch move tools',
  245. get_operation_object=lambda r, k: get_tool_operation_object_batch(permitted_ids))
  246. def inner(view, r, **kwargs):
  247. return ToolBatchOperateSerializer(
  248. data={'workspace_id': workspace_id}
  249. ).batch_move({'id_list': permitted_ids, 'folder_id': request.data.get('folder_id')})
  250. return result.success(inner(self, request, workspace_id=workspace_id))
  251. class Page(APIView):
  252. authentication_classes = [TokenAuth]
  253. @extend_schema(
  254. methods=['GET'],
  255. description=_('Get tool list by pagination'),
  256. summary=_('Get tool list by pagination'),
  257. operation_id=_('Get tool list by pagination'), # type: ignore
  258. parameters=ToolPageAPI.get_parameters(),
  259. responses=ToolPageAPI.get_response(),
  260. tags=[_('Tool')] # type: ignore
  261. )
  262. @has_permissions(
  263. PermissionConstants.TOOL_READ.get_workspace_permission(),
  264. PermissionConstants.TOOL_READ.get_workspace_permission_workspace_manage_role(),
  265. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  266. )
  267. @log(menu='Tool', operate='Get tool list')
  268. def get(self, request: Request, workspace_id: str, current_page: int, page_size: int):
  269. return result.success(ToolTreeSerializer.Query(
  270. data={
  271. 'workspace_id': workspace_id,
  272. 'folder_id': request.query_params.get('folder_id'),
  273. 'name': request.query_params.get('name'),
  274. 'scope': request.query_params.get('scope'),
  275. 'tool_type': request.query_params.get('tool_type'),
  276. 'user_id': request.user.id,
  277. 'create_user': request.query_params.get('create_user'),
  278. }
  279. ).page_tool_with_folders(current_page, page_size))
  280. class Query(APIView):
  281. authentication_classes = [TokenAuth]
  282. @extend_schema(
  283. methods=['GET'],
  284. description=_('Get tool list '),
  285. summary=_('Get tool list'),
  286. operation_id=_('Get tool list'), # type: ignore
  287. parameters=ToolReadAPI.get_parameters(),
  288. responses=ToolReadAPI.get_response(),
  289. tags=[_('Tool')] # type: ignore
  290. )
  291. @has_permissions(
  292. PermissionConstants.TOOL_READ.get_workspace_permission(),
  293. PermissionConstants.TOOL_READ.get_workspace_permission_workspace_manage_role(),
  294. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  295. )
  296. @log(menu='Tool', operate='Get tool list')
  297. def get(self, request: Request, workspace_id: str):
  298. return result.success(ToolSerializer.Query(
  299. data={
  300. 'workspace_id': workspace_id,
  301. 'folder_id': request.query_params.get('folder_id'),
  302. 'name': request.query_params.get('name'),
  303. 'scope': request.query_params.get('scope'),
  304. 'tool_type': request.query_params.get('tool_type'),
  305. 'user_id': request.user.id,
  306. 'create_user': request.query_params.get('create_user'),
  307. }
  308. ).get_tools())
  309. class Import(APIView):
  310. authentication_classes = [TokenAuth]
  311. parser_classes = [MultiPartParser]
  312. @extend_schema(
  313. methods=['POST'],
  314. description=_("Import tool"),
  315. summary=_("Import tool"),
  316. operation_id=_("Import tool"), # type: ignore
  317. parameters=ToolImportAPI.get_parameters(),
  318. request=ToolImportAPI.get_request(),
  319. responses=ToolImportAPI.get_response(),
  320. tags=[_("Tool")] # type: ignore
  321. )
  322. @has_permissions(
  323. PermissionConstants.TOOL_IMPORT.get_workspace_permission(),
  324. PermissionConstants.TOOL_IMPORT.get_workspace_permission_workspace_manage_role(),
  325. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  326. )
  327. @log(menu='Tool', operate='Import tool', )
  328. def post(self, request: Request, workspace_id: str):
  329. return result.success(ToolSerializer.Import(
  330. data={
  331. 'workspace_id': workspace_id,
  332. 'file': request.FILES.get('file'),
  333. 'user_id': request.user.id,
  334. 'folder_id': request.data.get('folder_id')
  335. }
  336. ).import_(ToolScope.WORKSPACE))
  337. class Export(APIView):
  338. authentication_classes = [TokenAuth]
  339. @extend_schema(
  340. methods=['GET'],
  341. description=_("Export tool"),
  342. summary=_("Export tool"),
  343. operation_id=_("Export tool"), # type: ignore
  344. parameters=ToolExportAPI.get_parameters(),
  345. responses=ToolExportAPI.get_response(),
  346. tags=[_("Tool")] # type: ignore
  347. )
  348. @has_permissions(
  349. PermissionConstants.TOOL_EXPORT.get_workspace_tool_permission(),
  350. PermissionConstants.TOOL_EXPORT.get_workspace_permission_workspace_manage_role(),
  351. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  352. ViewPermission([RoleConstants.USER.get_workspace_role()],
  353. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  354. CompareConstants.AND),
  355. )
  356. @log(
  357. menu='Tool', operate="Export tool",
  358. get_operation_object=lambda r, k: get_tool_operation_object(k.get('tool_id')),
  359. )
  360. def get(self, request: Request, tool_id: str, workspace_id: str):
  361. return ToolSerializer.Operate(
  362. data={'id': tool_id, 'workspace_id': workspace_id}
  363. ).export()
  364. class Pylint(APIView):
  365. authentication_classes = [TokenAuth]
  366. @extend_schema(
  367. methods=['POST'],
  368. summary=_('Check code'),
  369. operation_id=_('Check code'), # type: ignore
  370. description=_('Check code'),
  371. request=PylintAPI.get_request(),
  372. responses=PylintAPI.get_response(),
  373. parameters=PylintAPI.get_parameters(),
  374. tags=[_('Tool')] # type: ignore
  375. )
  376. @has_permissions(
  377. PermissionConstants.TOOL_READ.get_workspace_permission(),
  378. PermissionConstants.TOOL_READ.get_workspace_permission_workspace_manage_role(),
  379. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  380. RoleConstants.USER.get_workspace_role()
  381. )
  382. def post(self, request: Request, workspace_id: str):
  383. return result.success(ToolSerializer.Pylint(
  384. data={'workspace_id': workspace_id}
  385. ).run(request.data))
  386. class EditIcon(APIView):
  387. authentication_classes = [TokenAuth]
  388. parser_classes = [MultiPartParser]
  389. @extend_schema(
  390. methods=['PUT'],
  391. summary=_('Edit tool icon'),
  392. operation_id=_('Edit tool icon'), # type: ignore
  393. description=_('Edit tool icon'),
  394. request=EditIconAPI.get_request(),
  395. responses=EditIconAPI.get_response(),
  396. parameters=EditIconAPI.get_parameters(),
  397. tags=[_('Tool')] # type: ignore
  398. )
  399. @has_permissions(
  400. PermissionConstants.TOOL_EDIT.get_workspace_tool_permission(),
  401. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  402. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  403. ViewPermission([RoleConstants.USER.get_workspace_role()],
  404. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  405. CompareConstants.AND),
  406. )
  407. def put(self, request: Request, tool_id: str, workspace_id: str):
  408. return result.success(ToolSerializer.IconOperate(data={
  409. 'id': tool_id,
  410. 'workspace_id': workspace_id,
  411. 'user_id': request.user.id,
  412. 'image': request.FILES.get('file')
  413. }).edit(request.data))
  414. class TestConnection(APIView):
  415. authentication_classes = [TokenAuth]
  416. @extend_schema(
  417. methods=['POST'],
  418. description=_("Test tool connection"),
  419. summary=_("Test tool connection"),
  420. operation_id=_("Test tool connection"), # type: ignore
  421. request=ToolReadAPI.get_request(),
  422. responses=ToolReadAPI.get_response(),
  423. tags=[_("Tool")] # type: ignore
  424. )
  425. @has_permissions(
  426. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  427. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  428. PermissionConstants.TOOL_EDIT.get_workspace_permission(),
  429. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  430. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  431. )
  432. def post(self, request: Request, workspace_id: str):
  433. return result.success(ToolSerializer.TestConnection(data={
  434. 'workspace_id': workspace_id,
  435. 'code': request.data.get('code'),
  436. }).test_connection())
  437. class InternalTool(APIView):
  438. authentication_classes = [TokenAuth]
  439. @extend_schema(
  440. methods=['GET'],
  441. description=_("Get internal tool"),
  442. summary=_("Get internal tool"),
  443. operation_id=_("Get internal tool"), # type: ignore
  444. parameters=GetInternalToolAPI.get_parameters(),
  445. responses=GetInternalToolAPI.get_response(),
  446. tags=[_("Tool")] # type: ignore
  447. )
  448. def get(self, request: Request):
  449. return result.success(ToolSerializer.InternalTool(data={
  450. 'user_id': request.user.id,
  451. 'name': request.query_params.get('name', ''),
  452. }).get_internal_tools())
  453. class AddInternalTool(APIView):
  454. authentication_classes = [TokenAuth]
  455. @extend_schema(
  456. methods=['POST'],
  457. description=_("Add internal tool"),
  458. summary=_("Add internal tool"),
  459. operation_id=_("Add internal tool"), # type: ignore
  460. parameters=AddInternalToolAPI.get_parameters(),
  461. request=AddInternalToolAPI.get_request(),
  462. responses=AddInternalToolAPI.get_response(),
  463. tags=[_("Tool")] # type: ignore
  464. )
  465. @has_permissions(
  466. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  467. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  468. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  469. RoleConstants.USER.get_workspace_role(),
  470. )
  471. @log(
  472. menu='Tool', operate="Add internal tool",
  473. get_operation_object=lambda r, k: get_tool_operation_object(k.get('tool_id')),
  474. )
  475. def post(self, request: Request, tool_id: str, workspace_id: str):
  476. return result.success(ToolSerializer.AddInternalTool(data={
  477. 'tool_id': tool_id,
  478. 'user_id': request.user.id,
  479. 'workspace_id': workspace_id
  480. }).add(request.data))
  481. class StoreTool(APIView):
  482. authentication_classes = [TokenAuth]
  483. @extend_schema(
  484. methods=['GET'],
  485. description=_("Get Appstore tools"),
  486. summary=_("Get Appstore tools"),
  487. operation_id=_("Get Appstore tools"), # type: ignore
  488. responses=GetInternalToolAPI.get_response(),
  489. tags=[_("Tool")] # type: ignore
  490. )
  491. def get(self, request: Request):
  492. return result.success(ToolSerializer.StoreTool(data={
  493. 'user_id': request.user.id,
  494. 'name': request.query_params.get('name', ''),
  495. }).get_appstore_tools())
  496. class AddStoreTool(APIView):
  497. authentication_classes = [TokenAuth]
  498. @extend_schema(
  499. methods=['POST'],
  500. description=_("Add Appstore tool"),
  501. summary=_("Add Appstore tool"),
  502. operation_id=_("Add Appstore tool"), # type: ignore
  503. parameters=AddInternalToolAPI.get_parameters(),
  504. request=AddInternalToolAPI.get_request(),
  505. responses=AddInternalToolAPI.get_response(),
  506. tags=[_("Tool")] # type: ignore
  507. )
  508. @has_permissions(
  509. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  510. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  511. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  512. RoleConstants.USER.get_workspace_role(),
  513. )
  514. @log(
  515. menu='Tool', operate="Add Appstore tool",
  516. get_operation_object=lambda r, k: get_tool_operation_object(k.get('tool_id')),
  517. )
  518. def post(self, request: Request, tool_id: str, workspace_id: str):
  519. return result.success(ToolSerializer.AddStoreTool(data={
  520. 'tool_id': tool_id,
  521. 'user_id': request.user.id,
  522. 'workspace_id': workspace_id,
  523. }).add(request.data))
  524. class UpdateStoreTool(APIView):
  525. authentication_classes = [TokenAuth]
  526. @extend_schema(
  527. methods=['POST'],
  528. description=_("Update Appstore tool"),
  529. summary=_("Update Appstore tool"),
  530. operation_id=_("Update Appstore tool"), # type: ignore
  531. parameters=AddInternalToolAPI.get_parameters(),
  532. request=AddInternalToolAPI.get_request(),
  533. responses=AddInternalToolAPI.get_response(),
  534. tags=[_("Tool")] # type: ignore
  535. )
  536. @has_permissions(
  537. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  538. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  539. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  540. RoleConstants.USER.get_workspace_role(),
  541. )
  542. @log(
  543. menu='Tool', operate="Update Appstore tool",
  544. get_operation_object=lambda r, k: get_tool_operation_object(k.get('tool_id')),
  545. )
  546. def post(self, request: Request, tool_id: str, workspace_id: str):
  547. return result.success(ToolSerializer.UpdateStoreTool(data={
  548. 'tool_id': tool_id,
  549. 'user_id': request.user.id,
  550. 'workspace_id': workspace_id,
  551. 'download_url': request.data.get('download_url'),
  552. 'download_callback_url': request.data.get('download_callback_url'),
  553. 'icon': request.data.get('icon'),
  554. 'versions': request.data.get('versions'),
  555. }).update_tool(request.data))
  556. class PageToolRecord(APIView):
  557. authentication_classes = [TokenAuth]
  558. @extend_schema(
  559. methods=['GET'],
  560. description=_("Get tool records"),
  561. summary=_("Get tool records"),
  562. operation_id=_("Get tool records"), # type: ignore
  563. parameters=AddInternalToolAPI.get_parameters(),
  564. responses=AddInternalToolAPI.get_response(),
  565. tags=[_("Tool")] # type: ignore
  566. )
  567. @has_permissions(
  568. PermissionConstants.TOOL_EXECUTE_RECORD.get_workspace_tool_permission(),
  569. PermissionConstants.TOOL_EXECUTE_RECORD.get_workspace_permission_workspace_manage_role(),
  570. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  571. ViewPermission([RoleConstants.USER.get_workspace_role()],
  572. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  573. CompareConstants.AND),
  574. )
  575. def get(self, request: Request, tool_id: str, workspace_id: str, current_page: int, page_size: int):
  576. return result.success(ToolSerializer.ToolRecord(data={
  577. 'tool_id': tool_id,
  578. 'workspace_id': workspace_id,
  579. 'source_name': request.query_params.get('source_name'),
  580. 'source_type': request.query_params.get('source_type'),
  581. 'state': request.query_params.get('state'),
  582. }).get_tool_records(current_page, page_size))
  583. class ToolRecord(APIView):
  584. authentication_classes = [TokenAuth]
  585. @extend_schema(
  586. methods=['GET'],
  587. description=_("Get tool record"),
  588. summary=_("Get tool record"),
  589. operation_id=_("Get tool record"), # type: ignore
  590. parameters=AddInternalToolAPI.get_parameters(),
  591. responses=AddInternalToolAPI.get_response(),
  592. tags=[_("Tool")] # type: ignore
  593. )
  594. @has_permissions(
  595. PermissionConstants.TOOL_EXECUTE_RECORD.get_workspace_tool_permission(),
  596. PermissionConstants.TOOL_EXECUTE_RECORD.get_workspace_permission_workspace_manage_role(),
  597. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  598. ViewPermission([RoleConstants.USER.get_workspace_role()],
  599. [PermissionConstants.TOOL.get_workspace_tool_permission()],
  600. CompareConstants.AND),
  601. )
  602. def get(self, request: Request, tool_id: str, workspace_id: str, record_id: str):
  603. return result.success(ToolSerializer.ToolRecord.Operate(data={
  604. 'tool_id': tool_id,
  605. 'workspace_id': workspace_id,
  606. 'id': record_id,
  607. }).one())
  608. class UploadSkillFile(APIView):
  609. authentication_classes = [TokenAuth]
  610. parser_classes = [MultiPartParser]
  611. @extend_schema(
  612. methods=['PUT'],
  613. description=_("Upload skill file"),
  614. summary=_("Upload skill file"),
  615. operation_id=_("Upload skill file"), # type: ignore
  616. parameters=AddInternalToolAPI.get_parameters(),
  617. request=AddInternalToolAPI.get_request(),
  618. responses=AddInternalToolAPI.get_response(),
  619. tags=[_("Tool")] # type: ignore
  620. )
  621. @has_permissions(
  622. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  623. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  624. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), RoleConstants.USER.get_workspace_role()
  625. )
  626. def put(self, request: Request, workspace_id: str):
  627. return result.success(ToolSerializer.UploadSkillFile(data={
  628. 'workspace_id': workspace_id,
  629. 'user_id': request.user.id,
  630. 'file': request.FILES.get('file'),
  631. }).upload())
  632. class DownloadSkillFile(APIView):
  633. authentication_classes = [TokenAuth]
  634. @has_permissions(
  635. PermissionConstants.TOOL_EDIT.get_workspace_permission(),
  636. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  637. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  638. RoleConstants.USER.get_workspace_role()
  639. )
  640. def get(self, request: Request, workspace_id: str, tool_id: str):
  641. return ToolSerializer.DownloadSkillFile(data={
  642. 'workspace_id': workspace_id,
  643. 'user_id': request.user.id,
  644. 'tool_id': tool_id,
  645. }).download()
  646. class GenerateCode(APIView):
  647. authentication_classes = [TokenAuth]
  648. @has_permissions(
  649. PermissionConstants.TOOL_CREATE.get_workspace_permission(),
  650. PermissionConstants.TOOL_CREATE.get_workspace_permission_workspace_manage_role(),
  651. PermissionConstants.TOOL_EDIT.get_workspace_permission(),
  652. PermissionConstants.TOOL_EDIT.get_workspace_permission_workspace_manage_role(),
  653. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  654. RoleConstants.USER.get_workspace_role()
  655. )
  656. def post(self, request: Request, workspace_id: str):
  657. return ToolSerializer.GenerateCodeSerializer(data={
  658. 'workspace_id': workspace_id,
  659. **request.data
  660. }).generate_code()
  661. class Statistics(APIView):
  662. """工具使用统计"""
  663. authentication_classes = [TokenAuth]
  664. @extend_schema(
  665. methods=['GET'],
  666. description=_("Get tool usage statistics"),
  667. summary=_("Get tool usage statistics"),
  668. operation_id=_("Get tool usage statistics"),
  669. tags=[_('Tool')]
  670. )
  671. @has_permissions(
  672. PermissionConstants.TOOL_READ.get_workspace_permission(),
  673. PermissionConstants.TOOL_READ.get_workspace_permission_workspace_manage_role(),
  674. RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
  675. RoleConstants.USER.get_workspace_role()
  676. )
  677. def get(self, request: Request, workspace_id: str):
  678. tool_id = request.query_params.get('tool_id')
  679. days = int(request.query_params.get('days', 7))
  680. query = QuerySet(ToolRecord).filter(workspace_id=workspace_id)
  681. if tool_id:
  682. query = query.filter(tool_id=tool_id)
  683. stats = query.aggregate(
  684. total_count=Count('id'),
  685. success_count=Count('id', filter=Q(state='SUCCESS')),
  686. failure_count=Count('id', filter=Q(state='FAILURE')),
  687. avg_run_time=Avg('run_time'),
  688. min_run_time=Min('run_time'),
  689. max_run_time=Max('run_time')
  690. )
  691. total = stats['total_count'] or 0
  692. success = stats['success_count'] or 0
  693. success_rate = (success / total * 100) if total > 0 else 0
  694. return result.success({
  695. 'total_count': total,
  696. 'success_count': success,
  697. 'failure_count': stats['failure_count'] or 0,
  698. 'success_rate': round(success_rate, 2),
  699. 'avg_run_time': round(stats['avg_run_time'] or 0, 3),
  700. 'min_run_time': stats['min_run_time'] or 0,
  701. 'max_run_time': stats['max_run_time'] or 0
  702. })