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

@@ -10,6 +10,8 @@ import { getResourcePermission } from '../controller';
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
import { AuthResponseType } from '../type/auth.d';
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
export const authAppByTmbId = async ({
tmbId,
@@ -19,27 +21,57 @@ export const authAppByTmbId = async ({
tmbId: string;
appId: string;
per: PermissionValueType;
}) => {
}): Promise<{
app: AppDetailType;
}> => {
const { teamId, permission: tmbPer } = await getTmbInfoByTmbId({ tmbId });
const app = await (async () => {
// get app and per
const [app, rp] = await Promise.all([
MongoApp.findOne({ _id: appId, teamId }).lean(),
getResourcePermission({
teamId,
tmbId,
resourceId: appId,
resourceType: PerResourceTypeEnum.app
}) // this could be null
]);
const app = await MongoApp.findOne({ _id: appId }).lean();
if (!app) {
return Promise.reject(AppErrEnum.unExist);
}
const isOwner = tmbPer.isOwner || String(app.tmbId) === String(tmbId);
const Per = new AppPermission({ per: rp?.permission ?? app.defaultPermission, isOwner });
const { Per, defaultPermission } = await (async () => {
if (
AppFolderTypeList.includes(app.type) ||
app.inheritPermission === false ||
!app.parentId
) {
// 1. is a folder. (Folders have compeletely permission)
// 2. inheritPermission is false.
// 3. is root folder/app.
const rp = await getResourcePermission({
teamId,
tmbId,
resourceId: appId,
resourceType: PerResourceTypeEnum.app
});
const Per = new AppPermission({ per: rp?.permission ?? app.defaultPermission, isOwner });
return {
Per,
defaultPermission: app.defaultPermission
};
} else {
// is not folder and inheritPermission is true and is not root folder.
const { app: parent } = await authAppByTmbId({
tmbId,
appId: app.parentId,
per
});
const Per = new AppPermission({
per: parent.permission.value,
isOwner
});
return {
Per,
defaultPermission: parent.defaultPermission
};
}
})();
if (!Per.checkPer(per)) {
return Promise.reject(AppErrEnum.unAuthApp);
@@ -47,6 +79,7 @@ export const authAppByTmbId = async ({
return {
...app,
defaultPermission,
permission: Per
};
})();
@@ -59,7 +92,7 @@ export const authApp = async ({
per,
...props
}: AuthPropsType & {
appId: string;
appId: ParentIdType;
}): Promise<
AuthResponseType & {
app: AppDetailType;
@@ -68,6 +101,10 @@ export const authApp = async ({
const result = await parseHeaderCert(props);
const { tmbId } = result;
if (!appId) {
return Promise.reject(AppErrEnum.unExist);
}
const { app } = await authAppByTmbId({
tmbId,
appId,

View File

@@ -7,6 +7,9 @@ import { AuthUserTypeEnum, PerResourceTypeEnum } from '@fastgpt/global/support/p
import { authOpenApiKey } from '../openapi/auth';
import { FileTokenQuery } from '@fastgpt/global/common/file/type';
import { MongoResourcePermission } from './schema';
import { ClientSession } from 'mongoose';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { ResourcePermissionType } from '@fastgpt/global/support/permission/type';
export const getResourcePermission = async ({
resourceType,
@@ -31,9 +34,45 @@ export const getResourcePermission = async ({
}
return per;
};
export async function getResourceAllClbs({
resourceId,
teamId,
resourceType,
session
}: {
resourceId: ParentIdType;
teamId: string;
resourceType: PerResourceTypeEnum;
session?: ClientSession;
}): Promise<ResourcePermissionType[]> {
if (!resourceId) return [];
return MongoResourcePermission.find(
{
resourceId,
resourceType: resourceType,
teamId: teamId
},
null,
{
session
}
).lean();
}
export const delResourcePermissionById = (id: string) => {
return MongoResourcePermission.findByIdAndRemove(id);
};
export const delResourcePermission = ({
session,
...props
}: {
resourceType: PerResourceTypeEnum;
resourceId: string;
teamId: string;
tmbId: string;
session?: ClientSession;
}) => {
return MongoResourcePermission.deleteOne(props, { session });
};
/* 下面代码等迁移 */
/* create token */

View File

@@ -0,0 +1,221 @@
import { mongoSessionRun } from '../../common/mongo/sessionRun';
import { MongoResourcePermission } from './schema';
import { ClientSession, Model } from 'mongoose';
import { NullPermission, PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { getResourceAllClbs } from './controller';
export type SyncChildrenPermissionResourceType = {
_id: string;
type: string;
teamId: string;
parentId?: ParentIdType;
};
export type UpdateCollaboratorItem = {
permission: PermissionValueType;
tmbId: string;
};
// sync the permission to all children folders.
export async function syncChildrenPermission({
resource,
folderTypeList,
resourceType,
resourceModel,
session,
defaultPermission,
collaborators
}: {
resource: SyncChildrenPermissionResourceType;
// when the resource is a folder
folderTypeList: string[];
resourceModel: typeof Model;
resourceType: PerResourceTypeEnum;
// should be provided when inheritPermission is true
session: ClientSession;
defaultPermission?: PermissionValueType;
collaborators?: UpdateCollaboratorItem[];
}) {
// only folder has permission
const isFolder = folderTypeList.includes(resource.type);
if (!isFolder) return;
// get all folders and the resource permission of the app
const allFolders = await resourceModel
.find(
{
teamId: resource.teamId,
type: { $in: folderTypeList },
inheritPermission: true
},
'_id parentId'
)
.lean<SyncChildrenPermissionResourceType[]>()
.session(session);
// bfs to get all children
const queue = [String(resource._id)];
const children: string[] = [];
while (queue.length) {
const parentId = queue.shift();
const folderChildren = allFolders.filter(
(folder) => String(folder.parentId) === String(parentId)
);
children.push(...folderChildren.map((folder) => folder._id));
queue.push(...folderChildren.map((folder) => folder._id));
}
if (!children.length) return;
// Sync default permission
if (defaultPermission !== undefined) {
await resourceModel.updateMany(
{
_id: { $in: children }
},
{
defaultPermission
},
{ session }
);
}
// sync the resource permission
if (collaborators) {
// Update the collaborators of all children
for await (const childId of children) {
await syncCollaborators({
resourceType,
session,
collaborators,
teamId: resource.teamId,
resourceId: childId
});
}
}
}
/* Resume the inherit permission of the resource.
1. Folder: Sync parent's defaultPermission and clbs, and sync its children.
2. Resource: Sync parent's defaultPermission, and delete all its clbs.
*/
export async function resumeInheritPermission({
resource,
folderTypeList,
resourceType,
resourceModel,
session
}: {
resource: SyncChildrenPermissionResourceType;
folderTypeList: string[];
resourceType: PerResourceTypeEnum;
resourceModel: typeof Model;
session?: ClientSession;
}) {
const isFolder = folderTypeList.includes(resource.type);
const fn = async (session: ClientSession) => {
const parentResource = await resourceModel
.findById(resource.parentId, 'defaultPermission')
.lean<SyncChildrenPermissionResourceType & { defaultPermission: PermissionValueType }>()
.session(session);
const parentDefaultPermissionVal = parentResource?.defaultPermission ?? NullPermission;
// update the resource permission
await resourceModel.updateOne(
{
_id: resource._id
},
{
inheritPermission: true,
defaultPermission: parentDefaultPermissionVal
},
{ session }
);
// Folder resource, need to sync children
if (isFolder) {
const parentClbs = await getResourceAllClbs({
resourceId: resource.parentId,
teamId: resource.teamId,
resourceType,
session
});
// sync self
await syncCollaborators({
resourceType,
collaborators: parentClbs,
teamId: resource.teamId,
resourceId: resource._id,
session
});
// sync children
await syncChildrenPermission({
resource: {
...resource
},
resourceModel,
folderTypeList,
resourceType,
session,
defaultPermission: parentDefaultPermissionVal,
collaborators: parentClbs
});
} else {
// Not folder, delete all clb
await MongoResourcePermission.deleteMany({ resourceId: resource._id }, { session });
}
};
if (session) {
return fn(session);
} else {
return mongoSessionRun(fn);
}
}
/*
Delete all the collaborators and then insert the new collaborators.
*/
export async function syncCollaborators({
resourceType,
teamId,
resourceId,
collaborators,
session
}: {
resourceType: PerResourceTypeEnum;
teamId: string;
resourceId: string;
collaborators: UpdateCollaboratorItem[];
session: ClientSession;
}) {
await MongoResourcePermission.deleteMany(
{
resourceType,
teamId,
resourceId
},
{ session }
);
await MongoResourcePermission.insertMany(
collaborators.map((item) => ({
teamId: teamId,
resourceId,
resourceType: resourceType,
tmbId: item.tmbId,
permission: item.permission
})),
{
session
}
);
}

View File

@@ -14,7 +14,7 @@ export const createTrainingUsage = async ({
teamId: string;
tmbId: string;
appName: string;
billSource: `${UsageSourceEnum}`;
billSource: UsageSourceEnum;
vectorModel: string;
agentModel: string;
session?: ClientSession;