Files
calendar/apps/web/lib/signup/getServerSideProps.tsx
T
Eunjae LeeGitHubClaude Opus 4.5Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
81e4241f85 refactor: apply biome formatting to apps/web (#27692)
* refactor: apply biome formatting to apps/web (batch 1)

Formats apps/web non-modules directories:
- apps/web/app
- apps/web/lib
- apps/web/pages
- apps/web/styles
- apps/web/server
- apps/web/test
- Root-level .ts and .mjs files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/modules (batch 2)

Formats smaller apps/web/modules directories:
- onboarding, data-table, users, apps, auth
- integration-attribute-sync, shell, availability
- feature-flags, team, webhooks, getting-started
- feature-opt-in, troubleshooter, schedules, notifications
- signup-view.tsx

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/modules (batch 3)

Formats medium apps/web/modules directories:
- bookings
- event-types
- insights
- embed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/modules/ee (batch 4)

Formats apps/web/modules/ee directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web (batch 5)

Formats remaining apps/web directories:
- apps/web/modules/settings
- apps/web/modules/booking-audit
- apps/web/playwright

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/components (batch 6)

Formats remaining apps/web/components files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to new apps/web files from main

Formats newly added/modified files from main merge:
- WorkflowStepContainer.tsx (resolved merge conflicts)
- Newly moved files (blocklist, form-builder, schedules, etc.)
- Other files modified in main

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to new apps/web files from main

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 23:25:24 +05:30

225 lines
6.9 KiB
TypeScript

import type { GetServerSidePropsContext } from "next";
import { z } from "zod";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { getOrgUsernameFromEmail } from "@calcom/features/auth/signup/utils/getOrgUsernameFromEmail";
import { checkPremiumUsername } from "@calcom/features/ee/common/lib/checkPremiumUsername";
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
import { emailSchema } from "@calcom/lib/emailSchema";
import slugify from "@calcom/lib/slugify";
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
import { IS_GOOGLE_LOGIN_ENABLED } from "@server/lib/constants";
const checkValidEmail = (email: string) => emailSchema.safeParse(email).success;
const querySchema = z.object({
username: z
.string()
.optional()
.transform((val) => val || ""),
email: emailSchema.optional(),
});
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
const featuresRepository = new FeaturesRepository(prisma);
const emailVerificationEnabled =
await featuresRepository.checkIfFeatureIsEnabledGlobally("email-verification");
const signupDisabled = await featuresRepository.checkIfFeatureIsEnabledGlobally("disable-signup");
const onboardingV3Enabled = await featuresRepository.checkIfFeatureIsEnabledGlobally("onboarding-v3");
const token = z.string().optional().parse(ctx.query.token);
const redirectUrlData = z
.string()
.refine((value) => value.startsWith(WEBAPP_URL), {
params: (value: string) => ({ value }),
message: "Redirect URL must start with 'cal.com'",
})
.optional()
.safeParse(ctx.query.redirect);
const redirectUrl = redirectUrlData.success && redirectUrlData.data ? redirectUrlData.data : null;
const session = await getServerSession({
req: ctx.req,
});
if (session?.user?.id) {
return {
redirect: {
permanent: false,
destination: redirectUrl || "/",
},
} as const;
}
const props = {
redirectUrl,
isGoogleLoginEnabled: IS_GOOGLE_LOGIN_ENABLED,
isSAMLLoginEnabled,
prepopulateFormValues: undefined,
emailVerificationEnabled,
onboardingV3Enabled,
};
if ((process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" && !token) || signupDisabled) {
return {
redirect: {
permanent: false,
destination: `/auth/error?error=Signup is disabled in this instance`,
},
} as const;
}
// no token given, treat as a normal signup without verification token
if (!token) {
// username + email prepopulated from query params
const queryData = querySchema.safeParse(ctx.query);
return {
props: JSON.parse(
JSON.stringify({
...props,
prepopulateFormValues: {
username: queryData.success ? queryData.data.username : null,
email: queryData.success ? queryData.data.email : null,
},
})
),
};
}
const verificationToken = await prisma.verificationToken.findUnique({
where: {
token,
},
include: {
team: {
select: {
metadata: true,
isOrganization: true,
parentId: true,
parent: {
select: {
slug: true,
isOrganization: true,
organizationSettings: true,
},
},
slug: true,
organizationSettings: true,
},
},
},
});
if (!verificationToken || verificationToken.expires < new Date()) {
return {
redirect: {
permanent: false,
destination: `/auth/error?error=Verification Token is missing or has expired`,
},
} as const;
}
if (!verificationToken?.team) {
return {
redirect: {
permanent: false,
destination: `/auth/error?error=Verification Token is not associated with any team`,
},
} as const;
}
const isValidEmail = checkValidEmail(verificationToken.identifier);
if (isValidEmail) {
const existingUser = await prisma.user.findFirst({
where: {
AND: [
{
email: verificationToken.identifier,
},
{
emailVerified: {
not: null,
},
},
],
},
select: {
id: true,
},
});
if (existingUser) {
return {
redirect: {
permanent: false,
destination: `/auth/login?callbackUrl=${WEBAPP_URL}/${ctx.query.callbackUrl}`,
},
};
}
}
const guessUsernameFromEmail = (email: string) => {
const [username] = email.split("@");
return username;
};
let username = isValidEmail ? guessUsernameFromEmail(verificationToken.identifier) : "";
const tokenTeam = {
...verificationToken.team,
metadata: teamMetadataSchema.parse(verificationToken.team.metadata ?? null),
};
const isATeamInOrganization = tokenTeam?.parentId !== null;
// Detect if the team is an org by either the metadata flag or if it has a parent team
const isOrganization = tokenTeam.isOrganization;
const isOrganizationOrATeamInOrganization = isOrganization || isATeamInOrganization;
// If we are dealing with an org, the slug may come from the team itself or its parent
const orgSlug = isOrganizationOrATeamInOrganization
? tokenTeam.metadata?.requestedSlug || tokenTeam.parent?.slug || tokenTeam.slug
: null;
// Org context shouldn't check if a username is premium
if (!IS_SELF_HOSTED && !isOrganizationOrATeamInOrganization && username) {
// Im not sure we actually hit this because of next redirects signup to website repo - but just in case this is pretty cool :)
const { available, suggestion } = await checkPremiumUsername(username);
username = available ? username : suggestion || username;
}
const isOrgInviteByLink = isOrganizationOrATeamInOrganization && !isValidEmail;
const parentOrgSettings = tokenTeam?.parent?.organizationSettings ?? null;
return {
props: {
...props,
token,
prepopulateFormValues:
!isOrgInviteByLink && isValidEmail
? {
email: verificationToken.identifier,
username: isOrganizationOrATeamInOrganization
? getOrgUsernameFromEmail(
verificationToken.identifier,
(isOrganization
? tokenTeam.organizationSettings?.orgAutoAcceptEmail
: parentOrgSettings?.orgAutoAcceptEmail) || ""
)
: slugify(username),
}
: null,
orgSlug,
orgAutoAcceptEmail: isOrgInviteByLink
? (tokenTeam?.organizationSettings?.orgAutoAcceptEmail ??
parentOrgSettings?.orgAutoAcceptEmail ??
null)
: null,
},
};
};