feat: made project role multi support for org invite

This commit is contained in:
=
2024-09-09 16:17:59 +05:30
parent eb7c804bb9
commit e7191c2f71
7 changed files with 40 additions and 26 deletions

View File

@@ -21,7 +21,7 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
projects: z
.object({
id: z.string(),
projectRoleSlug: z.string().default(ProjectMembershipRole.Member)
projectRoleSlug: z.string().array().default([ProjectMembershipRole.Member])
})
.array()
.optional(),

View File

@@ -48,7 +48,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
projects: [
{
id: req.params.projectId,
projectRoleSlug: ProjectMembershipRole.Member
projectRoleSlug: [ProjectMembershipRole.Member]
}
]
});

View File

@@ -12,6 +12,7 @@ import {
SecretKeyEncoding,
TableName,
TProjectMemberships,
TProjectUserMembershipRolesInsert,
TUsers
} from "@app/db/schemas";
import { TProjects } from "@app/db/schemas/projects";
@@ -88,7 +89,7 @@ type TOrgServiceFactoryDep = {
"getPlan" | "updateSubscriptionOrgMemberCount" | "generateOrgCustomerId" | "removeOrgCustomer"
>;
projectUserAdditionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "delete">;
projectRoleDAL: Pick<TProjectRoleDALFactory, "findOne">;
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "findUserGroupMembershipsInProject">;
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "insertMany">;
@@ -652,12 +653,15 @@ export const orgServiceFactory = ({
if (!userWithEncryptionKeyInvitedToProject.length) continue;
// validate custom project role
const invitedProjectRole =
invitedProjects.find((el) => el.id === project.id)?.projectRoleSlug || ProjectMembershipRole.Member;
const isCustomProjectRole = !Object.values(ProjectMembershipRole).includes(
invitedProjectRole as ProjectMembershipRole
const invitedProjectRoles = invitedProjects.find((el) => el.id === project.id)?.projectRoleSlug || [
ProjectMembershipRole.Member
];
const customProjectRoles = invitedProjectRoles.filter(
(role) => !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole)
);
if (isCustomProjectRole) {
const hasCustomRole = Boolean(customProjectRoles.length);
if (hasCustomRole) {
if (!plan?.rbac)
throw new BadRequestError({
message:
@@ -665,6 +669,17 @@ export const orgServiceFactory = ({
});
}
const customRoles = hasCustomRole
? await projectRoleDAL.find({
projectId,
$in: { slug: customProjectRoles.map((role) => role) }
})
: [];
if (customRoles.length !== customProjectRoles.length)
throw new BadRequestError({ message: "Custom role not found" });
const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug);
const ghostUser = await projectDAL.findProjectGhostUser(projectId, tx);
if (!ghostUser) {
throw new BadRequestError({
@@ -698,7 +713,7 @@ export const orgServiceFactory = ({
userPrivateKey: botPrivateKey,
members: userWithEncryptionKeyInvitedToProject.map((userEnc) => ({
orgMembershipId: userEnc.userId,
projectMembershipRole: invitedProjectRole as ProjectMembershipRole,
projectMembershipRole: ProjectMembershipRole.Admin,
userPublicKey: userEnc.publicKey
}))
});
@@ -712,17 +727,18 @@ export const orgServiceFactory = ({
);
newProjectMemberships.push(...projectMemberships);
let customRoleId: string;
const projectRole = isCustomProjectRole ? ProjectMembershipRole.Custom : invitedProjectRole;
if (isCustomProjectRole) {
const customRole = await projectRoleDAL.findOne({ slug: invitedProjectRole, projectId });
if (!customRole) throw new BadRequestError({ name: "Invite membership", message: "Project role not found" });
customRoleId = customRole.id;
}
await projectUserMembershipRoleDAL.insertMany(
projectMemberships.map(({ id }) => ({ projectMembershipId: id, role: projectRole, customRoleId })),
tx
);
const sanitizedProjectMembershipRoles: TProjectUserMembershipRolesInsert[] = [];
invitedProjectRoles.forEach((projectRole) => {
const isCustomRole = Boolean(customRolesGroupBySlug?.[projectRole]?.[0]);
projectMemberships.forEach((membership) => {
sanitizedProjectMembershipRoles.push({
projectMembershipId: membership.id,
role: isCustomRole ? ProjectMembershipRole.Custom : projectRole,
customRoleId: customRolesGroupBySlug[projectRole] ? customRolesGroupBySlug[projectRole][0].id : null
});
});
});
await projectUserMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
await projectKeyDAL.insertMany(
newWsMembers.map((el) => ({

View File

@@ -34,7 +34,7 @@ export type TInviteUserToOrgDTO = {
organizationRoleSlug: string;
projects?: {
id: string;
projectRoleSlug?: string;
projectRoleSlug?: string[];
}[];
};

View File

@@ -150,7 +150,7 @@ export type DeletOrgMembershipDTO = {
export type AddUserToOrgDTO = {
inviteeEmails: string[];
projects?: { id: string; projectRoleSlug: string }[];
projects?: { id: string; projectRoleSlug: string[] }[];
organizationRoleSlug: string;
organizationId: string;
};

View File

@@ -129,7 +129,7 @@ export const AddOrgMemberModal = ({
organizationId: currentOrg?.id,
inviteeEmails: emails.split(",").map((email) => email.trim()),
organizationRoleSlug,
projects: projectIds.map((id) => ({ id, projectRoleSlug }))
projects: projectIds.map((id) => ({ id, projectRoleSlug: [projectRoleSlug] }))
});
setCompleteInviteLinks(data?.completeInviteLinks ?? null);

View File

@@ -101,9 +101,7 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => {
members?.forEach((member) => {
wsUserUsernames.set(member.user.username, true);
});
return (orgUsers || []).filter(
({ status, user: u }) => status === "accepted" && !wsUserUsernames.has(u.username)
);
return (orgUsers || []).filter(({ user: u }) => !wsUserUsernames.has(u.username));
}, [orgUsers, members]);
return (