Permission (#1687)

Co-authored-by: Archer <545436317@qq.com>
Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
Archer
2024-06-04 17:52:00 +08:00
committed by GitHub
parent fcb915c988
commit 19c8a06d51
109 changed files with 2291 additions and 1091 deletions

View File

@@ -31,7 +31,6 @@ export type FastGPTFeConfigsType = {
show_openai_account?: boolean;
show_promotion?: boolean;
show_team_chat?: boolean;
hide_app_flow?: boolean;
concatMd?: string;
docUrl?: string;
chatbotUrl?: string;

View File

@@ -0,0 +1,12 @@
import { PermissionValueType } from '../../support/permission/type';
export type UpdateAppCollaboratorBody = {
appId: string;
tmbIds: string[];
permission: PermissionValueType;
};
export type AppCollaboratorDeleteParams = {
appId: string;
tmbId: string;
};

View File

@@ -7,6 +7,8 @@ import { SelectedDatasetType } from '../workflow/api';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
import { StoreEdgeItemType } from '../workflow/type/edge';
import { PermissionValueType } from '../../support/permission/type';
import { AppPermission } from '../../support/permission/app/controller';
export type AppSchema = {
_id: string;
@@ -27,9 +29,9 @@ export type AppSchema = {
scheduledTriggerConfig?: AppScheduledTriggerConfigType | null;
scheduledTriggerNextTime?: Date;
permission: `${PermissionTypeEnum}`;
inited?: boolean;
teamTags: string[];
defaultPermission: PermissionValueType;
};
export type AppListItemType = {
@@ -37,13 +39,12 @@ export type AppListItemType = {
name: string;
avatar: string;
intro: string;
isOwner: boolean;
permission: `${PermissionTypeEnum}`;
defaultPermission: PermissionValueType;
permission: AppPermission;
};
export type AppDetailType = AppSchema & {
isOwner: boolean;
canWrite: boolean;
permission: AppPermission;
};
export type AppSimpleEditFormType = {

View File

@@ -0,0 +1,20 @@
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
import { PermissionListType } from '../type';
export enum AppPermissionKeyEnum {}
export const AppPermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
description: '可使用该应用进行对话'
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
description: '可查看和编辑应用'
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
description: '写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限'
}
};
export const AppDefaultPermission = NullPermission;

View File

@@ -0,0 +1,15 @@
import { PerConstructPros, Permission } from '../controller';
import { AppDefaultPermission } from './constant';
export class AppPermission extends Permission {
constructor(props?: PerConstructPros) {
if (!props) {
props = {
per: AppDefaultPermission
};
} else if (!props?.per) {
props.per = AppDefaultPermission;
}
super(props);
}
}

View File

View File

@@ -0,0 +1,9 @@
import { PermissionValueType } from './type';
export type CollaboratorItemType = {
teamId: string;
tmbId: string;
permission: PermissionValueType;
name: string;
avatar: string;
};

View File

@@ -1,3 +1,6 @@
import { Permission } from './controller';
import { PermissionListType } from './type';
export enum AuthUserTypeEnum {
token = 'token',
root = 'root',
@@ -21,8 +24,41 @@ export const PermissionTypeMap = {
}
};
export enum ResourceTypeEnum {
export enum PerResourceTypeEnum {
team = 'team',
app = 'app',
dataset = 'dataset'
}
/* new permission */
export enum PermissionKeyEnum {
read = 'read',
write = 'write',
manage = 'manage'
}
export const PermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
name: '读权限',
description: '',
value: 0b100,
checkBoxType: 'single'
},
[PermissionKeyEnum.write]: {
name: '写权限',
description: '',
value: 0b110, // 如果某个资源有特殊要求,再重写这个值
checkBoxType: 'single'
},
[PermissionKeyEnum.manage]: {
name: '管理员',
description: '',
value: 0b111,
checkBoxType: 'single'
}
};
export const NullPermission = 0;
export const OwnerPermissionVal = ~0 >>> 0;
export const ReadPermissionVal = PermissionList['read'].value;
export const WritePermissionVal = PermissionList['write'].value;
export const ManagePermissionVal = PermissionList['manage'].value;

View File

@@ -0,0 +1,71 @@
import { PermissionValueType } from './type';
import { PermissionList, NullPermission, OwnerPermissionVal } from './constant';
export type PerConstructPros = {
per?: PermissionValueType;
isOwner?: boolean;
};
// the Permission helper class
export class Permission {
value: PermissionValueType;
isOwner: boolean;
hasManagePer: boolean;
hasWritePer: boolean;
hasReadPer: boolean;
constructor(props?: PerConstructPros) {
const { per = NullPermission, isOwner = false } = props || {};
if (isOwner) {
this.value = OwnerPermissionVal;
} else {
this.value = per;
}
this.isOwner = isOwner;
this.hasManagePer = this.checkPer(PermissionList['manage'].value);
this.hasWritePer = this.checkPer(PermissionList['write'].value);
this.hasReadPer = this.checkPer(PermissionList['read'].value);
}
// add permission(s)
// it can be chaining called.
// @example
// const perm = new Permission(permission)
// perm.add(PermissionList['read'])
// perm.add(PermissionList['read'], PermissionList['write'])
// perm.add(PermissionList['read']).add(PermissionList['write'])
addPer(...perList: PermissionValueType[]) {
for (let oer of perList) {
this.value = this.value | oer;
}
this.updatePermissions();
return this.value;
}
removePer(...perList: PermissionValueType[]) {
for (let per of perList) {
this.value = this.value & ~per;
}
this.updatePermissions();
return this.value;
}
checkPer(perm: PermissionValueType): boolean {
// if the permission is owner permission, only owner has this permission.
if (perm === OwnerPermissionVal) {
return this.value === OwnerPermissionVal;
} else if (this.hasManagePer) {
// The manager has all permissions except the owner permission
return true;
}
return (this.value & perm) === perm;
}
private updatePermissions() {
this.isOwner = this.value === OwnerPermissionVal;
this.hasManagePer = this.checkPer(PermissionList['manage'].value);
this.hasWritePer = this.checkPer(PermissionList['write'].value);
this.hasReadPer = this.checkPer(PermissionList['read'].value);
}
}

View File

@@ -1,6 +1,20 @@
import { AuthUserTypeEnum } from './constant';
import { TeamMemberWithUserSchema } from '../user/team/type';
import { AuthUserTypeEnum, PermissionKeyEnum } from './constant';
// PermissionValueType, the type of permission's value is a number, which is a bit field actually.
// It is spired by the permission system in Linux.
// The lowest 3 bits present the permission of reading, writing and managing.
// The higher bits are advanced permissions or extended permissions, which could be customized.
export type PermissionValueType = number;
export type PermissionListType<T = {}> = Record<
T | PermissionKeyEnum,
{
name: string;
description: string;
value: PermissionValueType;
checkBoxType: 'single' | 'multiple';
}
>;
export type AuthResponseType = {
teamId: string;
@@ -17,4 +31,9 @@ export type ResourcePermissionType = {
tmbId: string;
resourceType: ResourceType;
permission: PermissionValueType;
resourceId: string;
};
export type ResourcePerWithTmbWithUser = Omit<ResourcePermissionType, 'tmbId'> & {
tmbId: TeamMemberWithUserSchema;
};

View File

@@ -0,0 +1,16 @@
import { PermissionKeyEnum, PermissionList, ReadPermissionVal } from '../constant';
export const TeamPermissionList = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read]
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write]
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
description: '可邀请, 删除成员'
}
};
export const TeamDefaultPermissionVal = ReadPermissionVal;

