4.8.6 merge (#1943)

* Dataset collection forbid (#1885)

* perf: tool call support same id

* feat: collection forbid

* feat: collection forbid

* Inheritance Permission for apps (#1897)

* feat: app schema define

chore: references of authapp

* feat: authApp method inheritance

* feat: create and update api

* feat: update

* feat: inheritance Permission controller for app.

* feat: abstract version of inheritPermission

* feat: ancestorId for apps

* chore: update app

* fix: inheritPermission abstract version

* feat: update folder defaultPermission

* feat: app update api

* chore: inheritance frontend

* chore: app list api

* feat: update defaultPermission in app deatil

* feat: backend api finished

* feat: app inheritance permission fe

* fix: app update defaultpermission causes collaborator miss

* fix: ts error

* chore: adjust the codes

* chore: i18n

chore: i18n

* chore: fe adjust and i18n

* chore: adjust the code

* feat: resume api;
chore: rewrite update api and inheritPermission methods

* chore: something

* chore: fe code adjusting

* feat: frontend adjusting

* chore: fe code adjusting

* chore: adjusting the code

* perf: fe loading

* format

* Inheritance fix (#1908)

* fix: SlideCard

* fix: authapp did not return parent app for inheritance app

* fix: fe adjusting

* feat: fe adjusing

* perf: inherit per ux

* doc

* fix: ts errors (#1916)

* perf: inherit permission

* fix: permission inherit

* Workflow type (#1938)

* perf: workflow type

tmp workflow

perf: workflow type

feat: custom field config

* perf: dynamic input

* perf: node classify

* perf: node classify

* perf: node classify

* perf: node classify

* fix: workflow custom input

* feat: text editor and customFeedback move to basic nodes

* feat: community system plugin

* fix: ts

* feat: exprEval plugin

* perf: workflow type

* perf: plugin important

* fix: default templates

* perf: markdown hr css

* lock

* perf: fetch url

* perf: new plugin version

* fix: chat histories update

* fix: collection paths invalid

* perf: app card ui

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
Archer
2024-07-04 17:42:09 +08:00
committed by GitHub
parent babf03c218
commit a9cdece341
303 changed files with 18883 additions and 13149 deletions

View File

@@ -0,0 +1,34 @@
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 { PgClient } from '@fastgpt/service/common/vectorStore/pg';
import { MongoApp } from '@fastgpt/service/core/app/schema';
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
await authCert({ req, authRoot: true });
await MongoApp.updateMany(
{},
{
$set: {
inheritPermission: true
}
}
);
jsonRes(res, {
message: 'success'
});
} catch (error) {
console.log(error);
jsonRes(res, {
code: 500,
error
});
}
}

View File

@@ -13,6 +13,7 @@ import { exit } from 'process';
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
import { initFastGPTConfig } from '@fastgpt/service/common/system/tools';
import json5 from 'json5';
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await getInitConfig();
@@ -69,10 +70,6 @@ export async function getInitConfig() {
// abandon
getSystemPluginV1()
]);
console.log({
communityPlugins: global.communityPlugins
});
} catch (error) {
console.error('Load init config error', error);
global.systemInitd = false;
@@ -155,16 +152,17 @@ function getSystemPlugin() {
const filterFiles = files.filter((item) => item.endsWith('.json'));
// read json file
const fileTemplates: (PluginTemplateType & { weight: number })[] = filterFiles.map((filename) => {
const fileTemplates = filterFiles.map<SystemPluginTemplateItemType>((filename) => {
const content = readFileSync(`${basePath}/${filename}`, 'utf-8');
return {
...json5.parse(content),
id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`,
source: PluginSourceEnum.community
originCost: 0,
currentCost: 0,
id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`
};
});
fileTemplates.sort((a, b) => b.weight - a.weight);
fileTemplates.sort((a, b) => (b.weight || 0) - (a.weight || 0));
global.communityPlugins = fileTemplates;
}

View File

@@ -1,6 +1,4 @@
import type { NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { checkTeamAppLimit } from '@fastgpt/service/support/permission/teamLimit';
@@ -14,6 +12,8 @@ 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';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
export type CreateAppBody = {
parentId?: ParentIdType;
@@ -24,15 +24,20 @@ export type CreateAppBody = {
edges?: AppSchema['edges'];
};
async function handler(req: ApiRequestProps<CreateAppBody>, res: NextApiResponse<any>) {
async function handler(req: ApiRequestProps<CreateAppBody>) {
const { parentId, name, avatar, type, modules, edges } = req.body;
if (!name || !type || !Array.isArray(modules)) {
throw new Error('缺少参数');
return Promise.reject(CommonErrEnum.inheritPermissionError);
}
// 凭证校验
const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
if (parentId) {
// if it is not a root app
// check the parent folder permission
await authApp({ req, appId: parentId, per: WritePermissionVal, authToken: true });
}
// 上限校验
await checkTeamAppLimit(teamId);
@@ -49,9 +54,7 @@ async function handler(req: ApiRequestProps<CreateAppBody>, res: NextApiResponse
tmbId
});
jsonRes(res, {
data: appId
});
return appId;
}
export default NextAPI(handler);
@@ -102,7 +105,7 @@ export const onCreateApp = async ({
{ session }
);
if (type !== AppTypeEnum.folder && type !== AppTypeEnum.httpPlugin) {
if (!AppFolderTypeList.includes(type!)) {
await MongoAppVersion.create(
[
{

View File

@@ -1,14 +1,15 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal, WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
/* 获取我的模型 */
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
if (!appId) {
throw new Error('参数错误');
Promise.reject(CommonErrEnum.missingParams);
}
// 凭证校验
const { app } = await authApp({ req, authToken: true, appId, per: ReadPermissionVal });

View File

@@ -1,13 +1,21 @@
import type { NextApiResponse } from 'next';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import {
PerResourceTypeEnum,
WritePermissionVal
} from '@fastgpt/global/support/permission/constant';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { FolderImgUrl } from '@fastgpt/global/common/file/image/constants';
import { NextAPI } from '@/service/middleware/entry';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPermission';
import { getResourceAllClbs } from '@fastgpt/service/support/permission/controller';
export type CreateAppFolderBody = {
parentId?: ParentIdType;
@@ -15,25 +23,59 @@ export type CreateAppFolderBody = {
intro?: string;
};
async function handler(req: ApiRequestProps<CreateAppFolderBody>, res: NextApiResponse<any>) {
async function handler(req: ApiRequestProps<CreateAppFolderBody>) {
const { name, intro, parentId } = req.body;
if (!name) {
throw new Error('缺少参数');
Promise.reject(CommonErrEnum.missingParams);
}
// 凭证校验
const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
const parentApp = await (async () => {
if (parentId) {
// if it is not a root folder
return (
await authApp({
req,
appId: parentId,
per: WritePermissionVal,
authToken: true
})
).app; // check the parent folder permission
}
})();
// Create app
await MongoApp.create({
...parseParentIdInMongo(parentId),
avatar: FolderImgUrl,
name,
intro,
teamId,
tmbId,
type: AppTypeEnum.folder
await mongoSessionRun(async (session) => {
const app = await MongoApp.create({
...parseParentIdInMongo(parentId),
avatar: FolderImgUrl,
name,
intro,
teamId,
tmbId,
type: AppTypeEnum.folder,
// inheritPermission: !!parentApp ? true : false,
defaultPermission: !!parentApp ? parentApp.defaultPermission : AppDefaultPermissionVal
});
if (parentId) {
const parentClbs = await getResourceAllClbs({
teamId,
resourceId: parentId,
resourceType: PerResourceTypeEnum.app,
session
});
await syncCollaborators({
resourceType: PerResourceTypeEnum.app,
teamId,
resourceId: app._id,
collaborators: parentClbs,
session
});
}
});
}

View File

@@ -1,7 +1,5 @@
import type { NextApiResponse } from 'next';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { AppListItemType } from '@fastgpt/global/core/app/type';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { NextAPI } from '@/service/middleware/entry';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import {
@@ -12,8 +10,10 @@ import { AppPermission } from '@fastgpt/global/support/permission/app/controller
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
export type ListAppBody = {
parentId?: ParentIdType;
@@ -22,22 +22,34 @@ export type ListAppBody = {
searchKey?: string;
};
async function handler(
req: ApiRequestProps<ListAppBody>,
res: NextApiResponse<any>
): Promise<AppListItemType[]> {
async function handler(req: ApiRequestProps<ListAppBody>): Promise<AppListItemType[]> {
const { parentId, type, getRecentlyChat, searchKey } = req.body;
// 凭证校验
const {
teamId,
app: ParentApp,
tmbId,
teamId,
permission: tmbPer
} = await authUserPer({
req,
authToken: true,
per: ReadPermissionVal
});
const { parentId, type, getRecentlyChat, searchKey } = req.body;
} = await (async () => {
if (parentId) {
return await authApp({
req,
authToken: true,
appId: parentId,
per: ReadPermissionVal
});
} else {
return {
...(await authUserPer({
req,
authToken: true,
per: ReadPermissionVal
})),
app: undefined
};
}
})();
const findAppsQuery = (() => {
const searchMatch = searchKey
@@ -71,7 +83,7 @@ async function handler(
const [myApps, rpList] = await Promise.all([
MongoApp.find(
findAppsQuery,
'_id avatar type name intro tmbId updateTime pluginData defaultPermission'
'_id parentId avatar type name intro tmbId updateTime pluginData defaultPermission inheritPermission'
)
.sort({
updateTime: -1
@@ -87,11 +99,29 @@ async function handler(
const filterApps = myApps
.map((app) => {
const perVal = rpList.find((item) => String(item.resourceId) === String(app._id))?.permission;
const Per = new AppPermission({
per: perVal ?? app.defaultPermission,
isOwner: String(app.tmbId) === tmbId || tmbPer.isOwner
});
const Per = (() => {
// Inherit app
if (app.inheritPermission && ParentApp && !AppFolderTypeList.includes(app.type)) {
// get its parent's permission as its permission
app.defaultPermission = ParentApp.defaultPermission;
const perVal = rpList.find(
(item) => String(item.resourceId) === String(ParentApp._id)
)?.permission;
return new AppPermission({
per: perVal ?? app.defaultPermission,
isOwner: String(app.tmbId) === String(tmbId) || tmbPer.isOwner
});
} else {
const perVal = rpList.find(
(item) => String(item.resourceId) === String(app._id)
)?.permission;
return new AppPermission({
per: perVal ?? app.defaultPermission,
isOwner: String(app.tmbId) === String(tmbId) || tmbPer.isOwner
});
}
})();
return {
...app,
@@ -112,7 +142,8 @@ async function handler(
updateTime: app.updateTime,
permission: app.permission,
defaultPermission: app.defaultPermission || AppDefaultPermissionVal,
pluginData: app.pluginData
pluginData: app.pluginData,
inheritPermission: app.inheritPermission ?? true
}));
}

View File

@@ -6,7 +6,7 @@ import {
getPluginPreviewNode,
splitCombinePluginId
} from '@fastgpt/service/core/app/plugin/controller';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
import { NextAPI } from '@/service/middleware/entry';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { authApp } from '@fastgpt/service/support/permission/app/auth';

View File

@@ -1,39 +1,26 @@
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, 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';
import { NodeTemplateListItemType } from '@fastgpt/global/core/workflow/type/node.d';
import { NextAPI } from '@/service/middleware/entry';
import { getCommunityPluginsTemplateList } from '@fastgpt/plugins/register';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
await authCert({ req, authToken: true });
async function handler(
req: NextApiRequest,
res: NextApiResponse<any>
): Promise<NodeTemplateListItemType[]> {
await authCert({ req, authToken: true });
const data: FlowNodeTemplateType[] =
global.communityPlugins?.map((plugin) => ({
id: plugin.id,
pluginId: plugin.id,
templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.pluginModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,
showStatus: true,
isTool: plugin.isTool,
version: defaultNodeVersion,
inputs: [],
outputs: []
})) || [];
// const data: NodeTemplateListItemType[] =
// global.communityPlugins?.map((plugin) => ({
// id: plugin.id,
// templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other,
// flowNodeType: FlowNodeTypeEnum.pluginModule,
// avatar: plugin.avatar,
// name: plugin.name,
// intro: plugin.intro
// })) || [];
jsonRes<FlowNodeTemplateType[]>(res, {
data
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
return getCommunityPluginsTemplateList();
}
export default NextAPI(handler);

View File

@@ -0,0 +1,45 @@
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import {
ManagePermissionVal,
PerResourceTypeEnum
} from '@fastgpt/global/support/permission/constant';
import { resumeInheritPermission } from '@fastgpt/service/support/permission/inheritPermission';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
export type ResumeInheritPermissionQuery = {
appId: string;
};
export type ResumeInheritPermissionBody = {};
// resume the app's inherit permission.
async function handler(
req: ApiRequestProps<ResumeInheritPermissionBody, ResumeInheritPermissionQuery>
) {
const { appId } = req.query;
const { app } = await authApp({
appId,
req,
authToken: true,
per: ManagePermissionVal
});
if (app.parentId) {
await resumeInheritPermission({
resource: app,
folderTypeList: AppFolderTypeList,
resourceType: PerResourceTypeEnum.app,
resourceModel: MongoApp
});
} else {
await MongoApp.updateOne(
{
_id: appId
},
{
inheritPermission: true
}
);
}
}
export default NextAPI(handler);

View File

@@ -1,4 +1,3 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import type { AppUpdateParams } from '@/global/core/app/api';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
@@ -6,12 +5,37 @@ import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { NextAPI } from '@/service/middleware/entry';
import {
ManagePermissionVal,
PerResourceTypeEnum,
WritePermissionVal
} from '@fastgpt/global/support/permission/constant';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import {
syncChildrenPermission,
syncCollaborators
} from '@fastgpt/service/support/permission/inheritPermission';
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
import { ClientSession } from 'mongoose';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { getResourceAllClbs } from '@fastgpt/service/support/permission/controller';
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
/* 获取我的模型 */
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
/*
修改默认权限
1. 继承态目录:关闭继承态,修改权限,同步子目录默认权限
2. 继承态资源:关闭继承态,修改权限, 复制父级协作者。
3. 非继承目录:修改权限,同步子目录默认权限
4. 非继承资源:修改权限
移动
1. 继承态目录:改 parentId, 修改成父的默认权限,同步子目录默认权限和协作者
2. 继承态资源:改 parentId
3. 非继承:改 parentId
*/
async function handler(req: ApiRequestProps<AppUpdateParams, { appId: string }>) {
const {
parentId,
name,
@@ -24,40 +48,152 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
teamTags,
defaultPermission
} = req.body as AppUpdateParams;
const { appId } = req.query as { appId: string };
if (!appId) {
throw new Error('appId is empty');
Promise.reject(CommonErrEnum.missingParams);
}
// 凭证校验
if (defaultPermission) {
await authApp({ req, authToken: true, appId, per: ManagePermissionVal });
} else {
await authApp({ req, authToken: true, appId, per: WritePermissionVal });
}
const { app } = await (async () => {
if (defaultPermission !== undefined) {
// if defaultPermission or inheritPermission is set, then need manage permission
return authApp({ req, authToken: true, appId, per: ManagePermissionVal });
} else {
return authApp({ req, authToken: true, appId, per: WritePermissionVal });
}
})();
// format nodes data
// 1. dataset search limit, less than model quoteMaxToken
const { nodes: formatNodes } = beforeUpdateAppFormat({ nodes });
const isDefaultPermissionChanged =
defaultPermission !== undefined && defaultPermission !== app.defaultPermission;
const isFolder = AppFolderTypeList.includes(app.type);
// 更新模型
await MongoApp.findByIdAndUpdate(appId, {
...parseParentIdInMongo(parentId),
...(name && { name }),
...(type && { type }),
...(avatar && { avatar }),
...(intro !== undefined && { intro }),
...(defaultPermission !== undefined && { defaultPermission }),
...(teamTags && { teamTags }),
...(formatNodes && {
modules: formatNodes
}),
...(edges && {
edges
}),
...(chatConfig && { chatConfig })
});
const onUpdate = async (
session?: ClientSession,
updatedDefaultPermission?: PermissionValueType
) => {
const { nodes: formatNodes } = beforeUpdateAppFormat({ nodes });
return MongoApp.findByIdAndUpdate(
appId,
{
...parseParentIdInMongo(parentId),
...(name && { name }),
...(type && { type }),
...(avatar && { avatar }),
...(intro !== undefined && { intro }),
// update default permission(Maybe move update)
...(updatedDefaultPermission !== undefined && {
defaultPermission: updatedDefaultPermission
}),
// Not root, update default permission
...(isDefaultPermissionChanged && { inheritPermission: false }),
...(teamTags && { teamTags }),
...(formatNodes && {
modules: formatNodes
}),
...(edges && {
edges
}),
...(chatConfig && { chatConfig })
},
{ session }
);
};
// Move
if (parentId !== undefined) {
await mongoSessionRun(async (session) => {
// Auth
const parentDefaultPermission = await (async () => {
if (parentId) {
const { app: parentApp } = await authApp({
req,
authToken: true,
appId: parentId,
per: WritePermissionVal
});
return parentApp.defaultPermission;
}
return AppDefaultPermissionVal;
})();
// Inherit folder: Sync children permission and it's clbs
if (isFolder && app.inheritPermission) {
const parentClbs = await getResourceAllClbs({
teamId: app.teamId,
resourceId: parentId,
resourceType: PerResourceTypeEnum.app,
session
});
// sync self
await syncCollaborators({
resourceId: app._id,
resourceType: PerResourceTypeEnum.app,
collaborators: parentClbs,
session,
teamId: app.teamId
});
// sync the children
await syncChildrenPermission({
resource: app,
resourceType: PerResourceTypeEnum.app,
resourceModel: MongoApp,
folderTypeList: AppFolderTypeList,
defaultPermission: parentDefaultPermission,
collaborators: parentClbs,
session
});
return onUpdate(session, parentDefaultPermission);
}
return onUpdate(session);
});
}
// Update default permission
if (isDefaultPermissionChanged) {
await mongoSessionRun(async (session) => {
if (isFolder) {
// Sync children default permission
await syncChildrenPermission({
resource: {
_id: app._id,
type: app.type,
teamId: app.teamId,
parentId: app.parentId
},
folderTypeList: AppFolderTypeList,
resourceModel: MongoApp,
resourceType: PerResourceTypeEnum.app,
session,
defaultPermission
});
} else if (app.inheritPermission && app.parentId) {
// Inherit app
const parentClbs = await getResourceAllClbs({
teamId: app.teamId,
resourceId: app.parentId,
resourceType: PerResourceTypeEnum.app,
session
});
await syncCollaborators({
resourceId: app._id,
resourceType: PerResourceTypeEnum.app,
collaborators: parentClbs,
session,
teamId: app.teamId
});
}
return onUpdate(session, defaultPermission);
});
}
}
export default NextAPI(handler);

View File

@@ -5,7 +5,7 @@ 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';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
export type getLatestVersionQuery = {
appId: string;

View File

@@ -10,8 +10,9 @@ import { DatasetDataCollectionName } from '@fastgpt/service/core/dataset/data/sc
import { startTrainingQueue } from '@/service/core/dataset/training/utils';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { PagingData } from '@/types';
async function handler(req: NextApiRequest) {
async function handler(req: NextApiRequest): Promise<PagingData<DatasetCollectionsListItemType>> {
let {
pageNum = 1,
pageSize = 10,
@@ -45,9 +46,24 @@ async function handler(req: NextApiRequest) {
: {})
};
const selectField = {
_id: 1,
parentId: 1,
tmbId: 1,
name: 1,
type: 1,
forbid: 1,
createTime: 1,
updateTime: 1,
trainingType: 1,
fileId: 1,
rawLink: 1
};
// not count data amount
if (simple) {
const collections = await MongoDatasetCollection.find(match, '_id parentId type name')
const collections = await MongoDatasetCollection.find(match)
.select(selectField)
.sort({
updateTime: -1
})
@@ -123,15 +139,7 @@ async function handler(req: NextApiRequest) {
},
{
$project: {
_id: 1,
parentId: 1,
tmbId: 1,
name: 1,
type: 1,
status: 1,
updateTime: 1,
fileId: 1,
rawLink: 1,
...selectField,
dataAmount: {
$ifNull: [{ $arrayElemAt: ['$dataCount.count', 0] }, 0]
},

View File

@@ -1,9 +1,11 @@
import type { NextApiRequest } from 'next';
import { getDatasetCollectionPaths } from '@fastgpt/service/core/dataset/collection/utils';
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import { NextAPI } from '@/service/middleware/entry';
export default async function handler(req: NextApiRequest) {
async function handler(req: NextApiRequest) {
const { parentId } = req.query as { parentId: string };
if (!parentId) {
@@ -16,9 +18,34 @@ export default async function handler(req: NextApiRequest) {
collectionId: parentId,
per: ReadPermissionVal
});
const paths = await getDatasetCollectionPaths({
parentId
});
return paths;
}
export default NextAPI(handler);
export async function getDatasetCollectionPaths({
parentId = ''
}: {
parentId?: string;
}): Promise<ParentTreePathItemType[]> {
async function find(parentId?: string): Promise<ParentTreePathItemType[]> {
if (!parentId) {
return [];
}
const parent = await MongoDatasetCollection.findOne({ _id: parentId }, 'name parentId');
if (!parent) return [];
const paths = await find(parent.parentId);
paths.push({ parentId, parentName: parent.name });
return paths;
}
return find(parentId);
}

View File

@@ -1,14 +1,20 @@
import type { NextApiRequest } from 'next';
import type { UpdateDatasetCollectionParams } from '@/global/core/api/datasetReq.d';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import { getCollectionUpdateTime } from '@fastgpt/service/core/dataset/collection/utils';
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { ApiRequestProps } from '@fastgpt/service/type/next';
async function handler(req: NextApiRequest) {
const { id, parentId, name } = req.body as UpdateDatasetCollectionParams;
export type UpdateDatasetCollectionParams = {
id: string;
parentId?: string;
name?: string;
forbid?: boolean;
};
async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) {
const { id, parentId, name, forbid } = req.body;
if (!id) {
return Promise.reject(CommonErrEnum.missingParams);
@@ -25,7 +31,8 @@ async function handler(req: NextApiRequest) {
const updateFields: Record<string, any> = {
...(parentId !== undefined && { parentId: parentId || null }),
...(name && { name, updateTime: getCollectionUpdateTime({ name }) })
...(name && { name, updateTime: getCollectionUpdateTime({ name }) }),
...(forbid !== undefined && { forbid })
};
await MongoDatasetCollection.findByIdAndUpdate(id, {

View File

@@ -1,18 +1,21 @@
import type { NextApiRequest } from 'next';
import type { GetDatasetDataListProps } from '@/global/core/api/datasetReq';
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { PagingData, RequestPaging } from '@/types';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { DatasetDataListItemType } from '@/global/core/dataset/type';
async function handler(req: NextApiRequest) {
let {
pageNum = 1,
pageSize = 10,
searchText = '',
collectionId
} = req.body as GetDatasetDataListProps;
export type GetDatasetDataListProps = RequestPaging & {
searchText?: string;
collectionId: string;
};
async function handler(
req: ApiRequestProps<GetDatasetDataListProps>
): Promise<PagingData<DatasetDataListItemType>> {
let { pageNum = 1, pageSize = 10, searchText = '', collectionId } = req.body;
pageSize = Math.min(pageSize, 30);
@@ -25,15 +28,14 @@ async function handler(req: NextApiRequest) {
per: ReadPermissionVal
});
searchText = replaceRegChars(searchText).replace(/'/g, '');
const queryReg = new RegExp(`${replaceRegChars(searchText)}`, 'i');
const match = {
teamId,
datasetId: collection.datasetId._id,
collectionId,
...(searchText
...(searchText.trim()
? {
$or: [{ q: new RegExp(searchText, 'i') }, { a: new RegExp(searchText, 'i') }]
$or: [{ q: queryReg }, { a: queryReg }]
}
: {})
};

View File

@@ -1,14 +1,14 @@
import type { NextApiRequest } from 'next';
import { updateData2Dataset } from '@/service/core/dataset/data/controller';
import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push';
import { UpdateDatasetDataProps } from '@/global/core/dataset/api';
import { checkDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
import { UpdateDatasetDataProps } from '@fastgpt/global/core/dataset/controller';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { authDatasetData } from '@fastgpt/service/support/permission/dataset/auth';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
async function handler(req: NextApiRequest) {
const { id, q = '', a, indexes = [] } = req.body as UpdateDatasetDataProps;
async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
const { dataId, q, a, indexes = [] } = req.body;
// auth data permission
const {
@@ -21,30 +21,30 @@ async function handler(req: NextApiRequest) {
req,
authToken: true,
authApiKey: true,
dataId: id,
dataId,
per: WritePermissionVal
});
// auth team balance
await checkDatasetLimit({
teamId,
insertLen: 1
});
if (q || a || indexes.length > 0) {
const { tokens } = await updateData2Dataset({
dataId,
q,
a,
indexes,
model: vectorModel
});
const { tokens } = await updateData2Dataset({
dataId: id,
q,
a,
indexes,
model: vectorModel
});
pushGenerateVectorUsage({
teamId,
tmbId,
tokens,
model: vectorModel
});
pushGenerateVectorUsage({
teamId,
tmbId,
tokens,
model: vectorModel
});
} else {
// await MongoDatasetData.findByIdAndUpdate(dataId, {
// ...(forbid !== undefined && { forbid })
// });
}
}
export default NextAPI(handler);

View File

@@ -27,7 +27,7 @@ async function handler(
}
/* user auth */
const [{ teamId, tmbId }] = await Promise.all([
const [{ teamId, tmbId }, { app }] = await Promise.all([
authCert({
req,
authToken: true
@@ -38,12 +38,6 @@ async function handler(
// auth balance
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
const app = {
...defaultApp,
teamId,
tmbId
};
/* start process */
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
res,

View File

@@ -3,17 +3,25 @@ import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { SystemVariablesType } from '@fastgpt/global/core/workflow/runtime/type';
import { replaceVariable } from '@fastgpt/global/common/string/tools';
type Props = HttpBodyType<{
customFeedback: string;
}>;
type Props = HttpBodyType<
SystemVariablesType & {
customFeedback: string;
customInputs: Record<string, any>;
}
>;
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const {
customFeedback,
[NodeInputKeyEnum.addInputParam]: { appId, chatId, responseChatItemId: chatItemId }
appId,
chatId,
responseChatItemId: chatItemId,
customInputs
} = req.body as Props;
await authRequestFromLocal({ req });
@@ -22,25 +30,27 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
return res.json({});
}
const feedbackText = replaceVariable(customFeedback, customInputs);
// wait the chat finish
setTimeout(() => {
addCustomFeedbacks({
appId,
chatId,
chatItemId,
feedbacks: [customFeedback]
feedbacks: [feedbackText]
});
}, 60000);
if (!chatId || !chatItemId) {
return res.json({
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`,
text: customFeedback
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${feedbackText}"\\n\\n`,
text: feedbackText
});
}
res.json({
text: customFeedback
text: feedbackText
});
} catch (err) {
console.log(err);

View File

@@ -1,18 +1,18 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { replaceVariable } from '@fastgpt/global/common/string/tools';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { ApiRequestProps } from '@fastgpt/service/type/next';
type Props = HttpBodyType<{
text: string;
[key: string]: any;
customInputs: Record<string, any>;
}>;
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
export default async function handler(req: ApiRequestProps<Props>, res: NextApiResponse<any>) {
try {
const { text, [NodeInputKeyEnum.addInputParam]: obj } = req.body as Props;
const { text, customInputs: obj = {} } = req.body;
await authRequestFromLocal({ req });