From 98e2be477bc033459336ad662b3d488563fb6f4a Mon Sep 17 00:00:00 2001 From: = Date: Thu, 23 Oct 2025 19:57:01 +0530 Subject: [PATCH] feat: completed scope service for membership --- .../membership-identity-service.ts | 3 ++- .../org/org-membership-identity-factory.ts | 13 ++++++++++++ .../project-membership-identity-factory.ts | 21 ++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/backend/src/services/membership-identity/membership-identity-service.ts b/backend/src/services/membership-identity/membership-identity-service.ts index 16292ea82..3f3eb6d6e 100644 --- a/backend/src/services/membership-identity/membership-identity-service.ts +++ b/backend/src/services/membership-identity/membership-identity-service.ts @@ -55,7 +55,8 @@ export const membershipIdentityServiceFactory = ({ [AccessScope.Project]: newProjectMembershipIdentityFactory({ membershipIdentityDAL, orgDAL, - permissionService + permissionService, + identityDAL }), [AccessScope.Namespace]: newNamespaceMembershipIdentityFactory({}) }; diff --git a/backend/src/services/membership-identity/org/org-membership-identity-factory.ts b/backend/src/services/membership-identity/org/org-membership-identity-factory.ts index 8b3bdf6d5..39bb32f8b 100644 --- a/backend/src/services/membership-identity/org/org-membership-identity-factory.ts +++ b/backend/src/services/membership-identity/org/org-membership-identity-factory.ts @@ -60,6 +60,10 @@ export const newOrgMembershipIdentityFactory = ({ throw new BadRequestError({ message: "Only identities from parent organization can be invited" }); } + if (identityDetails.projectId) { + throw new BadRequestError({ message: "Failed to create organization membership for a project scoped identity" }); + } + const permissionRoles = await permissionService.getOrgPermissionByRoles( dto.data.roles.map((el) => el.role), dto.permission.orgId @@ -129,6 +133,11 @@ export const newOrgMembershipIdentityFactory = ({ }); } } + + const identityDetails = await identityDAL.findById(dto.selector.identityId); + if (identityDetails.projectId) { + throw new BadRequestError({ message: "Failed to create organization membership for a project scoped identity" }); + } }; const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] = async ( @@ -153,6 +162,10 @@ export const newOrgMembershipIdentityFactory = ({ if (identityDetails.orgId === dto.permission.orgId) { throw new BadRequestError({ message: "Identity cannot exist as orphan" }); } + + if (identityDetails.projectId) { + throw new BadRequestError({ message: "Failed to create organization membership for a project scoped identity" }); + } }; const onListMembershipIdentityGuard: TMembershipIdentityScopeFactory["onListMembershipIdentityGuard"] = async ( diff --git a/backend/src/services/membership-identity/project/project-membership-identity-factory.ts b/backend/src/services/membership-identity/project/project-membership-identity-factory.ts index f2896047f..afbdecf0a 100644 --- a/backend/src/services/membership-identity/project/project-membership-identity-factory.ts +++ b/backend/src/services/membership-identity/project/project-membership-identity-factory.ts @@ -16,9 +16,12 @@ import { TOrgDALFactory } from "@app/services/org/org-dal"; import { TMembershipIdentityDALFactory } from "../membership-identity-dal"; import { TMembershipIdentityScopeFactory } from "../membership-identity-types"; +import { TIdentityDALFactory } from "@app/services/identity/identity-dal"; type TProjectMembershipIdentityScopeFactoryDep = { permissionService: Pick; + + identityDAL: Pick; orgDAL: Pick; membershipIdentityDAL: Pick; }; @@ -26,7 +29,8 @@ type TProjectMembershipIdentityScopeFactoryDep = { export const newProjectMembershipIdentityFactory = ({ permissionService, orgDAL, - membershipIdentityDAL + membershipIdentityDAL, + identityDAL }: TProjectMembershipIdentityScopeFactoryDep): TMembershipIdentityScopeFactory => { const getScopeField: TMembershipIdentityScopeFactory["getScopeField"] = (dto) => { if (dto.scope === AccessScope.Project) { @@ -68,6 +72,11 @@ export const newProjectMembershipIdentityFactory = ({ if (!orgMembership) throw new BadRequestError({ message: `Identity ${dto.data.identityId} is missing organization membership` }); + const identityDetails = await identityDAL.findById(dto.data.identityId); + if (identityDetails.projectId) { + throw new BadRequestError({ message: "Failed to create project membership for a project scoped identity" }); + } + const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(dto.permission.orgId); const permissionRoles = await permissionService.getProjectPermissionByRoles( dto.data.roles.map((el) => el.role), @@ -113,6 +122,11 @@ export const newProjectMembershipIdentityFactory = ({ ProjectPermissionSub.Identity ); + const identityDetails = await identityDAL.findById(dto.selector.identityId); + if (identityDetails.projectId && identityDetails.projectId !== scope.value) { + throw new BadRequestError({ message: "Failed to update project membership for a project scoped identity" }); + } + const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(dto.permission.orgId); const permissionRoles = await permissionService.getProjectPermissionByRoles( dto.data.roles.filter((el) => el.role !== ProjectMembershipRole.NoAccess).map((el) => el.role), @@ -156,6 +170,11 @@ export const newProjectMembershipIdentityFactory = ({ ProjectPermissionIdentityActions.Delete, ProjectPermissionSub.Identity ); + + const identityDetails = await identityDAL.findById(dto.selector.identityId); + if (identityDetails.projectId) { + throw new BadRequestError({ message: "Failed to delete project membership for a project scoped identity" }); + } }; const onListMembershipIdentityGuard: TMembershipIdentityScopeFactory["onListMembershipIdentityGuard"] = async (