Skip to content

Commit 0b8f5d7

Browse files
committed
feat: implement CRUD operations for tools with API views
1 parent f89e185 commit 0b8f5d7

File tree

7 files changed

+163
-23
lines changed

7 files changed

+163
-23
lines changed

apps/common/constants/permission_constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ class PermissionConstants(Enum):
133133

134134
TOOL_CREATE = Permission(group=Group.TOOL, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
135135
RoleConstants.USER])
136+
TOOL_EDIT = Permission(group=Group.TOOL, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN,
137+
RoleConstants.USER])
138+
TOOL_READ = Permission(group=Group.TOOL, operate=Operate.READ, role_list=[RoleConstants.ADMIN,
139+
RoleConstants.USER])
140+
TOOL_DELETE = Permission(group=Group.TOOL, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
141+
RoleConstants.USER])
136142

137143
def get_workspace_application_permission(self):
138144
return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate,

apps/tools/api/tool.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# coding=utf-8
2+
from drf_spectacular.types import OpenApiTypes
3+
from drf_spectacular.utils import OpenApiParameter
24

35
from common.mixins.api_mixin import APIMixin
46
from common.result import ResultSerializer
@@ -11,10 +13,58 @@ def get_data(self):
1113

1214

1315
class ToolCreateAPI(APIMixin):
16+
@staticmethod
17+
def get_parameters():
18+
return [
19+
OpenApiParameter(
20+
name="workspace_id",
21+
description="工作空间id",
22+
type=OpenApiTypes.STR,
23+
location='path',
24+
required=True,
25+
)
26+
]
27+
1428
@staticmethod
1529
def get_request():
1630
return ToolCreateRequest
1731

1832
@staticmethod
1933
def get_response():
2034
return ToolCreateResponse
35+
36+
37+
class ToolReadAPI(APIMixin):
38+
@staticmethod
39+
def get_parameters():
40+
return [
41+
OpenApiParameter(
42+
name="workspace_id",
43+
description="工作空间id",
44+
type=OpenApiTypes.STR,
45+
location='path',
46+
required=True,
47+
),
48+
OpenApiParameter(
49+
name="tool_id",
50+
description="工具id",
51+
type=OpenApiTypes.STR,
52+
location='path',
53+
required=True,
54+
)
55+
]
56+
57+
@staticmethod
58+
def get_response():
59+
return ToolCreateResponse
60+
61+
62+
class ToolEditAPI(ToolReadAPI):
63+
64+
@staticmethod
65+
def get_request():
66+
return ToolCreateRequest
67+
68+
69+
class ToolDeleteAPI(ToolReadAPI):
70+
pass

apps/tools/migrations/0001_initial.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ class Migration(migrations.Migration):
6666
models.CharField(choices=[('INTERNAL', '内置'), ('PUBLIC', '公开')], default='PUBLIC', max_length=20,
6767
verbose_name='函数类型')),
6868
('template_id', models.UUIDField(default=None, null=True, verbose_name='模版id')),
69-
('workspace_id', models.CharField(default='default', max_length=64, verbose_name='工作空间id')),
69+
('workspace_id', models.CharField(default='default', max_length=64, verbose_name='工作空间id', db_index=True)),
7070
('init_params', models.CharField(max_length=102400, null=True, verbose_name='初始化参数')),
7171
('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
7272
('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
7373
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.user',
7474
verbose_name='用户id')),
75-
('module_id',
75+
('module',
7676
models.ForeignKey(default='root', on_delete=django.db.models.deletion.CASCADE, to='tools.toolmodule',
7777
verbose_name='模块id')),
7878
],

apps/tools/models/tool.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class Tool(models.Model):
3030
tool_type = models.CharField(max_length=20, verbose_name='函数类型', choices=ToolType.choices,
3131
default=ToolType.PUBLIC)
3232
template_id = models.UUIDField(max_length=128, verbose_name="模版id", null=True, default=None)
33-
module_id = models.ForeignKey(ToolModule, on_delete=models.CASCADE, verbose_name="模块id", default='root')
34-
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default")
33+
module = models.ForeignKey(ToolModule, on_delete=models.CASCADE, verbose_name="模块id", default='root')
34+
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
3535
init_params = models.CharField(max_length=102400, verbose_name="初始化参数", null=True)
3636
create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True, null=True)
3737
update_time = models.DateTimeField(verbose_name="修改时间", auto_now=True, null=True)

apps/tools/serializers/tool.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import uuid_utils.compat as uuid
55
from django.core import validators
6+
from django.db.models import QuerySet
67
from django.utils.translation import gettext_lazy as _
78
from rest_framework import serializers
89

@@ -30,6 +31,17 @@ class ToolInputField(serializers.Serializer):
3031
])
3132

3233

34+
class InitField(serializers.Serializer):
35+
field = serializers.CharField(required=True, label=_('field name'))
36+
label = serializers.CharField(required=True, label=_('field label'))
37+
required = serializers.BooleanField(required=True, label=_('required'))
38+
input_type = serializers.CharField(required=True, label=_('input type'))
39+
default_value = serializers.CharField(required=False, allow_null=True, allow_blank=True)
40+
show_default_value = serializers.BooleanField(required=False, default=False)
41+
props_info = serializers.DictField(required=False, default=dict)
42+
attrs = serializers.DictField(required=False, default=dict)
43+
44+
3345
class ToolCreateRequest(serializers.Serializer):
3446
name = serializers.CharField(required=True, label=_('tool name'))
3547

@@ -38,9 +50,10 @@ class ToolCreateRequest(serializers.Serializer):
3850

3951
code = serializers.CharField(required=True, label=_('tool content'))
4052

41-
input_field_list = serializers.ListField(child=ToolInputField(), required=False, label=_('input field list'))
53+
input_field_list = serializers.ListField(child=ToolInputField(), required=False, default=list,
54+
label=_('input field list'))
4255

43-
init_field_list = serializers.ListField(required=False, default=list, label=_('init field list'))
56+
init_field_list = serializers.ListField(child=InitField(), required=False, default=list, label=_('init field list'))
4457

4558
is_active = serializers.BooleanField(required=False, label=_('Is active'))
4659

@@ -50,6 +63,7 @@ class ToolCreateRequest(serializers.Serializer):
5063
class ToolSerializer(serializers.Serializer):
5164
class Create(serializers.Serializer):
5265
user_id = serializers.UUIDField(required=True, label=_('user id'))
66+
workspace_id = serializers.UUIDField(required=True, label=_('workspace id'))
5367

5468
def insert(self, instance, with_valid=True):
5569
if with_valid:
@@ -66,3 +80,32 @@ def insert(self, instance, with_valid=True):
6680
is_active=False)
6781
tool.save()
6882
return ToolModelSerializer(tool).data
83+
84+
class Operate(serializers.Serializer):
85+
id = serializers.UUIDField(required=True, label=_('tool id'))
86+
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
87+
88+
def edit(self, instance, with_valid=True):
89+
if with_valid:
90+
self.is_valid(raise_exception=True)
91+
ToolCreateRequest(data=instance).is_valid(raise_exception=True)
92+
if not QuerySet(Tool).filter(id=self.data.get('id')).exists():
93+
raise serializers.ValidationError(_('Tool not found'))
94+
95+
edit_field_list = ['name', 'desc', 'code', 'icon', 'input_field_list', 'init_field_list', 'init_params',
96+
'is_active']
97+
edit_dict = {field: instance.get(field) for field in edit_field_list if (
98+
field in instance and instance.get(field) is not None)}
99+
100+
QuerySet(Tool).filter(id=self.data.get('id')).update(**edit_dict)
101+
102+
return self.one()
103+
104+
def delete(self):
105+
self.is_valid(raise_exception=True)
106+
QuerySet(Tool).filter(id=self.data.get('id')).delete()
107+
108+
def one(self):
109+
self.is_valid(raise_exception=True)
110+
tool = QuerySet(Tool).filter(id=self.data.get('id')).first()
111+
return ToolModelSerializer(tool).data

apps/tools/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44

