Revert "sub plan page (#885)" (#886)

This reverts commit 443ad37b6a.
This commit is contained in:
Archer
2024-02-23 17:48:15 +08:00
committed by GitHub
parent 443ad37b6a
commit fd9b6291af
246 changed files with 4281 additions and 6286 deletions

View File

@@ -19,15 +19,14 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
// auth limit
// @ts-ignore
if (global.feConfigs?.isPlus) {
await POST('/support/openapi/authLimit', {
openApi: openApi.toObject()
} as AuthOpenApiLimitProps);
await POST('/support/openapi/authLimit', { openApi } as AuthOpenApiLimitProps);
}
updateApiKeyUsedTime(openApi._id);
return {
apikey,
userId: String(openApi.userId),
teamId: String(openApi.teamId),
tmbId: String(openApi.tmbId),
appId: openApi.appId || ''

View File

@@ -1,6 +1,8 @@
import { connectionMongo, type Model } from '../../common/mongo';
const { Schema, model, models } = connectionMongo;
import type { OpenApiSchema } from '@fastgpt/global/support/openapi/type';
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import {
TeamCollectionName,
TeamMemberCollectionName
@@ -8,6 +10,10 @@ import {
const OpenApiSchema = new Schema(
{
userId: {
type: Schema.Types.ObjectId,
ref: 'user'
},
teamId: {
type: Schema.Types.ObjectId,
ref: TeamCollectionName,
@@ -38,17 +44,22 @@ const OpenApiSchema = new Schema(
type: String,
default: 'Api Key'
},
usagePoints: {
usage: {
// total usage. value from bill total
type: Number,
default: 0
default: 0,
get: (val: number) => formatStorePrice2Read(val)
},
limit: {
expiredTime: {
type: Date
},
maxUsagePoints: {
credit: {
// value from user settings
type: Number,
default: -1
default: -1,
set: (val: number) => val * PRICE_SCALE,
get: (val: number) => formatStorePrice2Read(val)
}
}
},

View File

@@ -8,21 +8,15 @@ export function updateApiKeyUsedTime(id: string) {
});
}
export function updateApiKeyUsage({
apikey,
totalPoints
}: {
apikey: string;
totalPoints: number;
}) {
export function updateApiKeyUsage({ apikey, usage }: { apikey: string; usage: number }) {
MongoOpenApi.findOneAndUpdate(
{ apiKey: apikey },
{
$inc: {
usagePoints: totalPoints
usage
}
}
).catch((err) => {
console.log('update apiKey totalPoints error', err);
console.log('update apiKey usage error', err);
});
}

View File

@@ -35,7 +35,8 @@ const OutLinkSchema = new Schema({
type: String,
required: true
},
usagePoints: {
total: {
// total amount
type: Number,
default: 0
},
@@ -47,10 +48,6 @@ const OutLinkSchema = new Schema({
default: false
},
limit: {
maxUsagePoints: {
type: Number,
default: -1
},
expiredTime: {
type: Date
},
@@ -58,18 +55,16 @@ const OutLinkSchema = new Schema({
type: Number,
default: 1000
},
credit: {
type: Number,
default: -1
},
hookUrl: {
type: String
}
}
});
try {
OutLinkSchema.index({ shareId: -1 });
} catch (error) {
console.log(error);
}
export const MongoOutLink: Model<SchemaType> =
models['outlinks'] || model('outlinks', OutLinkSchema);

View File

@@ -1,19 +1,18 @@
import axios from 'axios';
import { MongoOutLink } from './schema';
import { FastGPTProUrl } from '../../common/system/constants';
import { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type';
export const addOutLinkUsage = async ({
export const updateOutLinkUsage = async ({
shareId,
totalPoints
total
}: {
shareId: string;
totalPoints: number;
total: number;
}) => {
MongoOutLink.findOneAndUpdate(
{ shareId },
{
$inc: { usagePoints: totalPoints },
$inc: { total },
lastTime: new Date()
}
).catch((err) => {
@@ -24,13 +23,11 @@ export const addOutLinkUsage = async ({
export const pushResult2Remote = async ({
outLinkUid,
shareId,
appName,
responseData
}: {
outLinkUid?: string; // raw id, not parse
shareId?: string;
appName: string;
responseData?: ChatHistoryItemResType[];
responseData?: any[];
}) => {
if (!shareId || !outLinkUid || !FastGPTProUrl) return;
try {
@@ -45,7 +42,6 @@ export const pushResult2Remote = async ({
url: '/shareAuth/finish',
data: {
token: outLinkUid,
appName,
responseData
}
});

View File

@@ -107,7 +107,7 @@ export async function authDatasetCollection({
collection: CollectionWithDatasetType;
}
> {
const { teamId, tmbId } = await parseHeaderCert(props);
const { userId, teamId, tmbId } = await parseHeaderCert(props);
const { role } = await getTmbInfoByTmbId({ tmbId });
const { collection, isOwner, canWrite } = await (async () => {
@@ -143,6 +143,7 @@ export async function authDatasetCollection({
})();
return {
userId,
teamId,
tmbId,
collection,
@@ -162,7 +163,7 @@ export async function authDatasetFile({
file: DatasetFileSchema;
}
> {
const { teamId, tmbId } = await parseHeaderCert(props);
const { userId, teamId, tmbId } = await parseHeaderCert(props);
const [file, collection] = await Promise.all([
getFileById({ bucketName: BucketNameEnum.dataset, fileId }),
@@ -189,6 +190,7 @@ export async function authDatasetFile({
});
return {
userId,
teamId,
tmbId,
file,
@@ -198,4 +200,4 @@ export async function authDatasetFile({
} catch (error) {
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
}
}
}

View File

@@ -12,7 +12,7 @@ export async function authUserNotVisitor(props: AuthModeType): Promise<
role: `${TeamMemberRoleEnum}`;
}
> {
const { teamId, tmbId } = await parseHeaderCert(props);
const { userId, teamId, tmbId } = await parseHeaderCert(props);
const team = await getTmbInfoByTmbId({ tmbId });
if (team.role === TeamMemberRoleEnum.visitor) {
@@ -20,6 +20,7 @@ export async function authUserNotVisitor(props: AuthModeType): Promise<
}
return {
userId,
teamId,
tmbId,
team,

View File

@@ -94,10 +94,10 @@ export async function parseHeaderCert({
})();
// auth apikey
const { teamId, tmbId, appId: apiKeyAppId = '' } = await authOpenApiKey({ apikey });
const { userId, teamId, tmbId, appId: apiKeyAppId = '' } = await authOpenApiKey({ apikey });
return {
uid: '',
uid: userId,
teamId,
tmbId,
apikey,
@@ -217,4 +217,4 @@ export const authFileToken = (token?: string) =>
fileId: decoded.fileId
});
});
});
});

View File

@@ -0,0 +1,23 @@
import { StandSubPlanLevelMapType } from '@fastgpt/global/support/wallet/sub/type';
import { getVectorCountByTeamId } from '../../../common/vectorStore/controller';
import { getTeamDatasetMaxSize } from '../../wallet/sub/utils';
export const checkDatasetLimit = async ({
teamId,
insertLen = 0,
standardPlans
}: {
teamId: string;
insertLen?: number;
standardPlans?: StandSubPlanLevelMapType;
}) => {
const [{ maxSize }, usedSize] = await Promise.all([
getTeamDatasetMaxSize({ teamId, standardPlans }),
getVectorCountByTeamId(teamId)
]);
if (usedSize + insertLen >= maxSize) {
return Promise.reject(`数据库容量不足,无法继续添加。可以在账号页面进行扩容。`);
}
return;
};

View File

@@ -2,6 +2,7 @@ import { UserType } from '@fastgpt/global/support/user/type';
import { MongoUser } from './schema';
import { getTmbInfoByTmbId, getUserDefaultTeam } from './team/controller';
import { ERROR_ENUM } from '@fastgpt/global/common/error/errorCode';
import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
export async function authUserExist({ userId, username }: { userId?: string; username?: string }) {
if (userId) {
@@ -46,3 +47,22 @@ export async function getUserDetail({
team: tmb
};
}
export async function getUserAndAuthBalance({
tmbId,
minBalance
}: {
tmbId: string;
minBalance?: number;
}) {
const user = await getUserDetail({ tmbId });
if (!user) {
return Promise.reject(UserErrEnum.unAuthUser);
}
if (minBalance !== undefined && user.team.balance < minBalance) {
return Promise.reject(UserErrEnum.balanceNotEnough);
}
return user;
}

View File

@@ -1,7 +1,7 @@
import { connectionMongo, type Model } from '../../common/mongo';
const { Schema, model, models } = connectionMongo;
import { hashStr } from '@fastgpt/global/common/string/tools';
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/constants';
import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
import { UserStatusEnum, userStatusMap } from '@fastgpt/global/support/user/constant';
@@ -63,8 +63,6 @@ const UserSchema = new Schema({
});
try {
// login
UserSchema.index({ username: 1, password: 1 });
UserSchema.index({ createTime: -1 });
} catch (error) {
console.log(error);

View File

@@ -36,7 +36,7 @@ export async function getTmbInfoByTmbId({ tmbId }: { tmbId: string }) {
return Promise.reject('tmbId or userId is required');
}
return getTeamMember({
_id: new Types.ObjectId(String(tmbId)),
_id: new Types.ObjectId(tmbId),
status: notLeaveStatus
});
}

View File

@@ -27,10 +27,7 @@ const TeamSchema = new Schema({
},
maxSize: {
type: Number,
default: 1
},
tagsUrl: {
type: String
default: 3
},
limit: {
lastExportDatasetTime: {

View File

@@ -1,35 +0,0 @@
import { connectionMongo, type Model } from '../../../common/mongo';
const { Schema, model, models } = connectionMongo;
import { TeamTagsSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
import {
TeamCollectionName,
TeamTagsCollectionName
} from '@fastgpt/global/support/user/team/constant';
const TeamTagsSchema = new Schema({
label: {
type: String,
required: true
},
teamId: {
type: Schema.Types.ObjectId,
ref: TeamCollectionName,
required: true
},
key: {
type: String
},
createTime: {
type: Date,
default: () => new Date()
}
});
try {
TeamTagsSchema.index({ teamId: 1 });
} catch (error) {
console.log(error);
}
export const MongoTeamTags: Model<TeamTagsSchemaType> =
models[TeamTagsCollectionName] || model(TeamTagsCollectionName, TeamTagsSchema);

View File

@@ -1,8 +1,8 @@
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
import { MongoUsage } from './schema';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { MongoBill } from './schema';
import { ClientSession } from '../../../common/mongo';
export const createTrainingUsage = async ({
export const createTrainingBill = async ({
teamId,
tmbId,
appName,
@@ -14,33 +14,33 @@ export const createTrainingUsage = async ({
teamId: string;
tmbId: string;
appName: string;
billSource: `${UsageSourceEnum}`;
billSource: `${BillSourceEnum}`;
vectorModel: string;
agentModel: string;
session?: ClientSession;
}) => {
const [{ _id }] = await MongoUsage.create(
const [{ _id }] = await MongoBill.create(
[
{
teamId,
tmbId,
appName,
source: billSource,
totalPoints: 0,
list: [
{
moduleName: 'support.wallet.moduleName.index',
moduleName: 'wallet.moduleName.index',
model: vectorModel,
charsLength: 0,
amount: 0
},
{
moduleName: 'support.wallet.moduleName.qa',
moduleName: 'wallet.moduleName.qa',
model: agentModel,
charsLength: 0,
amount: 0
}
]
],
total: 0
}
],
{ session }

View File

@@ -1,15 +1,13 @@
import { connectionMongo, type Model } from '../../../common/mongo';
const { Schema, model, models } = connectionMongo;
import { UsageSchemaType } from '@fastgpt/global/support/wallet/usage/type';
import { UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
import { BillSchema as BillType } from '@fastgpt/global/support/wallet/bill/type';
import { BillSourceMap } from '@fastgpt/global/support/wallet/bill/constants';
import {
TeamCollectionName,
TeamMemberCollectionName
} from '@fastgpt/global/support/user/team/constant';
export const UsageCollectionName = 'usages';
const UsageSchema = new Schema({
const BillSchema = new Schema({
teamId: {
type: Schema.Types.ObjectId,
ref: TeamCollectionName,
@@ -20,11 +18,6 @@ const UsageSchema = new Schema({
ref: TeamMemberCollectionName,
required: true
},
source: {
type: String,
enum: Object.keys(UsageSourceMap),
required: true
},
appName: {
type: String,
default: ''
@@ -38,16 +31,16 @@ const UsageSchema = new Schema({
type: Date,
default: () => new Date()
},
totalPoints: {
// total points
total: {
// 1 * PRICE_SCALE
type: Number,
required: true
},
// total: {
// // total points
// type: Number,
// required: true
// },
source: {
type: String,
enum: Object.keys(BillSourceMap),
required: true
},
list: {
type: Array,
default: []
@@ -55,15 +48,11 @@ const UsageSchema = new Schema({
});
try {
UsageSchema.index({ teamId: 1, tmbId: 1, source: 1, time: -1 }, { background: true });
// timer task. clear dead team
UsageSchema.index({ teamId: 1, time: -1 }, { background: true });
UsageSchema.index({ time: 1 }, { expireAfterSeconds: 180 * 24 * 60 * 60 });
BillSchema.index({ teamId: 1, tmbId: 1, source: 1, time: -1 }, { background: true });
BillSchema.index({ time: 1 }, { expireAfterSeconds: 180 * 24 * 60 * 60 });
} catch (error) {
console.log(error);
}
export const MongoUsage: Model<UsageSchemaType> =
models[UsageCollectionName] || model(UsageCollectionName, UsageSchema);
MongoUsage.syncIndexes();
export const MongoBill: Model<BillType> = models['bill'] || model('bill', BillSchema);
MongoBill.syncIndexes();

View File

@@ -1,8 +1,3 @@
/*
user sub plan
1. type=standard: There will only be 1, and each team will have one
2. type=extraDatasetSize/extraPoints: Can buy multiple
*/
import { connectionMongo, type Model } from '../../../common/mongo';
const { Schema, model, models } = connectionMongo;
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
@@ -28,10 +23,25 @@ const SubSchema = new Schema({
required: true
},
status: {
// active: continue sub; canceled: canceled sub;
type: String,
enum: Object.keys(subStatusMap),
required: true
},
mode: {
type: String,
enum: Object.keys(subModeMap)
},
currentMode: {
type: String,
enum: Object.keys(subModeMap),
required: true
},
nextMode: {
type: String,
enum: Object.keys(subModeMap),
required: true
},
startTime: {
type: Date,
default: () => new Date()
@@ -45,16 +55,12 @@ const SubSchema = new Schema({
type: Number,
required: true
},
pointPrice: {
// stand level point total price
type: Number
},
// standard sub
currentMode: {
type: String,
enum: Object.keys(subModeMap)
},
nextMode: {
type: String,
enum: Object.keys(subModeMap)
},
// sub content
currentSubLevel: {
type: String,
enum: Object.keys(standardSubLevelMap)
@@ -63,34 +69,79 @@ const SubSchema = new Schema({
type: String,
enum: Object.keys(standardSubLevelMap)
},
// stand sub and extra points sub. Plan total points
totalPoints: {
type: Number
},
pointPrice: {
// stand level point total price
currentExtraDatasetSize: {
type: Number
},
surplusPoints: {
// plan surplus points
nextExtraDatasetSize: {
type: Number
},
// extra dataset size
currentExtraDatasetSize: {
currentExtraPoints: {
type: Number
}
},
nextExtraPoints: {
type: Number
},
// standard sub limit
// maxTeamMember: {
// type: Number
// },
// maxAppAmount: {
// type: Number
// },
// maxDatasetAmount: {
// type: Number
// },
// chatHistoryStoreDuration: {
// // n day
// type: Number
// },
// maxDatasetSize: {
// type: Number
// },
// trainingWeight: {
// // 0 1 2 3
// type: Number
// },
// customApiKey: {
// type: Boolean
// },
// customCopyright: {
// type: Boolean
// },
// websiteSyncInterval: {
// // hours
// type: Number
// },
// reRankWeight: {
// // 0 1 2 3
// type: Number
// },
// totalPoints: {
// // record standard sub points
// type: Number
// },
surplusPoints: {
// standard sub / extra points sub
type: Number
},
// abandon
renew: Boolean, //决定是否续费
datasetStoreAmount: Number
});
try {
// get team plan
SubSchema.index({ teamId: 1, type: 1, expiredTime: -1 });
// timer task. check expired plan; update standard plan;
SubSchema.index({ type: 1, expiredTime: -1 });
// timer task. clear dead team
SubSchema.index({ type: 1, currentSubLevel: 1, nextSubLevel: 1 });
SubSchema.index({ teamId: 1 });
SubSchema.index({ status: 1 });
SubSchema.index({ type: 1 });
SubSchema.index({ expiredTime: -1 });
} catch (error) {
console.log(error);
}

View File

@@ -1,70 +1,87 @@
import { SubTypeEnum } from '@fastgpt/global/support/wallet/sub/constants';
import { MongoTeamSub } from './schema';
import {
FeTeamPlanStatusType,
StandSubPlanLevelMapType
} from '@fastgpt/global/support/wallet/sub/type.d';
import { addHours } from 'date-fns';
import { FeTeamSubType, StandSubPlanLevelMapType } from '@fastgpt/global/support/wallet/sub/type.d';
import { getVectorCountByTeamId } from '../../../common/vectorStore/controller';
export const getTeamSubPlans = async ({
teamId,
standardPlans
}: {
teamId: string;
standardPlans?: StandSubPlanLevelMapType;
}): Promise<FeTeamPlanStatusType> => {
const [plans, usedDatasetSize] = await Promise.all([
MongoTeamSub.find({ teamId }).lean(),
getVectorCountByTeamId(teamId)
]);
const standard = plans.find((plan) => plan.type === SubTypeEnum.standard);
const extraDatasetSize = plans.filter((plan) => plan.type === SubTypeEnum.extraDatasetSize);
const extraPoints = plans.filter((plan) => plan.type === SubTypeEnum.extraPoints);
const totalPoints =
(standard?.totalPoints || 0) +
extraPoints.reduce((acc, cur) => acc + (cur.totalPoints || 0), 0);
const surplusPoints =
(standard?.surplusPoints || 0) +
extraPoints.reduce((acc, cur) => acc + (cur.surplusPoints || 0), 0);
const standardMaxDatasetSize =
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]?.maxDatasetSize || Infinity
: Infinity;
const totalDatasetSize =
standardMaxDatasetSize +
extraDatasetSize.reduce((acc, cur) => acc + (cur.currentExtraDatasetSize || 0), 0);
return {
[SubTypeEnum.standard]: standard,
standardConstants:
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]
: undefined,
totalPoints,
usedPoints: totalPoints - surplusPoints,
datasetMaxSize: totalDatasetSize,
usedDatasetSize
};
};
export const getTeamStandPlan = async ({
/* get team dataset max size */
export const getTeamDatasetMaxSize = async ({
teamId,
standardPlans
}: {
teamId: string;
standardPlans?: StandSubPlanLevelMapType;
}) => {
const standard = await MongoTeamSub.findOne({ teamId, type: SubTypeEnum.standard }).lean();
if (!standardPlans) {
return {
maxSize: Infinity,
sub: null
};
}
const plans = await MongoTeamSub.find({
teamId,
expiredTime: { $gte: addHours(new Date(), -3) }
}).lean();
const standard = plans.find((plan) => plan.type === SubTypeEnum.standard);
const extraDatasetSize = plans.find((plan) => plan.type === SubTypeEnum.extraDatasetSize);
const standardMaxDatasetSize =
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]?.maxDatasetSize || Infinity
: Infinity;
const totalDatasetSize =
standardMaxDatasetSize + (extraDatasetSize?.currentExtraDatasetSize || 0);
return {
maxSize: totalDatasetSize,
sub: extraDatasetSize
};
};
export const getTeamSubPlanStatus = async ({
teamId,
standardPlans
}: {
teamId: string;
standardPlans?: StandSubPlanLevelMapType;
}): Promise<FeTeamSubType> => {
const [plans, usedDatasetSize] = await Promise.all([
MongoTeamSub.find({ teamId }).lean(),
getVectorCountByTeamId(teamId)
]);
const standard = plans.find((plan) => plan.type === SubTypeEnum.standard);
const extraDatasetSize = plans.find((plan) => plan.type === SubTypeEnum.extraDatasetSize);
const extraPoints = plans.find((plan) => plan.type === SubTypeEnum.extraPoints);
const standardMaxDatasetSize =
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]?.maxDatasetSize || Infinity
: Infinity;
const totalDatasetSize =
standardMaxDatasetSize + (extraDatasetSize?.currentExtraDatasetSize || 0);
const standardMaxPoints =
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]?.totalPoints || Infinity
: Infinity;
const totalPoints = standardMaxPoints + (extraPoints?.currentExtraPoints || 0);
const surplusPoints = (standard?.surplusPoints || 0) + (extraPoints?.surplusPoints || 0);
return {
[SubTypeEnum.standard]: standard,
standardConstants:
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]
: undefined
[SubTypeEnum.extraDatasetSize]: extraDatasetSize,
[SubTypeEnum.extraPoints]: extraPoints,
standardMaxDatasetSize,
datasetMaxSize: totalDatasetSize,
usedDatasetSize,
standardMaxPoints,
totalPoints,
usedPoints: totalPoints - surplusPoints
};
};