perf: password check;perf: image upload check;perf: sso login check (#3509)
* perf: password check * perf: image upload check * perf: sso login check
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
import { ErrType } from '../errorCode';
|
||||
|
||||
/* dataset: 507000 */
|
||||
const startCode = 507000;
|
||||
export enum CommonErrEnum {
|
||||
invalidParams = 'invalidParams',
|
||||
fileNotFound = 'fileNotFound',
|
||||
unAuthFile = 'unAuthFile',
|
||||
missingParams = 'missingParams',
|
||||
inheritPermissionError = 'inheritPermissionError'
|
||||
}
|
||||
const datasetErr = [
|
||||
{
|
||||
statusText: CommonErrEnum.fileNotFound,
|
||||
message: i18nT('common:error.invalid_params')
|
||||
},
|
||||
{
|
||||
statusText: CommonErrEnum.fileNotFound,
|
||||
message: 'error.fileNotFound'
|
||||
|
||||
@@ -16,11 +16,7 @@ const errList = [
|
||||
{
|
||||
statusText: UserErrEnum.binVisitor,
|
||||
message: i18nT('common:code_error.user_error.bin_visitor')
|
||||
}, // 身份校验未通过
|
||||
{
|
||||
statusText: UserErrEnum.binVisitor,
|
||||
message: i18nT('common:code_error.user_error.bin_visitor_guest')
|
||||
}, // 游客身份
|
||||
},
|
||||
{
|
||||
statusText: UserErrEnum.balanceNotEnough,
|
||||
message: i18nT('common:code_error.user_error.balance_not_enough')
|
||||
|
||||
5
packages/global/common/file/api.d.ts
vendored
5
packages/global/common/file/api.d.ts
vendored
@@ -1,10 +1,7 @@
|
||||
import { MongoImageTypeEnum } from './image/constants';
|
||||
import { OutLinkChatAuthProps } from '../../support/permission/chat.d';
|
||||
|
||||
export type preUploadImgProps = OutLinkChatAuthProps & {
|
||||
type: `${MongoImageTypeEnum}`;
|
||||
|
||||
expiredTime?: Date;
|
||||
// expiredTime?: Date;
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
export type UploadImgProps = preUploadImgProps & {
|
||||
|
||||
@@ -1,66 +1,5 @@
|
||||
export const imageBaseUrl = '/api/system/img/';
|
||||
|
||||
export enum MongoImageTypeEnum {
|
||||
systemAvatar = 'systemAvatar',
|
||||
appAvatar = 'appAvatar',
|
||||
pluginAvatar = 'pluginAvatar',
|
||||
datasetAvatar = 'datasetAvatar',
|
||||
userAvatar = 'userAvatar',
|
||||
teamAvatar = 'teamAvatar',
|
||||
groupAvatar = 'groupAvatar',
|
||||
orgAvatar = 'orgAvatar',
|
||||
|
||||
chatImage = 'chatImage',
|
||||
collectionImage = 'collectionImage'
|
||||
}
|
||||
export const mongoImageTypeMap = {
|
||||
[MongoImageTypeEnum.systemAvatar]: {
|
||||
label: 'appAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.appAvatar]: {
|
||||
label: 'appAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.pluginAvatar]: {
|
||||
label: 'pluginAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.datasetAvatar]: {
|
||||
label: 'datasetAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.userAvatar]: {
|
||||
label: 'userAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.teamAvatar]: {
|
||||
label: 'teamAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.groupAvatar]: {
|
||||
label: 'groupAvatar',
|
||||
unique: true
|
||||
},
|
||||
[MongoImageTypeEnum.orgAvatar]: {
|
||||
label: 'orgAvatar',
|
||||
unique: true
|
||||
},
|
||||
|
||||
[MongoImageTypeEnum.chatImage]: {
|
||||
label: 'chatImage',
|
||||
unique: false
|
||||
},
|
||||
[MongoImageTypeEnum.collectionImage]: {
|
||||
label: 'collectionImage',
|
||||
unique: false
|
||||
}
|
||||
};
|
||||
|
||||
export const uniqueImageTypeList = Object.entries(mongoImageTypeMap)
|
||||
.filter(([key, value]) => value.unique)
|
||||
.map(([key]) => key as `${MongoImageTypeEnum}`);
|
||||
|
||||
export const FolderIcon = 'file/fill/folder';
|
||||
export const FolderImgUrl = '/imgs/files/folder.svg';
|
||||
export const HttpPluginImgUrl = '/imgs/app/httpPluginFill.svg';
|
||||
|
||||
4
packages/global/common/file/image/type.d.ts
vendored
4
packages/global/common/file/image/type.d.ts
vendored
@@ -1,12 +1,8 @@
|
||||
import { MongoImageTypeEnum } from './constants';
|
||||
|
||||
export type MongoImageSchemaType = {
|
||||
_id: string;
|
||||
teamId: string;
|
||||
binary: Buffer;
|
||||
createTime: Date;
|
||||
expiredTime?: Date;
|
||||
type: `${MongoImageTypeEnum}`;
|
||||
|
||||
metadata?: {
|
||||
mime?: string; // image mime type.
|
||||
|
||||
@@ -1,43 +1,92 @@
|
||||
import { UploadImgProps } from '@fastgpt/global/common/file/api';
|
||||
import { imageBaseUrl } from '@fastgpt/global/common/file/image/constants';
|
||||
import { MongoImage } from './schema';
|
||||
import { ClientSession } from '../../../common/mongo';
|
||||
import { ClientSession, Types } from '../../../common/mongo';
|
||||
import { guessBase64ImageType } from '../utils';
|
||||
import { readFromSecondary } from '../../mongo/utils';
|
||||
import { addHours } from 'date-fns';
|
||||
|
||||
export const maxImgSize = 1024 * 1024 * 12;
|
||||
const base64MimeRegex = /data:image\/([^\)]+);base64/;
|
||||
export async function uploadMongoImg({
|
||||
type,
|
||||
base64Img,
|
||||
teamId,
|
||||
expiredTime,
|
||||
metadata,
|
||||
shareId
|
||||
shareId,
|
||||
forever = false
|
||||
}: UploadImgProps & {
|
||||
teamId: string;
|
||||
forever?: Boolean;
|
||||
}) {
|
||||
if (base64Img.length > maxImgSize) {
|
||||
return Promise.reject('Image too large');
|
||||
}
|
||||
|
||||
const [base64Mime, base64Data] = base64Img.split(',');
|
||||
// Check if mime type is valid
|
||||
if (!base64MimeRegex.test(base64Mime)) {
|
||||
return Promise.reject('Invalid image mime type');
|
||||
}
|
||||
|
||||
const mime = `image/${base64Mime.match(base64MimeRegex)?.[1] ?? 'image/jpeg'}`;
|
||||
const binary = Buffer.from(base64Data, 'base64');
|
||||
const extension = mime.split('/')[1];
|
||||
|
||||
const { _id } = await MongoImage.create({
|
||||
type,
|
||||
teamId,
|
||||
binary,
|
||||
expiredTime,
|
||||
metadata: Object.assign({ mime }, metadata),
|
||||
shareId
|
||||
shareId,
|
||||
expiredTime: forever ? undefined : addHours(new Date(), 1)
|
||||
});
|
||||
|
||||
return `${process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL || ''}${imageBaseUrl}${String(_id)}.${extension}`;
|
||||
}
|
||||
|
||||
const getIdFromPath = (path?: string) => {
|
||||
if (!path) return;
|
||||
|
||||
const paths = path.split('/');
|
||||
const name = paths[paths.length - 1];
|
||||
|
||||
if (!name) return;
|
||||
|
||||
const id = name.split('.')[0];
|
||||
if (!id || !Types.ObjectId.isValid(id)) return;
|
||||
|
||||
return id;
|
||||
};
|
||||
// 删除旧的头像,新的头像去除过期时间
|
||||
export const refreshSourceAvatar = async (
|
||||
path?: string,
|
||||
oldPath?: string,
|
||||
session?: ClientSession
|
||||
) => {
|
||||
const newId = getIdFromPath(path);
|
||||
const oldId = getIdFromPath(oldPath);
|
||||
|
||||
if (!newId) return;
|
||||
|
||||
await MongoImage.updateOne({ _id: newId }, { $unset: { expiredTime: 1 } }, { session });
|
||||
|
||||
if (oldId) {
|
||||
await MongoImage.deleteOne({ _id: oldId }, { session });
|
||||
}
|
||||
};
|
||||
export const removeImageByPath = (path?: string, session?: ClientSession) => {
|
||||
if (!path) return;
|
||||
|
||||
const paths = path.split('/');
|
||||
const name = paths[paths.length - 1];
|
||||
|
||||
if (!name) return;
|
||||
|
||||
const id = name.split('.')[0];
|
||||
if (!id || !Types.ObjectId.isValid(id)) return;
|
||||
|
||||
return MongoImage.deleteOne({ _id: id }, { session });
|
||||
};
|
||||
|
||||
export async function readMongoImg({ id }: { id: string }) {
|
||||
const formatId = id.replace(/\.[^/.]+$/, '');
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
import { connectionMongo, getMongoModel, type Model } from '../../mongo';
|
||||
import { connectionMongo, getMongoModel } from '../../mongo';
|
||||
import { MongoImageSchemaType } from '@fastgpt/global/common/file/image/type.d';
|
||||
import { mongoImageTypeMap } from '@fastgpt/global/common/file/image/constants';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
const { Schema } = connectionMongo;
|
||||
|
||||
const ImageSchema = new Schema({
|
||||
teamId: {
|
||||
@@ -14,27 +13,15 @@ const ImageSchema = new Schema({
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
expiredTime: {
|
||||
type: Date
|
||||
},
|
||||
binary: {
|
||||
type: Buffer
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: Object.keys(mongoImageTypeMap),
|
||||
required: true
|
||||
},
|
||||
metadata: {
|
||||
type: Object
|
||||
}
|
||||
expiredTime: Date,
|
||||
binary: Buffer,
|
||||
metadata: Object
|
||||
});
|
||||
|
||||
try {
|
||||
// tts expired(60 Minutes)
|
||||
ImageSchema.index({ expiredTime: 1 }, { expireAfterSeconds: 60 * 60 });
|
||||
ImageSchema.index({ type: 1 });
|
||||
ImageSchema.index({ createTime: 1 });
|
||||
// delete related img
|
||||
ImageSchema.index({ teamId: 1, 'metadata.relatedId': 1 });
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { uploadMongoImg } from '../image/controller';
|
||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||
import FormData from 'form-data';
|
||||
|
||||
import { WorkerNameEnum, runWorker } from '../../../worker/utils';
|
||||
@@ -114,10 +113,9 @@ export const readRawContentByFileBuffer = async ({
|
||||
if (imageList) {
|
||||
await batchRun(imageList, async (item) => {
|
||||
const src = await uploadMongoImg({
|
||||
type: MongoImageTypeEnum.collectionImage,
|
||||
base64Img: `data:${item.mime};base64,${item.base64}`,
|
||||
teamId,
|
||||
expiredTime: addHours(new Date(), 1),
|
||||
// expiredTime: addHours(new Date(), 1),
|
||||
metadata: {
|
||||
...metadata,
|
||||
mime: item.mime
|
||||
|
||||
@@ -9,10 +9,10 @@ import { jsonRes } from '../response';
|
||||
// unit: times/s
|
||||
// how to use?
|
||||
// export default NextAPI(useQPSLimit(10), handler); // limit 10 times per second for a ip
|
||||
export function useReqFrequencyLimit(seconds: number, limit: number) {
|
||||
export function useReqFrequencyLimit(seconds: number, limit: number, force = false) {
|
||||
return async (req: ApiRequestProps, res: NextApiResponse) => {
|
||||
const ip = requestIp.getClientIp(req);
|
||||
if (!ip || process.env.USE_IP_LIMIT !== 'true') {
|
||||
if (!ip || (process.env.USE_IP_LIMIT !== 'true' && !force)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -25,7 +25,7 @@ export function useReqFrequencyLimit(seconds: number, limit: number) {
|
||||
res.status(429);
|
||||
jsonRes(res, {
|
||||
code: 429,
|
||||
message: ERROR_ENUM.tooManyRequest
|
||||
error: ERROR_ENUM.tooManyRequest
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ export const jsonRes = <T = any>(
|
||||
|
||||
addLog.error(`Api response error: ${url}`, ERROR_RESPONSE[errResponseKey]);
|
||||
|
||||
res.status(ERROR_RESPONSE[errResponseKey].code);
|
||||
return res.json(ERROR_RESPONSE[errResponseKey]);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,8 +97,12 @@ export const authGroupMemberRole = async ({
|
||||
tmbId
|
||||
};
|
||||
}
|
||||
const groupMember = await MongoGroupMemberModel.findOne({ groupId, tmbId });
|
||||
const tmb = await getTmbInfoByTmbId({ tmbId });
|
||||
const [groupMember, tmb] = await Promise.all([
|
||||
MongoGroupMemberModel.findOne({ groupId, tmbId }),
|
||||
getTmbInfoByTmbId({ tmbId })
|
||||
]);
|
||||
|
||||
// Team admin or role check
|
||||
if (tmb.permission.hasManagePer || (groupMember && role.includes(groupMember.role))) {
|
||||
return {
|
||||
...result,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { mongoSessionRun } from '../../../common/mongo/sessionRun';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import { getAIApi, openaiBaseUrl } from '../../../core/ai/config';
|
||||
import { createRootOrg } from '../../permission/org/controllers';
|
||||
import { refreshSourceAvatar } from '../../../common/file/image/controller';
|
||||
|
||||
async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemType> {
|
||||
const tmb = await MongoTeamMember.findOne(match).populate<{ team: TeamSchema }>('team').lean();
|
||||
@@ -218,7 +219,8 @@ export async function updateTeam({
|
||||
return obj;
|
||||
})();
|
||||
|
||||
await MongoTeam.findByIdAndUpdate(
|
||||
// This is where we get the old team
|
||||
const team = await MongoTeam.findByIdAndUpdate(
|
||||
teamId,
|
||||
{
|
||||
$set: {
|
||||
@@ -244,6 +246,8 @@ export async function updateTeam({
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
|
||||
await refreshSourceAvatar(avatar, team?.avatar, session);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
"package_expiry_time": "Expired",
|
||||
"package_usage_rules": "Package usage rules: The system will give priority to using more advanced packages, and the original unused packages will take effect later.",
|
||||
"password": "Password",
|
||||
"password_length_error": "Password must be at least 4 characters and at most 60 characters",
|
||||
"password_mismatch": "Password Inconsistency: Two passwords are inconsistent",
|
||||
"password_tip": "Password must be at least 6 characters long and contain at least two combinations: numbers, letters, or special characters",
|
||||
"password_update_error": "Exception when changing password",
|
||||
"password_update_success": "Password changed successfully",
|
||||
"pending_usage": "To be used",
|
||||
|
||||
@@ -74,24 +74,24 @@
|
||||
"code_error.team_error.ai_points_not_enough": "Insufficient AI Points",
|
||||
"code_error.team_error.app_amount_not_enough": "Application Limit Reached",
|
||||
"code_error.team_error.cannot_delete_default_group": "Cannot delete default group",
|
||||
"code_error.team_error.cannot_delete_non_empty_org": "Cannot delete non-empty organization",
|
||||
"code_error.team_error.cannot_modify_root_org": "Cannot modify root organization",
|
||||
"code_error.team_error.cannot_move_to_sub_path": "Cannot move to same or subdirectory",
|
||||
"code_error.team_error.dataset_amount_not_enough": "Dataset Limit Reached",
|
||||
"code_error.team_error.dataset_size_not_enough": "Insufficient Dataset Capacity, Please Expand",
|
||||
"code_error.team_error.group_name_duplicate": "Duplicate group name",
|
||||
"code_error.team_error.group_name_empty": "Group name cannot be empty",
|
||||
"code_error.team_error.group_not_exist": "Group does not exist",
|
||||
"code_error.team_error.org_member_duplicated": "Duplicate organization member",
|
||||
"code_error.team_error.org_member_not_exist": "Organization member does not exist",
|
||||
"code_error.team_error.org_not_exist": "Organization does not exist",
|
||||
"code_error.team_error.org_parent_not_exist": "Parent organization does not exist",
|
||||
"code_error.team_error.over_size": "error.team.overSize",
|
||||
"code_error.team_error.plugin_amount_not_enough": "Plugin Limit Reached",
|
||||
"code_error.team_error.re_rank_not_enough": "Unauthorized to Use Re-Rank",
|
||||
"code_error.team_error.un_auth": "Unauthorized to Operate This Team",
|
||||
"code_error.team_error.user_not_active": "The user did not accept or has left the team",
|
||||
"code_error.team_error.website_sync_not_enough": "Unauthorized to Use Website Sync",
|
||||
"code_error.team_error.org_member_not_exist": "Organization member does not exist",
|
||||
"code_error.team_error.org_member_duplicated": "Duplicate organization member",
|
||||
"code_error.team_error.org_not_exist": "Organization does not exist",
|
||||
"code_error.team_error.org_parent_not_exist": "Parent organization does not exist",
|
||||
"code_error.team_error.cannot_move_to_sub_path": "Cannot move to same or subdirectory",
|
||||
"code_error.team_error.cannot_modify_root_org": "Cannot modify root organization",
|
||||
"code_error.team_error.cannot_delete_non_empty_org": "Cannot delete non-empty organization",
|
||||
"code_error.token_error_code.403": "Invalid Login Status, Please Re-login",
|
||||
"code_error.user_error.balance_not_enough": "Insufficient Account Balance",
|
||||
"code_error.user_error.bin_visitor": "Identity Verification Failed",
|
||||
@@ -880,9 +880,11 @@
|
||||
"error.code_error": "Verification code error",
|
||||
"error.fileNotFound": "File not found~",
|
||||
"error.inheritPermissionError": "Inherit permission Error",
|
||||
"error.invalid_params": "Invalid parameter",
|
||||
"error.missingParams": "Insufficient parameters",
|
||||
"error.too_many_request": "Too many request",
|
||||
"error.upload_file_error_filename": "{{name}} Upload Failed",
|
||||
"error.upload_image_error": "File upload failed",
|
||||
"error.username_empty": "Account cannot be empty",
|
||||
"extraction_results": "Extraction Results",
|
||||
"field_name": "Field Name",
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"Chinese_ip_tip": "It is detected that you are a mainland Chinese IP, click to jump to visit the mainland China version.",
|
||||
"Login": "Login",
|
||||
"agree": "agree",
|
||||
"cookies_tip": " This website uses cookies to provide a better service experience. By continuing to use the site, you agree to our Cookie Policy.",
|
||||
"forget_password": "Find password",
|
||||
"login_failed": "Login failed",
|
||||
"login_success": "Login successful",
|
||||
"no_remind": "Don't remind again",
|
||||
"password_condition": "Password maximum 60 characters",
|
||||
"password_tip": "Password must be at least 6 characters long and contain at least two combinations: numbers, letters, or special characters",
|
||||
"policy_tip": "By useing, you agree to our",
|
||||
"privacy": "Privacy policy",
|
||||
"privacy_policy": "Privacy Policy",
|
||||
"redirect": "Jump",
|
||||
"register": "Register",
|
||||
"root_password_placeholder": "The root user password is the value of the environment variable DEFAULT_ROOT_PSW",
|
||||
"terms": "Terms",
|
||||
"use_root_login": "Log in as root user",
|
||||
"agree": "agree",
|
||||
"cookies_tip": " This website uses cookies to provide a better service experience. By continuing to use the site, you agree to our Cookie Policy.",
|
||||
"privacy_policy": "Privacy Policy"
|
||||
}
|
||||
"use_root_login": "Log in as root user"
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
"password.email_phone_void": "Email/Phone Number Cannot Be Empty",
|
||||
"password.get_code": "Get Verification Code",
|
||||
"password.get_code_again": "Get Again in s",
|
||||
"password.new_password": "New Password (4-20 characters)",
|
||||
"password.not_match": "Passwords Do Not Match",
|
||||
"password.password_condition": "Password must be between 4 and 20 characters",
|
||||
"password.password_required": "Password Cannot Be Empty",
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
"package_expiry_time": "套餐到期时间",
|
||||
"package_usage_rules": "套餐使用规则:系统优先使用更高级的套餐,原未用完的套餐将延后生效",
|
||||
"password": "密码",
|
||||
"password_length_error": "密码最少 4 位最多 60 位",
|
||||
"password_mismatch": "密码不一致: 两次密码不一致",
|
||||
"password_tip": "密码至少 6 位,且至少包含两种组合:数字、字母或特殊字符",
|
||||
"password_update_error": "修改密码异常",
|
||||
"password_update_success": "修改密码成功",
|
||||
"pending_usage": "待使用",
|
||||
|
||||
@@ -78,24 +78,24 @@
|
||||
"code_error.team_error.ai_points_not_enough": "",
|
||||
"code_error.team_error.app_amount_not_enough": "应用数量已达上限~",
|
||||
"code_error.team_error.cannot_delete_default_group": "不能删除默认群组",
|
||||
"code_error.team_error.cannot_delete_non_empty_org": "不能删除非空部门",
|
||||
"code_error.team_error.cannot_modify_root_org": "不能修改根部门",
|
||||
"code_error.team_error.cannot_move_to_sub_path": "不能移动到相同或子目录",
|
||||
"code_error.team_error.dataset_amount_not_enough": "知识库数量已达上限~",
|
||||
"code_error.team_error.dataset_size_not_enough": "知识库容量不足,请先扩容~",
|
||||
"code_error.team_error.group_name_duplicate": "群组名称重复",
|
||||
"code_error.team_error.group_name_empty": "群组名称不能为空",
|
||||
"code_error.team_error.group_not_exist": "群组不存在",
|
||||
"code_error.team_error.org_member_duplicated": "重复的部门成员",
|
||||
"code_error.team_error.org_member_not_exist": "部门成员不存在",
|
||||
"code_error.team_error.org_not_exist": "部门不存在",
|
||||
"code_error.team_error.org_parent_not_exist": "父部门不存在",
|
||||
"code_error.team_error.over_size": "error.team.overSize",
|
||||
"code_error.team_error.plugin_amount_not_enough": "插件数量已达上限~",
|
||||
"code_error.team_error.re_rank_not_enough": "无权使用检索重排~",
|
||||
"code_error.team_error.un_auth": "无权操作该团队",
|
||||
"code_error.team_error.user_not_active": "用户未接受或已离开团队",
|
||||
"code_error.team_error.website_sync_not_enough": "无权使用Web站点同步~",
|
||||
"code_error.team_error.org_member_not_exist": "部门成员不存在",
|
||||
"code_error.team_error.org_member_duplicated": "重复的部门成员",
|
||||
"code_error.team_error.org_not_exist": "部门不存在",
|
||||
"code_error.team_error.org_parent_not_exist": "父部门不存在",
|
||||
"code_error.team_error.cannot_move_to_sub_path": "不能移动到相同或子目录",
|
||||
"code_error.team_error.cannot_modify_root_org": "不能修改根部门",
|
||||
"code_error.team_error.cannot_delete_non_empty_org": "不能删除非空部门",
|
||||
"code_error.token_error_code.403": "登录状态无效,请重新登录",
|
||||
"code_error.user_error.balance_not_enough": "账号余额不足~",
|
||||
"code_error.user_error.bin_visitor": "您的身份校验未通过",
|
||||
@@ -883,9 +883,11 @@
|
||||
"error.code_error": "验证码错误",
|
||||
"error.fileNotFound": "文件找不到了~",
|
||||
"error.inheritPermissionError": "权限继承错误",
|
||||
"error.invalid_params": "参数无效",
|
||||
"error.missingParams": "参数缺失",
|
||||
"error.too_many_request": "请求太频繁了,请稍后重试",
|
||||
"error.upload_file_error_filename": "{{name}} 上传失败",
|
||||
"error.upload_image_error": "上传文件失败",
|
||||
"error.username_empty": "账号不能为空",
|
||||
"extraction_results": "提取结果",
|
||||
"field_name": "字段名",
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"Chinese_ip_tip": "检测到您是中国大陆 IP,点击跳转访问中国大陆版。",
|
||||
"Login": "登录",
|
||||
"agree": "同意",
|
||||
"cookies_tip": "本网站使用 cookies 提供更好的服务体验。继续使用即表示您同意我们的 Cookie 政策。",
|
||||
"forget_password": "忘记密码?",
|
||||
"login_failed": "登录异常",
|
||||
"login_success": "登录成功",
|
||||
"no_remind": "不再提醒",
|
||||
"password_condition": "密码最多 60 位",
|
||||
"password_tip": "密码至少 6 位,且至少包含两种组合:数字、字母或特殊字符",
|
||||
"policy_tip": "使用即代表你同意我们的",
|
||||
"privacy": "隐私协议",
|
||||
"privacy_policy": "隐私政策",
|
||||
"redirect": "跳转",
|
||||
"register": "注册账号",
|
||||
"root_password_placeholder": "root 用户密码为环境变量 DEFAULT_ROOT_PSW 的值",
|
||||
"terms": "服务协议",
|
||||
"use_root_login": "使用 root 用户登录",
|
||||
"redirect": "跳转",
|
||||
"no_remind": "不再提醒",
|
||||
"Chinese_ip_tip": "检测到您是中国大陆 IP,点击跳转访问中国大陆版。",
|
||||
"agree": "同意",
|
||||
"cookies_tip": "本网站使用 cookies 提供更好的服务体验。继续使用即表示您同意我们的 Cookie 政策。",
|
||||
"privacy_policy": "隐私政策"
|
||||
}
|
||||
"use_root_login": "使用 root 用户登录"
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
"password.email_phone_void": "邮箱/手机号不能为空",
|
||||
"password.get_code": "获取验证码",
|
||||
"password.get_code_again": "s后重新获取",
|
||||
"password.new_password": "新密码(4~20位)",
|
||||
"password.not_match": "两次密码不一致",
|
||||
"password.password_condition": "密码最少 4 位最多 20 位",
|
||||
"password.password_required": "密码不能为空",
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
"package_expiry_time": "套餐到期時間",
|
||||
"package_usage_rules": "套餐使用規則:系統優先使用更進階的套餐,原未用完的套餐將延遲生效",
|
||||
"password": "密碼",
|
||||
"password_length_error": "密碼最少 4 位最多 60 位",
|
||||
"password_mismatch": "密碼不一致: 兩次密碼不一致",
|
||||
"password_tip": "密碼至少 6 位,且至少包含兩種組合:數字、字母或特殊字符",
|
||||
"password_update_error": "修改密碼異常",
|
||||
"password_update_success": "修改密碼成功",
|
||||
"pending_usage": "待使用",
|
||||
|
||||
@@ -74,24 +74,24 @@
|
||||
"code_error.team_error.ai_points_not_enough": "AI 點數不足",
|
||||
"code_error.team_error.app_amount_not_enough": "已達應用程式數量上限",
|
||||
"code_error.team_error.cannot_delete_default_group": "無法刪除預設群組",
|
||||
"code_error.team_error.cannot_delete_non_empty_org": "無法刪除非空組織",
|
||||
"code_error.team_error.cannot_modify_root_org": "無法修改根組織",
|
||||
"code_error.team_error.cannot_move_to_sub_path": "無法移動到相同或子目錄",
|
||||
"code_error.team_error.dataset_amount_not_enough": "已達知識庫數量上限",
|
||||
"code_error.team_error.dataset_size_not_enough": "知識庫容量不足,請先擴充容量",
|
||||
"code_error.team_error.group_name_duplicate": "群組名稱重複",
|
||||
"code_error.team_error.group_name_empty": "群組名稱不能為空",
|
||||
"code_error.team_error.group_not_exist": "群組不存在",
|
||||
"code_error.team_error.org_member_duplicated": "重複的組織成員",
|
||||
"code_error.team_error.org_member_not_exist": "組織成員不存在",
|
||||
"code_error.team_error.org_not_exist": "組織不存在",
|
||||
"code_error.team_error.org_parent_not_exist": "父組織不存在",
|
||||
"code_error.team_error.over_size": "error.team.overSize",
|
||||
"code_error.team_error.plugin_amount_not_enough": "已達外掛程式數量上限",
|
||||
"code_error.team_error.re_rank_not_enough": "無權使用結果重新排名",
|
||||
"code_error.team_error.un_auth": "無權操作此團隊",
|
||||
"code_error.team_error.user_not_active": "使用者未接受或已離開團隊",
|
||||
"code_error.team_error.website_sync_not_enough": "無權使用網站同步",
|
||||
"code_error.team_error.org_member_not_exist": "組織成員不存在",
|
||||
"code_error.team_error.org_member_duplicated": "重複的組織成員",
|
||||
"code_error.team_error.org_not_exist": "組織不存在",
|
||||
"code_error.team_error.org_parent_not_exist": "父組織不存在",
|
||||
"code_error.team_error.cannot_move_to_sub_path": "無法移動到相同或子目錄",
|
||||
"code_error.team_error.cannot_modify_root_org": "無法修改根組織",
|
||||
"code_error.team_error.cannot_delete_non_empty_org": "無法刪除非空組織",
|
||||
"code_error.token_error_code.403": "登入狀態無效,請重新登入",
|
||||
"code_error.user_error.balance_not_enough": "帳戶餘額不足",
|
||||
"code_error.user_error.bin_visitor": "身份驗證未通過",
|
||||
@@ -881,9 +881,11 @@
|
||||
"error.code_error": "驗證碼錯誤",
|
||||
"error.fileNotFound": "找不到檔案",
|
||||
"error.inheritPermissionError": "繼承權限錯誤",
|
||||
"error.invalid_params": "參數無效",
|
||||
"error.missingParams": "參數不足",
|
||||
"error.too_many_request": "請求太頻繁了,請稍後重試",
|
||||
"error.upload_file_error_filename": "{{name}} 上傳失敗",
|
||||
"error.upload_image_error": "上傳文件失敗",
|
||||
"error.username_empty": "帳號不能為空",
|
||||
"extraction_results": "提取結果",
|
||||
"field_name": "欄位名稱",
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"Chinese_ip_tip": "偵測到您使用中國大陸 IP,點選這裡前往中國大陸版本。",
|
||||
"Login": "登入",
|
||||
"agree": "同意",
|
||||
"cookies_tip": "本網站使用 cookies 提供更好的服務體驗。繼續使用即表示您同意我們的 Cookie 政策。",
|
||||
"forget_password": "忘記密碼?",
|
||||
"login_failed": "登入失敗",
|
||||
"login_success": "登入成功",
|
||||
"no_remind": "不再提醒",
|
||||
"password_condition": "密碼最多 60 個字元",
|
||||
"password_tip": "密碼至少 6 位,且至少包含兩種組合:數字、字母或特殊字符",
|
||||
"policy_tip": "使用即代表您同意我們的",
|
||||
"privacy": "隱私權政策",
|
||||
"privacy_policy": "隱私權政策",
|
||||
"redirect": "跳轉",
|
||||
"register": "註冊帳號",
|
||||
"root_password_placeholder": "root 使用者密碼為環境變數 DEFAULT_ROOT_PSW 的值",
|
||||
"terms": "服務條款",
|
||||
"use_root_login": "使用 root 使用者登入",
|
||||
"agree": "同意",
|
||||
"cookies_tip": "本網站使用 cookies 提供更好的服務體驗。繼續使用即表示您同意我們的 Cookie 政策。",
|
||||
"privacy_policy": "隱私權政策"
|
||||
}
|
||||
"use_root_login": "使用 root 使用者登入"
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
"password.email_phone_void": "電子郵件/手機號碼不能空白",
|
||||
"password.get_code": "取得驗證碼",
|
||||
"password.get_code_again": "秒後重新取得",
|
||||
"password.new_password": "新密碼(4 至 20 字元)",
|
||||
"password.not_match": "兩次輸入的密碼不相符",
|
||||
"password.password_condition": "密碼長度需介於 4 至 20 字元之間",
|
||||
"password.password_required": "密碼不能空白",
|
||||
|
||||
Reference in New Issue
Block a user