55
app_name = "tool"
66
urlpatterns = [
7-
path('workspace/<str:workspace_id>/tool/create', views.ToolCreateView.as_view()),
7+
path('workspace/<str:workspace_id>/tool', views.ToolView.Create.as_view()),
8+
path('workspace/<str:workspace_id>/tool/<str:tool_id>', views.ToolView.Operate.as_view()),
89
]

apps/tools/views/tool.py

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,62 @@
77
from common.auth.authentication import has_permissions
88
from common.constants.permission_constants import PermissionConstants
99
from common.result import result
10-
from tools.api.tool import ToolCreateAPI
10+
from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI
1111
from tools.serializers.tool import ToolSerializer
1212

1313

14-
class ToolCreateView(APIView):
15-
authentication_classes = [TokenAuth]
16-
17-
@extend_schema(methods=['POST'],
18-
description=_('Create tool'),
19-
operation_id=_('Create tool'),
20-
request=ToolCreateAPI.get_request(),
21-
responses=ToolCreateAPI.get_response(),
22-
tags=[_('Tool')])
23-
@has_permissions(PermissionConstants.TOOL_CREATE)
24-
# @log(menu='Tool', operate="Create tool",
25-
# get_operation_object=lambda r, k: r.data.get('name'))
26-
def post(self, request: Request, workspace_id: str):
27-
print(workspace_id)
28-
return result.success(ToolSerializer.Create(data={'user_id': request.user.id}).insert(request.data))
14+
class ToolView(APIView):
15+
class Create(APIView):
16+
authentication_classes = [TokenAuth]
17+
18+
@extend_schema(methods=['POST'],
19+
description=_('Create tool'),
20+
operation_id=_('Create tool'),
21+
parameters=ToolCreateAPI.get_parameters(),
22+
request=ToolCreateAPI.get_request(),
23+
responses=ToolCreateAPI.get_response(),
24+
tags=[_('Tool')])
25+
@has_permissions(PermissionConstants.TOOL_CREATE.get_workspace_permission())
26+
def post(self, request: Request, workspace_id: str):
27+
return result.success(ToolSerializer.Create(
28+
data={'user_id': request.user.id, 'workspace_id': workspace_id}
29+
).insert(request.data))
30+
31+
class Operate(APIView):
32+
authentication_classes = [TokenAuth]
33+
34+
@extend_schema(methods=['PUT'],
35+
description=_('Update tool'),
36+
operation_id=_('Update tool'),
37+
parameters=ToolEditAPI.get_parameters(),
38+
request=ToolEditAPI.get_request(),
39+
responses=ToolEditAPI.get_response(),
40+
tags=[_('Tool')])
41+
@has_permissions(PermissionConstants.TOOL_EDIT.get_workspace_permission())
42+
def put(self, request: Request, workspace_id: str, tool_id: str):
43+
return result.success(ToolSerializer.Operate(
44+
data={'id': tool_id, 'workspace_id': workspace_id}
45+
).edit(request.data))
46+
47+
@extend_schema(methods=['GET'],
48+
description=_('Update tool'),
49+
operation_id=_('Update tool'),
50+
parameters=ToolReadAPI.get_parameters(),
51+
responses=ToolReadAPI.get_response(),
52+
tags=[_('Tool')])
53+
@has_permissions(PermissionConstants.TOOL_READ.get_workspace_permission())
54+
def get(self, request: Request, workspace_id: str, tool_id: str):
55+
return result.success(ToolSerializer.Operate(
56+
data={'id': tool_id, 'workspace_id': workspace_id}
57+
).one())
58+
59+
@extend_schema(methods=['DELETE'],
60+
description=_('Delete tool'),
61+
operation_id=_('Delete tool'),
62+
parameters=ToolDeleteAPI.get_parameters(),
63+
tags=[_('Tool')])
64+
@has_permissions(PermissionConstants.TOOL_DELETE.get_workspace_permission())
65+
def delete(self, request: Request, workspace_id: str, tool_id: str):
66+
return result.success(ToolSerializer.Operate(
67+
data={'id': tool_id, 'workspace_id': workspace_id}
68+
).delete())

0 commit comments

Comments
 (0)