diff --git a/server/emails/sendEmail.ts b/server/emails/sendEmail.ts index 2a3852f2..973f48ee 100644 --- a/server/emails/sendEmail.ts +++ b/server/emails/sendEmail.ts @@ -21,9 +21,7 @@ export async function sendEmail( return; } - logger.debug("Rendering email templatee...") const emailHtml = await render(template); - logger.debug("Done rendering email templatee") const options = { from: opts.from, diff --git a/server/emails/templates/SendInviteLink.tsx b/server/emails/templates/SendInviteLink.tsx index cc05881d..fabcffbd 100644 --- a/server/emails/templates/SendInviteLink.tsx +++ b/server/emails/templates/SendInviteLink.tsx @@ -33,9 +33,17 @@ export const SendInviteLink = ({ {previewText} - + - + You're invited to join a Fossorial organization @@ -58,7 +66,7 @@ export const SendInviteLink = ({
diff --git a/server/emails/templates/VerifyEmailCode.tsx b/server/emails/templates/VerifyEmailCode.tsx index dcae2971..fc8978ed 100644 --- a/server/emails/templates/VerifyEmailCode.tsx +++ b/server/emails/templates/VerifyEmailCode.tsx @@ -14,11 +14,13 @@ import * as React from "react"; interface VerifyEmailProps { username?: string; verificationCode: string; + verifyLink: string; } export const VerifyEmail = ({ username, verificationCode, + verifyLink, }: VerifyEmailProps) => { const previewText = `Verify your email, ${username}`; @@ -26,21 +28,34 @@ export const VerifyEmail = ({ {previewText} - + - + - Verify Your Email + Please verify your email Hi {username || "there"}, - You’ve requested to verify your email. Please use - the verification code below: + You’ve requested to verify your email. Please{" "} + + click here + {" "} + to verify your email, then enter the following code:
- + {verificationCode}
@@ -59,3 +74,5 @@ export const VerifyEmail = ({ ); }; + +export default VerifyEmail; diff --git a/server/routers/auth/login.ts b/server/routers/auth/login.ts index 9ffe651c..b7b68e47 100644 --- a/server/routers/auth/login.ts +++ b/server/routers/auth/login.ts @@ -139,7 +139,7 @@ export async function login( success: true, error: false, message: "Email verification code sent", - status: HttpCode.ACCEPTED, + status: HttpCode.OK, }); } diff --git a/server/routers/auth/sendEmailVerificationCode.ts b/server/routers/auth/sendEmailVerificationCode.ts index 3a167405..334eb23a 100644 --- a/server/routers/auth/sendEmailVerificationCode.ts +++ b/server/routers/auth/sendEmailVerificationCode.ts @@ -13,11 +13,18 @@ export async function sendEmailVerificationCode( ): Promise { const code = await generateEmailVerificationCode(userId, email); - await sendEmail(VerifyEmail({ username: email, verificationCode: code }), { - to: email, - from: config.email?.no_reply, - subject: "Verify your email address", - }); + await sendEmail( + VerifyEmail({ + username: email, + verificationCode: code, + verifyLink: `${config.app.base_url}/auth/verify-email`, + }), + { + to: email, + from: config.email?.no_reply, + subject: "Verify your email address", + }, + ); } async function generateEmailVerificationCode( diff --git a/src/app/[orgId]/layout.tsx b/src/app/[orgId]/layout.tsx index e02e8af2..cc0d59be 100644 --- a/src/app/[orgId]/layout.tsx +++ b/src/app/[orgId]/layout.tsx @@ -1,6 +1,8 @@ import { internal } from "@app/api"; import { authCookieHeader } from "@app/api/cookies"; +import { verifySession } from "@app/lib/auth/verifySession"; import { GetOrgResponse } from "@server/routers/org"; +import { GetOrgUserResponse } from "@server/routers/user"; import { AxiosResponse } from "axios"; import { redirect } from "next/navigation"; import { cache } from "react"; @@ -17,6 +19,25 @@ export default async function OrgLayout(props: { redirect(`/`); } + const getUser = cache(verifySession); + const user = await getUser(); + + if (!user) { + redirect(`/?redirect=/${orgId}`); + } + + try { + const getOrgUser = cache(() => + internal.get>( + `/org/${orgId}/user/${user.userId}`, + cookie, + ), + ); + const orgUser = await getOrgUser(); + } catch { + redirect(`/`); + } + try { const getOrg = cache(() => internal.get>( diff --git a/src/app/[orgId]/page.tsx b/src/app/[orgId]/page.tsx index 730e6851..cb3297d3 100644 --- a/src/app/[orgId]/page.tsx +++ b/src/app/[orgId]/page.tsx @@ -14,27 +14,6 @@ export default async function OrgPage(props: OrgPageProps) { const params = await props.params; const orgId = params.orgId; - const getUser = cache(verifySession); - const user = await getUser(); - - if (!user) { - redirect("/auth/login"); - } - - const cookie = await authCookieHeader(); - - try { - const getOrgUser = cache(() => - internal.get>( - `/org/${orgId}/user/${user.userId}`, - cookie - ) - ); - const orgUser = await getOrgUser(); - } catch { - redirect(`/`); - } - return ( <>

Welcome to {orgId} dashboard

diff --git a/src/app/[orgId]/settings/general/layout.tsx b/src/app/[orgId]/settings/general/layout.tsx index ee413b9e..f4dc6549 100644 --- a/src/app/[orgId]/settings/general/layout.tsx +++ b/src/app/[orgId]/settings/general/layout.tsx @@ -26,7 +26,7 @@ export default async function GeneralSettingsPage({ const user = await getUser(); if (!user) { - redirect("/auth/login"); + redirect(`/?redirect=/${orgId}/settings/general`); } let orgUser = null; @@ -34,8 +34,8 @@ export default async function GeneralSettingsPage({ const getOrgUser = cache(async () => internal.get>( `/org/${orgId}/user/${user.userId}`, - await authCookieHeader() - ) + await authCookieHeader(), + ), ); const res = await getOrgUser(); orgUser = res.data.data; @@ -48,8 +48,8 @@ export default async function GeneralSettingsPage({ const getOrg = cache(async () => internal.get>( `/org/${orgId}`, - await authCookieHeader() - ) + await authCookieHeader(), + ), ); const res = await getOrg(); org = res.data.data; diff --git a/src/app/[orgId]/settings/layout.tsx b/src/app/[orgId]/settings/layout.tsx index 45095896..b277b7f3 100644 --- a/src/app/[orgId]/settings/layout.tsx +++ b/src/app/[orgId]/settings/layout.tsx @@ -55,7 +55,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) { const user = await getUser(); if (!user) { - redirect("/auth/login"); + redirect(`/?redirect=/${params.orgId}/`); } const cookie = await authCookieHeader(); @@ -64,8 +64,8 @@ export default async function SettingsLayout(props: SettingsLayoutProps) { const getOrgUser = cache(() => internal.get>( `/org/${params.orgId}/user/${user.userId}`, - cookie - ) + cookie, + ), ); const orgUser = await getOrgUser(); @@ -79,7 +79,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) { let orgs: ListOrgsResponse["orgs"] = []; try { const getOrgs = cache(() => - internal.get>(`/orgs`, cookie) + internal.get>(`/orgs`, cookie), ); const res = await getOrgs(); if (res && res.data.data.orgs) { diff --git a/src/app/auth/login/DashboardLoginForm.tsx b/src/app/auth/login/DashboardLoginForm.tsx index 986993cd..61abe8cc 100644 --- a/src/app/auth/login/DashboardLoginForm.tsx +++ b/src/app/auth/login/DashboardLoginForm.tsx @@ -30,7 +30,15 @@ export default function DashboardLoginForm({ router.push("/")} + onLogin={() => { + if (redirect && redirect.includes("http")) { + window.location.href = redirect; + } else if (redirect) { + router.push(redirect); + } else { + router.push("/"); + } + }} /> diff --git a/src/app/auth/resource/[resourceId]/components/ResourceAuthPortal.tsx b/src/app/auth/resource/[resourceId]/components/ResourceAuthPortal.tsx index 3556bf51..4e3a612b 100644 --- a/src/app/auth/resource/[resourceId]/components/ResourceAuthPortal.tsx +++ b/src/app/auth/resource/[resourceId]/components/ResourceAuthPortal.tsx @@ -38,6 +38,7 @@ import { LoginResponse } from "@server/routers/auth"; import ResourceAccessDenied from "./ResourceAccessDenied"; import LoginForm from "@app/components/LoginForm"; import { AuthWithPasswordResponse } from "@server/routers/resource"; +import { redirect } from "next/dist/server/api-utils"; const pinSchema = z.object({ pin: z @@ -113,11 +114,6 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) { }, }); - function constructRedirect(redirect: string): string { - const redirectUrl = new URL(redirect); - return redirectUrl.toString(); - } - const onPinSubmit = (values: z.infer) => { setLoadingLogin(true); api.post>( @@ -127,9 +123,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) { .then((res) => { const session = res.data.data.session; if (session) { - const url = constructRedirect(props.redirect); - console.log(url); - window.location.href = url; + window.location.href = props.redirect; } }) .catch((e) => { @@ -152,7 +146,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) { .then((res) => { const session = res.data.data.session; if (session) { - window.location.href = constructRedirect(props.redirect); + window.location.href = props.redirect; } }) .catch((e) => { @@ -172,7 +166,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) { } if (!accessDenied) { - window.location.href = constructRedirect(props.redirect); + window.location.href = props.redirect; } } @@ -371,6 +365,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) { className={`${numMethods <= 1 ? "mt-0" : ""}`} > await handleSSOAuth() } diff --git a/src/app/auth/verify-email/VerifyEmailForm.tsx b/src/app/auth/verify-email/VerifyEmailForm.tsx index a8cedf9c..cceddc66 100644 --- a/src/app/auth/verify-email/VerifyEmailForm.tsx +++ b/src/app/auth/verify-email/VerifyEmailForm.tsx @@ -79,6 +79,7 @@ export default function VerifyEmailForm({ .catch((e) => { setError(formatAxiosError(e, "An error occurred")); console.error("Failed to verify email:", e); + setIsSubmitting(false); }); if (res && res.data?.data?.valid) { @@ -125,7 +126,7 @@ export default function VerifyEmailForm({
- Verify Your Email + Verify Email Enter the verification code sent to your email address. @@ -234,7 +235,7 @@ export default function VerifyEmailForm({ -
+