From 18a590d90d6a686d99204419e7105a7bbe0b87d1 Mon Sep 17 00:00:00 2001 From: ErikaKK <491649804@qq.com> Date: Fri, 1 Aug 2025 01:33:52 +0800 Subject: [PATCH 1/4] fix user email update issue --- src/app/join/page.tsx | 6 ++-- .../api/routers/admin/users/update-email.ts | 32 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/app/join/page.tsx b/src/app/join/page.tsx index df77efdd6..3ab9603cc 100644 --- a/src/app/join/page.tsx +++ b/src/app/join/page.tsx @@ -80,8 +80,10 @@ export default function Join() { // careful of order await setActive({ session: res.createdSessionId }) // sets token from clerk await utils.users.getCurrent.refetch() - - router.push("/dashboard") + const { data: user, isLoading } = api.users.getCurrent.useQuery() + !isLoading && (user?.role === "admin" || user?.role === "committee") + ? router.push("/dashboard/admin") + : router.push("/dashboard") } } catch (error) { const { errors = [] } = error as ClerkError diff --git a/src/server/api/routers/admin/users/update-email.ts b/src/server/api/routers/admin/users/update-email.ts index 5c2e19226..25c0fe5e0 100644 --- a/src/server/api/routers/admin/users/update-email.ts +++ b/src/server/api/routers/admin/users/update-email.ts @@ -10,10 +10,15 @@ import { User } from "~/server/db/schema" export const updateEmail = adminProcedure .input(z.object({ userId: z.string(), oldEmail: z.string().email(), newEmail: z.string().email() })) .mutation(async ({ ctx, input }) => { - // TODO: check if old email is the same as the user's email in db - - // TODO: wrap in a transaction - const [user] = await ctx.db.update(User).set({ email: input.newEmail }).where(eq(User.id, input.userId)).returning() + const user_data = await ctx.db.query.User.findFirst({ + where: eq(User.email, input.oldEmail), + }) + if (!user_data) { + throw new TRPCError({ code: "NOT_FOUND", message: `User with email: ${input.oldEmail} does not exist` }) + } + const user = await ctx.db.query.User.findFirst({ + where: eq(User.id, input.userId), + }) if (!user) { throw new TRPCError({ code: "NOT_FOUND", message: `User with id: ${input.userId} does not exist` }) } @@ -25,10 +30,12 @@ export const updateEmail = adminProcedure message: `Clerk user with id: ${input.userId} does not have a primary email address???`, }) - if (clerkUser.primaryEmailAddress?.emailAddress !== input.oldEmail) + // Clerk will always return the lowercased email from its API + if (clerkUser.primaryEmailAddress?.emailAddress !== input.oldEmail.toLowerCase()) throw new TRPCError({ code: "BAD_REQUEST", message: "Old email does not match" }) try { - await updateDbUserEmail(clerkUser.id, clerkUser.primaryEmailAddressId, input.newEmail) + await updateClerkUserEmail(clerkUser.id, input.newEmail) + await ctx.db.update(User).set({ email: input.newEmail }).where(eq(User.id, input.userId)) } catch (err) { console.error(err) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Failed to update email" }) @@ -37,13 +44,18 @@ export const updateEmail = adminProcedure return user }) -const updateDbUserEmail = async (userId: string, oldEmailAddressId: string, newEmailAddress: string) => { - const res = await clerkClient().emailAddresses.createEmailAddress({ +const updateClerkUserEmail = async (userId: string, newEmailAddress: string) => { + await clerkClient().emailAddresses.createEmailAddress({ userId, emailAddress: newEmailAddress, verified: true, primary: true, }) - await db.update(User).set({ email: res.emailAddress }).where(eq(User.id, userId)) - await clerkClient().emailAddresses.deleteEmailAddress(oldEmailAddressId) // cleanup + const user = await clerkClient().users.getUser(userId) + const primaryId = user.primaryEmailAddressId + const nonPrimaryEmails = user.emailAddresses.filter((email) => email.id !== primaryId) + + for (const email of nonPrimaryEmails) { + await clerkClient().emailAddresses.deleteEmailAddress(email.id) + } } From 9d52f471ae026c491d016d0ae2c8f0c3d27a4a2b Mon Sep 17 00:00:00 2001 From: ErikaKK <491649804@qq.com> Date: Fri, 1 Aug 2025 01:47:54 +0800 Subject: [PATCH 2/4] add user email update condition --- src/server/api/routers/admin/users/update-email.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/api/routers/admin/users/update-email.ts b/src/server/api/routers/admin/users/update-email.ts index 25c0fe5e0..d49f847fc 100644 --- a/src/server/api/routers/admin/users/update-email.ts +++ b/src/server/api/routers/admin/users/update-email.ts @@ -16,6 +16,12 @@ export const updateEmail = adminProcedure if (!user_data) { throw new TRPCError({ code: "NOT_FOUND", message: `User with email: ${input.oldEmail} does not exist` }) } + const user_email_data = await ctx.db.query.User.findFirst({ + where: eq(User.email, input.newEmail), + }) + if (!user_email_data) { + throw new TRPCError({ code: "FORBIDDEN", message: `User with email: ${input.newEmail} already exist` }) + } const user = await ctx.db.query.User.findFirst({ where: eq(User.id, input.userId), }) From d44ea7d7add7aabdf3b4474fe7b1fe7c8df625e0 Mon Sep 17 00:00:00 2001 From: ErikaKK <491649804@qq.com> Date: Fri, 1 Aug 2025 02:07:57 +0800 Subject: [PATCH 3/4] update logic --- src/server/api/routers/admin/users/update-email.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/server/api/routers/admin/users/update-email.ts b/src/server/api/routers/admin/users/update-email.ts index d49f847fc..403c9e027 100644 --- a/src/server/api/routers/admin/users/update-email.ts +++ b/src/server/api/routers/admin/users/update-email.ts @@ -19,7 +19,7 @@ export const updateEmail = adminProcedure const user_email_data = await ctx.db.query.User.findFirst({ where: eq(User.email, input.newEmail), }) - if (!user_email_data) { + if (user_email_data) { throw new TRPCError({ code: "FORBIDDEN", message: `User with email: ${input.newEmail} already exist` }) } const user = await ctx.db.query.User.findFirst({ @@ -40,7 +40,7 @@ export const updateEmail = adminProcedure if (clerkUser.primaryEmailAddress?.emailAddress !== input.oldEmail.toLowerCase()) throw new TRPCError({ code: "BAD_REQUEST", message: "Old email does not match" }) try { - await updateClerkUserEmail(clerkUser.id, input.newEmail) + await updateClerkUserEmail(clerkUser.id, clerkUser.primaryEmailAddressId, input.newEmail) await ctx.db.update(User).set({ email: input.newEmail }).where(eq(User.id, input.userId)) } catch (err) { console.error(err) @@ -50,18 +50,12 @@ export const updateEmail = adminProcedure return user }) -const updateClerkUserEmail = async (userId: string, newEmailAddress: string) => { +const updateClerkUserEmail = async (userId: string, oldEmailAddressId: string, newEmailAddress: string) => { await clerkClient().emailAddresses.createEmailAddress({ userId, emailAddress: newEmailAddress, verified: true, primary: true, }) - const user = await clerkClient().users.getUser(userId) - const primaryId = user.primaryEmailAddressId - const nonPrimaryEmails = user.emailAddresses.filter((email) => email.id !== primaryId) - - for (const email of nonPrimaryEmails) { - await clerkClient().emailAddresses.deleteEmailAddress(email.id) - } + await clerkClient().emailAddresses.deleteEmailAddress(oldEmailAddressId) } From d607a47af4add9535b2bb60cdc3d16e894895f1f Mon Sep 17 00:00:00 2001 From: ErikaKK <491649804@qq.com> Date: Fri, 1 Aug 2025 02:27:16 +0800 Subject: [PATCH 4/4] update redirect --- src/app/join/page.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/join/page.tsx b/src/app/join/page.tsx index 3ab9603cc..df77efdd6 100644 --- a/src/app/join/page.tsx +++ b/src/app/join/page.tsx @@ -80,10 +80,8 @@ export default function Join() { // careful of order await setActive({ session: res.createdSessionId }) // sets token from clerk await utils.users.getCurrent.refetch() - const { data: user, isLoading } = api.users.getCurrent.useQuery() - !isLoading && (user?.role === "admin" || user?.role === "committee") - ? router.push("/dashboard/admin") - : router.push("/dashboard") + + router.push("/dashboard") } } catch (error) { const { errors = [] } = error as ClerkError