Skip to content

Commit 6c436b6

Browse files
authored
Merge branch 'v2' into pr@v2@feat_resource_permission
2 parents 2a00d3c + 7aa294d commit 6c436b6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1433
-2507
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# coding=utf-8
2+
"""
3+
@project: qabot
4+
@Author:虎
5+
@file: exception_code_constants.py
6+
@date:2023/9/4 14:09
7+
@desc: 异常常量类
8+
"""
9+
from enum import Enum
10+
11+
from common.exception.app_exception import AppApiException
12+
from django.utils.translation import gettext_lazy as _
13+
14+
15+
class ExceptionCodeConstantsValue:
16+
def __init__(self, code, message):
17+
self.code = code
18+
self.message = message
19+
20+
def get_message(self):
21+
return self.message
22+
23+
def get_code(self):
24+
return self.code
25+
26+
def to_app_api_exception(self):
27+
return AppApiException(code=self.code, message=self.message)
28+
29+
30+
class ExceptionCodeConstants(Enum):
31+
INCORRECT_USERNAME_AND_PASSWORD = ExceptionCodeConstantsValue(1000, _('The username or password is incorrect'))
32+
NOT_AUTHENTICATION = ExceptionCodeConstantsValue(1001, _('Please log in first and bring the user Token'))
33+
EMAIL_SEND_ERROR = ExceptionCodeConstantsValue(1002, _('Email sending failed'))
34+
EMAIL_FORMAT_ERROR = ExceptionCodeConstantsValue(1003, _('Email format error'))
35+
EMAIL_IS_EXIST = ExceptionCodeConstantsValue(1004, _('The email has been registered, please log in directly'))
36+
EMAIL_IS_NOT_EXIST = ExceptionCodeConstantsValue(1005, _('The email is not registered, please register first'))
37+
CODE_ERROR = ExceptionCodeConstantsValue(1005,
38+
_('The verification code is incorrect or the verification code has expired'))
39+
USERNAME_IS_EXIST = ExceptionCodeConstantsValue(1006, _('The username has been registered, please log in directly'))
40+
USERNAME_ERROR = ExceptionCodeConstantsValue(1006,
41+
_('The username cannot be empty and must be between 6 and 20 characters long.'))
42+
PASSWORD_NOT_EQ_RE_PASSWORD = ExceptionCodeConstantsValue(1007,
43+
_('Password and confirmation password are inconsistent'))

apps/common/constants/permission_constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ class PermissionConstants(Enum):
153153
"""
154154
USER_READ = Permission(group=Group.USER, operate=Operate.READ, role_list=[RoleConstants.ADMIN,
155155
RoleConstants.USER])
156+
USER_CREATE = Permission(group=Group.USER, operate=Operate.CREATE,
157+
role_list=[RoleConstants.ADMIN, RoleConstants.USER])
156158
USER_EDIT = Permission(group=Group.USER, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN])
157159
USER_DELETE = Permission(group=Group.USER, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN])
158160

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: db_model_manage.py
6+
@date:2024/7/22 17:00
7+
@desc:
8+
"""
9+
from importlib import import_module
10+
from django.conf import settings
11+
12+
13+
def new_instance_by_class_path(class_path: str):
14+
parts = class_path.rpartition('.')
15+
package_path = parts[0]
16+
class_name = parts[2]
17+
module = import_module(package_path)
18+
HandlerClass = getattr(module, class_name)
19+
return HandlerClass()
20+
21+
22+
class DBModelManage:
23+
model_dict = {}
24+
25+
@staticmethod
26+
def get_model(model_name):
27+
return DBModelManage.model_dict.get(model_name)
28+
29+
@staticmethod
30+
def init():
31+
handles = [new_instance_by_class_path(class_path) for class_path in
32+
(settings.MODEL_HANDLES if hasattr(settings, 'MODEL_HANDLES') else [])]
33+
for h in handles:
34+
model_dict = h.get_model_dict()
35+
DBModelManage.model_dict = {**DBModelManage.model_dict, **model_dict}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: base_handle.py
6+
@date:2024/7/22 17:02
7+
@desc:
8+
"""
9+
from abc import ABC, abstractmethod
10+
11+
12+
class IBaseModelHandle(ABC):
13+
@abstractmethod
14+
def get_model_dict(self):
15+
pass
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: default_base_model_handle.py
6+
@date:2024/7/22 17:06
7+
@desc:
8+
"""
9+
from common.models.handle.base_handle import IBaseModelHandle
10+
11+
12+
class DefaultBaseModelHandle(IBaseModelHandle):
13+
def get_model_dict(self):
14+
return {}

