From cc9cee39539e5e2ed7d5905f34033c8c979a0a1f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 4 Dec 2025 20:43:30 -0800 Subject: [PATCH] fix(additional-privileges): return correct project membership ID --- ...ity-project-additional-privilege-router.ts | 10 +- .../additional-privilege-service.ts | 112 +++++++++++++++++- 2 files changed, 111 insertions(+), 11 deletions(-) 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 47b3f5258..70ef9990e 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: req.body.projectId, + projectMembershipId: privilege.projectMembershipId || req.body.projectId, projectId: req.body.projectId, slug: privilege.name } @@ -168,7 +168,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: privilegeDoc.actorIdentityId as string, - projectMembershipId: privilegeDoc.projectId as string, + projectMembershipId: privilege.projectMembershipId || (privilegeDoc.projectId as string), projectId: privilegeDoc.projectId as string, slug: privilege.name } @@ -222,7 +222,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: privilegeDoc.actorIdentityId as string, - projectMembershipId: privilegeDoc.projectId as string, + projectMembershipId: privilege.projectMembershipId || (privilegeDoc.projectId as string), projectId: privilegeDoc.projectId as string, slug: privilege.name } @@ -276,7 +276,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privilege: { ...privilege, identityId: privilegeDoc.actorIdentityId as string, - projectMembershipId: privilegeDoc.projectId as string, + projectMembershipId: privilege.projectMembershipId || (privilegeDoc.projectId as string), projectId: privilegeDoc.projectId as string, slug: privilege.name } @@ -391,7 +391,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F privileges: privileges.map((privilege) => ({ ...privilege, identityId: req.query.identityId, - projectMembershipId: privilege.projectId as string, + projectMembershipId: privilege.projectMembershipId || (privilege.projectId as string), projectId: req.query.projectId, slug: privilege.name })) diff --git a/backend/src/services/additional-privilege/additional-privilege-service.ts b/backend/src/services/additional-privilege/additional-privilege-service.ts index 2af9e6419..7fa99b47a 100644 --- a/backend/src/services/additional-privilege/additional-privilege-service.ts +++ b/backend/src/services/additional-privilege/additional-privilege-service.ts @@ -58,6 +58,21 @@ export const additionalPrivilegeServiceFactory = ({ const scope = factory.getScopeField(dto.scopeData); const dbActorField = data.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; + let projectMembershipId: string | undefined; + if (scope.key === "projectId") { + const projectMembership = await membershipDAL.findOne({ + [dbActorField]: data.actorId, + scopeProjectId: scope.value, + scope: AccessScope.Project + }); + + if (!projectMembership) { + throw new NotFoundError({ message: `Project membership for ${data.actorType} ${data.actorId} not found` }); + } + + projectMembershipId = projectMembership.id; + } + const existingSlug = await additionalPrivilegeDAL.findOne({ name: data.name, [dbActorField]: data.actorId, @@ -79,7 +94,11 @@ export const additionalPrivilegeServiceFactory = ({ }); return { - additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) } + additionalPrivilege: { + ...additionalPrivilege, + permissions: unpackPermissions(additionalPrivilege.permissions), + projectMembershipId + } }; } @@ -103,7 +122,11 @@ export const additionalPrivilegeServiceFactory = ({ }); return { - additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) } + additionalPrivilege: { + ...additionalPrivilege, + permissions: unpackPermissions(additionalPrivilege.permissions), + projectMembershipId + } }; }; @@ -114,6 +137,21 @@ export const additionalPrivilegeServiceFactory = ({ const scope = factory.getScopeField(dto.scopeData); const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; + let projectMembershipId: string | undefined; + if (scope.key === "projectId") { + const projectMembership = await membershipDAL.findOne({ + [dbActorField]: dto.selector.actorId, + scopeProjectId: scope.value, + scope: AccessScope.Project + }); + if (!projectMembership) { + throw new NotFoundError({ + message: `Project membership for ${dto.selector.actorType} ${dto.selector.actorId} not found` + }); + } + projectMembershipId = projectMembership.id; + } + const existingPrivilege = await additionalPrivilegeDAL.findOne({ [dbActorField]: dto.selector.actorId, id: dto.selector.id, @@ -136,7 +174,11 @@ export const additionalPrivilegeServiceFactory = ({ }); return { - additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) } + additionalPrivilege: { + ...additionalPrivilege, + permissions: unpackPermissions(additionalPrivilege.permissions), + projectMembershipId + } }; } @@ -158,7 +200,11 @@ export const additionalPrivilegeServiceFactory = ({ }); return { - additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) } + additionalPrivilege: { + ...additionalPrivilege, + permissions: unpackPermissions(additionalPrivilege.permissions), + projectMembershipId + } }; }; @@ -169,6 +215,21 @@ export const additionalPrivilegeServiceFactory = ({ const scope = factory.getScopeField(dto.scopeData); const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; + let projectMembershipId: string | undefined; + if (scope.key === "projectId") { + const projectMembership = await membershipDAL.findOne({ + [dbActorField]: dto.selector.actorId, + scopeProjectId: scope.value, + scope: AccessScope.Project + }); + if (!projectMembership) { + throw new NotFoundError({ + message: `Project membership for ${dto.selector.actorType} ${dto.selector.actorId} not found` + }); + } + projectMembershipId = projectMembership.id; + } + const existingPrivilege = await additionalPrivilegeDAL.findOne({ id: selector.id, [dbActorField]: dto.selector.actorId, @@ -179,7 +240,11 @@ export const additionalPrivilegeServiceFactory = ({ const additionalPrivilege = await additionalPrivilegeDAL.deleteById(existingPrivilege.id); return { - additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) } + additionalPrivilege: { + ...additionalPrivilege, + permissions: unpackPermissions(additionalPrivilege.permissions), + projectMembershipId + } }; }; @@ -190,6 +255,21 @@ export const additionalPrivilegeServiceFactory = ({ const scope = factory.getScopeField(dto.scopeData); const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; + let projectMembershipId: string | undefined; + if (scope.key === "projectId") { + const projectMembership = await membershipDAL.findOne({ + [dbActorField]: dto.selector.actorId, + scopeProjectId: scope.value, + scope: AccessScope.Project + }); + if (!projectMembership) { + throw new NotFoundError({ + message: `Project membership for ${dto.selector.actorType} ${dto.selector.actorId} not found` + }); + } + projectMembershipId = projectMembership.id; + } + const additionalPrivilege = await additionalPrivilegeDAL.findOne({ id: selector.id, [dbActorField]: dto.selector.actorId, @@ -199,7 +279,11 @@ export const additionalPrivilegeServiceFactory = ({ throw new NotFoundError({ message: `Additional privilege with id ${selector.id} doesn't exist` }); return { - additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) } + additionalPrivilege: { + ...additionalPrivilege, + permissions: unpackPermissions(additionalPrivilege.permissions), + projectMembershipId + } }; }; @@ -230,6 +314,21 @@ export const additionalPrivilegeServiceFactory = ({ const scope = factory.getScopeField(dto.scopeData); const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; + let projectMembershipId: string | undefined; + if (scope.key === "projectId") { + const projectMembership = await membershipDAL.findOne({ + [dbActorField]: dto.selector.actorId, + scopeProjectId: scope.value, + scope: AccessScope.Project + }); + if (!projectMembership) { + throw new NotFoundError({ + message: `Project membership for ${dto.selector.actorType} ${dto.selector.actorId} not found` + }); + } + projectMembershipId = projectMembership.id; + } + const additionalPrivileges = await additionalPrivilegeDAL.find({ [dbActorField]: dto.selector.actorId, [scope.key]: scope.value @@ -238,6 +337,7 @@ export const additionalPrivilegeServiceFactory = ({ return { additionalPrivileges: additionalPrivileges.map((el) => ({ ...el, + projectMembershipId, permissions: unpackPermissions(el.permissions) })) };