dataset inheritance permission (#2151)
* refactor: dataset create and update api * chore: defaultpermission & resume fe * refactor: database auth * fix(ts): add inheritPermission into default data types * chore: adjust the code * fix: list api type filter * fix: query condition
This commit is contained in:
@@ -1,23 +1,30 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import type { CreateDatasetParams } from '@/global/core/dataset/api.d';
|
||||
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { getLLMModel, getVectorModel, getDatasetModel } from '@fastgpt/service/core/ai/model';
|
||||
import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
|
||||
import { NullPermission, WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
|
||||
|
||||
async function handler(req: NextApiRequest) {
|
||||
export type DatasetCreateQuery = {};
|
||||
export type DatasetCreateBody = CreateDatasetParams;
|
||||
export type DatasetCreateResponse = string;
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<DatasetCreateBody, DatasetCreateQuery>
|
||||
): Promise<DatasetCreateResponse> {
|
||||
const {
|
||||
parentId,
|
||||
name,
|
||||
type = DatasetTypeEnum.dataset,
|
||||
avatar,
|
||||
vectorModel = global.vectorModels[0].model,
|
||||
agentModel = getDatasetModel().model,
|
||||
defaultPermission = NullPermission
|
||||
} = req.body as CreateDatasetParams;
|
||||
agentModel = getDatasetModel().model
|
||||
} = req.body;
|
||||
|
||||
// auth
|
||||
const { teamId, tmbId } = await authUserPer({
|
||||
@@ -31,25 +38,23 @@ async function handler(req: NextApiRequest) {
|
||||
const vectorModelStore = getVectorModel(vectorModel);
|
||||
const agentModelStore = getLLMModel(agentModel);
|
||||
if (!vectorModelStore || !agentModelStore) {
|
||||
throw new Error('vectorModel or qaModel is invalid'); // TODO: use enum code
|
||||
return Promise.reject(DatasetErrEnum.invalidVectorModelOrQAModel);
|
||||
}
|
||||
|
||||
// check limit
|
||||
await checkTeamDatasetLimit(teamId);
|
||||
|
||||
const { _id } = await MongoDataset.create({
|
||||
...parseParentIdInMongo(parentId),
|
||||
name,
|
||||
teamId,
|
||||
tmbId,
|
||||
vectorModel,
|
||||
agentModel,
|
||||
avatar,
|
||||
parentId: parentId || null,
|
||||
type,
|
||||
defaultPermission
|
||||
type
|
||||
});
|
||||
|
||||
return _id;
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
import type { DatasetListItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
@@ -14,29 +13,70 @@ import { MongoResourcePermission } from '@fastgpt/service/support/permission/sch
|
||||
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
|
||||
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
|
||||
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
|
||||
import { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
export type GetDatasetListBody = { parentId: ParentIdType; type?: DatasetTypeEnum };
|
||||
export type GetDatasetListBody = {
|
||||
parentId: ParentIdType;
|
||||
type?: DatasetTypeEnum;
|
||||
searchKey?: string;
|
||||
};
|
||||
|
||||
async function handler(req: NextApiRequest) {
|
||||
const { parentId, type } = req.body as GetDatasetListBody;
|
||||
async function handler(req: ApiRequestProps<GetDatasetListBody>) {
|
||||
const { parentId, type, searchKey } = req.body;
|
||||
// 凭证校验
|
||||
const {
|
||||
dataset: parentDataset,
|
||||
teamId,
|
||||
tmbId,
|
||||
permission: tmbPer
|
||||
} = await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: ReadPermissionVal
|
||||
});
|
||||
} = await (async () => {
|
||||
if (parentId) {
|
||||
return await authDataset({
|
||||
req,
|
||||
authToken: true,
|
||||
per: ReadPermissionVal,
|
||||
datasetId: parentId
|
||||
});
|
||||
}
|
||||
return {
|
||||
...(await authUserPer({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
per: ReadPermissionVal
|
||||
})),
|
||||
dataset: undefined
|
||||
};
|
||||
})();
|
||||
|
||||
const findDatasetQuery = (() => {
|
||||
const searchMatch = searchKey
|
||||
? {
|
||||
$or: [
|
||||
{ name: { $regex: new RegExp(`${replaceRegChars(searchKey)}`, 'i') } },
|
||||
{ intro: { $regex: new RegExp(`${replaceRegChars(searchKey)}`, 'i') } }
|
||||
]
|
||||
}
|
||||
: {};
|
||||
|
||||
if (searchKey) {
|
||||
return {
|
||||
teamId,
|
||||
...searchMatch
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
teamId,
|
||||
...(type ? (Array.isArray(type) ? { type: { $in: type } } : { type }) : {}),
|
||||
...parseParentIdInMongo(parentId)
|
||||
};
|
||||
})();
|
||||
|
||||
const [myDatasets, rpList] = await Promise.all([
|
||||
MongoDataset.find({
|
||||
teamId,
|
||||
...parseParentIdInMongo(parentId),
|
||||
...(type && { type })
|
||||
})
|
||||
MongoDataset.find(findDatasetQuery)
|
||||
.sort({
|
||||
updateTime: -1
|
||||
})
|
||||
@@ -50,14 +90,26 @@ async function handler(req: NextApiRequest) {
|
||||
|
||||
const filterDatasets = myDatasets
|
||||
.map((dataset) => {
|
||||
const perVal = rpList.find(
|
||||
(item) => String(item.resourceId) === String(dataset._id)
|
||||
)?.permission;
|
||||
const Per = new DatasetPermission({
|
||||
per: perVal ?? dataset.defaultPermission,
|
||||
isOwner: String(dataset.tmbId) === tmbId || tmbPer.isOwner
|
||||
});
|
||||
|
||||
const Per = (() => {
|
||||
if (dataset.inheritPermission && parentDataset && dataset.type !== DatasetTypeEnum.folder) {
|
||||
dataset.defaultPermission = parentDataset.defaultPermission;
|
||||
const perVal = rpList.find(
|
||||
(item) => String(item.resourceId) === String(parentDataset._id)
|
||||
)?.permission;
|
||||
return new DatasetPermission({
|
||||
per: perVal ?? parentDataset.defaultPermission,
|
||||
isOwner: String(parentDataset.tmbId) === tmbId || tmbPer.isOwner
|
||||
});
|
||||
} else {
|
||||
const perVal = rpList.find(
|
||||
(item) => String(item.resourceId) === String(dataset._id)
|
||||
)?.permission;
|
||||
return new DatasetPermission({
|
||||
per: perVal ?? dataset.defaultPermission,
|
||||
isOwner: String(dataset.tmbId) === tmbId || tmbPer.isOwner
|
||||
});
|
||||
}
|
||||
})();
|
||||
return {
|
||||
...dataset,
|
||||
permission: Per
|
||||
@@ -68,14 +120,14 @@ async function handler(req: NextApiRequest) {
|
||||
const data = await Promise.all(
|
||||
filterDatasets.map<DatasetListItemType>((item) => ({
|
||||
_id: item._id,
|
||||
parentId: item.parentId,
|
||||
avatar: item.avatar,
|
||||
name: item.name,
|
||||
intro: item.intro,
|
||||
type: item.type,
|
||||
permission: item.permission,
|
||||
vectorModel: getVectorModel(item.vectorModel),
|
||||
defaultPermission: item.defaultPermission ?? DatasetDefaultPermissionVal
|
||||
defaultPermission: item.defaultPermission ?? DatasetDefaultPermissionVal,
|
||||
inheritPermission: item.inheritPermission
|
||||
}))
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import {
|
||||
ManagePermissionVal,
|
||||
PerResourceTypeEnum
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { resumeInheritPermission } from '@fastgpt/service/support/permission/inheritPermission';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
export type ResumeInheritPermissionQuery = {
|
||||
datasetId: string;
|
||||
};
|
||||
export type ResumeInheritPermissionBody = {};
|
||||
// resume the dataset's inherit permission.
|
||||
async function handler(
|
||||
req: ApiRequestProps<ResumeInheritPermissionBody, ResumeInheritPermissionQuery>
|
||||
) {
|
||||
const { datasetId } = req.query;
|
||||
const { dataset } = await authDataset({
|
||||
datasetId,
|
||||
req,
|
||||
authToken: true,
|
||||
per: ManagePermissionVal
|
||||
});
|
||||
|
||||
if (dataset.parentId) {
|
||||
await resumeInheritPermission({
|
||||
resource: dataset,
|
||||
folderTypeList: [DatasetTypeEnum.folder],
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
resourceModel: MongoDataset
|
||||
});
|
||||
} else {
|
||||
await MongoDataset.updateOne(
|
||||
{
|
||||
_id: datasetId
|
||||
},
|
||||
{
|
||||
inheritPermission: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
export default NextAPI(handler);
|
||||
@@ -1,15 +1,34 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import type { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api.d';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import {
|
||||
OwnerPermissionVal,
|
||||
ManagePermissionVal,
|
||||
PerResourceTypeEnum,
|
||||
WritePermissionVal
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { ClientSession } from 'mongoose';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
|
||||
import { DatasetSchemaType } from '@fastgpt/global/core/dataset/type';
|
||||
import { getResourceAllClbs } from '@fastgpt/service/support/permission/controller';
|
||||
import {
|
||||
syncChildrenPermission,
|
||||
syncCollaborators
|
||||
} from '@fastgpt/service/support/permission/inheritPermission';
|
||||
|
||||
async function handler(req: NextApiRequest) {
|
||||
export type DatasetUpdateQuery = {};
|
||||
export type DatasetUpdateResponse = any;
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<DatasetUpdateBody, DatasetUpdateQuery>,
|
||||
_res: ApiResponseType<any>
|
||||
): Promise<DatasetUpdateResponse> {
|
||||
const {
|
||||
id,
|
||||
parentId,
|
||||
@@ -21,34 +40,131 @@ async function handler(req: NextApiRequest) {
|
||||
externalReadUrl,
|
||||
defaultPermission,
|
||||
status
|
||||
} = req.body as DatasetUpdateBody;
|
||||
} = req.body;
|
||||
|
||||
if (!id) {
|
||||
return Promise.reject(CommonErrEnum.missingParams);
|
||||
}
|
||||
|
||||
if (defaultPermission) {
|
||||
await authDataset({ req, authToken: true, datasetId: id, per: OwnerPermissionVal });
|
||||
} else {
|
||||
await authDataset({ req, authToken: true, datasetId: id, per: WritePermissionVal });
|
||||
}
|
||||
|
||||
await MongoDataset.findOneAndUpdate(
|
||||
{
|
||||
_id: id
|
||||
},
|
||||
{
|
||||
...(parentId !== undefined && { parentId: parentId || null }),
|
||||
...(name && { name }),
|
||||
...(avatar && { avatar }),
|
||||
...(agentModel && { agentModel: agentModel.model }),
|
||||
...(websiteConfig && { websiteConfig }),
|
||||
...(status && { status }),
|
||||
...(intro && { intro }),
|
||||
...(externalReadUrl && { externalReadUrl }),
|
||||
...(defaultPermission !== undefined && { defaultPermission })
|
||||
const { dataset } = (await (async () => {
|
||||
if (defaultPermission !== undefined) {
|
||||
return await authDataset({ req, authToken: true, datasetId: id, per: ManagePermissionVal });
|
||||
} else {
|
||||
return await authDataset({ req, authToken: true, datasetId: id, per: WritePermissionVal });
|
||||
}
|
||||
);
|
||||
}
|
||||
})()) as { dataset: DatasetSchemaType };
|
||||
|
||||
const isDefaultPermissionChanged =
|
||||
defaultPermission !== undefined && dataset.defaultPermission !== defaultPermission;
|
||||
const isFolder = dataset.type === DatasetTypeEnum.folder;
|
||||
|
||||
const onUpdate = async (
|
||||
session?: ClientSession,
|
||||
updatedDefaultPermission?: PermissionValueType
|
||||
) => {
|
||||
await MongoDataset.findByIdAndUpdate(
|
||||
id,
|
||||
{
|
||||
...parseParentIdInMongo(parentId),
|
||||
...(name && { name }),
|
||||
...(avatar && { avatar }),
|
||||
...(agentModel && { agentModel: agentModel.model }),
|
||||
...(websiteConfig && { websiteConfig }),
|
||||
...(status && { status }),
|
||||
...(intro !== undefined && { intro }),
|
||||
...(externalReadUrl && { externalReadUrl }),
|
||||
// move
|
||||
...(updatedDefaultPermission !== undefined && {
|
||||
defaultPermission: updatedDefaultPermission
|
||||
}),
|
||||
// update the defaultPermission
|
||||
...(isDefaultPermissionChanged && { inheritPermission: false })
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
};
|
||||
|
||||
// move
|
||||
if (parentId !== undefined) {
|
||||
await mongoSessionRun(async (session) => {
|
||||
const parentDefaultPermission = await (async () => {
|
||||
if (parentId) {
|
||||
const { dataset: parentDataset } = await authDataset({
|
||||
req,
|
||||
authToken: true,
|
||||
datasetId: parentId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
return parentDataset.defaultPermission;
|
||||
}
|
||||
return DatasetDefaultPermissionVal;
|
||||
})();
|
||||
|
||||
if (isFolder && dataset.inheritPermission) {
|
||||
const parentClbs = await getResourceAllClbs({
|
||||
teamId: dataset.teamId,
|
||||
resourceId: parentId,
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
session
|
||||
});
|
||||
|
||||
await syncCollaborators({
|
||||
teamId: dataset.teamId,
|
||||
resourceId: id,
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
collaborators: parentClbs,
|
||||
session
|
||||
});
|
||||
|
||||
await syncChildrenPermission({
|
||||
resource: dataset,
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
resourceModel: MongoDataset,
|
||||
folderTypeList: [DatasetTypeEnum.folder],
|
||||
collaborators: parentClbs,
|
||||
defaultPermission: parentDefaultPermission,
|
||||
session
|
||||
});
|
||||
return onUpdate(session, parentDefaultPermission);
|
||||
}
|
||||
return onUpdate(session);
|
||||
});
|
||||
} else if (isDefaultPermissionChanged) {
|
||||
await mongoSessionRun(async (session) => {
|
||||
if (isFolder) {
|
||||
await syncChildrenPermission({
|
||||
defaultPermission,
|
||||
resource: {
|
||||
_id: dataset._id,
|
||||
type: dataset.type,
|
||||
teamId: dataset.teamId,
|
||||
parentId: dataset.parentId
|
||||
},
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
resourceModel: MongoDataset,
|
||||
folderTypeList: [DatasetTypeEnum.folder],
|
||||
session
|
||||
});
|
||||
} else if (dataset.inheritPermission && dataset.parentId) {
|
||||
const parentClbs = await getResourceAllClbs({
|
||||
teamId: dataset.teamId,
|
||||
resourceId: parentId,
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
session
|
||||
});
|
||||
|
||||
await syncCollaborators({
|
||||
teamId: dataset.teamId,
|
||||
resourceId: id,
|
||||
resourceType: PerResourceTypeEnum.dataset,
|
||||
collaborators: parentClbs,
|
||||
session
|
||||
});
|
||||
}
|
||||
return onUpdate(session, defaultPermission);
|
||||
});
|
||||
} else {
|
||||
return onUpdate();
|
||||
}
|
||||
}
|
||||
export default NextAPI(handler);
|
||||
|
||||
Reference in New Issue
Block a user