refactor: permission role & app read chat log permission (#5416)

* refactor: permission role

* refactor: permission type

* fix: permission manage

* fix: group owner cannot be deleted

* chore: common per map

* chore: openapi

* chore: rename

* fix: type error

* chore: app chat log permission

* chore: add initv4112
This commit is contained in:
Finley Ge
2025-08-11 10:51:44 +08:00
committed by GitHub
parent 29edf1ea5f
commit 57e1ef1176
52 changed files with 730 additions and 402 deletions

View File

@@ -1,20 +1,56 @@
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
import { type PermissionListType } from '../type';
import {
NullRoleVal,
CommonPerKeyEnum,
CommonRoleList,
CommonPerList,
CommonRolePerMap
} from '../constant';
import type { PermissionListType, PermissionValueType, RolePerMapType } from '../type';
import { type RoleListType } from '../type';
import { i18nT } from '../../../../web/i18n/utils';
export enum AppPermissionKeyEnum {}
export const AppPermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
import { sumPer } from '../utils';
export enum AppPermissionKeyEnum {
ReadChatLog = 'readChatLog'
}
export const AppPerList: PermissionListType<AppPermissionKeyEnum> = {
...CommonPerList,
readChatLog: 0b1000
};
export const AppRoleList: RoleListType<AppPermissionKeyEnum> = {
[CommonPerKeyEnum.read]: {
...CommonRoleList[CommonPerKeyEnum.read],
description: i18nT('app:permission.des.read')
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
[CommonPerKeyEnum.write]: {
...CommonRoleList[CommonPerKeyEnum.write],
description: i18nT('app:permission.des.write')
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
[CommonPerKeyEnum.manage]: {
...CommonRoleList[CommonPerKeyEnum.manage],
description: i18nT('app:permission.des.manage')
},
[AppPermissionKeyEnum.ReadChatLog]: {
value: 0b1000,
checkBoxType: 'multiple',
name: i18nT('app:permission.name.readChatLog'),
description: i18nT('app:permission.des.readChatLog')
}
};
export const AppDefaultPermissionVal = NullPermission;
export const AppRolePerMap: RolePerMapType = new Map([
...CommonRolePerMap,
[
AppRoleList[AppPermissionKeyEnum.ReadChatLog].value,
sumPer(
CommonPerList[CommonPerKeyEnum.read],
AppPerList[AppPermissionKeyEnum.ReadChatLog]
) as PermissionValueType
]
]);
export const AppDefaultRoleVal = NullRoleVal;
export const AppReadChatLogPerVal = AppPerList[AppPermissionKeyEnum.ReadChatLog];
export const AppReadChatLogRoleVal = AppRoleList[AppPermissionKeyEnum.ReadChatLog].value;

View File

@@ -1,15 +1,25 @@
import { type PerConstructPros, Permission } from '../controller';
import { AppDefaultPermissionVal } from './constant';
import { AppDefaultRoleVal, AppPerList, AppRoleList, AppRolePerMap } from './constant';
export class AppPermission extends Permission {
hasReadChatLogPer: boolean = false;
hasReadChatLogRole: boolean = false;
constructor(props?: PerConstructPros) {
if (!props) {
props = {
per: AppDefaultPermissionVal
role: AppDefaultRoleVal
};
} else if (!props?.per) {
props.per = AppDefaultPermissionVal;
} else if (!props?.role) {
props.role = AppDefaultRoleVal;
}
props.roleList = AppRoleList;
props.rolePerMap = AppRolePerMap;
props.perList = AppPerList;
super(props);
this.setUpdatePermissionCallback(() => {
this.hasReadChatLogPer = this.checkPer(AppPerList.readChatLog);
this.hasReadChatLogRole = this.checkRole(AppRoleList.readChatLog.value);
});
}
}

View File

@@ -1,5 +1,7 @@
import { type PermissionListType } from './type';
import type { PermissionListType, PermissionValueType, RolePerMapType } from './type';
import { type RoleListType } from './type';
import { i18nT } from '../../../web/i18n/utils';
import { sumPer } from './utils';
export enum AuthUserTypeEnum {
token = 'token',
root = 'root',
@@ -15,6 +17,12 @@ export enum PermissionTypeEnum {
publicRead = 'publicRead',
publicWrite = 'publicWrite'
}
export const NullRoleVal = 0;
export const NullPermissionVal = 0;
export const OwnerRoleVal = ~0 >>> 0;
export const OwnerPermissionVal = ~0 >>> 0;
export const PermissionTypeMap = {
[PermissionTypeEnum.private]: {
iconLight: 'support/permission/privateLight',
@@ -45,34 +53,63 @@ export enum PerResourceTypeEnum {
}
/* new permission */
export enum PermissionKeyEnum {
export enum CommonPerKeyEnum {
owner = 'owner',
read = 'read',
write = 'write',
manage = 'manage'
}
export const PermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
export enum CommonRoleKeyEnum {
read = 'read',
write = 'write',
manage = 'manage'
}
export const CommonPerList: PermissionListType = {
[CommonPerKeyEnum.owner]: OwnerRoleVal,
[CommonPerKeyEnum.read]: 0b100,
[CommonPerKeyEnum.write]: 0b010,
[CommonPerKeyEnum.manage]: 0b001
} as const;
export const CommonRoleList: RoleListType = {
[CommonRoleKeyEnum.read]: {
name: i18nT('common:permission.read'),
description: '',
value: 0b100,
checkBoxType: 'single'
},
[PermissionKeyEnum.write]: {
[CommonRoleKeyEnum.write]: {
name: i18nT('common:permission.write'),
description: '',
value: 0b110,
value: 0b010,
checkBoxType: 'single'
},
[PermissionKeyEnum.manage]: {
[CommonRoleKeyEnum.manage]: {
name: i18nT('common:permission.manager'),
description: '',
value: 0b111,
value: 0b001,
checkBoxType: 'single'
}
};
} as const;
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;
export const CommonRolePerMap: RolePerMapType = new Map([
[CommonRoleList['read'].value, CommonPerList.read],
[
CommonRoleList['write'].value,
sumPer(CommonPerList.write, CommonPerList.read) as PermissionValueType
],
[
CommonRoleList['manage'].value,
sumPer(CommonPerList.manage, CommonPerList.write, CommonPerList.read) as PermissionValueType
]
]);
export const ReadRoleVal = CommonRoleList['read'].value;
export const WriteRoleVal = CommonRoleList['write'].value;
export const ManageRoleVal = CommonRoleList['manage'].value;
export const ManagePermissionVal = CommonPerList.manage;
export const ReadPermissionVal = CommonPerList.read;
export const WritePermissionVal = CommonPerList.write;

View File

@@ -1,58 +1,86 @@
import { type PermissionListType, type PermissionValueType } from './type';
import { PermissionList, NullPermission, OwnerPermissionVal } from './constant';
import type {
RoleValueType,
RoleListType,
PermissionValueType,
PermissionListType,
RolePerMapType
} from './type';
import {
CommonPerList,
CommonRoleList,
CommonRolePerMap,
NullPermissionVal,
NullRoleVal,
OwnerPermissionVal,
OwnerRoleVal
} from './constant';
export type PerConstructPros = {
per?: PermissionValueType;
role?: RoleValueType;
isOwner?: boolean;
permissionList?: PermissionListType;
childUpdatePermissionCallback?: () => void;
roleList?: RoleListType;
perList?: PermissionListType;
rolePerMap?: RolePerMapType;
};
// the Permission helper class
/**
* the Permission helper class
*/
export class Permission {
value: PermissionValueType;
role: PermissionValueType;
private permission: PermissionValueType = NullRoleVal; // default role
isOwner: boolean = false;
hasManagePer: boolean = false;
hasWritePer: boolean = false;
hasReadPer: boolean = false;
_permissionList: PermissionListType;
hasManageRole: boolean = false;
hasWriteRole: boolean = false;
hasReadRole: boolean = false;
constructor(props?: PerConstructPros) {
const { per = NullPermission, isOwner = false, permissionList = PermissionList } = props || {};
readonly roleList: RoleListType;
readonly perList: PermissionListType;
readonly rolePerMap: RolePerMapType;
constructor({
role = NullRoleVal,
isOwner = false,
roleList = CommonRoleList,
perList = CommonPerList,
rolePerMap = CommonRolePerMap
}: PerConstructPros = {}) {
if (isOwner) {
this.value = OwnerPermissionVal;
this.role = OwnerRoleVal;
} else {
this.value = per;
this.role = role;
}
this._permissionList = permissionList;
this.roleList = roleList;
this.perList = perList;
this.rolePerMap = rolePerMap;
this.updatePermissions();
}
// 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[]) {
addRole(...roleList: RoleValueType[]) {
if (this.isOwner) {
return this;
}
for (const per of perList) {
this.value = this.value | per;
for (const per of roleList) {
this.role = this.role | per;
}
this.updatePermissions();
return this;
}
removePer(...perList: PermissionValueType[]) {
removeRole(...roleList: RoleValueType[]) {
if (this.isOwner) {
return this.value;
return this.role;
}
for (const per of perList) {
this.value = this.value & ~per;
for (const per of roleList) {
this.role = this.role & ~per;
}
this.updatePermissions();
return this;
@@ -61,9 +89,16 @@ export class Permission {
checkPer(perm: PermissionValueType): boolean {
// if the permission is owner permission, only owner has this permission.
if (perm === OwnerPermissionVal) {
return this.value === OwnerPermissionVal;
return this.permission === OwnerPermissionVal;
}
return (this.value & perm) === perm;
return (this.permission & perm) === perm;
}
checkRole(role: RoleValueType): boolean {
if (role === OwnerRoleVal) {
return this.role === OwnerRoleVal;
}
return (this.role & role) === role;
}
private updatePermissionCallback?: () => void;
@@ -72,15 +107,32 @@ export class Permission {
this.updatePermissionCallback = callback;
}
private updatePermissions() {
this.isOwner = this.value === OwnerPermissionVal;
this.hasManagePer = this.checkPer(this._permissionList['manage'].value);
this.hasWritePer = this.checkPer(this._permissionList['write'].value);
this.hasReadPer = this.checkPer(this._permissionList['read'].value);
this.updatePermissionCallback?.();
private calculatePer() {
if (this.role === OwnerRoleVal) {
this.permission = OwnerPermissionVal;
return;
}
let role = this.role;
this.permission = 0;
while (role > 0) {
// Binary Magic
this.permission |= this.rolePerMap.get(role & -role) ?? 0;
role &= role - 1;
}
}
toBinary() {
return this.value.toString(2);
private updatePermissions() {
this.calculatePer();
this.isOwner = this.permission === OwnerRoleVal;
this.hasManagePer = this.checkPer(this.roleList['manage'].value);
this.hasWritePer = this.checkPer(this.roleList['write'].value);
this.hasReadPer = this.checkPer(this.roleList['read'].value);
this.hasManageRole = this.checkRole(this.roleList['manage'].value);
this.hasWriteRole = this.checkRole(this.roleList['write'].value);
this.hasReadRole = this.checkRole(this.roleList['read'].value);
this.updatePermissionCallback?.();
}
}

View File

@@ -1,21 +1,30 @@
import { i18nT } from '../../../../web/i18n/utils';
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
import {
NullRoleVal,
CommonPerKeyEnum,
CommonRoleList,
CommonRolePerMap,
CommonPerList
} from '../constant';
import type { RolePerMapType } from '../type';
export enum DatasetPermissionKeyEnum {}
export const DatasetPermissionList = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
export const DatasetRoleList = {
[CommonPerKeyEnum.read]: {
...CommonRoleList[CommonPerKeyEnum.read],
description: i18nT('dataset:permission.des.read')
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
[CommonPerKeyEnum.write]: {
...CommonRoleList[CommonPerKeyEnum.write],
description: i18nT('dataset:permission.des.write')
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
[CommonPerKeyEnum.manage]: {
...CommonRoleList[CommonPerKeyEnum.manage],
description: i18nT('dataset:permission.des.manage')
}
};
export const DatasetDefaultPermissionVal = NullPermission;
export const DatasetRolePerMap: RolePerMapType = CommonRolePerMap;
export const DatasetPerList = CommonPerList;
export const DataSetDefaultRoleVal = NullRoleVal;

View File

@@ -1,14 +1,22 @@
import { NullPermission } from '../constant';
import { type PerConstructPros, Permission } from '../controller';
import {
DataSetDefaultRoleVal,
DatasetPerList,
DatasetRoleList,
DatasetRolePerMap
} from './constant';
export class DatasetPermission extends Permission {
constructor(props?: PerConstructPros) {
if (!props) {
props = {
per: NullPermission
role: DataSetDefaultRoleVal
};
} else if (!props?.per) {
props.per = NullPermission;
} else if (!props?.role) {
props.role = DataSetDefaultRoleVal;
}
props.roleList = DatasetRoleList;
props.rolePerMap = DatasetRolePerMap;
props.perList = DatasetPerList;
super(props);
}
}

View File

@@ -1,5 +1,5 @@
import { PermissionKeyEnum, PermissionList } from '../constant';
import { type PermissionListType } from '../type';
import { CommonPerKeyEnum, CommonRoleList } from '../constant';
import { type RoleListType } from '../type';
export enum GroupMemberRole {
owner = 'owner',
@@ -7,17 +7,17 @@ export enum GroupMemberRole {
member = 'member'
}
export const memberGroupPermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
export const memberGroupPermissionList: RoleListType = {
[CommonPerKeyEnum.read]: {
...CommonRoleList[CommonPerKeyEnum.read],
value: 0b100
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
[CommonPerKeyEnum.write]: {
...CommonRoleList[CommonPerKeyEnum.write],
value: 0b010
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
[CommonPerKeyEnum.manage]: {
...CommonRoleList[CommonPerKeyEnum.manage],
value: 0b001
}
};

View File

@@ -3,25 +3,63 @@ import type { RequireOnlyOne } from '../../common/type/utils';
import type { TeamMemberSchema } from '../user/team/type';
import { MemberGroupSchemaType } from './memberGroup/type';
import type { TeamMemberWithUserSchema } from '../user/team/type';
import { AuthUserTypeEnum, type PermissionKeyEnum, type PerResourceTypeEnum } from './constant';
import type { CommonPerKeyEnum, CommonRoleKeyEnum } from './constant';
import { AuthUserTypeEnum, type CommonPerKeyEnum, type PerResourceTypeEnum } 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 RoleValueType = number;
export type ResourceType = `${PerResourceTypeEnum}`;
export type PermissionListType<T = {}> = Record<
T | PermissionKeyEnum,
{
name: string;
description: string;
value: PermissionValueType;
checkBoxType: 'single' | 'multiple';
}
/**
* Define the roles. Each role is a binary number, only one bit is set to 1.
*/
export type RoleListType<T = {}> = Readonly<
Record<
T | CommonRoleKeyEnum,
Readonly<{
name: string;
description: string;
value: RoleValueType;
checkBoxType: 'single' | 'multiple';
}>
>
>;
/**
* Define the permissions. Each permission is a binary number, only one bit is set to 1.
* @example
* CommonPerList = {
* read: 0b100,
* write: 0b010,
* manage: 0b001
* }
* @example_bad
* CommonPerList = {
* write: 0b110, // bad, should be 0b010
* }
*/
export type PermissionListType<T = {}> = Readonly<
Record<T | CommonPerKeyEnum, PermissionValueType>
>;
/**
* Define the role-permission map. Each role has a permission.
* @key: role (binary number), only one bit is set to 1.
* @value: permission (binary number), multiple bits are set to 1.
* @example
* CommonRolePerMap = {
* 0b100: 0b100,
* 0b010: 0b110,
* 0b001: 0b111
* }
*/
export type RolePerMapType = Readonly<Map<RoleValueType, PermissionValueType>>;
export type ResourcePermissionType = {
teamId: string;
resourceType: ResourceType;

View File

@@ -1,39 +1,59 @@
import { PermissionKeyEnum } from '../constant';
import { type PermissionListType } from '../type';
import { PermissionList } from '../constant';
import { CommonPerKeyEnum, CommonRolePerMap } from '../constant';
import type {
PermissionListType,
PermissionValueType,
RoleListType,
RolePerMapType
} from '../type';
import { CommonRoleList, CommonPerList } from '../constant';
import { i18nT } from '../../../../web/i18n/utils';
export enum TeamPermissionKeyEnum {
import { sumPer } from '../utils';
export enum TeamPerKeyEnum {
appCreate = 'appCreate',
datasetCreate = 'datasetCreate',
apikeyCreate = 'apikeyCreate'
}
export const TeamPermissionList: PermissionListType<TeamPermissionKeyEnum> = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
export enum TeamRoleKeyEnum {
appCreate = 'appCreate',
datasetCreate = 'datasetCreate',
apikeyCreate = 'apikeyCreate'
}
export const TeamPerList: PermissionListType<TeamPerKeyEnum> = {
...CommonPerList,
apikeyCreate: 0b100000,
appCreate: 0b001000,
datasetCreate: 0b010000
};
export const TeamRoleList: RoleListType<TeamRoleKeyEnum> = {
[CommonPerKeyEnum.read]: {
...CommonRoleList[CommonPerKeyEnum.read],
value: 0b000100
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
[CommonPerKeyEnum.write]: {
...CommonRoleList[CommonPerKeyEnum.write],
value: 0b000010
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
[CommonPerKeyEnum.manage]: {
...CommonRoleList[CommonPerKeyEnum.manage],
value: 0b000001
},
[TeamPermissionKeyEnum.appCreate]: {
[TeamRoleKeyEnum.appCreate]: {
checkBoxType: 'multiple',
description: '',
name: i18nT('account_team:permission_appCreate'),
value: 0b001000
},
[TeamPermissionKeyEnum.datasetCreate]: {
[TeamRoleKeyEnum.datasetCreate]: {
checkBoxType: 'multiple',
description: '',
name: i18nT('account_team:permission_datasetCreate'),
value: 0b010000
},
[TeamPermissionKeyEnum.apikeyCreate]: {
[TeamRoleKeyEnum.apikeyCreate]: {
checkBoxType: 'multiple',
description: '',
name: i18nT('account_team:permission_apikeyCreate'),
@@ -41,10 +61,38 @@ export const TeamPermissionList: PermissionListType<TeamPermissionKeyEnum> = {
}
};
export const TeamReadPermissionVal = TeamPermissionList['read'].value;
export const TeamWritePermissionVal = TeamPermissionList['write'].value;
export const TeamManagePermissionVal = TeamPermissionList['manage'].value;
export const TeamAppCreatePermissionVal = TeamPermissionList['appCreate'].value;
export const TeamDatasetCreatePermissionVal = TeamPermissionList['datasetCreate'].value;
export const TeamApikeyCreatePermissionVal = TeamPermissionList['apikeyCreate'].value;
export const TeamRolePerMap: RolePerMapType = new Map([
...CommonRolePerMap,
[
TeamRoleList['appCreate'].value,
sumPer(TeamPerList.appCreate, CommonPerList.read, CommonPerList.write) as PermissionValueType
],
[
TeamRoleList['datasetCreate'].value,
sumPer(
TeamPerList.datasetCreate,
CommonPerList.read,
CommonPerList.write
) as PermissionValueType
],
[
TeamRoleList['apikeyCreate'].value,
sumPer(TeamPerList.apikeyCreate, CommonPerList.read, CommonPerList.write) as PermissionValueType
]
]);
export const TeamReadRoleVal = TeamRoleList['read'].value;
export const TeamWriteRoleVal = TeamRoleList['write'].value;
export const TeamManageRoleVal = TeamRoleList['manage'].value;
export const TeamAppCreateRoleVal = TeamRoleList['appCreate'].value;
export const TeamDatasetCreateRoleVal = TeamRoleList['datasetCreate'].value;
export const TeamApikeyCreateRoleVal = TeamRoleList['apikeyCreate'].value;
export const TeamDefaultRoleVal = TeamReadRoleVal;
export const TeamReadPermissionVal = TeamPerList.read;
export const TeamWritePermissionVal = TeamPerList.write;
export const TeamManagePermissionVal = TeamPerList.manage;
export const TeamAppCreatePermissionVal = TeamPerList.appCreate;
export const TeamDatasetCreatePermissionVal = TeamPerList.datasetCreate;
export const TeamApikeyCreatePermissionVal = TeamPerList.apikeyCreate;
export const TeamDefaultPermissionVal = TeamReadPermissionVal;

View File

@@ -1,13 +1,18 @@
import { type PerConstructPros, Permission } from '../controller';
import {
TeamApikeyCreatePermissionVal,
TeamAppCreatePermissionVal,
TeamDatasetCreatePermissionVal,
TeamDefaultPermissionVal,
TeamPermissionList
TeamApikeyCreateRoleVal,
TeamAppCreateRoleVal,
TeamDatasetCreateRoleVal,
TeamDefaultRoleVal,
TeamPerList,
TeamRoleList,
TeamRolePerMap
} from './constant';
export class TeamPermission extends Permission {
hasAppCreateRole: boolean = false;
hasDatasetCreateRole: boolean = false;
hasApikeyCreateRole: boolean = false;
hasAppCreatePer: boolean = false;
hasDatasetCreatePer: boolean = false;
hasApikeyCreatePer: boolean = false;
@@ -15,18 +20,23 @@ export class TeamPermission extends Permission {
constructor(props?: PerConstructPros) {
if (!props) {
props = {
per: TeamDefaultPermissionVal
role: TeamDefaultRoleVal
};
} else if (!props?.per) {
props.per = TeamDefaultPermissionVal;
} else if (!props?.role) {
props.role = TeamDefaultRoleVal;
}
props.permissionList = TeamPermissionList;
props.roleList = TeamRoleList;
props.rolePerMap = TeamRolePerMap;
props.perList = TeamPerList;
super(props);
this.setUpdatePermissionCallback(() => {
this.hasAppCreatePer = this.checkPer(TeamAppCreatePermissionVal);
this.hasDatasetCreatePer = this.checkPer(TeamDatasetCreatePermissionVal);
this.hasApikeyCreatePer = this.checkPer(TeamApikeyCreatePermissionVal);
this.hasAppCreateRole = this.checkRole(TeamAppCreateRoleVal);
this.hasDatasetCreateRole = this.checkRole(TeamDatasetCreateRoleVal);
this.hasApikeyCreateRole = this.checkRole(TeamApikeyCreateRoleVal);
this.hasAppCreatePer = this.checkPer(TeamAppCreateRoleVal);
this.hasDatasetCreatePer = this.checkPer(TeamDatasetCreateRoleVal);
this.hasApikeyCreatePer = this.checkPer(TeamApikeyCreateRoleVal);
});
}
}

View File

@@ -1,5 +1,5 @@
import { type PermissionValueType } from './type';
import { NullPermission, PermissionTypeEnum } from './constant';
import { NullRoleVal, PermissionTypeEnum } from './constant';
import type { Permission } from './controller';
/* team public source, or owner source in team */
@@ -30,7 +30,7 @@ export function mongoOwnerPermission({ teamId, tmbId }: { teamId: string; tmbId:
}
// return permission-related schema to define the schema of resources
export function getPermissionSchema(defaultPermission: PermissionValueType = NullPermission) {
export function getPermissionSchema(defaultPermission: PermissionValueType = NullRoleVal) {
return {
defaultPermission: {
type: Number,
@@ -42,3 +42,11 @@ export function getPermissionSchema(defaultPermission: PermissionValueType = Nul
}
};
}
export const sumPer = (...per: PermissionValueType[]) => {
if (per.length === 0) {
// prevent sum 0 value, to fallback to default value
return undefined;
}
return per.reduce((acc, cur) => acc | cur, 0);
};

View File

@@ -16,17 +16,17 @@ export const filterDatasetsByTmbId = async ({
// First get all permissions
const permissions = await Promise.all(
datasetIds.map(async (datasetId) => {
const per = await getResourcePermission({
const role = await getResourcePermission({
teamId,
tmbId,
resourceId: datasetId,
resourceType: PerResourceTypeEnum.dataset
});
if (per === undefined) return false;
if (role === undefined) return false;
const datasetPer = new DatasetPermission({
per,
role,
isOwner: tmbPer.isOwner
});

View File

@@ -12,7 +12,6 @@ import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
import { type AuthModeType, type AuthResponseType } from '../type';
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
import { splitCombinePluginId } from '@fastgpt/global/core/app/plugin/utils';
export const authPluginByTmbId = async ({
@@ -83,16 +82,16 @@ export const authAppByTmbId = async ({
app.inheritPermission === false ||
!app.parentId
) {
// 1. is a folder. (Folders have compeletely permission)
// 1. is a folder. (Folders have completely permission)
// 2. inheritPermission is false.
// 3. is root folder/app.
const rp = await getResourcePermission({
const role = await getResourcePermission({
teamId,
tmbId,
resourceId: appId,
resourceType: PerResourceTypeEnum.app
});
const Per = new AppPermission({ per: rp ?? AppDefaultPermissionVal, isOwner });
const Per = new AppPermission({ role, isOwner });
return {
Per
};
@@ -105,7 +104,7 @@ export const authAppByTmbId = async ({
});
const Per = new AppPermission({
per: parent.permission.value,
role: parent.permission.role,
isOwner
});
return {

View File

@@ -4,7 +4,7 @@ import { parseHeaderCert } from '../controller';
import { getFileById } from '../../../common/file/gridfs/controller';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { OwnerPermissionVal, ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { OwnerPermissionVal, ReadRoleVal } from '@fastgpt/global/support/permission/constant';
import { Permission } from '@fastgpt/global/support/permission/controller';
export const authCollectionFile = async ({
@@ -32,7 +32,7 @@ export const authCollectionFile = async ({
}
const permission = new Permission({
per: ReadPermissionVal,
role: ReadRoleVal,
isOwner: file.metadata?.uid === tmbId || file.metadata?.tmbId === tmbId
});

View File

@@ -6,7 +6,6 @@ import { MongoOpenApi } from '../../openapi/schema';
import { OpenApiErrEnum } from '@fastgpt/global/common/error/code/openapi';
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
import { authAppByTmbId } from '../app/auth';
import { Permission } from '@fastgpt/global/support/permission/controller';
export async function authOpenApiKeyCrud({
id,
@@ -49,9 +48,7 @@ export async function authOpenApiKeyCrud({
return {
openapi,
permission: new Permission({
per
})
permission: tmbPer
};
})();

View File

@@ -21,6 +21,7 @@ import { type TeamMemberSchema } from '@fastgpt/global/support/user/team/type';
import { type OrgSchemaType } from '@fastgpt/global/support/user/team/org/type';
import { getOrgIdSetWithParentByTmbId } from './org/controllers';
import { authUserSession } from '../user/session';
import { sumPer } from '@fastgpt/global/support/permission/utils';
/** get resource permission for a team member
* If there is no permission for the team member, it will return undefined
@@ -102,7 +103,7 @@ export const getResourcePermission = async ({
.then((perList) => perList.map((item) => item.permission))
]);
return concatPer([...groupPers, ...orgPers]);
return sumPer(...groupPers, ...orgPers);
};
export async function getResourceClbsAndGroups({
@@ -402,11 +403,3 @@ export const authFileToken = (token?: string) =>
});
});
});
export const concatPer = (perList: PermissionValueType[] = []) => {
if (perList.length === 0) {
return undefined;
}
return new Permission().addPer(...perList).value;
};

View File

@@ -7,7 +7,10 @@ import {
} from '@fastgpt/global/core/dataset/type';
import { getTmbInfoByTmbId } from '../../user/team/controller';
import { MongoDataset } from '../../../core/dataset/schema';
import { NullPermission, PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
import {
NullPermissionVal,
PerResourceTypeEnum
} from '@fastgpt/global/support/permission/constant';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { DatasetPermission } from '@fastgpt/global/support/permission/dataset/controller';
import { getCollectionWithDataset } from '../../../core/dataset/controller';
@@ -15,7 +18,7 @@ import { MongoDatasetData } from '../../../core/dataset/data/schema';
import { type AuthModeType, type AuthResponseType } from '../type';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
import { DataSetDefaultRoleVal } from '@fastgpt/global/support/permission/dataset/constant';
import { getDatasetImagePreviewUrl } from '../../../core/dataset/image/utils';
import { i18nT } from '../../../../web/i18n/utils';
@@ -71,7 +74,7 @@ export const authDatasetByTmbId = async ({
dataset.inheritPermission === false ||
!dataset.parentId
) {
// 1. is a folder. (Folders have compeletely permission)
// 1. is a folder. (Folders have completely permission)
// 2. inheritPermission is false.
// 3. is root folder/dataset.
const rp = await getResourcePermission({
@@ -81,7 +84,7 @@ export const authDatasetByTmbId = async ({
resourceType: PerResourceTypeEnum.dataset
});
const Per = new DatasetPermission({
per: rp ?? DatasetDefaultPermissionVal,
role: rp,
isOwner
});
return {
@@ -97,7 +100,7 @@ export const authDatasetByTmbId = async ({
});
const Per = new DatasetPermission({
per: parent.permission.value,
role: parent.permission.role,
isOwner
});
@@ -158,7 +161,7 @@ export const authDataset = async ({
// the temporary solution for authDatasetCollection is getting the
export async function authDatasetCollection({
collectionId,
per = NullPermission,
per = NullPermissionVal,
isRoot = false,
...props
}: AuthModeType & {
@@ -242,7 +245,7 @@ export async function authDatasetCollection({
// }
// }
/*
/*
DatasetData permission is inherited from collection.
*/
export async function authDatasetData({

View File

@@ -3,7 +3,7 @@ import { parseHeaderCert } from '../controller';
import { getTmbInfoByTmbId } from '../../user/team/controller';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { type AuthModeType, type AuthResponseType } from '../type';
import { NullPermission } from '@fastgpt/global/support/permission/constant';
import { NullPermissionVal } from '@fastgpt/global/support/permission/constant';
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
import { authCert } from '../auth/common';
import { MongoUser } from '../../user/schema';
@@ -28,7 +28,7 @@ export async function authUserPer(props: AuthModeType): Promise<
tmb
};
}
if (!tmb.permission.checkPer(props.per ?? NullPermission)) {
if (!tmb.permission.checkPer(props.per ?? NullPermissionVal)) {
return Promise.reject(TeamErrEnum.unAuthTeam);
}

View File

@@ -11,7 +11,7 @@ import { type UpdateTeamProps } from '@fastgpt/global/support/user/team/controll
import { getResourcePermission } from '../../permission/controller';
import { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
import { TeamDefaultPermissionVal } from '@fastgpt/global/support/permission/user/constant';
import { TeamDefaultRoleVal } from '@fastgpt/global/support/permission/user/constant';
import { MongoMemberGroupModel } from '../../permission/memberGroup/memberGroupSchema';
import { mongoSessionRun } from '../../../common/mongo/sessionRun';
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
@@ -25,11 +25,12 @@ async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemTyp
return Promise.reject('member not exist');
}
const Per = await getResourcePermission({
resourceType: PerResourceTypeEnum.team,
teamId: tmb.teamId,
tmbId: tmb._id
});
const role =
(await getResourcePermission({
resourceType: PerResourceTypeEnum.team,
teamId: tmb.teamId,
tmbId: tmb._id
})) ?? TeamDefaultRoleVal;
return {
userId: String(tmb.userId),
@@ -44,7 +45,7 @@ async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemTyp
role: tmb.role,
status: tmb.status,
permission: new TeamPermission({
per: Per ?? TeamDefaultPermissionVal,
role,
isOwner: tmb.role === TeamMemberRoleEnum.owner
}),
notificationAccount: tmb.team.notificationAccount,

View File

@@ -143,6 +143,8 @@
"permission.des.manage": "Based on write permissions, you can configure publishing channels, view conversation logs, and assign permissions to the application.",
"permission.des.read": "Use the app to have conversations",
"permission.des.write": "Can view and edit apps",
"permission.des.readChatLog": "Can view chat logs",
"permission.name.readChatLog": "View chat logs",
"plugin.Instructions": "Instructions",
"plugin_cost_by_token": "Charged based on token usage",
"plugin_cost_per_times": "{{cost}} points/time",

View File

@@ -64,6 +64,7 @@
"Parse": "Analysis",
"Permission": "Permission",
"Permission_tip": "Individual permissions are greater than group permissions",
"permission_other": "Other permissions (multiple)",
"Preview": "Preview",
"Remove": "Remove",
"Rename": "Rename",

View File

@@ -143,6 +143,8 @@
"permission.des.manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限",
"permission.des.read": "可使用该应用进行对话",
"permission.des.write": "可查看和编辑应用",
"permission.des.readChatLog": "可查看对话日志",
"permission.name.readChatLog": "查看对话日志",
"plugin.Instructions": "使用说明",
"plugin_cost_by_token": "依据 token 消耗计费",
"plugin_cost_per_times": "{{cost}} 积分/次",

View File

@@ -64,6 +64,7 @@
"Parse": "解析",
"Permission": "权限",
"Permission_tip": "个人权限大于群组权限",
"permission_other": "其他权限(多选)",
"Preview": "预览",
"Remove": "移除",
"Rename": "重命名",

View File

@@ -143,6 +143,8 @@
"permission.des.manage": "在寫入權限基礎上,可以設定發布通道、檢視對話紀錄、分配這個應用程式的權限",
"permission.des.read": "可以使用這個應用程式進行對話",
"permission.des.write": "可以檢視和編輯應用程式",
"permission.des.readChatLog": "可以檢視對話紀錄",
"permission.name.readChatLog": "檢視對話紀錄",
"plugin.Instructions": "使用說明",
"plugin_cost_by_token": "根據 token 消耗計費",
"plugin_cost_per_times": "{{cost}} 積分/次",

View File

@@ -64,6 +64,7 @@
"Parse": "解析",
"Permission": "權限",
"Permission_tip": "個人權限大於群組權限",
"permission_other": "其他權限(多選)",
"Preview": "預覽",
"Remove": "移除",
"Rename": "重新命名",