From 44b50c93c3ce19895dcdd8bf1876aa9526267317 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 4 Oct 2025 01:29:13 +0530 Subject: [PATCH] feat: resolving bugs in checklist testing --- ...ity-project-additional-privilege-router.ts | 12 +++--- backend/src/ee/routes/v1/org-role-router.ts | 2 - ...ity-project-additional-privilege-router.ts | 12 +++--- backend/src/ee/services/group/group-dal.ts | 4 +- .../src/ee/services/group/group-service.ts | 24 +++++++----- .../src/ee/services/license/license-fns.ts | 2 +- .../ee/services/permission/permission-dal.ts | 5 ++- .../permission/permission-service-types.ts | 1 - .../src/services/identity/identity-service.ts | 6 +-- .../membership-group-service.ts | 31 +++++++++------- .../membership-identity-service.ts | 25 +++++++------ .../membership-user-service.ts | 37 ++++++++++++------- .../org/org-membership-user-factory.ts | 10 +++-- backend/src/services/org/org-service.ts | 18 +++++---- frontend/src/hooks/api/roles/queries.tsx | 2 +- frontend/src/hooks/api/users/queries.tsx | 11 +----- frontend/src/hooks/api/users/types.ts | 3 -- .../OrgMembersSection/AddOrgMemberModal.tsx | 19 ++++++++-- .../MembersTab/components/AddMemberModal.tsx | 27 ++++++++------ 19 files changed, 140 insertions(+), 111 deletions(-) diff --git a/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts b/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts index 9a74b3b72..57c5c8b9a 100644 --- a/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts +++ b/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts @@ -92,7 +92,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.body.identityId, - projectMembershipId: "", + projectMembershipId: projectId, projectId, slug: privilege.name } @@ -186,7 +186,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.body.identityId, - projectMembershipId: "", + projectMembershipId: projectId, projectId, slug: privilege.name } @@ -299,7 +299,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.body.identityId, - projectMembershipId: "", + projectMembershipId: projectId, projectId, slug: privilege.name } @@ -363,7 +363,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.body.identityId, - projectMembershipId: "", + projectMembershipId: projectId, projectId, slug: privilege.name } @@ -429,7 +429,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.query.identityId, - projectMembershipId: "", + projectMembershipId: projectId, projectId, slug: privilege.name } @@ -486,7 +486,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privileges: privileges.map((privilege) => ({ ...privilege, identityId: req.query.identityId, - projectMembershipId: "", + projectMembershipId: projectId, projectId, slug: privilege.name })) diff --git a/backend/src/ee/routes/v1/org-role-router.ts b/backend/src/ee/routes/v1/org-role-router.ts index 46fb58e54..3c165b0a6 100644 --- a/backend/src/ee/routes/v1/org-role-router.ts +++ b/backend/src/ee/routes/v1/org-role-router.ts @@ -211,7 +211,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { } }); - // TODO(simp): switch to top level roles server.route({ method: "GET", url: "/:organizationId/roles", @@ -248,7 +247,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { } }); - // TODO(simp): get this fixed server.route({ method: "GET", url: "/:organizationId/permissions", diff --git a/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts b/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts index 3d113e649..f8ac34b4b 100644 --- a/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts +++ b/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts @@ -84,7 +84,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.body.identityId, - projectMembershipId: "", + projectMembershipId: req.body.projectId, projectId: req.body.projectId, slug: privilege.name } @@ -167,7 +167,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: privilegeDoc.actorIdentityId as string, - projectMembershipId: "", + projectMembershipId: privilegeDoc.projectId as string, projectId: privilegeDoc.projectId as string, slug: privilege.name } @@ -221,7 +221,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: privilegeDoc.actorIdentityId as string, - projectMembershipId: "", + projectMembershipId: privilegeDoc.projectId as string, projectId: privilegeDoc.projectId as string, slug: privilege.name } @@ -275,7 +275,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: privilegeDoc.actorIdentityId as string, - projectMembershipId: "", + projectMembershipId: privilegeDoc.projectId as string, projectId: privilegeDoc.projectId as string, slug: privilege.name } @@ -338,7 +338,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: req.query.identityId, - projectMembershipId: "", + projectMembershipId: privilege.projectId as string, projectId, slug: privilege.name } @@ -390,7 +390,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privileges: privileges.map((privilege) => ({ ...privilege, identityId: req.query.identityId, - projectMembershipId: "", + projectMembershipId: privilege.projectId as string, projectId: req.query.projectId, slug: privilege.name })) diff --git a/backend/src/ee/services/group/group-dal.ts b/backend/src/ee/services/group/group-dal.ts index b40bcac03..90d499669 100644 --- a/backend/src/ee/services/group/group-dal.ts +++ b/backend/src/ee/services/group/group-dal.ts @@ -40,7 +40,7 @@ export const groupDALFactory = (db: TDbClient) => { .where(`${TableName.Membership}.scope`, AccessScope.Organization) .join(TableName.Membership, `${TableName.Groups}.id`, `${TableName.Membership}.actorGroupId`) .join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`) - .join(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`) + .leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`) .select(selectAllTableCols(TableName.Groups)) // cr stands for custom role .select(db.ref("id").as("crId").withSchema(TableName.Role)) @@ -210,7 +210,7 @@ export const groupDALFactory = (db: TDbClient) => { .where(`${TableName.Membership}.scope`, AccessScope.Organization) .where((queryBuilder) => { Object.entries(filter).forEach(([key, value]) => { - void queryBuilder.where(`${TableName.Membership}.${key}`, value); + void queryBuilder.where(`${TableName.Groups}.${key}`, value); }); }) .select( diff --git a/backend/src/ee/services/group/group-service.ts b/backend/src/ee/services/group/group-service.ts index c8bde0641..f4a014351 100644 --- a/backend/src/ee/services/group/group-service.ts +++ b/backend/src/ee/services/group/group-service.ts @@ -223,16 +223,20 @@ export const groupServiceFactory = ({ } } - const [updated] = await groupDAL.update( - { - id: group.id - }, - { - name, - slug: slug ? slugify(slug) : undefined - }, - tx - ); + let updated = group; + + if (name || slug) { + [updated] = await groupDAL.update( + { + id: group.id + }, + { + name, + slug: slug ? slugify(slug) : undefined + }, + tx + ); + } if (role) { const membership = await membershipGroupDAL.findOne( diff --git a/backend/src/ee/services/license/license-fns.ts b/backend/src/ee/services/license/license-fns.ts index 2a3cf82cc..6d5958faf 100644 --- a/backend/src/ee/services/license/license-fns.ts +++ b/backend/src/ee/services/license/license-fns.ts @@ -40,7 +40,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ oidcSSO: false, scim: false, ldap: false, - groups: false, + groups: true, status: null, trial_end: null, has_used_trial: true, diff --git a/backend/src/ee/services/permission/permission-dal.ts b/backend/src/ee/services/permission/permission-dal.ts index 7b81f592d..5875d0709 100644 --- a/backend/src/ee/services/permission/permission-dal.ts +++ b/backend/src/ee/services/permission/permission-dal.ts @@ -236,7 +236,8 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => { } else if (actorType === ActorType.IDENTITY) { void qb.where(`${TableName.Membership}.actorIdentityId`, actorId); } - + }) + .where((qb) => { if (scopeData.scope === AccessScope.Organization) { void qb.where(`${TableName.Membership}.scope`, AccessScope.Organization); } else if (scopeData.scope === AccessScope.Namespace) { @@ -361,6 +362,8 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => { } ] }); + + console.log(">>>", data); return data; } catch (error) { throw new DatabaseError({ error, name: "Get Permission" }); diff --git a/backend/src/ee/services/permission/permission-service-types.ts b/backend/src/ee/services/permission/permission-service-types.ts index a3d2327c8..321dad609 100644 --- a/backend/src/ee/services/permission/permission-service-types.ts +++ b/backend/src/ee/services/permission/permission-service-types.ts @@ -95,7 +95,6 @@ export type TPermissionServiceFactory = { membershipId: string; }[]; }>; - // TODO(simp): switch to role dal later getOrgPermissionByRoles: ( roles: string[], orgId: string diff --git a/backend/src/services/identity/identity-service.ts b/backend/src/services/identity/identity-service.ts index 5c89b9902..cd272e807 100644 --- a/backend/src/services/identity/identity-service.ts +++ b/backend/src/services/identity/identity-service.ts @@ -216,11 +216,9 @@ export const identityServiceFactory = ({ if (role) { await membershipRoleDAL.delete({ membershipId: identityOrgMembership.id }, tx); - await membershipRoleDAL.update( - { - membershipId: identityOrgMembership.id - }, + await membershipRoleDAL.create( { + membershipId: identityOrgMembership.id, role: customRole ? OrgMembershipRole.Custom : role, customRoleId: customRole?.id || null }, diff --git a/backend/src/services/membership-group/membership-group-service.ts b/backend/src/services/membership-group/membership-group-service.ts index 0081bc4ad..a861dc984 100644 --- a/backend/src/services/membership-group/membership-group-service.ts +++ b/backend/src/services/membership-group/membership-group-service.ts @@ -54,8 +54,8 @@ export const membershipGroupServiceFactory = ({ const { scopeData, data } = dto; const factory = scopeFactory[scopeData.scope]; - const hasOnePermanentRole = data.roles.some((el) => el.isTemporary); - if (hasOnePermanentRole) { + const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); + if (hasNoPermanentRole) { throw new BadRequestError({ message: "Group must have atleast one permanent role" }); @@ -148,8 +148,8 @@ export const membershipGroupServiceFactory = ({ const customInputRoles = data.roles.filter((el) => factory.isCustomRole(el.role)); const hasCustomRole = customInputRoles.length > 0; - const hasOnePermanentRole = data.roles.some((el) => el.isTemporary); - if (hasOnePermanentRole) { + const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); + if (hasNoPermanentRole) { throw new BadRequestError({ message: "Group must have atleast one permanent role" }); @@ -172,7 +172,7 @@ export const membershipGroupServiceFactory = ({ const existingMembership = await membershipGroupDAL.findOne({ scope: scopeData.scope, ...scopeDatabaseFields, - actorIdentityId: dto.selector.groupId + actorGroupId: dto.selector.groupId }); if (!existingMembership) throw new BadRequestError({ @@ -193,13 +193,16 @@ export const membershipGroupServiceFactory = ({ const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug); const membershipDoc = await membershipGroupDAL.transaction(async (tx) => { - const doc = await membershipGroupDAL.updateById( - existingMembership.id, - { - isActive: data.isActive - }, - tx - ); + const doc = + typeof data?.isActive === "undefined" + ? existingMembership + : await membershipGroupDAL.updateById( + existingMembership.id, + { + isActive: data.isActive + }, + tx + ); const roleDocs: TMembershipRolesInsert[] = []; data.roles.forEach((membershipRole) => { @@ -253,14 +256,14 @@ export const membershipGroupServiceFactory = ({ const existingMembership = await membershipGroupDAL.findOne({ scope: scopeData.scope, ...scopeDatabaseFields, - actorIdentityId: dto.selector.groupId + actorGroupId: dto.selector.groupId }); if (!existingMembership) throw new BadRequestError({ message: "Group doesn't have membership" }); - if (existingMembership.actorIdentityId === dto.permission.id) + if (existingMembership.actorGroupId === dto.permission.id) throw new BadRequestError({ message: "You can't delete you own membership" }); diff --git a/backend/src/services/membership-identity/membership-identity-service.ts b/backend/src/services/membership-identity/membership-identity-service.ts index 474de1e71..f1530fc29 100644 --- a/backend/src/services/membership-identity/membership-identity-service.ts +++ b/backend/src/services/membership-identity/membership-identity-service.ts @@ -57,8 +57,8 @@ export const membershipIdentityServiceFactory = ({ const { scopeData, data } = dto; const factory = scopeFactory[scopeData.scope]; - const hasOnePermanentRole = data.roles.some((el) => el.isTemporary); - if (hasOnePermanentRole) { + const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); + if (hasNoPermanentRole) { throw new BadRequestError({ message: "Identity must have atleast one permanent role" }); @@ -151,8 +151,8 @@ export const membershipIdentityServiceFactory = ({ const customInputRoles = data.roles.filter((el) => factory.isCustomRole(el.role)); const hasCustomRole = customInputRoles.length > 0; - const hasOnePermanentRole = data.roles.some((el) => el.isTemporary); - if (hasOnePermanentRole) { + const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); + if (hasNoPermanentRole) { throw new BadRequestError({ message: "Identity must have atleast one permanent role" }); @@ -196,13 +196,16 @@ export const membershipIdentityServiceFactory = ({ const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug); const membershipDoc = await membershipIdentityDAL.transaction(async (tx) => { - const doc = await membershipIdentityDAL.updateById( - existingMembership.id, - { - isActive: data.isActive - }, - tx - ); + const doc = + typeof data.isActive === "undefined" + ? existingMembership + : await membershipIdentityDAL.updateById( + existingMembership.id, + { + isActive: data.isActive + }, + tx + ); const roleDocs: TMembershipRolesInsert[] = []; data.roles.forEach((membershipRole) => { diff --git a/backend/src/services/membership-user/membership-user-service.ts b/backend/src/services/membership-user/membership-user-service.ts index be90045ee..18ad1f5d6 100644 --- a/backend/src/services/membership-user/membership-user-service.ts +++ b/backend/src/services/membership-user/membership-user-service.ts @@ -1,4 +1,10 @@ -import { AccessScope, ProjectMembershipRole, TemporaryPermissionMode, TMembershipRolesInsert } from "@app/db/schemas"; +import { + AccessScope, + OrgMembershipStatus, + ProjectMembershipRole, + TemporaryPermissionMode, + TMembershipRolesInsert +} from "@app/db/schemas"; import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; @@ -147,8 +153,8 @@ export const membershipUserServiceFactory = ({ const { scopeData, data } = dto; const factory = scopeFactory[scopeData.scope]; - const hasOnePermanentRole = data.roles.some((el) => el.isTemporary); - if (hasOnePermanentRole) { + const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); + if (hasNoPermanentRole) { throw new BadRequestError({ message: "User must have atleast one permanent role" }); @@ -184,7 +190,9 @@ export const membershipUserServiceFactory = ({ const newMemberships = newMembershipUsers.map((user) => ({ scope: scopeData.scope, ...scopeDatabaseFields, - actorUserId: user.id + actorUserId: user.id, + status: scopeData.scope === AccessScope.Organization ? OrgMembershipStatus.Invited : undefined, + inviteEmail: scopeData.scope === AccessScope.Organization ? user.email : undefined })); const customInputRoles = data.roles.filter((el) => factory.isCustomRole(el.role)); @@ -270,8 +278,8 @@ export const membershipUserServiceFactory = ({ }); } - const hasOnePermanentRole = data.roles.some((el) => el.isTemporary); - if (hasOnePermanentRole) { + const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); + if (hasNoPermanentRole) { throw new BadRequestError({ message: "User must have atleast one permanent role" }); @@ -315,13 +323,16 @@ export const membershipUserServiceFactory = ({ const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug); const membershipDoc = await membershipUserDAL.transaction(async (tx) => { - const doc = await membershipUserDAL.updateById( - existingMembership.id, - { - isActive: data.isActive - }, - tx - ); + const doc = + typeof data?.isActive === "undefined" + ? existingMembership + : await membershipUserDAL.updateById( + existingMembership.id, + { + isActive: data.isActive + }, + tx + ); const roleDocs: TMembershipRolesInsert[] = []; data.roles.forEach((membershipRole) => { diff --git a/backend/src/services/membership-user/org/org-membership-user-factory.ts b/backend/src/services/membership-user/org/org-membership-user-factory.ts index 34f6784ff..523e85bae 100644 --- a/backend/src/services/membership-user/org/org-membership-user-factory.ts +++ b/backend/src/services/membership-user/org/org-membership-user-factory.ts @@ -105,10 +105,12 @@ export const newOrgMembershipUserFactory = ({ }); if (el.email) { - signUpTokens.push({ - email: el.email, - link: `${appCfg.SITE_URL}/signupinvite?token=${token}&to=${el.email}&organization_id=${dto.permission.orgId}` - }); + if (!appCfg.isSmtpConfigured) { + signUpTokens.push({ + email: el.email, + link: `${appCfg.SITE_URL}/signupinvite?token=${token}&to=${el.email}&organization_id=${dto.permission.orgId}` + }); + } await smtpService.sendMail({ template: SmtpTemplates.OrgInvite, diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 3dd443cb8..180ae4733 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -779,16 +779,20 @@ export const orgServiceFactory = ({ userRoleId = customRole.id; } const membership = await orgDAL.transaction(async (tx) => { - const [updatedOrgMembership] = await orgDAL.updateMembership( - { id: membershipId, scopeOrgId: orgId }, - { isActive }, - tx - ); + // this is because if isActive is undefined then this would fail due to knexjs error + const [updatedOrgMembership] = + typeof isActive === "undefined" + ? [foundMembership] + : await orgDAL.updateMembership( + { id: membershipId, scopeOrgId: orgId, scope: AccessScope.Organization }, + { isActive }, + tx + ); if (userRole) { - await membershipRoleDAL.delete({ membershipId: updatedOrgMembership.id }, tx); + await membershipRoleDAL.delete({ membershipId }, tx); await membershipRoleDAL.create( { - membershipId: updatedOrgMembership.id, + membershipId, role: userRole, customRoleId: userRoleId }, diff --git a/frontend/src/hooks/api/roles/queries.tsx b/frontend/src/hooks/api/roles/queries.tsx index 4d4feef99..4ccde1c8d 100644 --- a/frontend/src/hooks/api/roles/queries.tsx +++ b/frontend/src/hooks/api/roles/queries.tsx @@ -78,7 +78,7 @@ export const useGetProjectRoleBySlug = (projectId: string, roleSlug: string) => const getOrgRoles = async (orgId: string) => { const { data } = await apiRequest.get<{ - data: { roles: Array & { permissions: unknown }> }; + data: { roles: Array & { permissions: TPermission[] }> }; }>(`/api/v1/organization/${orgId}/roles`); return data.data.roles; }; diff --git a/frontend/src/hooks/api/users/queries.tsx b/frontend/src/hooks/api/users/queries.tsx index 9c2d00b05..8b3593d86 100644 --- a/frontend/src/hooks/api/users/queries.tsx +++ b/frontend/src/hooks/api/users/queries.tsx @@ -190,20 +190,11 @@ export const useAddUsersToOrg = () => { mutationFn: (dto) => { return apiRequest.post("/api/v1/invite-org/signup", dto); }, - onSuccess: (_, { organizationId, projects }) => { + onSuccess: (_, { organizationId }) => { queryClient.invalidateQueries({ queryKey: userKeys.getOrgUsers(organizationId) }); queryClient.invalidateQueries({ queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId) }); - - projects?.forEach((project) => { - if (project.slug) { - queryClient.invalidateQueries({ - queryKey: projectKeys.getProjectGroupMemberships(project.slug) - }); - } - queryClient.invalidateQueries({ queryKey: projectKeys.getProjectUsers(project.id) }); - }); } }); }; diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index 247fd828d..c48b1037b 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -167,9 +167,6 @@ export type AddUserToOrgDTO = { inviteeEmails: string[]; organizationRoleSlug: string; organizationId: string; - - // We need the slug in order to invalidate the groups query. `slug` is only used for invalidation purposes. - projects?: { id: string; slug?: string; projectRoleSlug: string[] }[]; }; export type CreateAPIKeyRes = { diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx index c1c9f0b0a..d7a151e7f 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx @@ -19,6 +19,7 @@ import { useOrganization } from "@app/context"; import { findOrgMembershipRole } from "@app/helpers/roles"; import { useAddUsersToOrg, + useAddUserToWsNonE2EE, useFetchServerStatus, useGetOrgRoles, useGetUserProjects @@ -76,6 +77,7 @@ export const AddOrgMemberModal = ({ const { data: organizationRoles } = useGetOrgRoles(currentOrg?.id ?? ""); const { data: serverDetails } = useFetchServerStatus(); const { mutateAsync: addUsersMutateAsync } = useAddUsersToOrg(); + const { mutateAsync: addUserToProject } = useAddUserToWsNonE2EE(); const { data: projects, isPending: isProjectsLoading } = useGetUserProjects({ includeRoles: true }); @@ -140,13 +142,24 @@ export const AddOrgMemberModal = ({ return; } + const usernames = emails.split(",").map((email) => email.trim()); const { data } = await addUsersMutateAsync({ organizationId: currentOrg?.id, - inviteeEmails: emails.split(",").map((email) => email.trim()), - organizationRoleSlug: organizationRole.slug, - projects: selectedProjects.map(({ id }) => ({ id, projectRoleSlug: [projectRoleSlug] })) + inviteeEmails: usernames, + organizationRoleSlug: organizationRole.slug }); + await Promise.allSettled( + selectedProjects.map((el) => + addUserToProject({ + orgId: currentOrg.id, + projectId: el.id, + roleSlugs: [projectRoleSlug], + usernames + }) + ) + ); + setCompleteInviteLinks(data?.completeInviteLinks ?? null); // only show this notification when email is configured. diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx index cdf49cf12..cd9d76779 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx @@ -26,6 +26,7 @@ import { } from "@app/context"; import { useAddUsersToOrg, + useAddUserToWsNonE2EE, useGetOrgUsers, useGetProjectRoles, useGetWorkspaceUsers @@ -85,7 +86,8 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { defaultValues: { orgMemberships: [], projectRoleSlugs: [] } }); - const { mutateAsync: addMembersToProject } = useAddUsersToOrg(); + const { mutateAsync: addMemberToOrg } = useAddUsersToOrg(); + const { mutateAsync: addUserToProject } = useAddUserToWsNonE2EE(); useEffect(() => { if (requesterEmail) { @@ -139,18 +141,19 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { return; } - if (inviteeEmails.length || newInvitees.length) { - await addMembersToProject({ - inviteeEmails: [...inviteeEmails, ...newInvitees], + if (newInvitees.length) { + await addMemberToOrg({ + inviteeEmails: newInvitees, organizationId: orgId, - organizationRoleSlug: ProjectMembershipRole.Member, // only applies to new invites - projects: [ - { - slug: currentProject.slug, - id: currentProject.id, - projectRoleSlug: projectRoleSlugs.map((role) => role.slug) - } - ] + organizationRoleSlug: ProjectMembershipRole.Member // only applies to new invites + }); + } + if (newInvitees.length || inviteeEmails.length) { + await addUserToProject({ + usernames: [...inviteeEmails, ...newInvitees], + orgId, + projectId: currentProject.id, + roleSlugs: projectRoleSlugs.map((role) => role.slug) }); } }