diff --git a/packages/features/bookings/lib/payment/handleNoShowFee.test.ts b/packages/features/bookings/lib/payment/handleNoShowFee.test.ts index a9bb6d6cd7..9361ad59c7 100644 --- a/packages/features/bookings/lib/payment/handleNoShowFee.test.ts +++ b/packages/features/bookings/lib/payment/handleNoShowFee.test.ts @@ -4,7 +4,6 @@ import { PaymentServiceMap } from "@calcom/app-store/payment.services.generated" import { sendNoShowFeeChargedEmail } from "@calcom/emails/billing-email-service"; import { CredentialRepository } from "@calcom/features/credentials/repositories/CredentialRepository"; import { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository"; -import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; import { ErrorCode } from "@calcom/lib/errorCodes"; import { ErrorWithCode } from "@calcom/lib/errors"; import { getTranslation } from "@calcom/lib/server/i18n"; @@ -14,9 +13,11 @@ import { handleNoShowFee } from "./handleNoShowFee"; vi.mock("@calcom/app-store/payment.services.generated", () => ({ PaymentServiceMap: { stripepayment: Promise.resolve({ - PaymentService: vi.fn().mockImplementation(function() { return { - chargeCard: vi.fn(), - }; }), + PaymentService: vi.fn().mockImplementation(function () { + return { + chargeCard: vi.fn(), + }; + }), }), }, })); @@ -36,10 +37,18 @@ vi.mock("@calcom/features/credentials/repositories/CredentialRepository", () => }, })); +const { mockFindUniqueByUserIdAndTeamId, MockMembershipRepository } = vi.hoisted(() => { + const mockFindUniqueByUserIdAndTeamId = vi.fn(); + + class MockMembershipRepository { + findUniqueByUserIdAndTeamId = mockFindUniqueByUserIdAndTeamId; + } + + return { mockFindUniqueByUserIdAndTeamId, MockMembershipRepository }; +}); + vi.mock("@calcom/features/membership/repositories/MembershipRepository", () => ({ - MembershipRepository: { - findUniqueByUserIdAndTeamId: vi.fn(), - }, + MembershipRepository: MockMembershipRepository, })); vi.mock("@calcom/features/ee/teams/repositories/TeamRepository", () => ({ @@ -154,7 +163,7 @@ describe("handleNoShowFee", () => { mockPaymentService.chargeCard.mockResolvedValue({ success: true, paymentId: "pay_123" }); - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ id: 1, userId: 1, teamId: 1, @@ -175,7 +184,7 @@ describe("handleNoShowFee", () => { }); expect(result).toEqual({ success: true, paymentId: "pay_123" }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ + expect(mockFindUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ userId: 1, teamId: 1, }); @@ -192,7 +201,7 @@ describe("handleNoShowFee", () => { mockPaymentService.chargeCard.mockResolvedValue({ success: true, paymentId: "pay_123" }); - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ id: 1, userId: 1, teamId: 1, @@ -251,7 +260,7 @@ describe("handleNoShowFee", () => { }, }; - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue(null); + mockFindUniqueByUserIdAndTeamId.mockResolvedValue(null); await expect( handleNoShowFee({ diff --git a/packages/features/bookings/lib/payment/handleNoShowFee.ts b/packages/features/bookings/lib/payment/handleNoShowFee.ts index 58bae570b3..dbe965ac62 100644 --- a/packages/features/bookings/lib/payment/handleNoShowFee.ts +++ b/packages/features/bookings/lib/payment/handleNoShowFee.ts @@ -104,7 +104,8 @@ export const handleNoShowFee = async ({ }; if (teamId) { - const userIsInTeam = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const membershipRepository = new MembershipRepository(); + const userIsInTeam = await membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId, }); diff --git a/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.test.ts b/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.test.ts index d18078b111..db8c9d55f4 100644 --- a/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.test.ts +++ b/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.test.ts @@ -1,16 +1,23 @@ import { describe, expect, it, vi, beforeEach } from "vitest"; -import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; import type { Payment } from "@calcom/prisma/client"; import { handleNoShowFee } from "./handleNoShowFee"; import { processNoShowFeeOnCancellation } from "./processNoShowFeeOnCancellation"; import { shouldChargeNoShowCancellationFee } from "./shouldChargeNoShowCancellationFee"; +const { mockFindUniqueByUserIdAndTeamId, MockMembershipRepository } = vi.hoisted(() => { + const mockFindUniqueByUserIdAndTeamId = vi.fn(); + + class MockMembershipRepository { + findUniqueByUserIdAndTeamId = mockFindUniqueByUserIdAndTeamId; + } + + return { mockFindUniqueByUserIdAndTeamId, MockMembershipRepository }; +}); + vi.mock("@calcom/features/membership/repositories/MembershipRepository", () => ({ - MembershipRepository: { - findUniqueByUserIdAndTeamId: vi.fn(), - }, + MembershipRepository: MockMembershipRepository, })); vi.mock("./handleNoShowFee", () => ({ @@ -165,7 +172,7 @@ describe("processNoShowFeeOnCancellation", () => { }, }; - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ id: 1, userId: 999, teamId: 1, @@ -183,7 +190,7 @@ describe("processNoShowFeeOnCancellation", () => { cancelledByUserId: 999, }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ + expect(mockFindUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ userId: 999, teamId: 1, }); @@ -200,7 +207,7 @@ describe("processNoShowFeeOnCancellation", () => { }, }; - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ id: 1, userId: 999, teamId: 1, @@ -231,7 +238,7 @@ describe("processNoShowFeeOnCancellation", () => { }, }; - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ id: 1, userId: 999, teamId: 1, @@ -264,7 +271,7 @@ describe("processNoShowFeeOnCancellation", () => { cancelledByUserId: 999, }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ + expect(mockFindUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ userId: 999, teamId: 1, }); @@ -281,7 +288,7 @@ describe("processNoShowFeeOnCancellation", () => { }, }; - vi.mocked(MembershipRepository.findUniqueByUserIdAndTeamId).mockResolvedValue(null); + mockFindUniqueByUserIdAndTeamId.mockResolvedValue(null); vi.mocked(shouldChargeNoShowCancellationFee).mockReturnValue(true); vi.mocked(handleNoShowFee).mockResolvedValue({ id: 999, diff --git a/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.ts b/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.ts index 151aa7256a..a4c47ecb1a 100644 --- a/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.ts +++ b/packages/features/bookings/lib/payment/processNoShowFeeOnCancellation.ts @@ -28,7 +28,8 @@ export const processNoShowFeeOnCancellation = async ({ // Skip no-show fee if the booking was cancelled by a team/org admin if (cancelledByUserId && booking.eventType?.teamId) { - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const membershipRepository = new MembershipRepository(); + const membership = await membershipRepository.findUniqueByUserIdAndTeamId({ userId: cancelledByUserId, teamId: booking.eventType.teamId, }); diff --git a/packages/features/ee/dsync/lib/assignValueToUser.ts b/packages/features/ee/dsync/lib/assignValueToUser.ts index 5120212f4d..6fe52ebf90 100644 --- a/packages/features/ee/dsync/lib/assignValueToUser.ts +++ b/packages/features/ee/dsync/lib/assignValueToUser.ts @@ -424,7 +424,8 @@ export const assignValueToUserInOrgBulk = async ({ attributeLabelToValueMap: AttributeLabelToValueMap; updater: BulkAttributeAssigner; }) => { - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId: orgId }); + const membershipRepository = new MembershipRepository(); + const membership = await membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId: orgId }); const defaultReturn = { numOfAttributeOptionsSet: 0, numOfAttributeOptionsDeleted: 0 }; if (!membership) { console.error(`User ${userId} not a member of org ${orgId}, not assigning attribute options`); diff --git a/packages/features/membership/repositories/MembershipRepository.ts b/packages/features/membership/repositories/MembershipRepository.ts index b5c8b82272..89b7351337 100644 --- a/packages/features/membership/repositories/MembershipRepository.ts +++ b/packages/features/membership/repositories/MembershipRepository.ts @@ -329,8 +329,8 @@ export class MembershipRepository { }); } - static async findUniqueByUserIdAndTeamId({ userId, teamId }: { userId: number; teamId: number }) { - return await prisma.membership.findUnique({ + async findUniqueByUserIdAndTeamId({ userId, teamId }: { userId: number; teamId: number }) { + return await this.prismaClient.membership.findUnique({ where: { userId_teamId: { userId, diff --git a/packages/features/membership/services/membershipService.ts b/packages/features/membership/services/membershipService.ts index 20ecd6a5d3..33c24ec26f 100644 --- a/packages/features/membership/services/membershipService.ts +++ b/packages/features/membership/services/membershipService.ts @@ -15,7 +15,7 @@ export class MembershipService { * Checks the membership status of a user within a specific team. */ async checkMembership(teamId: number, userId: number): Promise { - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ teamId, userId }); + const membership = await this.membershipRepository.findUniqueByUserIdAndTeamId({ teamId, userId }); if (!membership || !membership.accepted) { return { diff --git a/packages/features/pbac/lib/resource-permissions.ts b/packages/features/pbac/lib/resource-permissions.ts index f68e690cbc..5d87bea2dd 100644 --- a/packages/features/pbac/lib/resource-permissions.ts +++ b/packages/features/pbac/lib/resource-permissions.ts @@ -166,7 +166,8 @@ export async function getRoutingFormPermissions({ }; } - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const membershipRepository = new MembershipRepository(); + const membership = await membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId: formTeamId, }); diff --git a/packages/features/pbac/services/__tests__/permission-check.service.test.ts b/packages/features/pbac/services/__tests__/permission-check.service.test.ts index 4989fa24c0..f09451fba5 100644 --- a/packages/features/pbac/services/__tests__/permission-check.service.test.ts +++ b/packages/features/pbac/services/__tests__/permission-check.service.test.ts @@ -30,6 +30,7 @@ describe("PermissionCheckService", () => { let mockRepository: MockRepository; let mockFeaturesRepository: { checkIfTeamHasFeature: Mock }; let mockPermissionService: { validatePermission: Mock; validatePermissions: Mock }; + let mockMembershipRepository: { findUniqueByUserIdAndTeamId: Mock }; beforeEach(() => { vi.clearAllMocks(); @@ -56,14 +57,16 @@ describe("PermissionCheckService", () => { validatePermissions: vi.fn().mockReturnValue({ isValid: true }), }; + mockMembershipRepository = { + findUniqueByUserIdAndTeamId: vi.fn(), + }; + service = new PermissionCheckService( mockRepository, mockFeaturesRepository as unknown as FeaturesRepository, - mockPermissionService as unknown as PermissionService + mockPermissionService as unknown as PermissionService, + mockMembershipRepository as unknown as MembershipRepository ); - - // Mock MembershipRepository static method - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock) = vi.fn(); }); describe("checkPermission", () => { @@ -104,7 +107,7 @@ describe("PermissionCheckService", () => { updatedAt: new Date(), }; - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock).mockResolvedValueOnce(membership); + mockMembershipRepository.findUniqueByUserIdAndTeamId.mockResolvedValueOnce(membership); mockFeaturesRepository.checkIfTeamHasFeature.mockResolvedValueOnce(false); const result = await service.checkPermission({ @@ -115,7 +118,7 @@ describe("PermissionCheckService", () => { }); expect(result).toBe(true); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ userId: 1, teamId: 1, }); @@ -125,7 +128,7 @@ describe("PermissionCheckService", () => { it("should return false if no team or org membership found when PBAC disabled", async () => { mockFeaturesRepository.checkIfTeamHasFeature.mockResolvedValueOnce(false); - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock).mockResolvedValue(null); + mockMembershipRepository.findUniqueByUserIdAndTeamId.mockResolvedValue(null); mockRepository.getTeamById.mockResolvedValueOnce({ id: 1, parentId: 100 }); const result = await service.checkPermission({ @@ -136,7 +139,7 @@ describe("PermissionCheckService", () => { }); expect(result).toBe(false); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledTimes(2); + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledTimes(2); }); it("should use org membership when team membership not found (PBAC disabled)", async () => { @@ -153,7 +156,7 @@ describe("PermissionCheckService", () => { }; mockFeaturesRepository.checkIfTeamHasFeature.mockResolvedValueOnce(false); - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock) + mockMembershipRepository.findUniqueByUserIdAndTeamId .mockResolvedValueOnce(null) // No team membership .mockResolvedValueOnce(orgMembership); // Has org membership mockRepository.getTeamById.mockResolvedValueOnce({ id: 1, parentId: 100 }); @@ -167,11 +170,11 @@ describe("PermissionCheckService", () => { expect(result).toBe(true); expect(mockRepository.getTeamById).toHaveBeenCalledWith(1); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(1, { + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(1, { userId: 1, teamId: 1, }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(2, { + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(2, { userId: 1, teamId: 100, }); @@ -203,7 +206,7 @@ describe("PermissionCheckService", () => { }; mockFeaturesRepository.checkIfTeamHasFeature.mockResolvedValueOnce(false); - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock) + mockMembershipRepository.findUniqueByUserIdAndTeamId .mockResolvedValueOnce(teamMembership) // Has team membership as MEMBER .mockResolvedValueOnce(orgMembership); // Has org membership as ADMIN mockRepository.getTeamById.mockResolvedValueOnce({ id: 1, parentId: 100 }); @@ -217,11 +220,11 @@ describe("PermissionCheckService", () => { expect(result).toBe(true); expect(mockRepository.getTeamById).toHaveBeenCalledWith(1); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(1, { + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(1, { userId: 1, teamId: 1, }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(2, { + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(2, { userId: 1, teamId: 100, }); @@ -362,7 +365,7 @@ describe("PermissionCheckService", () => { updatedAt: new Date(), }; - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock).mockResolvedValueOnce(membership); + mockMembershipRepository.findUniqueByUserIdAndTeamId.mockResolvedValueOnce(membership); mockFeaturesRepository.checkIfTeamHasFeature.mockResolvedValueOnce(false); const result = await service.checkPermissions({ @@ -373,7 +376,7 @@ describe("PermissionCheckService", () => { }); expect(result).toBe(true); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ userId: 1, teamId: 1, }); @@ -395,7 +398,7 @@ describe("PermissionCheckService", () => { }; mockFeaturesRepository.checkIfTeamHasFeature.mockResolvedValueOnce(false); - (MembershipRepository.findUniqueByUserIdAndTeamId as Mock) + mockMembershipRepository.findUniqueByUserIdAndTeamId .mockResolvedValueOnce(null) // No team membership .mockResolvedValueOnce(orgMembership); // Has org membership mockRepository.getTeamById.mockResolvedValueOnce({ id: 1, parentId: 100 }); @@ -409,11 +412,11 @@ describe("PermissionCheckService", () => { expect(result).toBe(true); expect(mockRepository.getTeamById).toHaveBeenCalledWith(1); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(1, { + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(1, { userId: 1, teamId: 1, }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(2, { + expect(mockMembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenNthCalledWith(2, { userId: 1, teamId: 100, }); diff --git a/packages/features/pbac/services/permission-check.service.ts b/packages/features/pbac/services/permission-check.service.ts index 84bdc89d17..8ddd7ce564 100644 --- a/packages/features/pbac/services/permission-check.service.ts +++ b/packages/features/pbac/services/permission-check.service.ts @@ -21,14 +21,17 @@ export class PermissionCheckService { private readonly logger = logger.getSubLogger({ prefix: ["PermissionCheckService"] }); private readonly featuresRepository: FeaturesRepository; private readonly permissionService: PermissionService; + private readonly membershipRepository: MembershipRepository; constructor( private readonly repository: IPermissionRepository = new PermissionRepository(), featuresRepository: FeaturesRepository = new FeaturesRepository(prisma), - permissionService: PermissionService = new PermissionService() + permissionService: PermissionService = new PermissionService(), + membershipRepository: MembershipRepository = new MembershipRepository() ) { this.featuresRepository = featuresRepository; this.permissionService = permissionService; + this.membershipRepository = membershipRepository; } async getUserPermissions(userId: number): Promise { @@ -119,7 +122,7 @@ export class PermissionCheckService { } // Fallback to role-based check - use highest role between team and org membership - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const membership = await this.membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId, }); @@ -129,7 +132,7 @@ export class PermissionCheckService { // Check if team has parent org and get org membership const team = await this.repository.getTeamById(teamId); if (team?.parentId) { - const orgMembership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const orgMembership = await this.membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId: team.parentId, }); @@ -183,7 +186,7 @@ export class PermissionCheckService { } // Fallback to role-based check - use highest role between team and org membership - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const membership = await this.membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId, }); @@ -193,7 +196,7 @@ export class PermissionCheckService { // Check if team has parent org and get org membership const team = await this.repository.getTeamById(teamId); if (team?.parentId) { - const orgMembership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const orgMembership = await this.membershipRepository.findUniqueByUserIdAndTeamId({ userId, teamId: team.parentId, }); diff --git a/packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.handler.ts b/packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.handler.ts index 5e863aabd1..fd66164ac7 100644 --- a/packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.handler.ts @@ -19,7 +19,8 @@ export default async function getAttributesForTeamHandler({ }: GetAttributesForTeamHandlerOptions) { const { teamId } = input; const { user } = ctx; - const isMemberOfTeam = await MembershipRepository.findUniqueByUserIdAndTeamId({ userId: user.id, teamId }); + const membershipRepository = new MembershipRepository(); + const isMemberOfTeam = await membershipRepository.findUniqueByUserIdAndTeamId({ userId: user.id, teamId }); if (!isMemberOfTeam) { throw new TRPCError({ diff --git a/packages/trpc/server/routers/viewer/eventTypes/__tests__/getUserEventGroups.test.ts b/packages/trpc/server/routers/viewer/eventTypes/__tests__/getUserEventGroups.test.ts index 9576494661..449a50db5a 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/__tests__/getUserEventGroups.test.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/__tests__/getUserEventGroups.test.ts @@ -12,10 +12,20 @@ vi.mock("@calcom/lib/checkRateLimitAndThrowError", () => ({ checkRateLimitAndThrowError: vi.fn(), })); +const { mockFindAllByUpIdIncludeTeam, MockMembershipRepository } = vi.hoisted(() => { + const mockFindAllByUpIdIncludeTeam = vi.fn(); + const mockFindUniqueByUserIdAndTeamId = vi.fn(); + + class MockMembershipRepository { + static findAllByUpIdIncludeTeam = mockFindAllByUpIdIncludeTeam; + findUniqueByUserIdAndTeamId = mockFindUniqueByUserIdAndTeamId; + } + + return { mockFindAllByUpIdIncludeTeam, MockMembershipRepository }; +}); + vi.mock("@calcom/features/membership/repositories/MembershipRepository", () => ({ - MembershipRepository: { - findAllByUpIdIncludeTeam: vi.fn(), - }, + MembershipRepository: MockMembershipRepository, })); vi.mock("@calcom/features/profile/repositories/ProfileRepository", () => ({ @@ -99,12 +109,9 @@ describe("getUserEventGroups", () => { it("should return user event groups when no filters are applied", async () => { const { ProfileRepository } = await import("@calcom/features/profile/repositories/ProfileRepository"); - const { MembershipRepository } = await import( - "@calcom/features/membership/repositories/MembershipRepository" - ); vi.mocked(ProfileRepository.findByUpIdWithAuth).mockResolvedValue(mockProfile); - vi.mocked(MembershipRepository.findAllByUpIdIncludeTeam).mockResolvedValue([]); + mockFindAllByUpIdIncludeTeam.mockResolvedValue([]); mockFilterTeamsByEventTypeReadPermission.mockResolvedValue([]); const result = await getUserEventGroups({ @@ -129,9 +136,6 @@ describe("getUserEventGroups", () => { describe("Team memberships", () => { it("should include team events when team memberships exist", async () => { const { ProfileRepository } = await import("@calcom/features/profile/repositories/ProfileRepository"); - const { MembershipRepository } = await import( - "@calcom/features/membership/repositories/MembershipRepository" - ); const { getResourcePermissions } = await import("@calcom/features/pbac/lib/resource-permissions"); const mockTeamMembership = { @@ -162,7 +166,7 @@ describe("getUserEventGroups", () => { >[0]; vi.mocked(ProfileRepository.findByUpIdWithAuth).mockResolvedValue(mockProfile); - vi.mocked(MembershipRepository.findAllByUpIdIncludeTeam).mockResolvedValue([mockTeamMembership]); + mockFindAllByUpIdIncludeTeam.mockResolvedValue([mockTeamMembership]); mockFilterTeamsByEventTypeReadPermission.mockResolvedValue([mockTeamMembership]); vi.mocked(getResourcePermissions).mockResolvedValue({ @@ -191,9 +195,6 @@ describe("getUserEventGroups", () => { describe("Permissions", () => { it("should handle PBAC permissions correctly", async () => { const { ProfileRepository } = await import("@calcom/features/profile/repositories/ProfileRepository"); - const { MembershipRepository } = await import( - "@calcom/features/membership/repositories/MembershipRepository" - ); const { getResourcePermissions } = await import("@calcom/features/pbac/lib/resource-permissions"); const mockTeamMembership = { @@ -224,7 +225,7 @@ describe("getUserEventGroups", () => { >[0]; vi.mocked(ProfileRepository.findByUpIdWithAuth).mockResolvedValue(mockProfile); - vi.mocked(MembershipRepository.findAllByUpIdIncludeTeam).mockResolvedValue([mockTeamMembership]); + mockFindAllByUpIdIncludeTeam.mockResolvedValue([mockTeamMembership]); mockFilterTeamsByEventTypeReadPermission.mockResolvedValue([mockTeamMembership]); vi.mocked(getResourcePermissions).mockResolvedValue({ @@ -247,9 +248,6 @@ describe("getUserEventGroups", () => { it("should fallback to role-based permissions when PBAC fails", async () => { const { ProfileRepository } = await import("@calcom/features/profile/repositories/ProfileRepository"); - const { MembershipRepository } = await import( - "@calcom/features/membership/repositories/MembershipRepository" - ); const { getResourcePermissions } = await import("@calcom/features/pbac/lib/resource-permissions"); const mockTeamMembership = { @@ -280,7 +278,7 @@ describe("getUserEventGroups", () => { >[0]; vi.mocked(ProfileRepository.findByUpIdWithAuth).mockResolvedValue(mockProfile); - vi.mocked(MembershipRepository.findAllByUpIdIncludeTeam).mockResolvedValue([mockTeamMembership]); + mockFindAllByUpIdIncludeTeam.mockResolvedValue([mockTeamMembership]); mockFilterTeamsByEventTypeReadPermission.mockResolvedValue([mockTeamMembership]); vi.mocked(getResourcePermissions).mockRejectedValue(new Error("PBAC failed")); @@ -301,9 +299,6 @@ describe("getUserEventGroups", () => { describe("Organization handling", () => { it("should handle organization locked event types", async () => { const { ProfileRepository } = await import("@calcom/features/profile/repositories/ProfileRepository"); - const { MembershipRepository } = await import( - "@calcom/features/membership/repositories/MembershipRepository" - ); const mockProfileWithOrg = { ...mockProfile, @@ -321,7 +316,7 @@ describe("getUserEventGroups", () => { >; vi.mocked(ProfileRepository.findByUpIdWithAuth).mockResolvedValue(mockProfileWithOrg); - vi.mocked(MembershipRepository.findAllByUpIdIncludeTeam).mockResolvedValue([]); + mockFindAllByUpIdIncludeTeam.mockResolvedValue([]); mockFilterTeamsByEventTypeReadPermission.mockResolvedValue([]); const result = await getUserEventGroups({ @@ -336,9 +331,6 @@ describe("getUserEventGroups", () => { describe("Routing forms", () => { it("should handle routing forms slug format", async () => { const { ProfileRepository } = await import("@calcom/features/profile/repositories/ProfileRepository"); - const { MembershipRepository } = await import( - "@calcom/features/membership/repositories/MembershipRepository" - ); const { getResourcePermissions } = await import("@calcom/features/pbac/lib/resource-permissions"); const mockTeamMembership = { @@ -369,7 +361,7 @@ describe("getUserEventGroups", () => { >[0]; vi.mocked(ProfileRepository.findByUpIdWithAuth).mockResolvedValue(mockProfile); - vi.mocked(MembershipRepository.findAllByUpIdIncludeTeam).mockResolvedValue([mockTeamMembership]); + mockFindAllByUpIdIncludeTeam.mockResolvedValue([mockTeamMembership]); mockFilterTeamsByEventTypeReadPermission.mockResolvedValue([mockTeamMembership]); vi.mocked(getResourcePermissions).mockResolvedValue({ diff --git a/packages/trpc/server/routers/viewer/teams/get.handler.test.ts b/packages/trpc/server/routers/viewer/teams/get.handler.test.ts index 282007fb6d..85fd64dfa5 100644 --- a/packages/trpc/server/routers/viewer/teams/get.handler.test.ts +++ b/packages/trpc/server/routers/viewer/teams/get.handler.test.ts @@ -1,15 +1,22 @@ import { describe, it, beforeEach, vi, expect } from "vitest"; import { getTeamWithoutMembers } from "@calcom/features/ee/teams/lib/queries"; -import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; import type { TrpcSessionUser } from "../../../types"; import getTeam from "./get.handler"; +const { mockFindUniqueByUserIdAndTeamId, MockMembershipRepository } = vi.hoisted(() => { + const mockFindUniqueByUserIdAndTeamId = vi.fn(); + + class MockMembershipRepository { + findUniqueByUserIdAndTeamId = mockFindUniqueByUserIdAndTeamId; + } + + return { mockFindUniqueByUserIdAndTeamId, MockMembershipRepository }; +}); + vi.mock("@calcom/features/membership/repositories/MembershipRepository", () => ({ - MembershipRepository: { - findUniqueByUserIdAndTeamId: vi.fn(), - }, + MembershipRepository: MockMembershipRepository, })); vi.mock("@calcom/features/ee/teams/lib/queries", () => ({ @@ -33,7 +40,7 @@ describe("getTeam", () => { }); it("throws UNAUTHORIZED if user is not a member of the team", async () => { - (MembershipRepository.findUniqueByUserIdAndTeamId as any).mockResolvedValue(null); + mockFindUniqueByUserIdAndTeamId.mockResolvedValue(null); await expect(getTeam({ ctx: { user }, input })).rejects.toMatchObject({ code: "UNAUTHORIZED", @@ -42,7 +49,7 @@ describe("getTeam", () => { }); it("throws NOT_FOUND if team does not exist", async () => { - (MembershipRepository.findUniqueByUserIdAndTeamId as any).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ role: "member", accepted: true, }); @@ -60,7 +67,7 @@ describe("getTeam", () => { organization: { isOrgAdmin: true }, }; - (MembershipRepository.findUniqueByUserIdAndTeamId as any).mockResolvedValue({ + mockFindUniqueByUserIdAndTeamId.mockResolvedValue({ role: "admin", accepted: true, }); @@ -89,7 +96,7 @@ describe("getTeam", () => { description: "A team", }; - (MembershipRepository.findUniqueByUserIdAndTeamId as any).mockResolvedValue(membershipData); + mockFindUniqueByUserIdAndTeamId.mockResolvedValue(membershipData); (getTeamWithoutMembers as any).mockResolvedValue(teamData); const result = await getTeam({ ctx: { user }, input }); @@ -99,7 +106,7 @@ describe("getTeam", () => { membership: membershipData, }); - expect(MembershipRepository.findUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ + expect(mockFindUniqueByUserIdAndTeamId).toHaveBeenCalledWith({ userId: user.id, teamId: input.teamId, }); diff --git a/packages/trpc/server/routers/viewer/teams/get.handler.ts b/packages/trpc/server/routers/viewer/teams/get.handler.ts index 615fbd6cea..fa7303fef9 100644 --- a/packages/trpc/server/routers/viewer/teams/get.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/get.handler.ts @@ -14,7 +14,8 @@ type GetDataOptions = { }; export const get = async ({ ctx, input }: GetDataOptions) => { - const teamMembership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + const membershipRepository = new MembershipRepository(); + const teamMembership = await membershipRepository.findUniqueByUserIdAndTeamId({ userId: ctx.user.id, teamId: input.teamId, });