* refactor: replace FeaturesRepository with DI-based feature repositories Migrate from the legacy FeaturesRepository pattern to separate DI-based repositories: - Add checkIfFeatureIsEnabledGlobally to IFeatureRepository - Add getTeamsWithFeatureEnabled to ITeamFeatureRepository - Update CalendarSubscriptionService to use featureRepository, teamFeatureRepository, and userFeatureRepository - Update SelectedCalendarRepository.findNextSubscriptionBatch to filter by teamIds instead of featureIds - Update OnboardingPathService to use DI via getFeatureRepository() - Remove prisma parameter from OnboardingPathService callsites Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: update tests to use new DI-based feature repositories Update CalendarSubscriptionService and SelectedCalendarRepository tests to use the new separate repository interfaces: - featureRepository for global feature checks - teamFeatureRepository for team-level feature checks - userFeatureRepository for user-level feature checks Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: update API routes to use DI-based feature repositories Update cron and webhook routes to use the new separate repository interfaces instead of the combined FeaturesRepository. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove prisma arg from getGettingStartedPathWithParams call The OnboardingPathService method no longer requires a prisma argument as it now uses DI containers internally. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: update route tests to expect new DI-based feature repositories Update service instantiation tests to expect featureRepository, teamFeatureRepository, and userFeatureRepository instead of the old featuresRepository. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: optimize global feature check and add guard in checkForNewSubscriptions - Use targeted select for only `enabled` field in checkIfFeatureIsEnabledGlobally - Add global feature flag guard in checkForNewSubscriptions to avoid unnecessary DB queries and API calls when the cache feature is globally disabled Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * remove redundant comment --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
71 lines
3.1 KiB
TypeScript
71 lines
3.1 KiB
TypeScript
import process from "node:process";
|
|
import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository";
|
|
import { DefaultAdapterFactory } from "@calcom/features/calendar-subscription/adapters/AdaptersFactory";
|
|
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 { CalendarSyncService } from "@calcom/features/calendar-subscription/lib/sync/CalendarSyncService";
|
|
import { getFeatureRepository } from "@calcom/features/di/containers/FeatureRepository";
|
|
import { getTeamFeatureRepository } from "@calcom/features/di/containers/TeamFeatureRepository";
|
|
import { getUserFeatureRepository } from "@calcom/features/di/containers/UserFeatureRepository";
|
|
import { SelectedCalendarRepository } from "@calcom/features/selectedCalendar/repositories/SelectedCalendarRepository";
|
|
import { prisma } from "@calcom/prisma";
|
|
import { defaultResponderForAppDir } from "@calcom/web/app/api/defaultResponderForAppDir";
|
|
import type { NextRequest } from "next/server";
|
|
import { NextResponse } from "next/server";
|
|
|
|
/**
|
|
* Cron webhook
|
|
* Checks for new calendar subscriptions (rollouts)
|
|
*
|
|
* @param request
|
|
* @returns
|
|
*/
|
|
async function getHandler(request: NextRequest) {
|
|
const apiKey = request.headers.get("authorization") || request.nextUrl.searchParams.get("apiKey");
|
|
|
|
if (![process.env.CRON_API_KEY, `Bearer ${process.env.CRON_SECRET}`].includes(`${apiKey}`)) {
|
|
return NextResponse.json({ message: "Forbiden" }, { status: 403 });
|
|
}
|
|
|
|
// instantiate dependencies
|
|
const bookingRepository = new BookingRepository(prisma);
|
|
const calendarSyncService = new CalendarSyncService({
|
|
bookingRepository,
|
|
});
|
|
const calendarCacheEventRepository = new CalendarCacheEventRepository(prisma);
|
|
const calendarCacheEventService = new CalendarCacheEventService({
|
|
calendarCacheEventRepository,
|
|
});
|
|
|
|
const calendarSubscriptionService = new CalendarSubscriptionService({
|
|
adapterFactory: new DefaultAdapterFactory(),
|
|
selectedCalendarRepository: new SelectedCalendarRepository(prisma),
|
|
featureRepository: getFeatureRepository(),
|
|
teamFeatureRepository: getTeamFeatureRepository(),
|
|
userFeatureRepository: getUserFeatureRepository(),
|
|
calendarSyncService,
|
|
calendarCacheEventService,
|
|
});
|
|
|
|
// are features globally enabled
|
|
const [isCacheEnabled, isSyncEnabled] = await Promise.all([
|
|
calendarSubscriptionService.isCacheEnabled(),
|
|
calendarSubscriptionService.isSyncEnabled(),
|
|
]);
|
|
|
|
if (!isCacheEnabled && !isSyncEnabled) {
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
|
|
try {
|
|
await calendarSubscriptionService.checkForNewSubscriptions();
|
|
return NextResponse.json({ ok: true });
|
|
} catch (e) {
|
|
const message = e instanceof Error ? e.message : "Unknown error";
|
|
return NextResponse.json({ message }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export const GET = defaultResponderForAppDir(getHandler);
|