Files
calendar/apps/web/app/api/auth/signup/route.ts
T
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>morgan@cal.com <morgan@cal.com>Morgan
1d1a242a72 refactor: convert getShouldServeCache to CacheService with dependency injection (#22814)
* refactor: convert getShouldServeCache to CacheService with dependency injection

- Create CacheService class following AvailableSlotsService DI pattern
- Add FeaturesRepository and CacheService to DI tokens and modules
- Create cache container with proper dependency injection setup
- Update handleNewBooking.ts and slots/util.ts to use new service
- Maintain backward compatibility with error-throwing wrapper function
- Follow established service patterns for clean architecture

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat: inject CacheService into AvailableSlotsService via dependency injection

- Add cacheService to IAvailableSlotsService interface
- Update available-slots container to load cache modules
- Update available-slots module to inject CacheService dependency
- Replace direct getShouldServeCache call with injected service method
- Add CacheService import to util.ts for proper typing

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore: DI api v2 cache service

* refactor: convert FeaturesRepository to use factory pattern in DI

- Change from constructor injection to factory pattern to avoid PRISMA_CLIENT binding issues in tests
- FeaturesRepository now uses default prisma instance instead of DI injection
- Resolves test failures while maintaining DI container compatibility
- Tests reduced from 123+ failures to only 5 unrelated failures

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* revert: use direct FeaturesRepository instantiation in most usage points

- Revert getFeaturesRepository() calls back to new FeaturesRepository()
- Tests require direct instantiation for mocking compatibility
- Keep DI container for specific use cases that need dependency injection
- Resolves test failures while maintaining both DI and direct usage patterns

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: resolve FeaturesRepository DI container issues

- Update cache module to use factory pattern with proper ICacheService interface
- Remove featuresModule loading from cache and available-slots containers
- Use direct FeaturesRepository instantiation via getFeaturesRepository()
- Resolves 'No binding found for key: Symbol(FeaturesRepository)' errors
- Reduces test failures from 125 to 7 (remaining failures appear unrelated)

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update all FeaturesRepository instantiations to include prisma parameter

- Add prisma parameter to all new FeaturesRepository() calls across the codebase
- Update API v2 services to match main repo interfaces
- Fix PrismaFeaturesRepository to implement IFeaturesRepository directly
- Update CacheService in API v2 to expose required dependencies and getShouldServeCache
- Implement CheckBookingLimitsService in API v2 with proper interface
- Resolves type assignment errors between API v2 and main repo implementations

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: add prisma parameter to remaining FeaturesRepository instantiations in apps/web/lib

- Update getServerSideProps files to pass prisma parameter to FeaturesRepository
- Ensures all FeaturesRepository instantiations follow the new constructor pattern
- Completes the refactoring to use direct instantiation with prisma parameter

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor clean and fix devin issues

* chore: bump platform libs

* chore: bump platform libs

* chore: bump platform libs

* chore: bump platform libs

* fix: missing di

* fix workflow test

* fix workflow test

* fix integration test

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: morgan@cal.com <morgan@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2025-07-31 20:39:27 +03:00

71 lines
2.6 KiB
TypeScript

import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";
import { parseRequestData } from "app/api/parseRequestData";
import { NextResponse, type NextRequest } from "next/server";
import calcomSignupHandler from "@calcom/feature-auth/signup/handlers/calcomHandler";
import selfHostedSignupHandler from "@calcom/feature-auth/signup/handlers/selfHostedHandler";
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
import { IS_PREMIUM_USERNAME_ENABLED } from "@calcom/lib/constants";
import getIP from "@calcom/lib/getIP";
import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { checkCfTurnstileToken } from "@calcom/lib/server/checkCfTurnstileToken";
import { prisma } from "@calcom/prisma";
import { signupSchema } from "@calcom/prisma/zod-utils";
async function ensureSignupIsEnabled(body: Record<string, string>) {
const { token } = signupSchema
.pick({
token: true,
})
.parse(body);
// Still allow signups if there is a team invite
if (token) return;
const featuresRepository = new FeaturesRepository(prisma);
const signupDisabled = await featuresRepository.checkIfFeatureIsEnabledGlobally("disable-signup");
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" || signupDisabled) {
throw new HttpError({
statusCode: 403,
message: "Signup is disabled",
});
}
}
async function handler(req: NextRequest) {
const remoteIp = getIP(req);
// Use a try catch instead of returning res every time
try {
const body = await parseRequestData(req);
await checkCfTurnstileToken({
token: req.headers.get("cf-access-token") as string,
remoteIp,
});
await ensureSignupIsEnabled(body);
/**
* Im not sure its worth merging these two handlers. They are different enough to be separate.
* Calcom handles things like creating a stripe customer - which we don't need to do for self hosted.
* It also handles things like premium username.
* TODO: (SEAN) - Extract a lot of the logic from calcomHandler into a separate file and import it into both handlers.
* @zomars: We need to be able to test this with E2E. They way it's done RN it will never run on CI.
*/
if (IS_PREMIUM_USERNAME_ENABLED) {
return await calcomSignupHandler(body);
}
return await selfHostedSignupHandler(body);
} catch (e) {
if (e instanceof HttpError) {
return NextResponse.json({ message: e.message }, { status: e.statusCode });
}
logger.error(e);
return NextResponse.json({ message: "Internal server error" }, { status: 500 });
}
}
export const POST = defaultResponderForAppDir(handler);