From ab43031375c05a2142480dacfddc049eeaf751b4 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Wed, 19 Aug 2026 21:46:01 +0100 Subject: [PATCH] fix race issue --- .../space/services/space-member.service.ts | 32 +++++++++++++------ .../database/repos/space/space-member.repo.ts | 13 ++++++-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/apps/server/src/core/space/services/space-member.service.ts b/apps/server/src/core/space/services/space-member.service.ts index bc280f252..e9b836f1f 100644 --- a/apps/server/src/core/space/services/space-member.service.ts +++ b/apps/server/src/core/space/services/space-member.service.ts @@ -339,15 +339,25 @@ export class SpaceMemberService { return; } - if (spaceMember.role === SpaceRole.ADMIN) { - await this.validateLastAdmin(dto.spaceId); - } + await executeTx(this.db, async (trx) => { + await trx + .selectFrom('spaces') + .select('id') + .where('id', '=', dto.spaceId) + .forUpdate() + .executeTakeFirst(); - await this.spaceMemberRepo.updateSpaceMember( - { role: dto.role }, - spaceMember.id, - dto.spaceId, - ); + if (spaceMember.role === SpaceRole.ADMIN) { + await this.validateLastAdmin(dto.spaceId, trx); + } + + await this.spaceMemberRepo.updateSpaceMember( + { role: dto.role }, + spaceMember.id, + dto.spaceId, + trx, + ); + }); this.auditService.log({ event: AuditEvent.SPACE_MEMBER_ROLE_CHANGED, @@ -368,10 +378,14 @@ export class SpaceMemberService { }); } - async validateLastAdmin(spaceId: string): Promise { + async validateLastAdmin( + spaceId: string, + trx?: KyselyTransaction, + ): Promise { const spaceOwnerCount = await this.spaceMemberRepo.roleCountBySpaceId( SpaceRole.ADMIN, spaceId, + trx, ); if (spaceOwnerCount === 1) { throw new BadRequestException( diff --git a/apps/server/src/database/repos/space/space-member.repo.ts b/apps/server/src/database/repos/space/space-member.repo.ts index 6711c30c7..d6172e282 100644 --- a/apps/server/src/database/repos/space/space-member.repo.ts +++ b/apps/server/src/database/repos/space/space-member.repo.ts @@ -46,8 +46,10 @@ export class SpaceMemberRepo { updatableSpaceMember: UpdatableSpaceMember, spaceMemberId: string, spaceId: string, + trx?: KyselyTransaction, ): Promise { - await this.db + const db = dbOrTx(this.db, trx); + await db .updateTable('spaceMembers') .set(updatableSpaceMember) .where('id', '=', spaceMemberId) @@ -92,8 +94,13 @@ export class SpaceMemberRepo { .execute(); } - async roleCountBySpaceId(role: string, spaceId: string): Promise { - const { count } = await this.db + async roleCountBySpaceId( + role: string, + spaceId: string, + trx?: KyselyTransaction, + ): Promise { + const db = dbOrTx(this.db, trx); + const { count } = await db .selectFrom('spaceMembers') .select((eb) => eb.fn.count('role').as('count')) .where('role', '=', role)