From b4fea53bac8a421f1e9a8f92a1baad1bf8b655af Mon Sep 17 00:00:00 2001 From: notmd <33456881+notmd@users.noreply.github.com> Date: Wed, 19 Apr 2023 23:25:26 +0700 Subject: [PATCH] Create backend user when generate jwt (#2702) Avoid flooding the backend log with user not found error --- website/src/lib/oasst_api_client.ts | 8 +++- website/src/pages/api/auth/[...nextauth].ts | 42 ++++++++++++--------- website/types/next-auth.d.ts | 2 +- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 3eac7d6396..c9064c4c04 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -400,7 +400,7 @@ export class OasstApiClient { async set_tos_acceptance(user: BackendUserCore) { // NOTE: we do a post here to force create the user if it does not exist - const backendUser = await this.post(`/api/v1/frontend_users/`, user); + const backendUser = await this.upsert_frontend_user(user); await this.put(`/api/v1/users/${backendUser.user_id}?tos_acceptance=true`); } @@ -419,6 +419,12 @@ export class OasstApiClient { return this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); } + // TODO: add update-able fields eg: enbaled, notes, show_on_leaderboard, etc.. + upsert_frontend_user(user: BackendUserCore) { + // the backend does a upsert operation with this call + return this.post(`/api/v1/frontend_users/`, user); + } + fetch_trollboard(time_frame: TrollboardTimeFrame, { limit, enabled }: { limit?: number; enabled?: boolean }) { return this.get(`/api/v1/trollboards/${time_frame}`, { max_count: limit, diff --git a/website/src/pages/api/auth/[...nextauth].ts b/website/src/pages/api/auth/[...nextauth].ts index 5a61922a65..b1a5a801a4 100644 --- a/website/src/pages/api/auth/[...nextauth].ts +++ b/website/src/pages/api/auth/[...nextauth].ts @@ -137,7 +137,9 @@ const authOptions: AuthOptions = { * Update the user's role after they have successfully signed in */ async signIn({ user, account, isNewUser }) { - if (isNewUser && account.provider === "email") { + if (isNewUser && account.provider === "email" && !user.name) { + // only generate a username if the user is new and they signed up with email and they don't have a name + // although the name already assigned in the jwt callback, this is to ensure notthing breaks, and we should never reach here. await prisma.user.update({ data: { name: generateUsername(), @@ -200,6 +202,25 @@ export default function auth(req: NextApiRequest, res: NextApiResponse) { select: { name: true, role: true, isNew: true, accounts: true, id: true }, }); + if (!frontendUser) { + // should never reach here + throw new Error("User not found"); + } + + // TODO avoid duplicate logic with the signIn event + if (frontendUser.isNew && !frontendUser.name) { + // jwt callback is called before signIn event, so we need to assign the name here otherwise the backend will refuse the request + frontendUser.name = generateUsername(); + await prisma.user.update({ + data: { + name: frontendUser.name, + }, + where: { + id: frontendUser.id, + }, + }); + } + const backendUser = convertToBackendUserCore(frontendUser); if (backendUser.auth_method === "discord") { const discordAccount = frontendUser.accounts.find((a) => a.provider === "discord"); @@ -214,22 +235,9 @@ export default function auth(req: NextApiRequest, res: NextApiResponse) { if (!token.tosAcceptanceDate || !token.backendUserId) { const oasstApiClient = createApiClientFromUser(backendUser); - try { - /** - * when first creating a new user, the python backend is not informed about it - * so this call will return a 404 - * - * in the frontend, when the user accepts the tos, we do a full refresh - * which means this function will be called again. - */ - const { user_id, tos_acceptance_date } = await oasstApiClient.fetch_frontend_user(backendUser); - token.backendUserId = user_id; - token.tosAcceptanceDate = tos_acceptance_date; - } catch (err) { - if (err.httpStatusCode !== 404) { - throw err; - } - } + const frontendUser = await oasstApiClient.upsert_frontend_user(backendUser); + token.backendUserId = frontendUser.user_id; + token.tosAcceptanceDate = frontendUser.tos_acceptance_date; } return token; }, diff --git a/website/types/next-auth.d.ts b/website/types/next-auth.d.ts index 7eb51ff853..f7effcdc89 100644 --- a/website/types/next-auth.d.ts +++ b/website/types/next-auth.d.ts @@ -29,6 +29,6 @@ declare module "next-auth/jwt" { /** id of user in the data backend */ backendUserId?: string; /** Iso timestamp of the user's acceptance of the terms of service */ - tosAcceptanceDate?: string; + tosAcceptanceDate: string | null; } }