mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
parent
ed526c3bf3
commit
60e65a8b17
|
|
@ -32,6 +32,7 @@ from common.db.search import get_dynamics_model, native_search, native_page_sear
|
|||
from common.db.sql_execute import select_list
|
||||
from common.exception.app_exception import AppApiException, NotFound404, AppUnauthorizedFailed
|
||||
from common.field.common import UploadedImageField
|
||||
from common.util.common import valid_license
|
||||
from common.util.field_message import ErrMessage
|
||||
from common.util.file_util import get_file_content
|
||||
from dataset.models import DataSet, Document, Image
|
||||
|
|
@ -329,6 +330,8 @@ class ApplicationSerializer(serializers.Serializer):
|
|||
class Create(serializers.Serializer):
|
||||
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))
|
||||
|
||||
@valid_license(model=Application, count=5,
|
||||
message='社区版最多支持 5 个应用,如需拥有更多应用,请联系我们(https://fit2cloud.com/)。')
|
||||
@transaction.atomic
|
||||
def insert(self, application: Dict):
|
||||
application_type = application.get('type')
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ import importlib
|
|||
from functools import reduce
|
||||
from typing import Dict, List
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from ..exception.app_exception import AppApiException
|
||||
|
||||
|
||||
def sub_array(array: List, item_num=10):
|
||||
result = []
|
||||
|
|
@ -66,3 +71,19 @@ def post(post_function):
|
|||
return run
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
def valid_license(model=None, count=None, message=None):
|
||||
def inner(func):
|
||||
def run(*args, **kwargs):
|
||||
if (not (settings.XPACK_LICENSE_IS_VALID if hasattr(settings,
|
||||
'XPACK_LICENSE_IS_VALID') else None)
|
||||
and QuerySet(
|
||||
model).count() >= count):
|
||||
error = message or f'超出限制{count},请联系我们(https://fit2cloud.com/)。'
|
||||
raise AppApiException(400, error)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return run
|
||||
|
||||
return inner
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from functools import reduce
|
|||
from typing import Dict, List
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import xlwt
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.core import validators
|
||||
from django.db import transaction, models
|
||||
|
|
@ -31,7 +31,7 @@ from common.db.sql_execute import select_list
|
|||
from common.event import ListenerManagement, SyncWebDatasetArgs
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.mixins.api_mixin import ApiMixin
|
||||
from common.util.common import post, flat_map
|
||||
from common.util.common import post, flat_map, valid_license
|
||||
from common.util.field_message import ErrMessage
|
||||
from common.util.file_util import get_file_content
|
||||
from common.util.fork import ChildLink, Fork
|
||||
|
|
@ -368,6 +368,8 @@ class DataSetSerializers(serializers.ModelSerializer):
|
|||
dataset_instance = {'name': instance.get('name'), 'desc': instance.get('desc'), 'documents': document_list}
|
||||
return self.save(dataset_instance, with_valid=True)
|
||||
|
||||
@valid_license(model=DataSet, count=50,
|
||||
message='社区版最多支持 50 个知识库,如需拥有更多知识库,请联系我们(https://fit2cloud.com/)。')
|
||||
@post(post_function=post_embedding_dataset)
|
||||
@transaction.atomic
|
||||
def save(self, instance: Dict, with_valid=True):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: MaxKB
|
||||
@Author:虎
|
||||
@file: valid_serializers.py
|
||||
@date:2024/7/8 18:00
|
||||
@desc:
|
||||
"""
|
||||
import re
|
||||
|
||||
from django.core import validators
|
||||
from django.db.models import QuerySet
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.models import Application
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.util.field_message import ErrMessage
|
||||
from dataset.models import DataSet
|
||||
from smartdoc import settings
|
||||
from users.models import User
|
||||
|
||||
model_message_dict = {
|
||||
'dataset': {'model': DataSet, 'count': 50,
|
||||
'message': '社区版最多支持 50 个知识库,如需拥有更多知识库,请联系我们(https://fit2cloud.com/)。'},
|
||||
'application': {'model': Application, 'count': 5,
|
||||
'message': '社区版最多支持 5 个应用,如需拥有更多应用,请联系我们(https://fit2cloud.com/)。'},
|
||||
'user': {'model': User, 'count': 2,
|
||||
'message': '社区版最多支持 2 个用户,如需拥有更多用户,请联系我们(https://fit2cloud.com/)。'}
|
||||
}
|
||||
|
||||
|
||||
class ValidSerializer(serializers.Serializer):
|
||||
valid_type = serializers.CharField(required=True, error_messages=ErrMessage.char("类型"), validators=[
|
||||
validators.RegexValidator(regex=re.compile("^application|dataset|user$"),
|
||||
message="类型只支持:application|dataset|user", code=500)
|
||||
])
|
||||
valid_count = serializers.IntegerField(required=True, error_messages=ErrMessage.integer("校验数量"))
|
||||
|
||||
def valid(self, is_valid=True):
|
||||
if is_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
model_value = model_message_dict.get(self.data.get('valid_type'))
|
||||
if not (settings.XPACK_LICENSE_IS_VALID if hasattr(settings,
|
||||
'XPACK_LICENSE_IS_VALID') else None):
|
||||
if self.data.get('valid_count') != model_value.get('count'):
|
||||
raise AppApiException(400, model_value.get('message'))
|
||||
if QuerySet(
|
||||
model_value.get('model')).count() >= model_value.get('count'):
|
||||
raise AppApiException(400, model_value.get('message'))
|
||||
return True
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: MaxKB
|
||||
@Author:虎
|
||||
@file: valid_api.py
|
||||
@date:2024/7/8 17:52
|
||||
@desc:
|
||||
"""
|
||||
from drf_yasg import openapi
|
||||
|
||||
from common.mixins.api_mixin import ApiMixin
|
||||
|
||||
|
||||
class ValidApi(ApiMixin):
|
||||
@staticmethod
|
||||
def get_request_params_api():
|
||||
return [openapi.Parameter(name='valid_type',
|
||||
in_=openapi.IN_PATH,
|
||||
type=openapi.TYPE_STRING,
|
||||
required=True,
|
||||
description='校验类型:application|dataset|user'),
|
||||
openapi.Parameter(name='valid_count',
|
||||
in_=openapi.IN_PATH,
|
||||
type=openapi.TYPE_STRING,
|
||||
required=True,
|
||||
description='校验数量')
|
||||
]
|
||||
|
|
@ -17,6 +17,7 @@ urlpatterns = [
|
|||
path('model', views.Model.as_view(), name='model'),
|
||||
path('model/<str:model_id>', views.Model.Operate.as_view(), name='model/operate'),
|
||||
path('model/<str:model_id>/meta', views.Model.ModelMeta.as_view(), name='model/operate/meta'),
|
||||
path('email_setting', views.SystemSetting.Email.as_view(), name='email_setting')
|
||||
path('email_setting', views.SystemSetting.Email.as_view(), name='email_setting'),
|
||||
path('valid/<str:valid_type>/<int:valid_count>', views.Valid.as_view())
|
||||
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@
|
|||
from .Team import *
|
||||
from .model import *
|
||||
from .system_setting import *
|
||||
from .valid import *
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: MaxKB
|
||||
@Author:虎
|
||||
@file: valid.py
|
||||
@date:2024/7/8 17:50
|
||||
@desc:
|
||||
"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from common.auth import TokenAuth, has_permissions
|
||||
from common.constants.permission_constants import RoleConstants
|
||||
from common.response import result
|
||||
from setting.serializers.valid_serializers import ValidSerializer
|
||||
from setting.swagger_api.valid_api import ValidApi
|
||||
|
||||
|
||||
class Valid(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
@swagger_auto_schema(operation_summary="获取校验结果",
|
||||
operation_id="获取校验结果",
|
||||
manual_parameters=ValidApi.get_request_params_api(),
|
||||
responses=result.get_default_response()
|
||||
, tags=["校验"])
|
||||
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
|
||||
def get(self, request: Request, valid_type: str, valid_count: int):
|
||||
return result.success(ValidSerializer(data={'valid_type': valid_type, 'valid_count': valid_count}).valid())
|
||||
|
|
@ -12,6 +12,7 @@ import random
|
|||
import re
|
||||
import uuid
|
||||
|
||||
from django.conf import settings
|
||||
from django.core import validators, signing, cache
|
||||
from django.core.mail import send_mail
|
||||
from django.core.mail.backends.smtp import EmailBackend
|
||||
|
|
@ -29,6 +30,7 @@ from common.event import ListenerManagement
|
|||
from common.exception.app_exception import AppApiException
|
||||
from common.mixins.api_mixin import ApiMixin
|
||||
from common.response.result import get_api_response
|
||||
from common.util.common import valid_license
|
||||
from common.util.field_message import ErrMessage
|
||||
from common.util.lock import lock
|
||||
from dataset.models import DataSet, Document, Paragraph, Problem, ProblemParagraphMapping
|
||||
|
|
@ -43,7 +45,9 @@ class SystemSerializer(ApiMixin, serializers.Serializer):
|
|||
@staticmethod
|
||||
def get_profile():
|
||||
version = os.environ.get('MAXKB_VERSION')
|
||||
return {'version': version}
|
||||
return {'version': version, 'IS_XPACK': hasattr(settings, 'XPACK_LICENSE_IS_VALID'),
|
||||
'XPACK_LICENSE_IS_VALID': (settings.XPACK_LICENSE_IS_VALID if hasattr(settings,
|
||||
'XPACK_LICENSE_IS_VALID') else False)}
|
||||
|
||||
@staticmethod
|
||||
def get_response_body_api():
|
||||
|
|
@ -174,6 +178,8 @@ class RegisterSerializer(ApiMixin, serializers.Serializer):
|
|||
|
||||
return True
|
||||
|
||||
@valid_license(model=User, count=2,
|
||||
message='社区版最多支持 2 个用户,如需拥有更多用户,请联系我们(https://fit2cloud.com/)。')
|
||||
@transaction.atomic
|
||||
def save(self, **kwargs):
|
||||
m = User(
|
||||
|
|
@ -681,6 +687,8 @@ class UserManageSerializer(serializers.Serializer):
|
|||
if self.data.get('password') != self.data.get('re_password'):
|
||||
raise ExceptionCodeConstants.PASSWORD_NOT_EQ_RE_PASSWORD.value.to_app_api_exception()
|
||||
|
||||
@valid_license(model=User, count=2,
|
||||
message='社区版最多支持 2 个用户,如需拥有更多用户,请联系我们(https://fit2cloud.com/)。')
|
||||
@transaction.atomic
|
||||
def save(self, instance, with_valid=True):
|
||||
if with_valid:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ interface User {
|
|||
* 是否需要修改密码
|
||||
*/
|
||||
is_edit_password?: boolean
|
||||
IS_XPACK?: boolean
|
||||
XPACK_LICENSE_IS_VALID?: boolean
|
||||
}
|
||||
|
||||
interface LoginRequest {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,19 @@ const getVersion: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) =
|
|||
return get('/profile', undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取校验
|
||||
* @param valid_type 校验类型: application|dataset|user
|
||||
* @param valid_count 校验数量: 5 | 50 | 2
|
||||
*/
|
||||
const getValid: (
|
||||
valid_type: string,
|
||||
valid_count: number,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (valid_type, valid_count, loading) => {
|
||||
return get(`/valid/${valid_type}/${valid_count}`, undefined, loading)
|
||||
}
|
||||
|
||||
export default {
|
||||
login,
|
||||
register,
|
||||
|
|
@ -142,5 +155,6 @@ export default {
|
|||
resetCurrentUserPassword,
|
||||
logout,
|
||||
getUserList,
|
||||
getVersion
|
||||
getVersion,
|
||||
getValid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,15 @@ export enum DeviceType {
|
|||
Mobile = 'Mobile',
|
||||
Desktop = 'Desktop'
|
||||
}
|
||||
|
||||
export enum ValidType {
|
||||
Application = 'application',
|
||||
Dataset = 'dataset',
|
||||
User = 'user'
|
||||
}
|
||||
|
||||
export enum ValidCount {
|
||||
Application = 5,
|
||||
Dataset = 50,
|
||||
User = 2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,10 @@ instance.interceptors.response.use(
|
|||
(response: any) => {
|
||||
if (response.data) {
|
||||
if (response.data.code !== 200 && !(response.data instanceof Blob)) {
|
||||
MsgError(response.data.message)
|
||||
return Promise.reject(response.data)
|
||||
if (!response.config.url.includes('/valid')) {
|
||||
MsgError(response.data.message)
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { DeviceType } from '@/enums/common'
|
||||
import { DeviceType, ValidType } from '@/enums/common'
|
||||
import type { Ref } from 'vue'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export interface commonTypes {
|
||||
breadcrumb: any
|
||||
|
|
@ -32,6 +34,18 @@ const useCommonStore = defineStore({
|
|||
},
|
||||
isMobile() {
|
||||
return this.device === DeviceType.Mobile
|
||||
},
|
||||
async asyncGetValid(valid_type: ValidType, valid_count: number, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
userApi
|
||||
.getValid(valid_type, valid_count, loading)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export interface userStateTypes {
|
|||
token: any
|
||||
version?: string
|
||||
accessToken?: string
|
||||
isXPack: false
|
||||
}
|
||||
|
||||
const useUserStore = defineStore({
|
||||
|
|
@ -16,9 +17,13 @@ const useUserStore = defineStore({
|
|||
userType: 1,
|
||||
userInfo: null,
|
||||
token: '',
|
||||
version: ''
|
||||
version: '',
|
||||
isXPack: false
|
||||
}),
|
||||
actions: {
|
||||
isEnterprise() {
|
||||
return this.userInfo?.IS_XPACK && this.userInfo?.XPACK_LICENSE_IS_VALID
|
||||
},
|
||||
getToken(): String | null {
|
||||
if (this.token) {
|
||||
return this.token
|
||||
|
|
|
|||
|
|
@ -36,6 +36,14 @@ export const MsgError = (message: string) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const MsgAlert = (title: string, description: string, options?: any) => {
|
||||
const defaultOptions: Object = {
|
||||
confirmButtonText: '确定',
|
||||
...options
|
||||
}
|
||||
return ElMessageBox.alert(description, title, defaultOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库
|
||||
* @param 参数 message: {title, description,type}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
<el-button @click.prevent="dialogVisible = false">
|
||||
{{ $t('views.application.applicationForm.buttons.cancel') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="submitHandle(applicationFormRef)">
|
||||
<el-button type="primary" @click="submitValid(applicationFormRef)">
|
||||
{{ $t('views.application.applicationForm.buttons.create') }}
|
||||
</el-button>
|
||||
</span>
|
||||
|
|
@ -79,9 +79,13 @@ import { useRouter, useRoute } from 'vue-router'
|
|||
import type { ApplicationFormType } from '@/api/type/application'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import applicationApi from '@/api/application'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { MsgSuccess, MsgAlert } from '@/utils/message'
|
||||
import { isWorkFlow } from '@/utils/application'
|
||||
import { t } from '@/locales'
|
||||
import useStore from '@/stores'
|
||||
import { ValidType, ValidCount } from '@/enums/common'
|
||||
|
||||
const { common, user } = useStore()
|
||||
const router = useRouter()
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
|
|
@ -169,6 +173,24 @@ const open = () => {
|
|||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const submitValid = (formEl: FormInstance | undefined) => {
|
||||
if (user.isEnterprise()) {
|
||||
submitHandle(formEl)
|
||||
} else {
|
||||
common
|
||||
.asyncGetValid(ValidType.Application, ValidCount.Application, loading)
|
||||
.then(async (res: any) => {
|
||||
if (res?.data?.data) {
|
||||
submitHandle(formEl)
|
||||
} else {
|
||||
MsgAlert(
|
||||
'提示',
|
||||
'社区版最多支持 5 个应用,如需拥有更多应用,请联系我们(https://fit2cloud.com/)。'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const submitHandle = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid) => {
|
||||
|
|
|
|||
|
|
@ -83,9 +83,13 @@
|
|||
import { ref, onMounted, reactive } from 'vue'
|
||||
import UserDialog from './component/UserDialog.vue'
|
||||
import UserPwdDialog from './component/UserPwdDialog.vue'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import { MsgSuccess, MsgConfirm, MsgAlert } from '@/utils/message'
|
||||
import userApi from '@/api/user-manage'
|
||||
import { datetimeFormat } from '@/utils/time'
|
||||
import useStore from '@/stores'
|
||||
import { ValidType, ValidCount } from '@/enums/common'
|
||||
|
||||
const { common, user } = useStore()
|
||||
|
||||
const UserDialogRef = ref()
|
||||
const UserPwdDialogRef = ref()
|
||||
|
|
@ -127,8 +131,22 @@ function editUser(row: any) {
|
|||
}
|
||||
|
||||
function createUser() {
|
||||
title.value = '创建用户'
|
||||
UserDialogRef.value.open()
|
||||
if (user.isEnterprise()) {
|
||||
title.value = '创建用户'
|
||||
UserDialogRef.value.open()
|
||||
} else {
|
||||
common.asyncGetValid(ValidType.User, ValidCount.User, loading).then((res: any) => {
|
||||
if (res?.data?.data) {
|
||||
title.value = '创建用户'
|
||||
UserDialogRef.value.open()
|
||||
} else {
|
||||
MsgAlert(
|
||||
'提示',
|
||||
'社区版最多支持 2 个用户,如需拥有更多用户,请联系我们(https://fit2cloud.com/)。'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function deleteUserManage(row: any) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue