From 4051594b2f410f01e883febad22eb9001a84f90e Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sun, 1 Feb 2026 17:20:17 +0000 Subject: feat: add support for redirectUrl after signup (#2439) * feat: add support for redirectUrl after signup * pr review * more fixes * format * another fix --- packages/trpc/email.ts | 6 +++++- packages/trpc/models/users.ts | 12 +++++++++--- packages/trpc/routers/users.test.ts | 1 + packages/trpc/routers/users.ts | 17 ++++++++++++++--- 4 files changed, 29 insertions(+), 7 deletions(-) (limited to 'packages/trpc') diff --git a/packages/trpc/email.ts b/packages/trpc/email.ts index b837656e..15e1ef74 100644 --- a/packages/trpc/email.ts +++ b/packages/trpc/email.ts @@ -55,8 +55,12 @@ export const sendVerificationEmail = withTracing( email: string, name: string, token: string, + redirectUrl?: string, ) => { - const verificationUrl = `${serverConfig.publicUrl}/verify-email?token=${encodeURIComponent(token)}&email=${encodeURIComponent(email)}`; + let verificationUrl = `${serverConfig.publicUrl}/verify-email?token=${encodeURIComponent(token)}&email=${encodeURIComponent(email)}`; + if (redirectUrl) { + verificationUrl += `&redirectUrl=${encodeURIComponent(redirectUrl)}`; + } const mailOptions = { from: serverConfig.email.smtp!.from, diff --git a/packages/trpc/models/users.ts b/packages/trpc/models/users.ts index 5d3c3785..671f7d74 100644 --- a/packages/trpc/models/users.ts +++ b/packages/trpc/models/users.ts @@ -61,7 +61,7 @@ export class User { static async create( ctx: Context, - input: z.infer, + input: z.infer & { redirectUrl?: string }, role?: "user" | "admin", ) { const salt = generatePasswordSalt(); @@ -76,7 +76,12 @@ export class User { if (serverConfig.auth.emailVerificationRequired) { const token = await User.genEmailVerificationToken(ctx.db, input.email); try { - await sendVerificationEmail(input.email, input.name, token); + await sendVerificationEmail( + input.email, + input.name, + token, + input.redirectUrl, + ); } catch (error) { console.error("Failed to send verification email:", error); } @@ -227,6 +232,7 @@ export class User { static async resendVerificationEmail( ctx: Context, email: string, + redirectUrl?: string, ): Promise { if ( !serverConfig.auth.emailVerificationRequired || @@ -255,7 +261,7 @@ export class User { const token = await User.genEmailVerificationToken(ctx.db, email); try { - await sendVerificationEmail(email, user.name, token); + await sendVerificationEmail(email, user.name, token, redirectUrl); } catch (error) { console.error("Failed to send verification email:", error); throw new TRPCError({ diff --git a/packages/trpc/routers/users.test.ts b/packages/trpc/routers/users.test.ts index 605d14fc..ccde4c86 100644 --- a/packages/trpc/routers/users.test.ts +++ b/packages/trpc/routers/users.test.ts @@ -1116,6 +1116,7 @@ describe("User Routes", () => { "resend@test.com", "Test User", expect.any(String), // token + undefined, // redirectUrl ); }); diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts index abd50d63..c11a0ffd 100644 --- a/packages/trpc/routers/users.ts +++ b/packages/trpc/routers/users.ts @@ -11,6 +11,7 @@ import { zWhoAmIResponseSchema, zWrappedStatsResponseSchema, } from "@karakeep/shared/types/users"; +import { validateRedirectUrl } from "@karakeep/shared/utils/redirectUrl"; import { adminProcedure, @@ -31,7 +32,7 @@ export const usersAppRouter = router({ maxRequests: 3, }), ) - .input(zSignUpSchema) + .input(zSignUpSchema.and(z.object({ redirectUrl: z.string().optional() }))) .output( z.object({ id: z.string(), @@ -65,7 +66,11 @@ export const usersAppRouter = router({ }); } } - const user = await User.create(ctx, input); + const validatedRedirectUrl = validateRedirectUrl(input.redirectUrl); + const user = await User.create(ctx, { + ...input, + redirectUrl: validatedRedirectUrl, + }); return { id: user.id, name: user.name, @@ -206,10 +211,16 @@ export const usersAppRouter = router({ .input( z.object({ email: z.string().email(), + redirectUrl: z.string().optional(), }), ) .mutation(async ({ input, ctx }) => { - await User.resendVerificationEmail(ctx, input.email); + const validatedRedirectUrl = validateRedirectUrl(input.redirectUrl); + await User.resendVerificationEmail( + ctx, + input.email, + validatedRedirectUrl, + ); return { success: true }; }), forgotPassword: publicProcedure -- cgit v1.2.3-70-g09d2