apps/common/utils/common.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
from typing import List, Dict
1818

1919
from django.core.files.uploadedfile import InMemoryUploadedFile
20+
from django.db.models import QuerySet
2021
from django.utils.translation import gettext as _
2122
from pydub import AudioSegment
2223

2324
from ..exception.app_exception import AppApiException
25+
from ..models.db_model_manage import DBModelManage
2426

2527

2628
def password_encrypt(row_password):
@@ -211,3 +213,23 @@ def query_params_to_single_dict(query_params: Dict):
211213
filter(lambda item: item is not None, [({key: value} if value is not None and len(value) > 0 else None) for
212214
key, value in
213215
query_params.items()])), {})
216+
217+
218+
def valid_license(model=None, count=None, message=None):
219+
def inner(func):
220+
def run(*args, **kwargs):
221+
xpack_cache = DBModelManage.get_model('xpack_cache')
222+
is_license_valid = xpack_cache.get('XPACK_LICENSE_IS_VALID', False) if xpack_cache is not None else False
223+
record_count = QuerySet(model).count()
224+
225+
if not is_license_valid and record_count >= count:
226+
error_message = message or _(
227+
'Limit {count} exceeded, please contact us (https://fit2cloud.com/).').format(
228+
count=count)
229+
raise AppApiException(400, error_message)
230+
231+
return func(*args, **kwargs)
232+
233+
return run
234+
235+
return inner

apps/knowledge/api/knowledge.py

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -55,50 +55,6 @@ def get_response():
5555
return KnowledgeCreateResponse
5656

5757

58-
class KnowledgeLarkCreateAPI(APIMixin):
59-
@staticmethod
60-
def get_parameters():
61-
return [
62-
OpenApiParameter(
63-
name="workspace_id",
64-
description="工作空间id",
65-
type=OpenApiTypes.STR,
66-
location='path',
67-
required=True,
68-
)
69-
]
70-
71-
@staticmethod
72-
def get_request():
73-
return KnowledgeBaseCreateRequest
74-
75-
@staticmethod
76-
def get_response():
77-
return KnowledgeCreateResponse
78-
79-
80-
class KnowledgeYuqueCreateAPI(APIMixin):
81-
@staticmethod
82-
def get_parameters():
83-
return [
84-
OpenApiParameter(
85-
name="workspace_id",
86-
description="工作空间id",
87-
type=OpenApiTypes.STR,
88-
location='path',
89-
required=True,
90-
)
91-
]
92-
93-
@staticmethod
94-
def get_request():
95-
return KnowledgeBaseCreateRequest
96-
97-
@staticmethod
98-
def get_response():
99-
return KnowledgeCreateResponse
100-
101-
10258
class KnowledgeTreeReadAPI(APIMixin):
10359
@staticmethod
10460
def get_parameters():

apps/knowledge/urls.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,4 @@
77
path('workspace/<str:workspace_id>/knowledge', views.KnowledgeView.as_view()),
88
path('workspace/<str:workspace_id>/knowledge/base', views.KnowledgeBaseView.as_view()),
99
path('workspace/<str:workspace_id>/knowledge/web', views.KnowledgeWebView.as_view()),
10-
path('workspace/<str:workspace_id>/knowledge/lark', views.KnowledgeLarkView.as_view()),
11-
path('workspace/<str:workspace_id>/knowledge/yuque', views.KnowledgeYuqueView.as_view()),
1210
]

apps/knowledge/views/knowledge.py

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
from common.auth.authentication import has_permissions
88
from common.constants.permission_constants import PermissionConstants
99
from common.result import result
10-
from knowledge.api.knowledge import KnowledgeBaseCreateAPI, KnowledgeLarkCreateAPI, \
11-
KnowledgeWebCreateAPI, KnowledgeYuqueCreateAPI, KnowledgeTreeReadAPI
10+
from knowledge.api.knowledge import KnowledgeBaseCreateAPI, KnowledgeWebCreateAPI, KnowledgeTreeReadAPI
1211
from knowledge.serializers.knowledge import KnowledgeSerializer, KnowledgeTreeSerializer
1312

