Feat: App folder and permission (#1726)
* app folder * feat: app foldere * fix: run app param error * perf: select app ux * perf: folder rerender * fix: ts * fix: parentId * fix: permission * perf: loading ux * perf: per select ux * perf: clb context * perf: query extension tip * fix: ts * perf: app detail per * perf: default per
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import type { NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import type { CreateAppParams } from '@/global/core/app/api.d';
|
||||
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';
|
||||
@@ -9,17 +8,24 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
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';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
const {
|
||||
name = 'APP',
|
||||
avatar,
|
||||
type = AppTypeEnum.advanced,
|
||||
modules,
|
||||
edges
|
||||
} = req.body as CreateAppParams;
|
||||
export type CreateAppBody = {
|
||||
parentId?: ParentIdType;
|
||||
name?: string;
|
||||
avatar?: string;
|
||||
type?: AppTypeEnum;
|
||||
modules: AppSchema['modules'];
|
||||
edges?: AppSchema['edges'];
|
||||
};
|
||||
|
||||
if (!name || !Array.isArray(modules)) {
|
||||
async function handler(req: ApiRequestProps<CreateAppBody>, res: NextApiResponse<any>) {
|
||||
const { parentId, name, avatar, type, modules, edges } = req.body;
|
||||
|
||||
if (!name || !type || !Array.isArray(modules)) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
@@ -34,6 +40,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
const [{ _id: appId }] = await MongoApp.create(
|
||||
[
|
||||
{
|
||||
...parseParentIdInMongo(parentId),
|
||||
avatar,
|
||||
name,
|
||||
teamId,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
|
||||
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { findAppAndAllChildren } from '@fastgpt/service/core/app/controller';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
const { appId } = req.query as { appId: string };
|
||||
@@ -17,50 +18,61 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
throw new Error('参数错误');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
await authApp({ req, authToken: true, appId, per: OwnerPermissionVal });
|
||||
// Auth owner (folder owner, can delete all apps in the folder)
|
||||
const { teamId } = await authApp({ req, authToken: true, appId, per: OwnerPermissionVal });
|
||||
|
||||
const apps = await findAppAndAllChildren({
|
||||
teamId,
|
||||
appId,
|
||||
fields: '_id'
|
||||
});
|
||||
|
||||
console.log(apps);
|
||||
|
||||
// 删除对应的聊天
|
||||
await mongoSessionRun(async (session) => {
|
||||
await MongoChatItem.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
await MongoChat.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
// 删除分享链接
|
||||
await MongoOutLink.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
// delete version
|
||||
await MongoAppVersion.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
await MongoChatInputGuide.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
// delete app
|
||||
await MongoApp.deleteOne(
|
||||
{
|
||||
_id: appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
for await (const app of apps) {
|
||||
const appId = app._id;
|
||||
// Chats
|
||||
await MongoChatItem.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
await MongoChat.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
// 删除分享链接
|
||||
await MongoOutLink.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
// delete version
|
||||
await MongoAppVersion.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
await MongoChatInputGuide.deleteMany(
|
||||
{
|
||||
appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
// delete app
|
||||
await MongoApp.deleteOne(
|
||||
{
|
||||
_id: appId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { ReadPermissionVal, WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
|
||||
/* 获取我的模型 */
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
@@ -11,7 +11,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
throw new Error('参数错误');
|
||||
}
|
||||
// 凭证校验
|
||||
const { app } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
|
||||
const { app } = await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
|
||||
|
||||
if (!app.permission.hasWritePer) {
|
||||
app.modules = [];
|
||||
app.edges = [];
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
40
projects/app/src/pages/api/core/app/folder/create.ts
Normal file
40
projects/app/src/pages/api/core/app/folder/create.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
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 { 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';
|
||||
|
||||
export type CreateAppFolderBody = {
|
||||
parentId?: ParentIdType;
|
||||
name: string;
|
||||
intro?: string;
|
||||
};
|
||||
|
||||
async function handler(req: ApiRequestProps<CreateAppFolderBody>, res: NextApiResponse<any>) {
|
||||
const { name, intro, parentId } = req.body;
|
||||
|
||||
if (!name) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
|
||||
|
||||
// Create app
|
||||
await MongoApp.create({
|
||||
...parseParentIdInMongo(parentId),
|
||||
avatar: FolderImgUrl,
|
||||
name,
|
||||
intro,
|
||||
teamId,
|
||||
tmbId,
|
||||
type: AppTypeEnum.folder
|
||||
});
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
41
projects/app/src/pages/api/core/app/folder/path.ts
Normal file
41
projects/app/src/pages/api/core/app/folder/path.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import type {
|
||||
ParentIdType,
|
||||
ParentTreePathItemType
|
||||
} from '@fastgpt/global/common/parentFolder/type.d';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
|
||||
async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<any>
|
||||
): Promise<ParentTreePathItemType[]> {
|
||||
const { parentId } = req.query as { parentId: string };
|
||||
|
||||
if (!parentId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
await authApp({ req, authToken: true, appId: parentId, per: ReadPermissionVal });
|
||||
|
||||
return await getParents(parentId);
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
||||
async function getParents(parentId: ParentIdType): Promise<ParentTreePathItemType[]> {
|
||||
if (!parentId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parent = await MongoApp.findById(parentId, 'name parentId');
|
||||
|
||||
if (!parent) return [];
|
||||
|
||||
const paths = await getParents(parent.parentId);
|
||||
paths.push({ parentId, parentName: parent.name });
|
||||
|
||||
return paths;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
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';
|
||||
@@ -9,8 +9,21 @@ import {
|
||||
ReadPermissionVal
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
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 { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<AppListItemType[]> {
|
||||
export type ListAppBody = {
|
||||
parentId: ParentIdType;
|
||||
type?: AppTypeEnum;
|
||||
};
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<ListAppBody>,
|
||||
res: NextApiResponse<any>
|
||||
): Promise<AppListItemType[]> {
|
||||
// 凭证校验
|
||||
const {
|
||||
teamId,
|
||||
@@ -22,9 +35,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
|
||||
per: ReadPermissionVal
|
||||
});
|
||||
|
||||
const { parentId, type } = req.body;
|
||||
|
||||
/* temp: get all apps and per */
|
||||
const [myApps, rpList] = await Promise.all([
|
||||
MongoApp.find({ teamId }, '_id avatar name intro tmbId defaultPermission')
|
||||
MongoApp.find(
|
||||
{ teamId, ...(type && { type }), ...parseParentIdInMongo(parentId) },
|
||||
'_id avatar type name intro tmbId defaultPermission'
|
||||
)
|
||||
.sort({
|
||||
updateTime: -1
|
||||
})
|
||||
@@ -54,10 +72,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
|
||||
return filterApps.map((app) => ({
|
||||
_id: app._id,
|
||||
avatar: app.avatar,
|
||||
type: app.type,
|
||||
name: app.name,
|
||||
intro: app.intro,
|
||||
permission: app.permission,
|
||||
defaultPermission: app.defaultPermission
|
||||
defaultPermission: app.defaultPermission || AppDefaultPermissionVal
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,12 @@ import {
|
||||
WritePermissionVal,
|
||||
OwnerPermissionVal
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
|
||||
|
||||
/* 获取我的模型 */
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
const {
|
||||
parentId,
|
||||
name,
|
||||
avatar,
|
||||
type,
|
||||
@@ -49,6 +51,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
_id: appId
|
||||
},
|
||||
{
|
||||
...parseParentIdInMongo(parentId),
|
||||
name,
|
||||
type,
|
||||
avatar,
|
||||
|
||||
@@ -92,7 +92,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
data: {
|
||||
list: searchRes,
|
||||
duration: `${((Date.now() - start) / 1000).toFixed(3)}s`,
|
||||
usingQueryExtension: !!aiExtensionResult,
|
||||
queryExtensionModel: aiExtensionResult?.model,
|
||||
...result
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user