Files
FastGPT/packages/service/support/permission/controller.ts
Archer 2ed1545eb5 V4.12.4 features (#5626)
* fix: push again, user select option button and form input radio content overflow (#5601)

* fix: push again, user select option button and form input radio content overflow

* fix: use useCallback instead of useMemo, fix unnecessary delete

* fix: Move the variable inside the component

* fix: do not pass valueLabel to MySelect

* ui

* del collection api adapt

* refactor: inherit permission (#5529)

* refactor: permission update conflict check function

* refactor(permission): app collaborator update api

* refactor(permission): support app update collaborator

* feat: support fe permission conflict check

* refactor(permission): app permission

* refactor(permission): dataset permission

* refactor(permission): team permission

* chore: fe adjust

* fix: type error

* fix: audit pagiation

* fix: tc

* chore: initv4130

* fix: app/dataset auth logic

* chore: move code

* refactor(permission): remove selfPermission

* fix: mock

* fix: test

* fix: app & dataset auth

* fix: inherit

* test(inheritPermission): test syncChildrenPermission

* prompt editor add list plugin (#5620)

* perf: search result (#5608)

* fix: table size (#5598)

* temp: list value

* backspace

* optimize code

---------

Co-authored-by: Archer <545436317@qq.com>
Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>

* fix: fe & member list (#5619)

* chore: initv4130

* fix: MemberItemCard

* fix: MemberItemCard

* chore: fe adjust & init script

* perf: test code

* doc

* fix debug variables (#5617)

* perf: search result (#5608)

* fix: table size (#5598)

* fix debug variables

* fix

---------

Co-authored-by: Archer <545436317@qq.com>
Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>

* perf: member ui

* fix: inherit bug (#5624)

* refactor(permission): remove getClbsWithInfo, which is useless

* fix: app list privateApp

* fix: get infos

* perf(fe): remove delete icon when it is disable in MemberItemCard

* fix: dataset private dataset

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Archer <545436317@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* perf: auto coupon

* chore: upgrade script & get infos avatar  (#5625)

* fix: get infos

* chore: initv4130

* feat: support WecomRobot publish, and fix AesKey can not save bug (#5526)

* feat: resolve conflicts

* fix: add param 'show_publish_wecom'

* feat: abstract out WecomCrypto type

* doc: wecom robot document

* fix: solve instability in AI output

* doc: update some pictures

* feat: remove functions from request.ts to chat.ts and toolCall.ts

* doc: wecom robot doc update

* fix

* delete unused code

* doc: update version and prompt

* feat: remove wecom crypto, delete wecom code in workflow

* feat: delete unused codes

---------

Co-authored-by: heheer <zhiyu44@qq.com>

* remove test

* rename init shell

* feat: collection page store

* reload sandbox

* pysandbox

* remove log

* chore: remove useless code (#5629)

* chore: remove useless code

* fix: checkConflict

* perf: support hidden type for RoleList

* fix: copy node

* update doc

* fix(permission): some bug (#5632)

* fix: app/dataset list

* fix: inherit bug

* perf: del app;i18n;save chat

* fix: test

* i18n

* fix: sumper overflow return OwnerRoleVal (#5633)

* remove invalid code

* fix: scroll

* fix: objectId

* update next

* update package

* object id

* mock redis

* feat: add redis append to resolve wecom stream response  (#5643)

* feat: resolve conflicts

* fix: add param 'show_publish_wecom'

* feat: abstract out WecomCrypto type

* doc: wecom robot document

* fix: solve instability in AI output

* doc: update some pictures

* feat: remove functions from request.ts to chat.ts and toolCall.ts

* doc: wecom robot doc update

* fix

* delete unused code

* doc: update version and prompt

* feat: remove wecom crypto, delete wecom code in workflow

* feat: delete unused codes

* feat: add redis append method

---------

Co-authored-by: heheer <zhiyu44@qq.com>

* cache per

* fix(test): init team sub when creating mocked user (#5646)

* fix: button is not vertically centered (#5647)

* doc

* fix: gridFs objectId (#5649)

---------

Co-authored-by: Zeng Qingwen <143274079+fishwww-ww@users.noreply.github.com>
Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: heheer <zhiyu44@qq.com>
2025-09-15 20:02:54 +08:00

241 lines
6.4 KiB
TypeScript

import type { ClientSession, AnyBulkWriteOperation } from '../../common/mongo';
import type { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
import { ManageRoleVal, OwnerRoleVal } from '@fastgpt/global/support/permission/constant';
import { MongoResourcePermission } from './schema';
import type { ResourcePermissionType, ResourceType } from '@fastgpt/global/support/permission/type';
import { type PermissionValueType } from '@fastgpt/global/support/permission/type';
import { getGroupsByTmbId } from './memberGroup/controllers';
import { Permission } from '@fastgpt/global/support/permission/controller';
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { getOrgIdSetWithParentByTmbId } from './org/controllers';
import { getCollaboratorId, sumPer } from '@fastgpt/global/support/permission/utils';
import { type SyncChildrenPermissionResourceType } from './inheritPermission';
import { pickCollaboratorIdFields } from './utils';
import type {
CollaboratorItemDetailType,
CollaboratorItemType
} from '@fastgpt/global/support/permission/collaborator';
import { MongoTeamMember } from '../../support/user/team/teamMemberSchema';
import { MongoOrgModel } from './org/orgSchema';
import { MongoMemberGroupModel } from './memberGroup/memberGroupSchema';
import { DEFAULT_ORG_AVATAR, DEFAULT_TEAM_AVATAR } from '@fastgpt/global/common/system/constants';
/** get resource permission for a team member
* If there is no permission for the team member, it will return undefined
* @param resourceType: PerResourceTypeEnum
* @param teamId
* @param tmbId
* @param resourceId
* @returns PermissionValueType | undefined
*/
export const getTmbPermission = async ({
resourceType,
teamId,
tmbId,
resourceId
}: {
teamId: string;
tmbId: string;
} & (
| {
resourceType: 'team';
resourceId?: undefined;
}
| {
resourceType: Omit<PerResourceTypeEnum, 'team'>;
resourceId: string;
}
)): Promise<PermissionValueType | undefined> => {
// Personal permission has the highest priority
const tmbPer = (
await MongoResourcePermission.findOne(
{
resourceType,
teamId,
resourceId,
tmbId
},
'permission'
).lean()
)?.permission;
// could be 0
if (tmbPer !== undefined) {
return tmbPer;
}
// If there is no personal permission, get the group permission
const [groupPers, orgPers] = await Promise.all([
getGroupsByTmbId({ tmbId, teamId })
.then((res) => res.map((item) => item._id))
.then((groupIdList) =>
MongoResourcePermission.find(
{
teamId,
resourceType,
groupId: {
$in: groupIdList
},
resourceId
},
'permission'
).lean()
)
.then((perList) => perList.map((item) => item.permission)),
getOrgIdSetWithParentByTmbId({ tmbId, teamId })
.then((item) => Array.from(item))
.then((orgIds) =>
MongoResourcePermission.find(
{
teamId,
resourceType,
orgId: {
$in: Array.from(orgIds)
},
resourceId
},
'permission'
).lean()
)
.then((perList) => perList.map((item) => item.permission))
]);
return sumPer(...groupPers, ...orgPers);
};
/**
* Only get resource's owned clbs, not including parents'.
*/
export async function getResourceOwnedClbs({
resourceType,
teamId,
resourceId,
session
}: {
teamId: string;
session?: ClientSession;
} & (
| {
resourceType: 'team';
resourceId?: undefined;
}
| {
resourceType: Omit<PerResourceTypeEnum, 'team'>;
resourceId: ParentIdType;
}
)) {
return MongoResourcePermission.find(
{
resourceId,
resourceType,
teamId
},
undefined,
{ ...(session ? { session } : {}) }
).lean();
}
export const getClbsInfo = async ({
clbs,
teamId,
ownerTmbId
}: {
clbs: CollaboratorItemType[];
teamId: string;
ownerTmbId?: string;
}): Promise<CollaboratorItemDetailType[]> => {
const tmbIds = [];
const orgIds = [];
const groupIds = [];
for (const clb of clbs) {
if (clb.tmbId) tmbIds.push(clb.tmbId);
if (clb.orgId) orgIds.push(clb.orgId);
if (clb.groupId) groupIds.push(clb.groupId);
}
const infos = (
await Promise.all([
MongoTeamMember.find({ _id: { $in: tmbIds }, teamId }, '_id name avatar').lean(),
MongoOrgModel.find({ _id: { $in: orgIds }, teamId }, '_id name avatar').lean(),
MongoMemberGroupModel.find({ _id: { $in: groupIds }, teamId }, '_id name avatar').lean()
])
).flat();
return clbs.map((clb) => {
const info = infos.find((info) => info._id === getCollaboratorId(clb));
return {
...clb,
teamId,
permission: new Permission({
role: clb.permission,
isOwner: Boolean(ownerTmbId && clb.tmbId && ownerTmbId === clb.tmbId)
}),
name: info?.name ?? 'Unknown name',
avatar: info?.avatar || (clb.orgId ? DEFAULT_ORG_AVATAR : DEFAULT_TEAM_AVATAR)
};
});
};
export const createResourceDefaultCollaborators = async ({
resource,
resourceType,
session,
tmbId
}: {
resource: SyncChildrenPermissionResourceType;
resourceType: PerResourceTypeEnum;
// should be provided when inheritPermission is true
session: ClientSession;
tmbId: string;
}) => {
const parentClbs = await getResourceOwnedClbs({
resourceId: resource.parentId,
resourceType,
teamId: resource.teamId,
session
});
// 1. add owner into the permission list with owner per
// 2. remove parent's owner permission, instead of manager
const collaborators: CollaboratorItemType[] = [
...parentClbs
.filter((item) => item.tmbId !== tmbId)
.map((clb) => {
if (clb.permission === OwnerRoleVal) {
clb.permission = ManageRoleVal;
}
return clb;
}),
{
tmbId,
permission: OwnerRoleVal
}
];
const ops: AnyBulkWriteOperation<ResourcePermissionType>[] = [];
for (const clb of collaborators) {
ops.push({
updateOne: {
filter: {
...pickCollaboratorIdFields(clb),
teamId: resource.teamId,
resourceId: resource._id,
resourceType
},
update: {
$set: {
permission: clb.permission
}
},
upsert: true
}
});
}
await MongoResourcePermission.bulkWrite(ops, { session });
};