1413

@@ -66,41 +65,3 @@ def post(self, request: Request, workspace_id: str):
6665
return result.success(KnowledgeSerializer.Create(
6766
data={'user_id': request.user.id, 'workspace_id': workspace_id}
6867
).insert(request.data))
69-
70-
71-
class KnowledgeLarkView(APIView):
72-
authentication_classes = [TokenAuth]
73-
74-
@extend_schema(
75-
methods=['POST'],
76-
description=_('Create lark knowledge'),
77-
operation_id=_('Create lark knowledge'),
78-
parameters=KnowledgeLarkCreateAPI.get_parameters(),
79-
request=KnowledgeLarkCreateAPI.get_request(),
80-
responses=KnowledgeLarkCreateAPI.get_response(),
81-
tags=[_('Knowledge Base')]
82-
)
83-
@has_permissions(PermissionConstants.KNOWLEDGE_CREATE.get_workspace_permission())
84-
def post(self, request: Request, workspace_id: str):
85-
return result.success(KnowledgeSerializer.Create(
86-
data={'user_id': request.user.id, 'workspace_id': workspace_id}
87-
).insert(request.data))
88-
89-
90-
class KnowledgeYuqueView(APIView):
91-
authentication_classes = [TokenAuth]
92-
93-
@extend_schema(
94-
methods=['POST'],
95-
description=_('Create yuque knowledge'),
96-
operation_id=_('Create yuque knowledge'),
97-
parameters=KnowledgeYuqueCreateAPI.get_parameters(),
98-
request=KnowledgeYuqueCreateAPI.get_request(),
99-
responses=KnowledgeYuqueCreateAPI.get_response(),
100-
tags=[_('Knowledge Base')]
101-
)
102-
@has_permissions(PermissionConstants.KNOWLEDGE_CREATE.get_workspace_permission())
103-
def post(self, request: Request, workspace_id: str):
104-
return result.success(KnowledgeSerializer.Create(
105-
data={'user_id': request.user.id, 'workspace_id': workspace_id}
106-
).insert(request.data))

apps/modules/serializers/module.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ def get_module_type(source):
2525
return None
2626

2727

28-
MODULE_DEPTH = 3 # Module 不能超过3层
28+
MODULE_DEPTH = 2 # Module 不能超过3层
2929

3030

31-
def check_depth(source, parent_id):
31+
def check_depth(source, parent_id, current_depth=0):
3232
# Module 不能超过3层
3333
Module = get_module_type(source)
3434

@@ -46,10 +46,28 @@ def check_depth(source, parent_id):
4646
current_parent_id = parent_node.parent_id
4747

4848
# 验证层级深度
49-
if depth > MODULE_DEPTH:
49+
if depth + current_depth > MODULE_DEPTH:
5050
raise serializers.ValidationError(_('Module depth cannot exceed 3 levels'))
5151

5252

53+
def get_max_depth(current_node):
54+
if not current_node:
55+
return 0
56+
57+
# 获取所有后代节点
58+
descendants = current_node.get_descendants()
59+
60+
if not descendants.exists():
61+
return 0
62+
63+
# 获取最大深度
64+
max_level = descendants.order_by('-level').first().level
65+
current_level = current_node.level
66+
max_depth = max_level - current_level
67+
68+
return max_depth
69+
70+
5371
class ModuleSerializer(serializers.Serializer):
5472
id = serializers.CharField(required=True, label=_('module id'))
5573
name = serializers.CharField(required=True, label=_('module name'))
@@ -110,7 +128,8 @@ def edit(self, instance):
110128
parent_id = instance.get('parent_id')
111129
if parent_id is not None and current_id != 'root':
112130
# Module 不能超过3层
113-
check_depth(self.data.get('source'), parent_id)
131+
current_depth = get_max_depth(current_node)
132+
check_depth(self.data.get('source'), parent_id, current_depth)
114133
parent = Module.objects.get(id=parent_id)
115134
current_node.move_to(parent)
116135

0 commit comments

Comments
 (0)