🐛 Fix issues with merging guest user data (#1478)

This commit is contained in:
Luke Vella 2025-01-03 21:35:42 +00:00 committed by GitHub
parent f72f713946
commit 00548ab763
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 63 additions and 95 deletions

View file

@ -24,7 +24,7 @@ import { getValueByPath } from "@/utils/get-value-by-path";
import { decryptToken } from "@/utils/session"; import { decryptToken } from "@/utils/session";
import { CustomPrismaAdapter } from "./auth/custom-prisma-adapter"; import { CustomPrismaAdapter } from "./auth/custom-prisma-adapter";
import { mergeGuestsIntoUser, temporarilyMigrateData } from "./auth/merge-user"; import { mergeGuestsIntoUser } from "./auth/merge-user";
const providers: Provider[] = [ const providers: Provider[] = [
// When a user registers, we don't want to go through the email verification process // When a user registers, we don't want to go through the email verification process
@ -170,7 +170,14 @@ if (
const getAuthOptions = (...args: GetServerSessionParams) => const getAuthOptions = (...args: GetServerSessionParams) =>
({ ({
adapter: CustomPrismaAdapter(prisma), adapter: CustomPrismaAdapter(prisma, {
migrateData: async (userId) => {
const session = await getServerSession(...args);
if (session && session.user.email === null) {
await mergeGuestsIntoUser(userId, [session.user.id]);
}
},
}),
secret: process.env.SECRET_PASSWORD, secret: process.env.SECRET_PASSWORD,
session: { session: {
strategy: "jwt", strategy: "jwt",
@ -238,24 +245,18 @@ const getAuthOptions = (...args: GetServerSessionParams) =>
if (isUnregisteredUser) { if (isUnregisteredUser) {
return false; return false;
} }
} else { }
// when we login with a social account for the first time, the user is not created yet
// and the user id will be the same as the provider account id
// we handle this case the the prisma adapter when we link accounts
const isInitialSocialLogin = user.id === profile?.sub;
if (!isInitialSocialLogin) {
// merge guest user into newly logged in user // merge guest user into newly logged in user
const session = await getServerSession(...args); const session = await getServerSession(...args);
if (session && session.user.email === null) { if (session && session.user.email === null) {
// check if user exists
const count = await prisma.user.count({
where: {
email: user.email as string,
},
});
if (count !== 0) {
await mergeGuestsIntoUser(user.id, [session.user.id]); await mergeGuestsIntoUser(user.id, [session.user.id]);
} else {
// when logging in with a social account, the user doesn't exist yet
// so we temporarily migrate the data to a different guest user.
await temporarilyMigrateData(user.id, [session.user.id]);
}
} }
} }

View file

@ -13,10 +13,14 @@ import { PrismaAdapter } from "@auth/prisma-adapter";
import type { ExtendedPrismaClient, PrismaClient } from "@rallly/database"; import type { ExtendedPrismaClient, PrismaClient } from "@rallly/database";
import type { Adapter, AdapterAccount } from "next-auth/adapters"; import type { Adapter, AdapterAccount } from "next-auth/adapters";
export function CustomPrismaAdapter(client: ExtendedPrismaClient): Adapter { export function CustomPrismaAdapter(
client: ExtendedPrismaClient,
options: { migrateData: (userId: string) => Promise<void> },
): Adapter {
return { return {
...PrismaAdapter(client as PrismaClient), ...PrismaAdapter(client as PrismaClient),
linkAccount: (data) => { linkAccount: async (data) => {
await options.migrateData(data.userId);
return client.account.create({ return client.account.create({
data: { data: {
userId: data.userId, userId: data.userId,

View file

@ -1,9 +1,11 @@
import { prisma } from "@rallly/database"; import { prisma } from "@rallly/database";
import * as Sentry from "@sentry/nextjs";
export const mergeGuestsIntoUser = async ( export const mergeGuestsIntoUser = async (
userId: string, userId: string,
guestIds: string[], guestIds: string[],
) => { ) => {
try {
return await prisma.$transaction(async (tx) => { return await prisma.$transaction(async (tx) => {
await Promise.all([ await Promise.all([
tx.poll.updateMany({ tx.poll.updateMany({
@ -43,46 +45,7 @@ export const mergeGuestsIntoUser = async (
}), }),
]); ]);
}); });
}; } catch (error) {
Sentry.captureException(error);
export const temporarilyMigrateData = async ( }
providerId: string,
guestIds: string[],
) => {
return await prisma.$transaction(async (tx) => {
await Promise.all([
tx.poll.updateMany({
where: {
guestId: {
in: guestIds,
},
},
data: {
guestId: providerId,
},
}),
tx.participant.updateMany({
where: {
guestId: {
in: guestIds,
},
},
data: {
guestId: providerId,
},
}),
tx.comment.updateMany({
where: {
guestId: {
in: guestIds,
},
},
data: {
guestId: providerId,
},
}),
]);
});
}; };