Files
Benny JooGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: [email protected] <[email protected]>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

133 lines
4.4 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, type Mock } from "vitest";
import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository";
import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository";
import {
BookingAuditAccessService,
BookingAuditErrorCode,
BookingAuditPermissionError,
} from "../BookingAuditAccessService";
vi.mock("@calcom/features/bookings/repositories/BookingRepository");
vi.mock("@calcom/features/membership/repositories/MembershipRepository");
const DB = {
bookings: {} as Record<
string,
{
uid: string;
userId: number | null;
eventType: {
teamId: number | null;
parent: { teamId: number } | null;
hosts: never[];
users: never[];
};
user: { id: number; email: string };
attendees: never[];
}
>,
};
const createMockBooking = (overrides: { bookingUid: string; userId?: number | null }) => {
const userId = overrides.userId === undefined ? 456 : overrides.userId;
const booking = {
uid: overrides.bookingUid,
userId,
eventType: {
teamId: null,
parent: null,
hosts: [] as never[],
users: [] as never[],
},
user: {
id: typeof userId === "number" ? userId : 456,
email: "[email protected]",
},
attendees: [] as never[],
};
DB.bookings[booking.uid] = booking;
return booking;
};
const mockBookingRepository: {
findByUidIncludeEventType: Mock<BookingRepository["findByUidIncludeEventType"]>;
} = {
findByUidIncludeEventType: vi.fn().mockImplementation(({ bookingUid }) => {
return Promise.resolve(DB.bookings[bookingUid] ?? null);
}),
};
const mockMembershipRepository: {
hasMembership: Mock<MembershipRepository["hasMembership"]>;
} = {
hasMembership: vi.fn().mockResolvedValue(false),
};
describe("BookingAuditAccessService", () => {
let service: BookingAuditAccessService;
beforeEach(() => {
vi.clearAllMocks();
DB.bookings = {};
vi.mocked(BookingRepository).mockImplementation(function () {
return mockBookingRepository as unknown as BookingRepository;
});
vi.mocked(MembershipRepository).mockImplementation(function () {
return mockMembershipRepository as unknown as MembershipRepository;
});
service = new BookingAuditAccessService({
bookingRepository: mockBookingRepository as unknown as BookingRepository,
membershipRepository: mockMembershipRepository as unknown as MembershipRepository,
});
});
describe("assertPermissions", () => {
it("should grant access when the user is the booking owner", async () => {
const bookingUid = "test-booking-uid";
const userId = 123;
createMockBooking({ bookingUid, userId });
await expect(
service.assertPermissions({ bookingUid, userId, organizationId: null })
).resolves.not.toThrow();
});
it("should throw PERMISSION_DENIED when user is not the booking owner", async () => {
const bookingUid = "test-booking-uid";
createMockBooking({ bookingUid, userId: 456 });
await expect(
service.assertPermissions({ bookingUid, userId: 123, organizationId: null })
).rejects.toThrow(BookingAuditPermissionError);
await expect(
service.assertPermissions({ bookingUid, userId: 123, organizationId: null })
).rejects.toThrow(BookingAuditErrorCode.PERMISSION_DENIED);
});
it("should throw BOOKING_NOT_FOUND_OR_PERMISSION_DENIED when booking does not exist", async () => {
await expect(
service.assertPermissions({ bookingUid: "non-existent", userId: 123, organizationId: null })
).rejects.toThrow(BookingAuditPermissionError);
await expect(
service.assertPermissions({ bookingUid: "non-existent", userId: 123, organizationId: null })
).rejects.toThrow(BookingAuditErrorCode.BOOKING_NOT_FOUND_OR_PERMISSION_DENIED);
});
it("should throw BOOKING_HAS_NO_OWNER when booking has no userId", async () => {
const bookingUid = "test-booking-uid";
createMockBooking({ bookingUid, userId: null });
await expect(
service.assertPermissions({ bookingUid, userId: 123, organizationId: null })
).rejects.toThrow(BookingAuditPermissionError);
await expect(
service.assertPermissions({ bookingUid, userId: 123, organizationId: null })
).rejects.toThrow(BookingAuditErrorCode.BOOKING_HAS_NO_OWNER);
});
});
});