Concat plugin to app (#1799)

This commit is contained in:
Archer
2024-06-19 14:38:21 +08:00
committed by GitHub
parent b17d14bb7d
commit 565bfc8486
220 changed files with 5018 additions and 4667 deletions

View File

@@ -0,0 +1,163 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { NextAPI } from '@/service/middleware/entry';
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
/*
1. 先读取 HTTP plugin 内容,并找到所有的子plugin,然后事务批量创建,最后修改 inited
2. 读取剩下未 inited 的plugin,逐一创建
*/
let success = 0;
async function handler(req: NextApiRequest, res: NextApiResponse) {
await authCert({ req, authRoot: true });
const total = await MongoPlugin.countDocuments({
inited: { $ne: true }
});
console.log('Total plugin', total);
await initHttp();
await initPlugin();
}
async function initHttp(): Promise<any> {
/* 读取http插件和他的children */
const plugin = await MongoPlugin.findOne({
type: PluginTypeEnum.folder,
inited: { $ne: true }
}).lean();
if (!plugin) return;
const children = await MongoPlugin.find({
teamId: plugin.teamId,
parentId: plugin._id,
inited: { $ne: true }
}).lean();
await mongoSessionRun(async (session) => {
/* 创建HTTP插件作为目录 */
const [{ _id }] = await MongoApp.create(
[
{
teamId: plugin.teamId,
tmbId: plugin.tmbId,
type: AppTypeEnum.httpPlugin,
name: plugin.name,
avatar: plugin.avatar,
intro: plugin.intro,
metadata: plugin.metadata,
version: 'v2',
pluginData: {
apiSchemaStr: plugin.metadata?.apiSchemaStr,
customHeaders: plugin.metadata?.customHeaders
}
}
],
{ session }
);
/* 批量创建子插件 */
for await (const item of children) {
await MongoApp.create(
[
{
parentId: _id,
teamId: item.teamId,
tmbId: item.tmbId,
type: AppTypeEnum.plugin,
name: item.name,
avatar: item.avatar,
intro: item.intro,
version: 'v2',
modules: item.modules,
edges: item.edges,
pluginData: {
nodeVersion: item.nodeVersion,
pluginUniId: plugin.metadata?.pluginUid
}
}
],
{ session }
);
}
/* 更新插件信息 */
await MongoPlugin.findOneAndUpdate(
{
_id: plugin._id
},
{
$set: { inited: true }
},
{ session }
);
await MongoPlugin.updateMany(
{
teamId: plugin.teamId,
parentId: plugin._id
},
{
$set: { inited: true }
},
{ session }
);
success += children.length + 1;
console.log(success);
});
return initHttp();
}
async function initPlugin(): Promise<any> {
const plugin = await MongoPlugin.findOne({
type: PluginTypeEnum.custom,
inited: { $ne: true }
}).lean();
if (!plugin) return;
await mongoSessionRun(async (session) => {
await MongoApp.create(
[
{
teamId: plugin.teamId,
tmbId: plugin.tmbId,
type: AppTypeEnum.plugin,
name: plugin.name,
avatar: plugin.avatar,
intro: plugin.intro,
version: 'v2',
modules: plugin.modules,
edges: plugin.edges,
pluginData: {
nodeVersion: plugin.nodeVersion
}
}
],
{ session }
);
await MongoPlugin.findOneAndUpdate(
{
_id: plugin._id
},
{
$set: { inited: true }
},
{ session }
);
success++;
console.log(success);
});
return initPlugin();
}
export default NextAPI(handler);

View File

@@ -12,6 +12,8 @@ import type { AppSchema } from '@fastgpt/global/core/app/type';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import type { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
import { defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
import { ClientSession } from '@fastgpt/service/common/mongo';
export type CreateAppBody = {
parentId?: ParentIdType;
@@ -35,37 +37,16 @@ async function handler(req: ApiRequestProps<CreateAppBody>, res: NextApiResponse
// 上限校验
await checkTeamAppLimit(teamId);
// 创建模型
const appId = await mongoSessionRun(async (session) => {
const [{ _id: appId }] = await MongoApp.create(
[
{
...parseParentIdInMongo(parentId),
avatar,
name,
teamId,
tmbId,
modules,
edges,
type,
version: 'v2'
}
],
{ session }
);
await MongoAppVersion.create(
[
{
appId,
nodes: modules,
edges
}
],
{ session }
);
return appId;
// 创建app
const appId = await onCreateApp({
parentId,
name,
avatar,
type,
modules,
edges,
teamId,
tmbId
});
jsonRes(res, {
@@ -74,3 +55,72 @@ async function handler(req: ApiRequestProps<CreateAppBody>, res: NextApiResponse
}
export default NextAPI(handler);
export const onCreateApp = async ({
parentId,
name,
intro,
avatar,
type,
modules,
edges,
teamId,
tmbId,
pluginData,
session
}: {
parentId?: ParentIdType;
name?: string;
avatar?: string;
type?: AppTypeEnum;
modules?: AppSchema['modules'];
edges?: AppSchema['edges'];
intro?: string;
teamId: string;
tmbId: string;
pluginData?: AppSchema['pluginData'];
session?: ClientSession;
}) => {
const create = async (session: ClientSession) => {
const [{ _id: appId }] = await MongoApp.create(
[
{
...parseParentIdInMongo(parentId),
avatar,
name,
intro,
teamId,
tmbId,
modules,
edges,
type,
version: 'v2',
pluginData,
...(type === AppTypeEnum.plugin && { 'pluginData.nodeVersion': defaultNodeVersion })
}
],
{ session }
);
if (type !== AppTypeEnum.folder && type !== AppTypeEnum.httpPlugin) {
await MongoAppVersion.create(
[
{
appId,
nodes: modules,
edges
}
],
{ session }
);
}
return appId;
};
if (session) {
return create(session);
} else {
return await mongoSessionRun(create);
}
};

View File

@@ -14,6 +14,7 @@ import {
} from '@fastgpt/global/support/permission/constant';
import { findAppAndAllChildren } from '@fastgpt/service/core/app/controller';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { ClientSession } from '@fastgpt/service/common/mongo';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
@@ -25,13 +26,30 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
// Auth owner (folder owner, can delete all apps in the folder)
const { teamId } = await authApp({ req, authToken: true, appId, per: OwnerPermissionVal });
await onDelOneApp({
teamId,
appId
});
}
export default NextAPI(handler);
export const onDelOneApp = async ({
teamId,
appId,
session
}: {
teamId: string;
appId: string;
session?: ClientSession;
}) => {
const apps = await findAppAndAllChildren({
teamId,
appId,
fields: '_id'
});
await mongoSessionRun(async (session) => {
const del = async (session: ClientSession) => {
for await (const app of apps) {
const appId = app._id;
// Chats
@@ -83,7 +101,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
{ session }
);
}
});
}
};
export default NextAPI(handler);
if (session) {
return del(session);
}
return mongoSessionRun(del);
};

View File

@@ -0,0 +1,68 @@
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { httpApiSchema2Plugins } from '@fastgpt/global/core/app/httpPlugin/utils';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { onCreateApp, type CreateAppBody } from '../create';
import { AppSchema } from '@fastgpt/global/core/app/type';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
export type createHttpPluginQuery = {};
export type createHttpPluginBody = Omit<CreateAppBody, 'type' | 'modules' | 'edges'> & {
intro?: string;
pluginData: AppSchema['pluginData'];
};
export type createHttpPluginResponse = {};
async function handler(
req: ApiRequestProps<createHttpPluginBody, createHttpPluginQuery>,
res: ApiResponseType<any>
): Promise<createHttpPluginResponse> {
const { parentId, name, intro, avatar, pluginData } = req.body;
if (!name || !pluginData) {
return Promise.reject('缺少参数');
}
const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
await mongoSessionRun(async (session) => {
// create http plugin folder
const httpPluginIid = await onCreateApp({
parentId,
name,
avatar,
intro,
teamId,
tmbId,
type: AppTypeEnum.httpPlugin,
pluginData,
session
});
// compute children plugins
const childrenPlugins = await httpApiSchema2Plugins({
parentId: httpPluginIid,
apiSchemaStr: pluginData.apiSchemaStr,
customHeader: pluginData.customHeaders
});
// create children plugins
for await (const item of childrenPlugins) {
await onCreateApp({
...item,
teamId,
tmbId,
session
});
}
});
return {};
}
export default NextAPI(handler);

View File

@@ -0,0 +1,127 @@
import type { NextApiResponse } from 'next';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { ClientSession } from '@fastgpt/service/common/mongo';
import { httpApiSchema2Plugins } from '@fastgpt/global/core/app/httpPlugin/utils';
import { NextAPI } from '@/service/middleware/entry';
import { AppSchema } from '@fastgpt/global/core/app/type';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { isEqual } from 'lodash';
import { onCreateApp } from '../create';
import { onDelOneApp } from '../del';
export type UpdateHttpPluginBody = {
appId: string;
name: string;
avatar?: string;
intro?: string;
pluginData: AppSchema['pluginData'];
};
async function handler(req: ApiRequestProps<UpdateHttpPluginBody>, res: NextApiResponse<any>) {
const { appId, name, avatar, intro, pluginData } = req.body;
const { app } = await authApp({ req, authToken: true, appId, per: ManagePermissionVal });
const storeData = {
apiSchemaStr: app.pluginData?.apiSchemaStr,
customHeaders: app.pluginData?.customHeaders
};
const updateData = {
apiSchemaStr: pluginData?.apiSchemaStr,
customHeaders: pluginData?.customHeaders
};
await mongoSessionRun(async (session) => {
// update children
if (!isEqual(storeData, updateData)) {
await updateHttpChildrenPlugin({
teamId: app.teamId,
tmbId: app.tmbId,
parentId: app._id,
pluginData,
session
});
}
await MongoApp.findByIdAndUpdate(
appId,
{
name,
avatar,
intro,
pluginData
},
{ session }
);
});
}
export default NextAPI(handler);
const updateHttpChildrenPlugin = async ({
teamId,
tmbId,
parentId,
pluginData,
session
}: {
teamId: string;
tmbId: string;
parentId: string;
pluginData?: AppSchema['pluginData'];
session: ClientSession;
}) => {
if (!pluginData?.apiSchemaStr) return;
const dbPlugins = await MongoApp.find({
parentId,
teamId
}).select({
pluginData: 1
});
const schemaPlugins = await httpApiSchema2Plugins({
parentId,
apiSchemaStr: pluginData?.apiSchemaStr,
customHeader: pluginData?.customHeaders
});
// 数据库中存在schema不存在删除
for await (const plugin of dbPlugins) {
if (!schemaPlugins.find((p) => p.name === plugin.pluginData?.pluginUniId)) {
await onDelOneApp({
teamId,
appId: plugin._id,
session
});
}
}
// 数据库中不存在schema存在新增
for await (const plugin of schemaPlugins) {
if (!dbPlugins.find((p) => p.pluginData?.pluginUniId === plugin.name)) {
await onCreateApp({
...plugin,
teamId,
tmbId,
session
});
}
}
// 数据库中存在schema存在更新
for await (const plugin of schemaPlugins) {
const dbPlugin = dbPlugins.find((p) => plugin.name === p.pluginData?.pluginUniId);
if (dbPlugin) {
await MongoApp.findByIdAndUpdate(
dbPlugin._id,
{
...plugin,
version: 'v2'
},
{ session }
);
}
}
};

View File

@@ -17,8 +17,9 @@ import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/
export type ListAppBody = {
parentId?: ParentIdType;
type?: AppTypeEnum;
type?: AppTypeEnum | AppTypeEnum[];
getRecentlyChat?: boolean;
searchKey?: string;
};
async function handler(
@@ -36,26 +37,43 @@ async function handler(
per: ReadPermissionVal
});
const { parentId, type, getRecentlyChat } = req.body;
const { parentId, type, getRecentlyChat, searchKey } = req.body;
const findAppsQuery = getRecentlyChat
? {
const findAppsQuery = (() => {
const searchMatch = searchKey
? {
$or: [
{ name: { $regex: searchKey, $options: 'i' } },
{ intro: { $regex: searchKey, $options: 'i' } }
]
}
: {};
if (getRecentlyChat) {
return {
// get all chat app
teamId,
type: { $in: [AppTypeEnum.advanced, AppTypeEnum.simple] }
}
: {
teamId,
...(type && { type }),
...parseParentIdInMongo(parentId)
type: { $in: [AppTypeEnum.workflow, AppTypeEnum.simple] },
...searchMatch
};
}
return {
teamId,
...(type && Array.isArray(type) && { type: { $in: type } }),
...(type && { type }),
...parseParentIdInMongo(parentId),
...searchMatch
};
})();
/* temp: get all apps and per */
const [myApps, rpList] = await Promise.all([
MongoApp.find(findAppsQuery, '_id avatar type name intro tmbId defaultPermission')
MongoApp.find(findAppsQuery, '_id avatar type name intro tmbId pluginData defaultPermission')
.sort({
updateTime: -1
})
.limit(searchKey ? 20 : 1000)
.lean(),
MongoResourcePermission.find({
resourceType: PerResourceTypeEnum.app,
@@ -88,7 +106,8 @@ async function handler(
name: app.name,
intro: app.intro,
permission: app.permission,
defaultPermission: app.defaultPermission || AppDefaultPermissionVal
defaultPermission: app.defaultPermission || AppDefaultPermissionVal,
pluginData: app.pluginData
}));
}

View File

@@ -0,0 +1,33 @@
/*
get plugin preview modules
*/
import type { NextApiResponse } from 'next';
import {
getPluginPreviewNode,
splitCombinePluginId
} from '@fastgpt/service/core/app/plugin/controller';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { NextAPI } from '@/service/middleware/entry';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
export type GetPreviewNodeQuery = { appId: string };
async function handler(
req: ApiRequestProps<{}, GetPreviewNodeQuery>,
res: NextApiResponse<any>
): Promise<FlowNodeTemplateType> {
const { appId } = req.query;
const { source } = await splitCombinePluginId(appId);
if (source === PluginSourceEnum.personal) {
await authApp({ req, authToken: true, appId, per: WritePermissionVal });
}
return getPluginPreviewNode({ id: appId });
}
export default NextAPI(handler);

View File

@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
@@ -22,7 +22,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
intro: plugin.intro,
showStatus: true,
isTool: plugin.isTool,
version: '481',
version: defaultNodeVersion,
inputs: [],
outputs: []
})) || [];

View File

@@ -0,0 +1,53 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { onCreateApp } from './create';
export type transitionWorkflowQuery = {};
export type transitionWorkflowBody = {
appId: string;
createNew?: boolean;
};
export type transitionWorkflowResponse = {
id?: string;
};
async function handler(
req: ApiRequestProps<transitionWorkflowBody, transitionWorkflowQuery>,
res: ApiResponseType<any>
): Promise<transitionWorkflowResponse> {
const { appId, createNew } = req.body;
const { app, tmbId } = await authApp({
req,
appId,
authToken: true,
per: OwnerPermissionVal
});
if (createNew) {
const appId = await onCreateApp({
parentId: app.parentId,
name: app.name + ' Copy',
avatar: app.avatar,
type: AppTypeEnum.workflow,
modules: app.modules,
edges: app.edges,
teamId: app.teamId,
tmbId
});
return { id: appId };
} else {
await MongoApp.findByIdAndUpdate(appId, { type: AppTypeEnum.workflow });
}
return {};
}
export default NextAPI(handler);

View File

@@ -6,8 +6,7 @@ import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { NextAPI } from '@/service/middleware/entry';
import {
ManagePermissionVal,
WritePermissionVal,
OwnerPermissionVal
WritePermissionVal
} from '@fastgpt/global/support/permission/constant';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
@@ -22,7 +21,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
nodes,
edges,
chatConfig,
permission,
teamTags,
defaultPermission
} = req.body as AppUpdateParams;
@@ -33,9 +31,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
}
// 凭证校验
if (permission) {
await authApp({ req, authToken: true, appId, per: OwnerPermissionVal });
} else if (defaultPermission) {
if (defaultPermission) {
await authApp({ req, authToken: true, appId, per: ManagePermissionVal });
} else {
await authApp({ req, authToken: true, appId, per: WritePermissionVal });
@@ -56,7 +52,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
type,
avatar,
intro,
permission,
defaultPermission,
...(teamTags && teamTags),
...(formatNodes && {

View File

@@ -0,0 +1,36 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
export type getLatestVersionQuery = {
appId: string;
};
export type getLatestVersionBody = {};
export type getLatestVersionResponse = {
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
chatConfig: AppChatConfigType;
};
async function handler(
req: ApiRequestProps<getLatestVersionBody, getLatestVersionQuery>,
res: ApiResponseType<any>
): Promise<getLatestVersionResponse> {
const { app } = await authApp({
req,
authToken: true,
appId: req.query.appId,
per: WritePermissionVal
});
return getAppLatestVersion(req.query.appId, app);
}
export default NextAPI(handler);

View File

@@ -8,6 +8,7 @@ import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { PostPublishAppProps } from '@/global/core/app/api';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
type Response = {};
@@ -15,13 +16,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
const { appId } = req.query as { appId: string };
const { nodes = [], edges = [], chatConfig, type } = req.body as PostPublishAppProps;
await authApp({ appId, req, per: WritePermissionVal, authToken: true });
const { app } = await authApp({ appId, req, per: WritePermissionVal, authToken: true });
const { nodes: formatNodes } = beforeUpdateAppFormat({ nodes });
await mongoSessionRun(async (session) => {
// create version histories
await MongoAppVersion.create(
const [{ _id }] = await MongoAppVersion.create(
[
{
appId,
@@ -34,18 +35,25 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
);
// update app
await MongoApp.findByIdAndUpdate(appId, {
modules: formatNodes,
edges,
chatConfig,
updateTime: new Date(),
version: 'v2',
type,
scheduledTriggerConfig: chatConfig?.scheduledTriggerConfig,
scheduledTriggerNextTime: chatConfig?.scheduledTriggerConfig
? getNextTimeByCronStringAndTimezone(chatConfig.scheduledTriggerConfig)
: null
});
await MongoApp.findByIdAndUpdate(
appId,
{
modules: formatNodes,
edges,
chatConfig,
updateTime: new Date(),
version: 'v2',
type,
scheduledTriggerConfig: chatConfig?.scheduledTriggerConfig,
scheduledTriggerNextTime: chatConfig?.scheduledTriggerConfig?.cronString
? getNextTimeByCronStringAndTimezone(chatConfig.scheduledTriggerConfig)
: null,
...(app.type === AppTypeEnum.plugin && { 'pluginData.nodeVersion': _id })
},
{
session
}
);
});
return {};

View File

@@ -8,14 +8,20 @@ import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { PostRevertAppProps } from '@/global/core/app/api';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
type Response = {};
async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<{}> {
const { appId } = req.query as { appId: string };
const { editNodes = [], editEdges = [], versionId } = req.body as PostRevertAppProps;
const {
editNodes = [],
editEdges = [],
editChatConfig,
versionId
} = req.body as PostRevertAppProps;
await authApp({ appId, req, per: WritePermissionVal, authToken: true });
const { app } = await authApp({ appId, req, per: WritePermissionVal, authToken: true });
const version = await MongoAppVersion.findOne({
_id: versionId,
@@ -37,19 +43,21 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
{
appId,
nodes: formatEditNodes,
edges: editEdges
edges: editEdges,
chatConfig: editChatConfig
}
],
{ session }
);
// 为历史版本再创建一个版本
await MongoAppVersion.create(
const [{ _id }] = await MongoAppVersion.create(
[
{
appId,
nodes: version.nodes,
edges: version.edges
edges: version.edges,
chatConfig: version.chatConfig
}
],
{ session }
@@ -59,11 +67,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
await MongoApp.findByIdAndUpdate(appId, {
modules: version.nodes,
edges: version.edges,
chatConfig: version.chatConfig,
updateTime: new Date(),
scheduledTriggerConfig,
scheduledTriggerNextTime: scheduledTriggerConfig
scheduledTriggerNextTime: scheduledTriggerConfig?.cronString
? getNextTimeByCronStringAndTimezone(scheduledTriggerConfig)
: null
: null,
...(app.type === AppTypeEnum.plugin && { 'pluginData.nodeVersion': _id })
});
});

View File

@@ -6,6 +6,7 @@ import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { authChatCert } from '@/service/support/permission/auth/chat';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
export type QueryChatInputGuideBody = OutLinkChatAuthProps & {
appId: string;
@@ -28,7 +29,7 @@ async function handler(
const params = {
appId,
...(searchKey && { text: { $regex: new RegExp(searchKey, 'i') } })
...(searchKey && { text: { $regex: new RegExp(`${replaceRegChars(searchKey)}`, 'i') } })
};
const result = await MongoChatInputGuide.find(params).sort({ _id: -1 }).limit(6);

View File

@@ -1,78 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { CreateOnePluginParams } from '@fastgpt/global/core/plugin/controller';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { httpApiSchema2Plugins } from '@fastgpt/global/core/plugin/httpPlugin/utils';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
const body = req.body as CreateOnePluginParams;
// await checkTeamPluginLimit(teamId);
// create parent plugin and child plugin
if (body.metadata?.apiSchemaStr) {
const parentId = await mongoSessionRun(async (session) => {
const [{ _id: parentId }] = await MongoPlugin.create(
[
{
...body,
parentId: null,
teamId,
tmbId,
version: 'v2'
}
],
{ session }
);
const childrenPlugins = await httpApiSchema2Plugins({
parentId,
apiSchemaStr: body.metadata?.apiSchemaStr,
customHeader: body.metadata?.customHeaders
});
await MongoPlugin.create(
childrenPlugins.map((item) => ({
...item,
metadata: {
pluginUid: item.name
},
teamId,
tmbId,
version: 'v2'
})),
{
session
}
);
return parentId;
});
jsonRes(res, {
data: parentId
});
} else {
const { _id } = await MongoPlugin.create({
...body,
teamId,
tmbId,
version: 'v2'
});
jsonRes(res, {
data: _id
});
}
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -1,41 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { teamId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
const { pluginId } = req.query as { pluginId: string };
if (!pluginId) {
throw new Error('缺少参数');
}
await authPluginCrud({ req, authToken: true, pluginId, per: 'owner' });
await mongoSessionRun(async (session) => {
await MongoPlugin.deleteMany(
{
teamId,
parentId: pluginId
},
{
session
}
);
await MongoPlugin.findByIdAndDelete(pluginId, { session });
});
jsonRes(res, {});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -1,21 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const { id } = req.query as { id: string };
await connectToDatabase();
const { plugin } = await authPluginCrud({ req, authToken: true, pluginId: id, per: 'r' });
jsonRes(res, {
data: plugin
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -1,28 +0,0 @@
/*
get plugin preview modules
*/
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { getPluginPreviewNode } from '@fastgpt/service/core/plugin/controller';
import { authPluginCanUse } from '@fastgpt/service/support/permission/auth/plugin';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const { id } = req.query as { id: string };
await connectToDatabase();
const { teamId, tmbId } = await authCert({ req, authToken: true });
await authPluginCanUse({ id, teamId, tmbId });
jsonRes<FlowNodeTemplateType>(res, {
data: await getPluginPreviewNode({ id })
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -1,36 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { PluginListItemType } from '@fastgpt/global/core/plugin/controller';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { parentId, type } = req.query as { parentId?: string; type?: DatasetTypeEnum };
const { teamId } = await authCert({ req, authToken: true });
const plugins = await MongoPlugin.find(
{
teamId,
...(parentId !== undefined && { parentId: parentId || null }),
...(type && { type })
},
'_id parentId type name avatar intro metadata'
)
.sort({ updateTime: -1 })
.lean();
jsonRes<PluginListItemType[]>(res, {
data: plugins
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -1,46 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type.d';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { parentId } = req.query as { parentId: string };
if (!parentId) {
return jsonRes(res, {
data: []
});
}
await authCert({ req, authToken: true });
jsonRes<ParentTreePathItemType[]>(res, {
data: await getParents(parentId)
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}
async function getParents(parentId?: string): Promise<ParentTreePathItemType[]> {
if (!parentId) {
return [];
}
const parent = await MongoPlugin.findById(parentId, 'name parentId');
if (!parent) return [];
const paths = await getParents(parent.parentId);
paths.push({ parentId, parentName: parent.name });
return paths;
}

View File

@@ -1,64 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { parentId, searchKey } = req.query as { parentId?: string; searchKey?: string };
const { teamId } = await authCert({ req, authToken: true });
const userPlugins = await (async () => {
if (searchKey) {
return MongoPlugin.find({
teamId,
// search name or intro
$or: [
{ name: { $regex: searchKey, $options: 'i' } },
{ intro: { $regex: searchKey, $options: 'i' } }
]
})
.sort({
updateTime: -1
})
.lean();
} else {
return MongoPlugin.find({ teamId, parentId: parentId || null })
.sort({
updateTime: -1
})
.lean();
}
})();
const data: FlowNodeTemplateType[] = userPlugins.map((plugin) => ({
id: String(plugin._id),
parentId: String(plugin.parentId),
pluginId: String(plugin._id),
pluginType: plugin.type,
templateType: FlowNodeTemplateTypeEnum.personalPlugin,
flowNodeType: FlowNodeTypeEnum.pluginModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,
showStatus: false,
version: '481',
inputs: [],
outputs: []
}));
jsonRes<FlowNodeTemplateType[]>(res, {
data
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -1,152 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { UpdatePluginParams } from '@fastgpt/global/core/plugin/controller';
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { ClientSession } from '@fastgpt/service/common/mongo';
import { httpApiSchema2Plugins } from '@fastgpt/global/core/plugin/httpPlugin/utils';
import { isEqual } from 'lodash';
import { nanoid } from 'nanoid';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const body = req.body as UpdatePluginParams;
const { id, modules, edges, ...props } = body;
const { teamId, tmbId } = await authPluginCrud({
req,
authToken: true,
pluginId: id,
per: 'owner'
});
const originPlugin = await MongoPlugin.findById(id);
let updateData = {
name: props.name,
intro: props.intro,
avatar: props.avatar,
parentId: props.parentId,
version: 'v2',
...(modules?.length && {
modules: modules
}),
...(edges?.length && { edges }),
metadata: props.metadata,
nodeVersion: originPlugin?.nodeVersion
};
const isNodeVersionEqual =
isEqual(
originPlugin?.modules.map((module) => {
return { ...module, position: undefined };
}),
updateData.modules?.map((module) => {
return { ...module, position: undefined };
})
) && isEqual(originPlugin?.edges, updateData.edges);
if (!isNodeVersionEqual) {
updateData = {
...updateData,
nodeVersion: nanoid(6)
};
}
if (props.metadata?.apiSchemaStr) {
await mongoSessionRun(async (session) => {
// update children
await updateHttpChildrenPlugin({
teamId,
tmbId,
parent: body,
session
});
await MongoPlugin.findByIdAndUpdate(id, updateData, { session });
});
jsonRes(res, {});
} else {
jsonRes(res, {
data: await MongoPlugin.findByIdAndUpdate(id, updateData)
});
}
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}
const updateHttpChildrenPlugin = async ({
teamId,
tmbId,
parent,
session
}: {
teamId: string;
tmbId: string;
parent: UpdatePluginParams;
session: ClientSession;
}) => {
if (!parent.metadata?.apiSchemaStr) return;
const dbPlugins = await MongoPlugin.find(
{
parentId: parent.id,
teamId
},
'_id metadata'
);
const schemaPlugins = await httpApiSchema2Plugins({
parentId: parent.id,
apiSchemaStr: parent.metadata?.apiSchemaStr,
customHeader: parent.metadata?.customHeaders
});
// 数据库中存在schema不存在删除
for await (const plugin of dbPlugins) {
if (!schemaPlugins.find((p) => p.name === plugin.metadata?.pluginUid)) {
await MongoPlugin.deleteOne({ _id: plugin._id }, { session });
}
}
// 数据库中不存在schema存在新增
for await (const plugin of schemaPlugins) {
if (!dbPlugins.find((p) => p.metadata?.pluginUid === plugin.name)) {
await MongoPlugin.create(
[
{
...plugin,
metadata: {
pluginUid: plugin.name
},
teamId,
tmbId,
version: 'v2'
}
],
{
session
}
);
}
}
// 数据库中存在schema存在更新
for await (const plugin of schemaPlugins) {
const dbPlugin = dbPlugins.find((p) => plugin.name === p.metadata?.pluginUid);
if (dbPlugin) {
await MongoPlugin.findByIdAndUpdate(
dbPlugin._id,
{
...plugin,
version: 'v2'
},
{ session }
);
}
}
};

View File

@@ -6,7 +6,6 @@ import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { defaultApp } from '@/web/core/app/constants';
@@ -15,13 +14,7 @@ async function handler(
req: NextApiRequest,
res: NextApiResponse
): Promise<PostWorkflowDebugResponse> {
const {
nodes = [],
edges = [],
variables = {},
appId,
pluginId
} = req.body as PostWorkflowDebugProps;
const { nodes = [], edges = [], variables = {}, appId } = req.body as PostWorkflowDebugProps;
if (!nodes) {
throw new Error('Prams Error');
@@ -39,8 +32,7 @@ async function handler(
req,
authToken: true
}),
appId && authApp({ req, authToken: true, appId, per: ReadPermissionVal }),
pluginId && authPluginCrud({ req, authToken: true, pluginId, per: 'r' })
authApp({ req, authToken: true, appId, per: ReadPermissionVal })
]);
// auth balance