refactor: Membership.findByUserIdAndTeamId to instance method (#26628)
* Make and instance method * Refactor files * fix: update MembershipRepository mocks to use vi.hoisted() for proper hoisting Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
joe@cal.com
Devin AI
parent
2a26a591a8
commit
f6d3b11582
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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`);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<MembershipCheckResult> {
|
||||
const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ teamId, userId });
|
||||
const membership = await this.membershipRepository.findUniqueByUserIdAndTeamId({ teamId, userId });
|
||||
|
||||
if (!membership || !membership.accepted) {
|
||||
return {
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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<TeamPermissions[]> {
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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({
|
||||
|
||||
+19
-27
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user