diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index f7fdb9205..d94d00ccb 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -411,7 +411,12 @@ export const registerRoutes = async ( folderDAL }); - const projectRoleService = projectRoleServiceFactory({ permissionService, projectRoleDAL }); + const projectRoleService = projectRoleServiceFactory({ + permissionService, + projectRoleDAL, + projectUserMembershipRoleDAL, + identityProjectMembershipRoleDAL + }); const snapshotService = secretSnapshotServiceFactory({ permissionService, diff --git a/backend/src/services/project-role/project-role-service.ts b/backend/src/services/project-role/project-role-service.ts index 5c8ecdcff..831af3200 100644 --- a/backend/src/services/project-role/project-role-service.ts +++ b/backend/src/services/project-role/project-role-service.ts @@ -14,16 +14,25 @@ import { import { BadRequestError } from "@app/lib/errors"; import { ActorAuthMethod, ActorType } from "../auth/auth-type"; +import { TIdentityProjectMembershipRoleDALFactory } from "../identity-project/identity-project-membership-role-dal"; +import { TProjectUserMembershipRoleDALFactory } from "../project-membership/project-user-membership-role-dal"; import { TProjectRoleDALFactory } from "./project-role-dal"; type TProjectRoleServiceFactoryDep = { projectRoleDAL: TProjectRoleDALFactory; permissionService: Pick; + identityProjectMembershipRoleDAL: TIdentityProjectMembershipRoleDALFactory; + projectUserMembershipRoleDAL: TProjectUserMembershipRoleDALFactory; }; export type TProjectRoleServiceFactory = ReturnType; -export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }: TProjectRoleServiceFactoryDep) => { +export const projectRoleServiceFactory = ({ + projectRoleDAL, + permissionService, + identityProjectMembershipRoleDAL, + projectUserMembershipRoleDAL +}: TProjectRoleServiceFactoryDep) => { const createRole = async ( actor: ActorType, actorId: string, @@ -96,8 +105,25 @@ export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }: actorOrgId ); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Role); + + const identityRole = await identityProjectMembershipRoleDAL.findOne({ customRoleId: roleId }); + const projectUserRole = await projectUserMembershipRoleDAL.findOne({ customRoleId: roleId }); + + if (identityRole) { + throw new BadRequestError({ + message: "The role is assigned to one or more identities. Make sure to unassign them before deleting the role.", + name: "Delete role" + }); + } + if (projectUserRole) { + throw new BadRequestError({ + message: "The role is assigned to one or more users. Make sure to unassign them before deleting the role.", + name: "Delete role" + }); + } + const [deletedRole] = await projectRoleDAL.delete({ id: roleId, projectId }); - if (!deletedRole) throw new BadRequestError({ message: "Role not found", name: "Update role" }); + if (!deletedRole) throw new BadRequestError({ message: "Role not found", name: "Delete role" }); return deletedRole; }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleTable.tsx b/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleTable.tsx index e2086a6ab..b4e08f51a 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleTable.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleTable.tsx @@ -31,7 +31,7 @@ export const OrgRoleTable = ({ onSelectRole }: Props) => { const [searchRoles, setSearchRoles] = useState(""); const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; - + const { popUp, handlePopUpOpen, handlePopUpClose } = usePopUp(["deleteRole"] as const); const { data: roles, isLoading: isRolesLoading } = useGetOrgRoles(orgId); @@ -49,7 +49,7 @@ export const OrgRoleTable = ({ onSelectRole }: Props) => { handlePopUpClose("deleteRole"); } catch (err) { console.log(err); - createNotification({ type: "error", text: "Failed to create role" }); + createNotification({ type: "error", text: "Failed to delete role" }); } }; diff --git a/frontend/src/views/Project/MembersPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx b/frontend/src/views/Project/MembersPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx index aa29a363b..d8a22bdb4 100644 --- a/frontend/src/views/Project/MembersPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx +++ b/frontend/src/views/Project/MembersPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx @@ -29,7 +29,7 @@ type Props = { export const ProjectRoleList = ({ onSelectRole }: Props) => { const [searchRoles, setSearchRoles] = useState(""); - + const { popUp, handlePopUpOpen, handlePopUpClose } = usePopUp(["deleteRole"] as const); const { currentWorkspace } = useWorkspace(); const workspaceId = currentWorkspace?.id || ""; @@ -50,7 +50,7 @@ export const ProjectRoleList = ({ onSelectRole }: Props) => { handlePopUpClose("deleteRole"); } catch (err) { console.log(err); - createNotification({ type: "error", text: "Failed to create role" }); + createNotification({ type: "error", text: "Failed to delete role" }); } };