add send email verification opt out

This commit is contained in:
miloschwartz
2026-02-17 17:33:24 -08:00
parent 831eb6325c
commit 8a83e32c42
4 changed files with 26 additions and 7 deletions

View File

@@ -1,7 +1,7 @@
import { NextFunction, Request, Response } from "express";
import { db, users } from "@server/db";
import HttpCode from "@server/types/HttpCode";
import { z } from "zod";
import { email, z } from "zod";
import { fromError } from "zod-validation-error";
import createHttpError from "http-errors";
import response from "@server/lib/response";
@@ -30,7 +30,8 @@ export const signupBodySchema = z.object({
inviteToken: z.string().optional(),
inviteId: z.string().optional(),
termsAcceptedTimestamp: z.string().nullable().optional(),
marketingEmailConsent: z.boolean().optional()
marketingEmailConsent: z.boolean().optional(),
skipVerificationEmail: z.boolean().optional()
});
export type SignUpBody = z.infer<typeof signupBodySchema>;
@@ -61,7 +62,8 @@ export async function signup(
inviteToken,
inviteId,
termsAcceptedTimestamp,
marketingEmailConsent
marketingEmailConsent,
skipVerificationEmail
} = parsedBody.data;
const passwordHash = await hashPassword(password);
@@ -214,7 +216,13 @@ export async function signup(
}
if (config.getRawConfig().flags?.require_email_verification) {
sendEmailVerificationCode(email, userId);
if (!skipVerificationEmail) {
sendEmailVerificationCode(email, userId);
} else {
logger.debug(
`User ${email} opted out of verification email during signup.`
);
}
return response<SignUpResponse>(res, {
data: {
@@ -222,7 +230,9 @@ export async function signup(
},
success: true,
error: false,
message: `User created successfully. We sent an email to ${email} with a verification code.`,
message: skipVerificationEmail
? "User created successfully. Please verify your email."
: `User created successfully. We sent an email to ${email} with a verification code.`,
status: HttpCode.OK
});
}

View File

@@ -436,6 +436,7 @@ export async function validateOidcCallback(
}
}
// These are the orgs that the user should be provisioned into based on the IdP mappings and the token claims
logger.debug("User org info", { userOrgInfo });
let existingUserId = existingUser?.userId;

View File

@@ -15,6 +15,7 @@ export default async function Page(props: {
redirect: string | undefined;
email: string | undefined;
fromSmartLogin: string | undefined;
skipVerificationEmail: string | undefined;
}>;
}) {
const searchParams = await props.searchParams;
@@ -75,6 +76,10 @@ export default async function Page(props: {
inviteId={inviteId}
emailParam={searchParams.email}
fromSmartLogin={searchParams.fromSmartLogin === "true"}
skipVerificationEmail={
searchParams.skipVerificationEmail === "true" ||
searchParams.skipVerificationEmail === "1"
}
/>
<p className="text-center text-muted-foreground mt-4">

View File

@@ -72,6 +72,7 @@ type SignupFormProps = {
inviteToken?: string;
emailParam?: string;
fromSmartLogin?: boolean;
skipVerificationEmail?: boolean;
};
const formSchema = z
@@ -103,7 +104,8 @@ export default function SignupForm({
inviteId,
inviteToken,
emailParam,
fromSmartLogin = false
fromSmartLogin = false,
skipVerificationEmail = false
}: SignupFormProps) {
const router = useRouter();
const { env } = useEnvContext();
@@ -147,7 +149,8 @@ export default function SignupForm({
inviteToken,
termsAcceptedTimestamp: termsAgreedAt,
marketingEmailConsent:
build === "saas" ? marketingEmailConsent : undefined
build === "saas" ? marketingEmailConsent : undefined,
skipVerificationEmail: skipVerificationEmail || undefined
})
.catch((e) => {
console.error(e);