Skip to content

Commit

Permalink
Update permission (#1522)
Browse files Browse the repository at this point in the history
* Permission (#1442)

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* feat: add permission display in the team manager modal

* feat: add permission i18n

* feat: let team module acquire permission ablity

* feat: add ownerPermission property into metaData

* feat: team premission system

* feat: extract the resourcePermission from resource schemas

* fix: move enum definition to constant

* feat: auth member permission handler, invite user

* feat: permission manage

* feat: adjust the style

* feat: team card style
- add a new icon

* feat: team permission in guest mode

* chore: change the type

* chore: delete useless file

* chore: delete useless code

* feat: do not show owner in PermissionManage view

* chore: fix style

* fix: icon remove fill

* feat: adjust the codes

---------

Co-authored-by: Archer <[email protected]>

* perf: permission modal

* lock

---------

Co-authored-by: Finley Ge <[email protected]>
  • Loading branch information
c121914yu and FinleyGe authored May 17, 2024
1 parent 67c5299 commit 2f93ded
Show file tree
Hide file tree
Showing 30 changed files with 1,079 additions and 377 deletions.
1 change: 1 addition & 0 deletions .vscode/i18n-ally-custom-framework.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ usageMatchRegex:
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]workflowT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]userT\\(['\"`]({key})['\"`]"

# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
# and works like how the i18next framework identifies the namespace scope from the
Expand Down
6 changes: 6 additions & 0 deletions packages/global/support/permission/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@ export const PermissionTypeMap = {
label: 'permission.Public'
}
};

export enum ResourceTypeEnum {
team = 'team',
app = 'app',
dataset = 'dataset'
}
9 changes: 9 additions & 0 deletions packages/global/support/permission/type.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { AuthUserTypeEnum } from './constant';

export type PermissionValueType = number;

export type AuthResponseType = {
teamId: string;
tmbId: string;
Expand All @@ -9,3 +11,10 @@ export type AuthResponseType = {
appId?: string;
apikey?: string;
};

export type ResourcePermissionType = {
teamId: string;
tmbId: string;
resourceType: ResourceType;
permission: PermissionValueType;
};
7 changes: 7 additions & 0 deletions packages/global/support/user/team/controller.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PermissionValueType } from 'support/permission/type';
import { TeamMemberRoleEnum } from './constant';
import { LafAccountType, TeamMemberSchema } from './type';

Expand Down Expand Up @@ -44,3 +45,9 @@ export type InviteMemberResponse = Record<
'invite' | 'inValid' | 'inTeam',
{ username: string; userId: string }[]
>;

export type UpdateTeamMemberPermissionProps = {
teamId: string;
memberIds: string[];
permission: PermissionValueType;
};
5 changes: 5 additions & 0 deletions packages/global/support/user/team/type.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { UserModelSchema } from '../type';
import type { TeamMemberRoleEnum, TeamMemberStatusEnum } from './constant';
import { LafAccountType } from './type';
import { PermissionValueType, ResourcePermissionType } from '../../permission/type';

export type TeamSchema = {
_id: string;
Expand All @@ -15,6 +16,7 @@ export type TeamSchema = {
lastWebsiteSyncTime: Date;
};
lafAccount: LafAccountType;
defaultPermission: PermissionValueType;
};
export type tagsType = {
label: string;
Expand Down Expand Up @@ -61,6 +63,7 @@ export type TeamItemType = {
status: `${TeamMemberStatusEnum}`;
canWrite: boolean;
lafAccount?: LafAccountType;
defaultPermission: PermissionValueType;
};

export type TeamMemberItemType = {
Expand All @@ -69,8 +72,10 @@ export type TeamMemberItemType = {
teamId: string;
memberName: string;
avatar: string;
// TODO: this should be deprecated.
role: `${TeamMemberRoleEnum}`;
status: `${TeamMemberStatusEnum}`;
permission: PermissionValueType;
};

export type TeamTagItemType = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ResourcePermissionType } from '@fastgpt/global/support/permission/type';
import { MongoResourcePermission } from './schema';
import { ResourceTypeEnum } from '@fastgpt/global/support/permission/constant';

export async function getResourcePermission({
tmbId,
resourceType
}: {
tmbId: string;
resourceType: ResourceTypeEnum;
}) {
return (await MongoResourcePermission.findOne({
tmbId,
resourceType
})) as ResourcePermissionType;
}
127 changes: 127 additions & 0 deletions packages/service/support/permission/resourcePermission/permisson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// 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 = { [key: string]: PermissionValueType };
export const NullPermission: PermissionValueType = 0;

// the Permission helper class
export class Permission {
value: PermissionValueType;
constructor(value: PermissionValueType) {
this.value = 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'])
add(...perm: PermissionValueType[]): Permission {
for (let p of perm) {
this.value = addPermission(this.value, p);
}
return this;
}

remove(...perm: PermissionValueType[]): Permission {
for (let p of perm) {
this.value = removePermission(this.value, p);
}
return this;
}

check(perm: PermissionValueType): Permission | boolean {
if (checkPermission(this.value, perm)) {
return this;
} else {
return false;
}
}
}

export function constructPermission(permList: PermissionValueType[]) {
return new Permission(NullPermission).add(...permList);
}

// The base Permissions List
// It can be extended, for example:
// export const UserPermissionList: PermissionListType = {
// ...PermissionList,
// 'Invite': 0b1000
// }
export const PermissionList: PermissionListType = {
Read: 0b100,
Write: 0b010,
Manage: 0b001
};

// list of permissions. could be customized.
// ! removal of the basic permissions is not recommended.
// const PermList: Array<PermissionType> = [ReadPerm, WritePerm, ManagePerm];

// return the list of permissions
// @param Perm(optional): the list of permissions to be added
// export function getPermList(Perm?: PermissionType[]): Array<PermissionType> {
// if (Perm === undefined) {
// return PermList;
// } else {
// return PermList.concat(Perm);
// }
// }

// check the permission
// @param [val]: The permission value to be checked
// @parma [perm]: Which Permission value will be checked
// @returns [booean]: if the [val] has the [perm]
// example:
// const perm = user.permission // get this permisiion from db or somewhere else
// const ok = checkPermission(perm, PermissionList['Read'])
export function checkPermission(val: PermissionValueType, perm: PermissionValueType): boolean {
return (val & perm) === perm;
}

// add the permission
// it can be chaining called.
// return the new permission value based on [val] added with [perm]
// @param val: PermissionValueType
// @param perm: PermissionValueType
// example:
// const basePerm = 0b001; // Manage only
export function addPermission(
val: PermissionValueType,
perm: PermissionValueType
): PermissionValueType {
return val | perm;
}

// remove the permission
export function removePermission(
val: PermissionValueType,
perm: PermissionValueType
): PermissionValueType {
return val & ~perm;
}

// export function parsePermission(val: PermissionValueType, list: PermissionValueType[]) {
// const result: [[string, boolean]] = [] as any;
// list.forEach((perm) => {
// result.push([perm[0], checkPermission(val, perm)]);
// });
// return result;
// }

export function hasManage(val: PermissionValueType) {
return checkPermission(val, PermissionList['Manage']);
}

export function hasWrite(val: PermissionValueType) {
return checkPermission(val, PermissionList['Write']);
}

export function hasRead(val: PermissionValueType) {
return checkPermission(val, PermissionList['Read']);
}
48 changes: 48 additions & 0 deletions packages/service/support/permission/resourcePermission/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
TeamCollectionName,
TeamMemberCollectionName
} from '@fastgpt/global/support/user/team/constant';
import { Model, connectionMongo } from '../../../common/mongo';
import type { ResourcePermissionType } from '@fastgpt/global/support/permission/type';
import { ResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
const { Schema, model, models } = connectionMongo;

export const ResourcePermissionSchema = new Schema({
teamId: {
type: Schema.Types.ObjectId,
ref: TeamCollectionName
},
tmbId: {
type: Schema.Types.ObjectId,
ref: TeamMemberCollectionName
},
resourceType: {
type: Object.values(ResourceTypeEnum),
required: true
},
permission: {
type: Number,
required: true
}
});

try {
ResourcePermissionSchema.index({
teamId: 1,
resourceType: 1
});
ResourcePermissionSchema.index({
tmbId: 1,
resourceType: 1
});
} catch (error) {
console.log(error);
}

export const ResourcePermissionCollectionName = 'resource_permission';

export const MongoResourcePermission: Model<ResourcePermissionType> =
models[ResourcePermissionCollectionName] ||
model(ResourcePermissionCollectionName, ResourcePermissionSchema);

MongoResourcePermission.syncIndexes();
3 changes: 2 additions & 1 deletion packages/service/support/user/team/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ async function getTeamMember(match: Record<string, any>): Promise<TeamItemType>
status: tmb.status,
defaultTeam: tmb.defaultTeam,
canWrite: tmb.role !== TeamMemberRoleEnum.visitor,
lafAccount: tmb.teamId.lafAccount
lafAccount: tmb.teamId.lafAccount,
defaultPermission: tmb.teamId.defaultPermission
};
}

Expand Down
5 changes: 5 additions & 0 deletions packages/service/support/user/team/teamSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { Schema, model, models } = connectionMongo;
import { TeamSchema as TeamType } from '@fastgpt/global/support/user/team/type.d';
import { userCollectionName } from '../../user/schema';
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
import { NullPermission } from '../../permission/resourcePermission/permisson';

const TeamSchema = new Schema({
name: {
Expand All @@ -13,6 +14,10 @@ const TeamSchema = new Schema({
type: Schema.Types.ObjectId,
ref: userCollectionName
},
defaultPermission: {
type: Number,
default: NullPermission
},
avatar: {
type: String,
default: '/icon/logo.svg'
Expand Down
3 changes: 3 additions & 0 deletions packages/web/components/common/Icon/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const iconPaths = {
'common/settingLight': () => import('./icons/common/settingLight.svg'),
'common/text/t': () => import('./icons/common/text/t.svg'),
'common/tickFill': () => import('./icons/common/tickFill.svg'),
'common/trash': () => import('./icons/common/trash.svg'),
'common/uploadFileFill': () => import('./icons/common/uploadFileFill.svg'),
'common/viewLight': () => import('./icons/common/viewLight.svg'),
'common/voiceLight': () => import('./icons/common/voiceLight.svg'),
Expand Down Expand Up @@ -207,8 +208,10 @@ export const iconPaths = {
'support/outlink/iframeLight': () => import('./icons/support/outlink/iframeLight.svg'),
'support/outlink/share': () => import('./icons/support/outlink/share.svg'),
'support/outlink/shareLight': () => import('./icons/support/outlink/shareLight.svg'),
'support/permission/collaborator': () => import('./icons/support/permission/collaborator.svg'),
'support/permission/privateLight': () => import('./icons/support/permission/privateLight.svg'),
'support/permission/publicLight': () => import('./icons/support/permission/publicLight.svg'),
'support/team/key': () => import('./icons/support/team/key.svg'),
'support/team/memberLight': () => import('./icons/support/team/memberLight.svg'),
'support/usage/usageRecordLight': () => import('./icons/support/usage/usageRecordLight.svg'),
'support/user/individuation': () => import('./icons/support/user/individuation.svg'),
Expand Down
3 changes: 3 additions & 0 deletions packages/web/components/common/Icon/icons/common/trash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 2f93ded

Please sign in to comment.