Files
Benny JooandDevin AI 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: benny@cal.com <sldisek783@gmail.com>

* 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

633 lines
19 KiB
TypeScript

import { prisma } from "@calcom/prisma/__mocks__/prisma";
import { beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("@calcom/features/watchlist/lib/utils/normalization", () => ({
normalizeEmail: vi.fn(),
extractDomainFromEmail: vi.fn(),
normalizeDomain: vi.fn(),
}));
vi.mock("@calcom/features/watchlist/lib/service/GlobalBlockingService", () => ({
GlobalBlockingService: vi.fn(),
}));
vi.mock("@calcom/features/watchlist/lib/freeEmailDomainCheck/checkIfFreeEmailDomain", () => ({
checkIfFreeEmailDomain: vi.fn(),
}));
vi.mock("@calcom/features/watchlist/operations/check-if-users-are-blocked.controller", () => ({
checkIfUsersAreBlocked: vi.fn(),
}));
vi.mock("@calcom/features/watchlist/lib/telemetry", () => ({
sentrySpan: vi.fn(),
}));
vi.mock("@calcom/lib/i18n", () => ({
locales: ["en"],
localeOptions: [{ value: "en", label: "English" }],
defaultLocaleOption: { value: "en", label: "English" },
}));
import process from "node:process";
import { CredentialRepository } from "@calcom/features/credentials/repositories/CredentialRepository";
import { symmetricDecrypt } from "@calcom/lib/crypto";
import type { DestinationCalendar } from "@calcom/prisma/client";
import type { CredentialForCalendarService } from "@calcom/types/Credential";
import EventManager from "./EventManager";
vi.mock("@calcom/prisma", () => ({
prisma,
}));
vi.mock("@calcom/lib/crypto", () => ({
symmetricDecrypt: vi.fn(),
}));
vi.mock("@calcom/features/credentials/repositories/CredentialRepository", () => ({
CredentialRepository: {
findCredentialForCalendarServiceById: vi.fn(),
},
}));
vi.mock("@calcom/app-store/delegationCredential", () => ({
enrichHostsWithDelegationCredentials: vi.fn(),
getUsersCredentialsIncludeServiceAccountKey: vi.fn(),
getCredentialForSelectedCalendar: vi.fn(),
}));
const mockedSymmetricDecrypt = vi.mocked(symmetricDecrypt);
const mockedCredentialRepository = vi.mocked(CredentialRepository);
function buildCalDAVCredential(data: {
id: number;
key: string;
userId?: number;
}): CredentialForCalendarService {
return {
id: data.id,
type: "caldav_calendar",
key: data.key,
userId: data.userId || 1,
user: { email: "test@example.com" },
teamId: null,
appId: "caldav-calendar",
invalid: false,
delegatedTo: null,
delegationCredentialId: null,
};
}
function buildDestinationCalendar(data: {
id: number;
integration: string;
externalId: string | null;
}): DestinationCalendar {
return {
id: data.id,
integration: data.integration,
externalId: data.externalId || "",
userId: 1,
eventTypeId: null,
credentialId: null,
primaryEmail: null,
createdAt: new Date(),
updatedAt: new Date(),
delegationCredentialId: null,
};
}
function buildCalendarCredential(data: {
id: number;
type?: string;
userId?: number;
delegatedToId?: string | null;
}): CredentialForCalendarService {
return {
id: data.id,
type: data.type || "google_calendar",
key: {},
userId: data.userId || 1,
user: { email: "test@example.com" },
teamId: null,
appId: "google-calendar",
invalid: false,
delegatedTo: null,
delegationCredentialId: null,
delegatedToId: data.delegatedToId || null,
};
}
function buildVideoCredential(data: {
id: number;
type?: string;
userId?: number;
}): CredentialForCalendarService {
return {
id: data.id,
type: data.type || "zoom_video",
key: {},
userId: data.userId || 1,
user: { email: "test@example.com" },
teamId: null,
appId: "zoom",
invalid: false,
delegatedTo: null,
delegationCredentialId: null,
};
}
describe("EventManager CalDAV credential validation", () => {
let eventManager: EventManager;
beforeEach(() => {
vi.clearAllMocks();
eventManager = new EventManager({
credentials: [],
destinationCalendar: null,
});
});
describe("extractServerUrlFromCredential", () => {
it("should extract server URL from valid CalDAV credential", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com/dav/calendars/user/",
})
);
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBe("https://caldav.example.com");
expect(mockedSymmetricDecrypt).toHaveBeenCalledWith(
"encrypted_key",
process.env.CALENDSO_ENCRYPTION_KEY || ""
);
});
it("should return null for non-CalDAV credential", () => {
const credential = {
...buildCalDAVCredential({ id: 1, key: "encrypted_key" }),
type: "google_calendar",
} as CredentialForCalendarService;
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBeNull();
expect(mockedSymmetricDecrypt).not.toHaveBeenCalled();
});
it("should return null when decryption fails", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "invalid_key",
});
mockedSymmetricDecrypt.mockImplementation(() => {
throw new Error("Decryption failed");
});
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBeNull();
});
it("should return null when decrypted data has no URL", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
})
);
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBeNull();
});
it("should return null when URL is invalid", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "invalid-url",
})
);
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBeNull();
});
it("should handle URLs with different ports", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com:8443/dav/calendars/user/",
})
);
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBe("https://caldav.example.com:8443");
});
it("should handle HTTP URLs", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "http://caldav.internal.com/dav/calendars/user/",
})
);
const result = (eventManager as any).extractServerUrlFromCredential(credential);
expect(result).toBe("http://caldav.internal.com");
});
});
describe("extractServerUrlFromDestination", () => {
it("should extract server URL from CalDAV destination calendar", () => {
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com/dav/calendars/user/calendar1/",
});
const result = (eventManager as any).extractServerUrlFromDestination(destination);
expect(result).toBe("https://caldav.example.com");
});
it("should return null for non-CalDAV destination", () => {
const destination = buildDestinationCalendar({
id: 1,
integration: "google_calendar",
externalId: "calendar@gmail.com",
});
const result = (eventManager as any).extractServerUrlFromDestination(destination);
expect(result).toBeNull();
});
it("should return null when externalId is null", () => {
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: null,
});
const result = (eventManager as any).extractServerUrlFromDestination(destination);
expect(result).toBeNull();
});
it("should return null when externalId is invalid URL", () => {
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "invalid-url",
});
const result = (eventManager as any).extractServerUrlFromDestination(destination);
expect(result).toBeNull();
});
it("should handle URLs with different ports", () => {
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com:8443/dav/calendars/user/calendar1/",
});
const result = (eventManager as any).extractServerUrlFromDestination(destination);
expect(result).toBe("https://caldav.example.com:8443");
});
it("should handle HTTP URLs", () => {
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "http://caldav.internal.com/dav/calendars/user/calendar1/",
});
const result = (eventManager as any).extractServerUrlFromDestination(destination);
expect(result).toBe("http://caldav.internal.com");
});
});
describe("credentialMatchesDestination", () => {
it("should return true for matching CalDAV server URLs", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com/dav/calendars/user/calendar1/",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com/dav/calendars/user/",
})
);
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(true);
});
it("should return false for non-matching CalDAV server URLs", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://different.example.com/dav/calendars/user/calendar1/",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com/dav/calendars/user/",
})
);
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(false);
});
it("should return true for non-CalDAV credentials", () => {
const credential = {
...buildCalDAVCredential({ id: 1, key: "encrypted_key" }),
type: "google_calendar",
} as CredentialForCalendarService;
const destination = buildDestinationCalendar({
id: 1,
integration: "google_calendar",
externalId: "calendar@gmail.com",
});
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(true);
expect(symmetricDecrypt).not.toHaveBeenCalled();
});
it("should return true when credential is CalDAV but destination is not", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "google_calendar",
externalId: "calendar@gmail.com",
});
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(true);
expect(symmetricDecrypt).not.toHaveBeenCalled();
});
it("should return false when credential URL extraction fails", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "invalid_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com/dav/calendars/user/calendar1/",
});
mockedSymmetricDecrypt.mockImplementation(() => {
throw new Error("Decryption failed");
});
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(false);
});
it("should return false when destination URL extraction fails", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "invalid-url",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com/dav/calendars/user/",
})
);
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(false);
});
it("should handle URLs with different paths but same server", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com/different/path/calendar1/",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com/dav/calendars/user/",
})
);
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(true);
});
it("should handle URLs with different ports as non-matching", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com:8443/dav/calendars/user/calendar1/",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "https://caldav.example.com:9443/dav/calendars/user/",
})
);
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(false);
});
it("should handle HTTP vs HTTPS as non-matching", () => {
const credential = buildCalDAVCredential({
id: 1,
key: "encrypted_key",
});
const destination = buildDestinationCalendar({
id: 1,
integration: "caldav_calendar",
externalId: "https://caldav.example.com/dav/calendars/user/calendar1/",
});
mockedSymmetricDecrypt.mockReturnValue(
JSON.stringify({
username: "user",
password: "pass",
url: "http://caldav.example.com/dav/calendars/user/",
})
);
const result = (eventManager as any).credentialMatchesDestination(credential, destination);
expect(result).toBe(false);
});
});
});
describe("EventManager credential lookup methods", () => {
let eventManager: EventManager;
beforeEach(() => {
vi.clearAllMocks();
});
describe("getVideoCredential", () => {
it("returns a cached credential when credentialId matches", async () => {
const videoCredential = buildVideoCredential({ id: 42, type: "zoom_video" });
eventManager = new EventManager({
credentials: [videoCredential],
destinationCalendar: null,
});
const result = await (eventManager as any).getVideoCredential(42, "zoom_video");
expect(result).toMatchObject({ id: 42, type: "zoom_video" });
expect(mockedCredentialRepository.findCredentialForCalendarServiceById).not.toHaveBeenCalled();
});
it("fetches credential from repository when not cached locally", async () => {
const dbCredential = buildVideoCredential({ id: 7, type: "zoom_video" });
eventManager = new EventManager({
credentials: [],
destinationCalendar: null,
});
mockedCredentialRepository.findCredentialForCalendarServiceById.mockResolvedValue(dbCredential as any);
const result = await (eventManager as any).getVideoCredential(7, "zoom_video");
expect(result).toEqual(dbCredential);
expect(mockedCredentialRepository.findCredentialForCalendarServiceById).toHaveBeenCalledWith({ id: 7 });
});
it("falls back to credential type when credentialId is missing", async () => {
const zoomCredential = buildVideoCredential({ id: 1, type: "zoom_video" });
eventManager = new EventManager({
credentials: [zoomCredential],
destinationCalendar: null,
});
const result = await (eventManager as any).getVideoCredential(null, "zoom_video");
expect(result).toMatchObject({ type: "zoom_video" });
expect(mockedCredentialRepository.findCredentialForCalendarServiceById).not.toHaveBeenCalled();
});
});
describe("getCalendarCredential", () => {
it("prefers delegation credentials when delegationCredentialId is provided", async () => {
const delegatedCredential = buildCalendarCredential({
id: 10,
delegatedToId: "delegation-123",
});
eventManager = new EventManager({
credentials: [delegatedCredential],
destinationCalendar: null,
});
const result = await (eventManager as any).getCalendarCredential(
99,
"google_calendar",
"delegation-123"
);
expect(result).toMatchObject({ id: 10, delegatedToId: "delegation-123" });
expect(mockedCredentialRepository.findCredentialForCalendarServiceById).not.toHaveBeenCalled();
});
it("fetches credential from repository when local cache misses", async () => {
const dbCredential = buildCalendarCredential({ id: 5, type: "google_calendar" });
eventManager = new EventManager({
credentials: [],
destinationCalendar: null,
});
mockedCredentialRepository.findCredentialForCalendarServiceById.mockResolvedValue(dbCredential as any);
const result = await (eventManager as any).getCalendarCredential(5, "google_calendar");
expect(result).toEqual(dbCredential);
expect(mockedCredentialRepository.findCredentialForCalendarServiceById).toHaveBeenCalledWith({ id: 5 });
});
it("falls back to matching credential type when credentialId is absent", async () => {
const calendarCredential = buildCalendarCredential({ id: 22, type: "google_calendar" });
eventManager = new EventManager({
credentials: [calendarCredential],
destinationCalendar: null,
});
const result = await (eventManager as any).getCalendarCredential(null, "google_calendar");
expect(result).toMatchObject({ id: 22, type: "google_calendar" });
expect(mockedCredentialRepository.findCredentialForCalendarServiceById).not.toHaveBeenCalled();
});
});
});