Skip to content

Commit d49fd74

Browse files
committed
feat: add ToolModule model and API for managing tool modules with workspace support
1 parent dcb77bb commit d49fd74

File tree

19 files changed

+439
-36
lines changed

19 files changed

+439
-36
lines changed

apps/common/constants/permission_constants.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class Group(Enum):
2121

2222
MODEL = "MODEL"
2323

24+
TOOL = "TOOL"
25+
2426

2527
class Operate(Enum):
2628
"""
@@ -111,8 +113,7 @@ class PermissionConstants(Enum):
111113
RoleConstants.USER])
112114
USER_EDIT = Permission(group=Group.USER, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN])
113115
USER_DELETE = Permission(group=Group.USER, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN])
114-
TOOL_CREATE = Permission(group=Group.USER, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
115-
RoleConstants.USER])
116+
116117
MODEL_CREATE = Permission(group=Group.MODEL, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
117118
RoleConstants.USER])
118119
MODEL_READ = Permission(group=Group.MODEL, operate=Operate.READ, role_list=[RoleConstants.ADMIN,
@@ -121,6 +122,15 @@ class PermissionConstants(Enum):
121122
role_list=[RoleConstants.ADMIN, RoleConstants.USER])
122123
MODEL_DELETE = Permission(group=Group.MODEL, operate=Operate.DELETE,
123124
role_list=[RoleConstants.ADMIN, RoleConstants.USER])
125+
TOOL_MODULE_CREATE = Permission(group=Group.TOOL, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
126+
RoleConstants.USER])
127+
TOOL_MODULE_READ = Permission(group=Group.TOOL, operate=Operate.READ, role_list=[RoleConstants.ADMIN,
128+
RoleConstants.USER])
129+
TOOL_MODULE_EDIT = Permission(group=Group.TOOL, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN,
130+
RoleConstants.USER])
131+
132+
TOOL_CREATE = Permission(group=Group.TOOL, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
133+
RoleConstants.USER])
124134

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

apps/maxkb/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
path("api/", include("users.urls")),
2525
path("api/", include("tools.urls")),
2626
path("api/", include("models_provider.urls")),
27+
path("api/", include("modules.urls"))
2728
]
2829
urlpatterns += [
2930
path('schema/', SpectacularAPIView.as_view(), name='schema'), # schema的配置文件的路由,下面两个ui也是根据这个配置文件来生成的

apps/modules/__init__.py

Whitespace-only changes.

apps/modules/api/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# coding=utf-8

apps/modules/api/module.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# coding=utf-8
2+
from drf_spectacular.types import OpenApiTypes
3+
from drf_spectacular.utils import OpenApiParameter
4+
5+
from common.mixins.api_mixin import APIMixin
6+
from common.result import ResultSerializer
7+
from modules.models.module import ModuleCreateRequest, ModuleEditRequest
8+
from modules.serializers.module import ModuleSerializer
9+
10+
11+
class ModuleCreateResponse(ResultSerializer):
12+
def get_data(self):
13+
return ModuleSerializer()
14+
15+
16+
class ModuleCreateAPI(APIMixin):
17+
@staticmethod
18+
def get_parameters():
19+
return [
20+
OpenApiParameter(
21+
name="workspace_id",
22+
description="工作空间id",
23+
type=OpenApiTypes.STR,
24+
location='path',
25+
required=True,
26+
),
27+
OpenApiParameter(
28+
name="source",
29+
description="菜单",
30+
type=OpenApiTypes.STR,
31+
enum=["APPLICATION", "KNOWLEDGE", "TOOL"],
32+
location='path',
33+
required=True,
34+
)
35+
]
36+
37+
@staticmethod
38+
def get_request():
39+
return ModuleCreateRequest
40+
41+
@staticmethod
42+
def get_response():
43+
return ModuleCreateResponse
44+
45+
46+
class ModuleReadAPI(APIMixin):
47+
@staticmethod
48+
def get_parameters():
49+
return [
50+
OpenApiParameter(
51+
name="workspace_id",
52+
description="工作空间id",
53+
type=OpenApiTypes.STR,
54+
location='path',
55+
required=True,
56+
),
57+
OpenApiParameter(
58+
name="source",
59+
description="菜单",
60+
type=OpenApiTypes.STR,
61+
enum=["APPLICATION", "KNOWLEDGE", "TOOL"],
62+
location='path',
63+
required=True,
64+
),
65+
OpenApiParameter(
66+
name="module_id",
67+
description="模块id",
68+
type=OpenApiTypes.STR,
69+
location='path',
70+
required=True,
71+
)
72+
]
73+
74+
@staticmethod
75+
def get_response():
76+
return ModuleCreateResponse
77+
78+
79+
class ModuleEditAPI(ModuleReadAPI):
80+
81+
@staticmethod
82+
def get_request():
83+
return ModuleEditRequest
84+
85+
86+
class ModuleTreeReadAPI(APIMixin):
87+
@staticmethod
88+
def get_parameters():
89+
return [
90+
OpenApiParameter(
91+
name="workspace_id",
92+
description="工作空间id",
93+
type=OpenApiTypes.STR,
94+
location='path',
95+
required=True,
96+
),
97+
OpenApiParameter(
98+
name="source",
99+
description="菜单",
100+
type=OpenApiTypes.STR,
101+
enum=["APPLICATION", "KNOWLEDGE", "TOOL"],
102+
location='path',
103+
required=True,
104+
)
105+
]

apps/modules/models/__init__.py

Whitespace-only changes.

apps/modules/models/module.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from django.utils.translation import gettext_lazy as _
2+
from rest_framework import serializers
3+
4+
5+
class ModuleCreateRequest(serializers.Serializer):
6+
name = serializers.CharField(required=True, label=_('module name'))
7+
8+
parent_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, default='root',
9+
label=_('parent id'))
10+
11+
12+
class ModuleEditRequest(serializers.Serializer):
13+
name = serializers.CharField(required=True, label=_('module name'))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# coding=utf-8

apps/modules/serializers/module.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import uuid_utils.compat as uuid
4+
from django.db.models import QuerySet
5+
from django.utils.translation import gettext_lazy as _
6+
from rest_framework import serializers
7+
8+
from common.constants.permission_constants import Group
9+
from modules.api.module import ModuleCreateRequest
10+
from tools.models import ToolModule
11+
from tools.serializers.tool_module import ToolModuleTreeSerializer
12+
13+
14+
def get_module_type(source):
15+
if source == Group.TOOL.name:
16+
return ToolModule
17+
elif source == Group.APPLICATION.name:
18+
# todo app module
19+
return None
20+
elif source == Group.KNOWLEDGE.name:
21+
# todo knowledge module
22+
return None
23+
else:
24+
return None
25+
26+
27+
class ModuleSerializer(serializers.Serializer):
28+
id = serializers.CharField(required=True, label=_('module id'))
29+
name = serializers.CharField(required=True, label=_('module name'))
30+
user_id = serializers.CharField(required=True, label=_('module user id'))
31+
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_('workspace id'))
32+
parent_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_('parent id'))
33+
34+
class Create(serializers.Serializer):
35+
user_id = serializers.UUIDField(required=True, label=_('user id'))
36+
source = serializers.CharField(required=True, label=_('source'))
37+
38+
def insert(self, instance, with_valid=True):
39+
if with_valid:
40+
self.is_valid(raise_exception=True)
41+
ModuleCreateRequest(data=instance).is_valid(raise_exception=True)
42+
43+
workspace_id = self.data.get('workspace_id', 'default')
44+
parent_id = instance.get('parent_id', 'root')
45+
name = instance.get('name')
46+
47+
Module = get_module_type(self.data.get('source'))
48+
if QuerySet(Module).filter(name=name, workspace_id=workspace_id, parent_id=parent_id).exists():
49+
raise serializers.ValidationError(_('Module name already exists'))
50+
51+
module = Module(
52+
id=uuid.uuid7(),
53+
name=instance.get('name'),
54+
user_id=self.data.get('user_id'),
55+
workspace_id=workspace_id,
56+
parent_id=parent_id
57+
)
58+
module.save()
59+
return ModuleSerializer(module).data
60+
61+
class Operate(serializers.Serializer):
62+
id = serializers.CharField(required=True, label=_('module id'))
63+
workspace_id = serializers.CharField(required=True, allow_null=True, allow_blank=True, label=_('workspace id'))
64+
source = serializers.CharField(required=True, label=_('source'))
65+
66+
def edit(self, instance):
67+
self.is_valid(raise_exception=True)
68+
Module = get_module_type(self.data.get('source'))
69+
if not QuerySet(Module).filter(id=self.data.get('id')).exists():
70+
raise serializers.ValidationError(_('Module does not exist'))
71+
72+
edit_field_list = ['name']
73+
edit_dict = {field: instance.get(field) for field in edit_field_list if (
74+
field in instance and instance.get(field) is not None)}
75+
76+
QuerySet(Module).filter(id=self.data.get('id')).update(**edit_dict)
77+
78+
return self.one()
79+
80+
def one(self):
81+
self.is_valid(raise_exception=True)
82+
Module = get_module_type(self.data.get('source'))
83+
module = QuerySet(Module).filter(id=self.data.get('id')).first()
84+
return ModuleSerializer(module).data
85+
86+
87+
class ModuleTreeSerializer(serializers.Serializer):
88+
workspace_id = serializers.CharField(required=True, allow_null=True, allow_blank=True, label=_('workspace id'))
89+
source = serializers.CharField(required=True, label=_('source'))
90+
91+
def get_module_tree(self):
92+
self.is_valid(raise_exception=True)
93+
Module = get_module_type(self.data.get('source'))
94+
nodes = Module.objects.filter(workspace_id=self.data.get('workspace_id')).get_cached_trees()
95+
serializer = ToolModuleTreeSerializer(nodes, many=True)
96+
return serializer.data # 这是可序列化的字典

apps/modules/urls.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from django.urls import path
2+
3+
from . import views
4+
5+
app_name = "module"
6+
urlpatterns = [
7+
path('workspace/<str:workspace_id>/<str:source>/module', views.ModuleView.Create.as_view()),
8+
path('workspace/<str:workspace_id>/<str:source>/module/tree', views.ModuleTreeView.as_view()),
9+
path('workspace/<str:workspace_id>/<str:source>/module/<str:module_id>', views.ModuleView.Operate.as_view()),
10+
]

0 commit comments

Comments
 (0)