cc1efe1298
* Fix cache to fetch only when it's available * Non hierarchical feature check * Fix tests: Add missing mock method and comprehensive CalendarCacheWrapper tests - Add checkIfUserHasFeatureNonHierarchical to features.repository mock to fix failing GoogleCalendar tests - Add comprehensive unit tests for CalendarCacheWrapper covering: - Calendars with sync only (cache-only path) - Calendars without sync only (original calendar path) - Mixed calendars (both cache and original) - Timezone handling with UTC defaults - Edge cases (empty arrays, undefined methods, null ids) - Use proper types instead of 'as any' to satisfy lint rules Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * Fix: Sanitize logging to avoid exposing PII - Replace logging full selectedCalendars objects with only calendar IDs and count - Prevents exposure of email fields and other sensitive information in logs - Addresses AI code reviewer feedback Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * Apply suggestion from @volnei --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
78 lines
3.3 KiB
TypeScript
78 lines
3.3 KiB
TypeScript
import { CalendarSubscriptionService } from "@calcom/features/calendar-subscription/lib/CalendarSubscriptionService";
|
|
import { CalendarCacheEventRepository } from "@calcom/features/calendar-subscription/lib/cache/CalendarCacheEventRepository";
|
|
import { CalendarCacheEventService } from "@calcom/features/calendar-subscription/lib/cache/CalendarCacheEventService";
|
|
import { CalendarCacheWrapper } from "@calcom/features/calendar-subscription/lib/cache/CalendarCacheWrapper";
|
|
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
|
|
import logger from "@calcom/lib/logger";
|
|
import { prisma } from "@calcom/prisma";
|
|
import type { Calendar } from "@calcom/types/Calendar";
|
|
import type { CredentialForCalendarService } from "@calcom/types/Credential";
|
|
|
|
import { CalendarServiceMap } from "../calendar.services.generated";
|
|
|
|
const log = logger.getSubLogger({ prefix: ["CalendarManager"] });
|
|
|
|
export const getCalendar = async (
|
|
credential: CredentialForCalendarService | null,
|
|
shouldServeCache?: boolean
|
|
): Promise<Calendar | null> => {
|
|
if (!credential || !credential.key) return null;
|
|
let { type: calendarType } = credential;
|
|
if (calendarType?.endsWith("_other_calendar")) {
|
|
calendarType = calendarType.split("_other_calendar")[0];
|
|
}
|
|
// Backwards compatibility until CRM manager is created
|
|
if (calendarType?.endsWith("_crm")) {
|
|
calendarType = calendarType.split("_crm")[0];
|
|
}
|
|
|
|
const calendarAppImportFn =
|
|
CalendarServiceMap[calendarType.split("_").join("") as keyof typeof CalendarServiceMap];
|
|
|
|
if (!calendarAppImportFn) {
|
|
log.warn(`calendar of type ${calendarType} is not implemented`);
|
|
return null;
|
|
}
|
|
|
|
const calendarApp = await calendarAppImportFn;
|
|
|
|
const CalendarService = calendarApp.default;
|
|
|
|
if (!CalendarService || typeof CalendarService !== "function") {
|
|
log.warn(`calendar of type ${calendarType} is not implemented`);
|
|
return null;
|
|
}
|
|
// if shouldServeCache is not supplied, determine on the fly.
|
|
if (typeof shouldServeCache === "undefined") {
|
|
const featuresRepository = new FeaturesRepository(prisma);
|
|
const [isCalendarSubscriptionCacheEnabled, isCalendarSubscriptionCacheEnabledForUser] = await Promise.all(
|
|
[
|
|
featuresRepository.checkIfFeatureIsEnabledGlobally(
|
|
CalendarSubscriptionService.CALENDAR_SUBSCRIPTION_CACHE_FEATURE
|
|
),
|
|
featuresRepository.checkIfUserHasFeatureNonHierarchical(
|
|
credential.userId as number,
|
|
CalendarSubscriptionService.CALENDAR_SUBSCRIPTION_CACHE_FEATURE
|
|
),
|
|
]
|
|
);
|
|
shouldServeCache = isCalendarSubscriptionCacheEnabled && isCalendarSubscriptionCacheEnabledForUser;
|
|
}
|
|
if (CalendarCacheEventService.isCalendarTypeSupported(calendarType) && shouldServeCache) {
|
|
log.info(`Calendar Cache is enabled, using CalendarCacheService for credential ${credential.id}`);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const originalCalendar = new CalendarService(credential as any);
|
|
if (originalCalendar) {
|
|
// return cacheable calendar
|
|
const calendarCacheEventRepository = new CalendarCacheEventRepository(prisma);
|
|
return new CalendarCacheWrapper({
|
|
originalCalendar,
|
|
calendarCacheEventRepository,
|
|
});
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
return new CalendarService(credential as any);
|
|
};
|