View File

@@ -0,0 +1,15 @@
import { PerConstructPros, Permission } from '../controller';
import { TeamDefaultPermissionVal } from './constant';
export class TeamPermission extends Permission {
constructor(props?: PerConstructPros) {
if (!props) {
props = {
per: TeamDefaultPermissionVal
};
} else if (!props?.per) {
props.per = TeamDefaultPermissionVal;
}
super(props);
}
}

View File

@@ -1,22 +1,25 @@
import { TeamMemberRoleEnum } from '../user/team/constant';
import { PermissionTypeEnum } from './constant';
import { Permission } from './controller';
/* team public source, or owner source in team */
export function mongoRPermission({
teamId,
tmbId,
role
permission
}: {
teamId: string;
tmbId: string;
role: `${TeamMemberRoleEnum}`;
permission: Permission;
}) {
if (permission.isOwner) {
return {
teamId
};
}
return {
teamId,
...(role === TeamMemberRoleEnum.visitor && { permission: PermissionTypeEnum.public }),
...(role === TeamMemberRoleEnum.admin && {
$or: [{ permission: PermissionTypeEnum.public }, { tmbId }]
})
$or: [{ permission: PermissionTypeEnum.public }, { tmbId }]
};
}
export function mongoOwnerPermission({ teamId, tmbId }: { teamId: string; tmbId: string }) {

View File

@@ -1,4 +1,4 @@
import { PermissionValueType } from 'support/permission/type';
import { PermissionValueType } from '../../permission/type';
import { TeamMemberRoleEnum } from './constant';
import { LafAccountType, TeamMemberSchema } from './type';
@@ -22,7 +22,6 @@ export type UpdateTeamProps = {
/* ------------- member ----------- */
export type DelMemberProps = {
teamId: string;
memberId: string;
};
export type UpdateTeamMemberProps = {
@@ -46,7 +45,6 @@ export type InviteMemberResponse = Record<
>;
export type UpdateTeamMemberPermissionProps = {
teamId: string;
memberIds: string[];
permission: PermissionValueType;
};

View File

@@ -2,6 +2,7 @@ import type { UserModelSchema } from '../type';
import type { TeamMemberRoleEnum, TeamMemberStatusEnum } from './constant';
import { LafAccountType } from './type';
import { PermissionValueType, ResourcePermissionType } from '../../permission/type';
import { TeamPermission } from '../../permission/user/controller';
export type TeamSchema = {
_id: string;
@@ -49,7 +50,7 @@ export type TeamMemberWithTeamAndUserSchema = Omit<TeamMemberWithTeamSchema, 'us
userId: UserModelSchema;
};
export type TeamItemType = {
export type TeamTmbItemType = {
userId: string;
teamId: string;
teamName: string;
@@ -61,9 +62,8 @@ export type TeamItemType = {
defaultTeam: boolean;
role: `${TeamMemberRoleEnum}`;
status: `${TeamMemberStatusEnum}`;
canWrite: boolean;
lafAccount?: LafAccountType;
defaultPermission: PermissionValueType;
permission: TeamPermission;
};
export type TeamMemberItemType = {
@@ -75,7 +75,7 @@ export type TeamMemberItemType = {
// TODO: this should be deprecated.
role: `${TeamMemberRoleEnum}`;
status: `${TeamMemberStatusEnum}`;
permission: PermissionValueType;
permission: TeamPermission;
};
export type TeamTagItemType = {

View File

@@ -1,5 +1,5 @@
import { UserStatusEnum } from './constant';
import { TeamItemType } from './team/type';
import { TeamTmbItemType } from './team/type';
export type UserModelSchema = {
_id: string;
@@ -29,6 +29,6 @@ export type UserType = {
timezone: string;
promotionRate: UserModelSchema['promotionRate'];
openaiAccount: UserModelSchema['openaiAccount'];
team: TeamItemType;
team: TeamTmbItemType;
standardInfo?: standardInfoType;
};