[WEB-2357] fix: update and redefine user roles across the platform (#5466)

* chore: removed viewer role

* chore: indentation

* chore: remove viewer role

* chore: handled user permissions in store

* chore: updated the migration file

* chore: updated user permissions store

* chore: removed the owner key

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* fix: build error

* chore: updated user permissions store and handled the permissions fetch in workspace and project wrappers

* chore: package user enum updated

* chore: user permission updated

* chore: user permission updated

* chore: resolved build errors

* chore: resolved build error

* chore: resolved build errors

* chore: computedFn deep map issue resolved

* chore: added back migration

* chore: added new field in project table

* chore: removed member store in users

* chore: private project for admins

* chore: workspace notification access validation updated

* fix: workspace member edit option

* fix: project intake permission validation updated

* chore: workspace export settings permission updated

* chore: guest_view_all_issues added

* chore: guest_view_all_issues added

* chore: key changed for guest access

* chore: added validation for individual issues

* chore: changed the dashboard issues count

* chore: added new yarn file

* chore: modified yarn file

* chore: project page permission updated

* chore: project page permission updated

* chore: member setting ux updated

* chore: build error

* fix: yarn lock

* fix: build error

---------

Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
Bavisetti Narayan 2024-09-11 17:10:15 +05:30 committed by GitHub
parent 7013a36629
commit fdcd9a376c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
172 changed files with 2057 additions and 1627 deletions

View file

@ -4,10 +4,9 @@ import { action, makeObservable, observable, runInAction, computed } from "mobx"
// types
import { IUser } from "@plane/types";
// constants
import { EUserProjectRoles } from "@/constants/project";
import { EUserWorkspaceRoles } from "@/constants/workspace";
// helpers
import { API_BASE_URL } from "@/helpers/common.helper";
import { EUserPermissions } from "@/plane-web/constants/user-permissions";
// services
import { AuthService } from "@/services/auth.service";
import { UserService } from "@/services/user.service";
@ -15,8 +14,9 @@ import { UserService } from "@/services/user.service";
import { CoreRootStore } from "@/store/root.store";
import { IAccountStore } from "@/store/user/account.store";
import { ProfileStore, IUserProfileStore } from "@/store/user/profile.store";
import { IUserMembershipStore, UserMembershipStore } from "@/store/user/user-membership.store";
import { IUserPermissionStore, UserPermissionStore } from "./permissions.store";
import { IUserSettingsStore, UserSettingsStore } from "./settings.store";
import { TUserPermissions } from "@plane/types/src/enums";
type TUserErrorStatus = {
status: string;
@ -33,7 +33,7 @@ export interface IUserStore {
userProfile: IUserProfileStore;
userSettings: IUserSettingsStore;
accounts: Record<string, IAccountStore>;
membership: IUserMembershipStore;
permission: IUserPermissionStore;
// actions
fetchCurrentUser: () => Promise<IUser | undefined>;
updateCurrentUser: (data: Partial<IUser>) => Promise<IUser | undefined>;
@ -42,18 +42,6 @@ export interface IUserStore {
reset: () => void;
signOut: () => Promise<void>;
// computed
// workspace level
canPerformWorkspaceAdminActions: boolean;
canPerformWorkspaceMemberActions: boolean;
canPerformWorkspaceViewerActions: boolean;
canPerformWorkspaceGuestActions: boolean;
// project level
canPerformProjectAdminActions: boolean;
canPerformProjectMemberActions: boolean;
canPerformProjectViewerActions: boolean;
canPerformProjectGuestActions: boolean;
canPerformAnyCreateAction: boolean;
projectsWithCreatePermissions: { [projectId: string]: number } | null;
}
@ -68,7 +56,7 @@ export class UserStore implements IUserStore {
userProfile: IUserProfileStore;
userSettings: IUserSettingsStore;
accounts: Record<string, IAccountStore> = {};
membership: IUserMembershipStore;
permission: IUserPermissionStore;
// service
userService: UserService;
authService: AuthService;
@ -77,7 +65,7 @@ export class UserStore implements IUserStore {
// stores
this.userProfile = new ProfileStore(store);
this.userSettings = new UserSettingsStore();
this.membership = new UserMembershipStore(store);
this.permission = new UserPermissionStore(store);
// service
this.userService = new UserService();
this.authService = new AuthService();
@ -92,7 +80,7 @@ export class UserStore implements IUserStore {
userProfile: observable,
userSettings: observable,
accounts: observable,
membership: observable,
permission: observable,
// actions
fetchCurrentUser: action,
updateCurrentUser: action,
@ -101,16 +89,6 @@ export class UserStore implements IUserStore {
reset: action,
signOut: action,
// computed
canPerformWorkspaceAdminActions: computed,
canPerformWorkspaceMemberActions: computed,
canPerformWorkspaceViewerActions: computed,
canPerformWorkspaceGuestActions: computed,
canPerformProjectAdminActions: computed,
canPerformProjectMemberActions: computed,
canPerformProjectViewerActions: computed,
canPerformProjectGuestActions: computed,
canPerformAnyCreateAction: computed,
projectsWithCreatePermissions: computed,
});
@ -158,26 +136,6 @@ export class UserStore implements IUserStore {
}
};
/**
* @description fetches the prjects with write permissions
* @returns {{[projectId: string]: number} || null}
*/
fetchProjectsWithCreatePermissions() {
const allWorkspaceRoles =
this.membership.workspaceProjectsRole &&
this.membership.workspaceProjectsRole[this.membership.router.workspaceSlug || ""];
return (
(allWorkspaceRoles &&
Object.keys(allWorkspaceRoles)
.filter((key) => allWorkspaceRoles[key] >= EUserProjectRoles.MEMBER)
.reduce(
(res: { [projectId: string]: number }, key: string) => ((res[key] = allWorkspaceRoles[key]), res),
{}
)) ||
null
);
}
/**
* @description updates the current user
* @param data
@ -258,7 +216,7 @@ export class UserStore implements IUserStore {
this.data = undefined;
this.userProfile = new ProfileStore(this.store);
this.userSettings = new UserSettingsStore();
this.membership = new UserMembershipStore(this.store);
this.permission = new UserPermissionStore(this.store);
});
};
@ -271,6 +229,30 @@ export class UserStore implements IUserStore {
this.store.resetOnSignOut();
};
// helper actions
/**
* @description fetches the prjects with write permissions
* @returns {{[projectId: string]: number} || null}
*/
fetchProjectsWithCreatePermissions = (): { [key: string]: TUserPermissions } => {
const { workspaceSlug } = this.store.router;
const allWorkspaceProjectRoles =
this.permission.workspaceProjectsPermissions && this.permission.workspaceProjectsPermissions[workspaceSlug || ""];
const userPermissions =
(allWorkspaceProjectRoles &&
Object.keys(allWorkspaceProjectRoles)
.filter((key) => allWorkspaceProjectRoles[key] >= EUserPermissions.MEMBER)
.reduce(
(res: { [projectId: string]: number }, key: string) => ((res[key] = allWorkspaceProjectRoles[key]), res),
{}
)) ||
null;
return userPermissions;
};
/**
* @description returns projects where user has permissions
* @returns {{[projectId: string]: number} || null}
@ -287,70 +269,4 @@ export class UserStore implements IUserStore {
const filteredProjects = this.fetchProjectsWithCreatePermissions();
return filteredProjects ? Object.keys(filteredProjects).length > 0 : false;
}
/**
* @description returns true if user has workspace admin actions permissions
* @returns {boolean}
*/
get canPerformWorkspaceAdminActions() {
return !!this.membership.currentWorkspaceRole && this.membership.currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
}
/**
* @description returns true if user has workspace member actions permissions
* @returns {boolean}
*/
get canPerformWorkspaceMemberActions() {
return !!this.membership.currentWorkspaceRole && this.membership.currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
}
/**
* @description returns true if user has workspace viewer actions permissions
* @returns {boolean}
*/
get canPerformWorkspaceViewerActions() {
return !!this.membership.currentWorkspaceRole && this.membership.currentWorkspaceRole >= EUserWorkspaceRoles.VIEWER;
}
/**
* @description returns true if user has workspace guest actions permissions
* @returns {boolean}
*/
get canPerformWorkspaceGuestActions() {
return !!this.membership.currentWorkspaceRole && this.membership.currentWorkspaceRole >= EUserWorkspaceRoles.GUEST;
}
/**
* @description returns true if user has project admin actions permissions
* @returns {boolean}
*/
get canPerformProjectAdminActions() {
return !!this.membership.currentProjectRole && this.membership.currentProjectRole === EUserProjectRoles.ADMIN;
}
/**
* @description returns true if user has project member actions permissions
* @returns {boolean}
*/
get canPerformProjectMemberActions() {
return !!this.membership.currentProjectRole && this.membership.currentProjectRole >= EUserProjectRoles.MEMBER;
}
/**
* @description returns true if user has project viewer actions permissions
* @returns {boolean}
*/
get canPerformProjectViewerActions() {
return !!this.membership.currentProjectRole && this.membership.currentProjectRole >= EUserProjectRoles.VIEWER;
}
/**
* @description returns true if user has project guest actions permissions
* @returns {boolean}
*/
get canPerformProjectGuestActions() {
return !!this.membership.currentProjectRole && this.membership.currentProjectRole >= EUserProjectRoles.GUEST;
}
}

View file

@ -0,0 +1,270 @@
import set from "lodash/set";
import unset from "lodash/unset";
import { action, makeObservable, observable, runInAction } from "mobx";
import { computedFn } from "mobx-utils";
// types
import { IProjectMember, IUserProjectsRole, IWorkspaceMemberMe } from "@plane/types";
// plane web types
import {
EUserPermissions,
EUserPermissionsLevel,
TUserPermissions,
TUserPermissionsLevel,
} from "@/plane-web/constants/user-permissions";
// plane web services
import { WorkspaceService } from "@/plane-web/services/workspace.service";
// services
import projectMemberService from "@/services/project/project-member.service";
import userService from "@/services/user.service";
// store
import { CoreRootStore } from "@/store/root.store";
// derived services
const workspaceService = new WorkspaceService();
export interface IUserPermissionStore {
// observables
workspaceUserInfo: Record<string, IWorkspaceMemberMe>; // workspaceSlug -> IWorkspaceMemberMe
projectUserInfo: Record<string, Record<string, IProjectMember>>; // workspaceSlug -> projectId -> IProjectMember
workspaceProjectsPermissions: Record<string, IUserProjectsRole>; // workspaceSlug -> IUserProjectsRole
// computed
// computed helpers
workspaceInfoBySlug: (workspaceSlug: string) => IWorkspaceMemberMe | undefined;
projectPermissionsByWorkspaceSlugAndProjectId: (
workspaceSlug: string,
projectId: string
) => TUserPermissions | undefined;
allowPermissions: (
allowPermissions: TUserPermissions[],
level: TUserPermissionsLevel,
workspaceSlug?: string,
projectId?: string,
onPermissionAllowed?: () => boolean
) => boolean;
// action helpers
// actions
fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMemberMe | undefined>;
leaveWorkspace: (workspaceSlug: string) => Promise<void>;
fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember | undefined>;
fetchUserProjectPermissions: (workspaceSlug: string) => Promise<IUserProjectsRole | undefined>;
joinProject: (workspaceSlug: string, projectId: string) => Promise<void | undefined>;
leaveProject: (workspaceSlug: string, projectId: string) => Promise<void>;
}
export class UserPermissionStore implements IUserPermissionStore {
// constants
workspaceUserInfo: Record<string, IWorkspaceMemberMe> = {};
projectUserInfo: Record<string, Record<string, IProjectMember>> = {};
workspaceProjectsPermissions: Record<string, IUserProjectsRole> = {};
// observables
constructor(private store: CoreRootStore) {
makeObservable(this, {
// observables
workspaceUserInfo: observable,
projectUserInfo: observable,
workspaceProjectsPermissions: observable,
// computed
// actions
fetchUserWorkspaceInfo: action,
leaveWorkspace: action,
fetchUserProjectInfo: action,
fetchUserProjectPermissions: action,
joinProject: action,
leaveProject: action,
});
}
// computed
// computed helpers
/**
* @description Returns the current workspace information
* @param { string } workspaceSlug
* @returns { IWorkspaceMemberMe | undefined }
*/
workspaceInfoBySlug = computedFn((workspaceSlug: string): IWorkspaceMemberMe | undefined => {
if (!workspaceSlug) return undefined;
return this.workspaceUserInfo[workspaceSlug] || undefined;
});
/**
* @description Returns the current project permissions
* @param { string } workspaceSlug
* @param { string } projectId
* @returns { IUserProjectsRole | undefined }
*/
projectPermissionsByWorkspaceSlugAndProjectId = computedFn(
(workspaceSlug: string, projectId: string): TUserPermissions | undefined => {
if (!workspaceSlug || !projectId) return undefined;
return this.workspaceProjectsPermissions?.[workspaceSlug]?.[projectId] || undefined;
}
);
// action helpers
/**
* @description Returns whether the user has the permission to perform an action
* @param { TUserPermissions[] } allowPermissions
* @param { TUserPermissionsLevel } level
* @param { string } workspaceSlug
* @param { string } projectId
* @param { () => boolean } onPermissionAllowed
* @returns { boolean }
*/
allowPermissions = (
allowPermissions: TUserPermissions[],
level: TUserPermissionsLevel,
workspaceSlug?: string,
projectId?: string,
onPermissionAllowed?: () => boolean
): boolean => {
const { workspaceSlug: currentWorkspaceSlug, projectId: currentProjectId } = this.store.router;
if (!workspaceSlug) workspaceSlug = currentWorkspaceSlug;
if (!projectId) projectId = currentProjectId;
let currentUserRole: TUserPermissions | undefined = undefined;
if (level === EUserPermissionsLevel.WORKSPACE) {
const workspaceInfoBySlug = workspaceSlug && this.workspaceInfoBySlug(workspaceSlug);
if (workspaceInfoBySlug) {
currentUserRole = workspaceInfoBySlug?.role as unknown as EUserPermissions;
}
}
if (level === EUserPermissionsLevel.PROJECT) {
currentUserRole = (workspaceSlug &&
projectId &&
this.projectPermissionsByWorkspaceSlugAndProjectId(workspaceSlug, projectId)) as EUserPermissions | undefined;
}
if (currentUserRole && allowPermissions.includes(currentUserRole)) {
if (onPermissionAllowed) {
return onPermissionAllowed();
} else {
return true;
}
}
return false;
};
// actions
/**
* @description Fetches the user's workspace information
* @param { string } workspaceSlug
* @returns { Promise<void | undefined> }
*/
fetchUserWorkspaceInfo = async (workspaceSlug: string): Promise<IWorkspaceMemberMe | undefined> => {
try {
const response = await workspaceService.workspaceMemberMe(workspaceSlug);
if (response) {
runInAction(() => {
set(this.workspaceUserInfo, [workspaceSlug], response);
});
}
return response;
} catch (error) {
console.error("Error fetching user workspace information", error);
throw error;
}
};
/**
* @description Leaves a workspace
* @param { string } workspaceSlug
* @returns { Promise<void | undefined> }
*/
leaveWorkspace = async (workspaceSlug: string): Promise<void> => {
try {
await userService.leaveWorkspace(workspaceSlug);
runInAction(() => {
unset(this.workspaceUserInfo, workspaceSlug);
unset(this.projectUserInfo, workspaceSlug);
unset(this.workspaceProjectsPermissions, workspaceSlug);
});
} catch (error) {
console.error("Error user leaving the workspace", error);
throw error;
}
};
/**
* @description Fetches the user's project information
* @param { string } workspaceSlug
* @param { string } projectId
* @returns { Promise<void | undefined> }
*/
fetchUserProjectInfo = async (workspaceSlug: string, projectId: string): Promise<IProjectMember | undefined> => {
try {
const response = await projectMemberService.projectMemberMe(workspaceSlug, projectId);
if (response) {
runInAction(() => {
set(this.projectUserInfo, [workspaceSlug, projectId], response);
set(this.workspaceProjectsPermissions, [workspaceSlug, projectId], response.role);
});
}
return response;
} catch (error) {
console.error("Error fetching user project information", error);
throw error;
}
};
/**
* @description Fetches the user's project permissions
* @param { string } workspaceSlug
* @returns { Promise<void | undefined> }
*/
fetchUserProjectPermissions = async (workspaceSlug: string): Promise<IUserProjectsRole | undefined> => {
try {
const response = await workspaceService.getWorkspaceUserProjectsRole(workspaceSlug);
runInAction(() => {
set(this.workspaceProjectsPermissions, [workspaceSlug], response);
});
return response;
} catch (error) {
console.error("Error fetching user project permissions", error);
throw error;
}
};
/**
* @description Joins a project
* @param { string } workspaceSlug
* @param { string } projectId
* @returns { Promise<void | undefined> }
*/
joinProject = async (workspaceSlug: string, projectId: string): Promise<void | undefined> => {
try {
const response = await userService.joinProject(workspaceSlug, [projectId]);
if (response) {
runInAction(() => {
set(this.workspaceProjectsPermissions, [workspaceSlug, projectId], response);
});
}
return response;
} catch (error) {
console.error("Error user joining the project", error);
throw error;
}
};
/**
* @description Leaves a project
* @param { string } workspaceSlug
* @param { string } projectId
* @returns { Promise<void | undefined> }
*/
leaveProject = async (workspaceSlug: string, projectId: string): Promise<void> => {
try {
await userService.leaveProject(workspaceSlug, projectId);
runInAction(() => {
unset(this.workspaceProjectsPermissions, [workspaceSlug, projectId]);
unset(this.projectUserInfo, [workspaceSlug, projectId]);
});
} catch (error) {
console.error("Error user leaving the project", error);
throw error;
}
};
}

View file

@ -1,283 +0,0 @@
import set from "lodash/set";
import update from "lodash/update";
import { action, observable, runInAction, makeObservable, computed } from "mobx";
// types
import { IWorkspaceMemberMe, IProjectMember, IUserProjectsRole, IProjectMemberLite } from "@plane/types";
// constants
import { EUserProjectRoles } from "@/constants/project";
import { EUserWorkspaceRoles } from "@/constants/workspace";
// services
import { WorkspaceService } from "@/plane-web/services";
import { ProjectMemberService } from "@/services/project";
import { UserService } from "@/services/user.service";
// plane web store
import { CoreRootStore } from "../root.store";
import { IRouterStore } from "../router.store";
export interface IUserMembershipStore {
// observables
workspaceMemberInfo: {
[workspaceSlug: string]: IWorkspaceMemberMe;
};
hasPermissionToWorkspace: {
[workspaceSlug: string]: boolean | null;
};
projectMemberInfo: {
[projectId: string]: IProjectMember;
};
hasPermissionToProject: {
[projectId: string]: boolean | null;
};
workspaceProjectsRole: { [workspaceSlug: string]: IUserProjectsRole };
// computed
currentProjectMemberInfo: IProjectMember | undefined;
currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined;
currentProjectRole: EUserProjectRoles | undefined;
currentWorkspaceRole: EUserWorkspaceRoles | undefined;
currentWorkspaceAllProjectsRole: IUserProjectsRole | undefined;
// computed functions
currentProjectRoleByProjectId: (projectId: string) => EUserProjectRoles | undefined;
hasPermissionToCurrentWorkspace: boolean | undefined;
hasPermissionToCurrentProject: boolean | undefined;
// fetch actions
fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMemberMe>;
fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember>;
fetchUserWorkspaceProjectsRole: (workspaceSlug: string) => Promise<IUserProjectsRole>;
// crud actions
leaveWorkspace: (workspaceSlug: string) => Promise<void>;
joinProject: (workspaceSlug: string, projectIds: string[]) => Promise<any>;
leaveProject: (workspaceSlug: string, projectId: string) => Promise<void>;
router: IRouterStore;
}
export class UserMembershipStore implements IUserMembershipStore {
workspaceMemberInfo: {
[workspaceSlug: string]: IWorkspaceMemberMe;
} = {};
hasPermissionToWorkspace: {
[workspaceSlug: string]: boolean;
} = {};
projectMemberInfo: {
[projectId: string]: IProjectMember;
} = {};
hasPermissionToProject: {
[projectId: string]: boolean;
} = {};
workspaceProjectsRole: { [workspaceSlug: string]: IUserProjectsRole } = {};
// stores
router;
store;
// services
userService;
workspaceService;
projectMemberService;
constructor(_rootStore: CoreRootStore) {
makeObservable(this, {
// observables
workspaceMemberInfo: observable,
hasPermissionToWorkspace: observable,
projectMemberInfo: observable,
hasPermissionToProject: observable,
workspaceProjectsRole: observable,
// computed
currentWorkspaceMemberInfo: computed,
currentWorkspaceRole: computed,
currentProjectMemberInfo: computed,
currentProjectRole: computed,
currentWorkspaceAllProjectsRole: computed,
hasPermissionToCurrentWorkspace: computed,
hasPermissionToCurrentProject: computed,
// actions
fetchUserWorkspaceInfo: action,
fetchUserProjectInfo: action,
leaveWorkspace: action,
joinProject: action,
leaveProject: action,
fetchUserWorkspaceProjectsRole: action,
});
this.router = _rootStore.router;
this.store = _rootStore;
// services
this.userService = new UserService();
this.workspaceService = new WorkspaceService();
this.projectMemberService = new ProjectMemberService();
}
/**
* Returns the current workspace member info
*/
get currentWorkspaceMemberInfo() {
if (!this.router.workspaceSlug) return;
return this.workspaceMemberInfo[this.router.workspaceSlug];
}
/**
* Returns the current workspace role
*/
get currentWorkspaceRole() {
if (!this.router.workspaceSlug) return;
return this.workspaceMemberInfo[this.router.workspaceSlug]?.role;
}
/**
* Returns the current project member info
*/
get currentProjectMemberInfo() {
if (!this.router.projectId) return;
return this.projectMemberInfo[this.router.projectId];
}
/**
* Returns the current project role
*/
get currentProjectRole() {
if (!this.router.projectId) return;
return this.projectMemberInfo[this.router.projectId]?.role;
}
/**
* Returns all projects role for the current workspace
*/
get currentWorkspaceAllProjectsRole() {
if (!this.router.workspaceSlug) return;
return this.workspaceProjectsRole?.[this.router.workspaceSlug];
}
/**
* Returns if the user has permission to the current workspace
*/
get hasPermissionToCurrentWorkspace() {
if (!this.router.workspaceSlug) return;
return this.hasPermissionToWorkspace[this.router.workspaceSlug];
}
/**
* Returns if the user has permission to the current project
*/
get hasPermissionToCurrentProject() {
if (!this.router.projectId) return;
return this.hasPermissionToProject[this.router.projectId];
}
// computed functions
/**
* Returns the current project role by project id
* @param projectId
* @returns EUserProjectRoles
*/
currentProjectRoleByProjectId = (projectId: string) => this.projectMemberInfo[projectId]?.role || undefined;
/**
* Fetches the current user workspace info
* @param workspaceSlug
* @returns Promise<IWorkspaceMemberMe>
*/
fetchUserWorkspaceInfo = async (workspaceSlug: string) =>
await this.workspaceService.workspaceMemberMe(workspaceSlug).then((response) => {
runInAction(() => {
set(this.workspaceMemberInfo, [workspaceSlug], response);
set(this.hasPermissionToWorkspace, [workspaceSlug], true);
});
return response;
});
/**
* Fetches the current user project info
* @param workspaceSlug
* @param projectId
* @returns Promise<IProjectMember>
*/
fetchUserProjectInfo = async (workspaceSlug: string, projectId: string) =>
await this.projectMemberService.projectMemberMe(workspaceSlug, projectId).then((response) => {
runInAction(() => {
this.projectMemberInfo = {
...this.projectMemberInfo,
[projectId]: response,
};
this.hasPermissionToProject = {
...this.hasPermissionToProject,
[projectId]: true,
};
});
return response;
});
/**
* Leaves a workspace
* @param workspaceSlug
* @returns Promise<void>
*/
leaveWorkspace = async (workspaceSlug: string) => {
const currentWorksSpace = this.store.workspaceRoot?.currentWorkspace;
await this.userService.leaveWorkspace(workspaceSlug).then(() => {
runInAction(() => {
if (currentWorksSpace) delete this.store.workspaceRoot?.workspaces?.[currentWorksSpace?.id];
delete this.workspaceMemberInfo[workspaceSlug];
delete this.hasPermissionToWorkspace[workspaceSlug];
});
});
};
/**
* Joins a project
* @param workspaceSlug
* @param projectIds
* @returns Promise<void>
*/
joinProject = async (workspaceSlug: string, projectIds: string[]) =>
await this.userService.joinProject(workspaceSlug, projectIds).then(() => {
const newPermissions: { [projectId: string]: boolean } = {};
projectIds.forEach((projectId) => {
newPermissions[projectId] = true;
});
runInAction(() => {
this.hasPermissionToProject = {
...this.hasPermissionToProject,
...newPermissions,
};
projectIds.forEach((projectId) => {
set(this.workspaceProjectsRole, [workspaceSlug, projectId], EUserProjectRoles.MEMBER);
});
});
});
/**
* Leaves a project
* @param workspaceSlug
* @param projectId
* @returns Promise<void>
*/
leaveProject = async (workspaceSlug: string, projectId: string) =>
await this.userService.leaveProject(workspaceSlug, projectId).then(() => {
// remove the user membership for a project
set(this.hasPermissionToProject, [projectId], false);
// update the project member list with the new permissions
set(this.store.projectRoot.project.projectMap, [projectId, "is_member"], false);
// remove user from project members list
update(this.store.projectRoot.project.projectMap, projectId, (project) => {
if (project) {
project.members = project.members.filter(
(member: IProjectMemberLite) => member.member_id !== this.store.user?.data?.id
);
}
return project;
});
});
/**
* Fetches the current user workspace projects role
* @param workspaceSlug
* @returns Promise<IUserProjectsRole>
*/
fetchUserWorkspaceProjectsRole = async (workspaceSlug: string) =>
await this.workspaceService.getWorkspaceUserProjectsRole(workspaceSlug).then((response) => {
runInAction(() => {
set(this.workspaceProjectsRole, [workspaceSlug], response);
});
return response;
});
}