🐛 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 { CustomPrismaAdapter } from "./auth/custom-prisma-adapter";
import { mergeGuestsIntoUser, temporarilyMigrateData } from "./auth/merge-user";
import { mergeGuestsIntoUser } from "./auth/merge-user";
const providers: Provider[] = [
// When a user registers, we don't want to go through the email verification process
@ -170,7 +170,14 @@ if (
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,
session: {
strategy: "jwt",
@ -238,24 +245,18 @@ const getAuthOptions = (...args: GetServerSessionParams) =>
if (isUnregisteredUser) {
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
const session = await getServerSession(...args);
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]);
} 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]);
}
await mergeGuestsIntoUser(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 { 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 {
...PrismaAdapter(client as PrismaClient),
linkAccount: (data) => {
linkAccount: async (data) => {
await options.migrateData(data.userId);
return client.account.create({
data: {
userId: data.userId,

View file

@ -1,88 +1,51 @@
import { prisma } from "@rallly/database";
import * as Sentry from "@sentry/nextjs";
export const mergeGuestsIntoUser = async (
userId: string,
guestIds: string[],
) => {
return await prisma.$transaction(async (tx) => {
await Promise.all([
tx.poll.updateMany({
where: {
guestId: {
in: guestIds,
try {
return await prisma.$transaction(async (tx) => {
await Promise.all([
tx.poll.updateMany({
where: {
guestId: {
in: guestIds,
},
},
},
data: {
guestId: null,
userId: userId,
},
}),
data: {
guestId: null,
userId: userId,
},
}),
tx.participant.updateMany({
where: {
guestId: {
in: guestIds,
tx.participant.updateMany({
where: {
guestId: {
in: guestIds,
},
},
},
data: {
guestId: null,
userId: userId,
},
}),
data: {
guestId: null,
userId: userId,
},
}),
tx.comment.updateMany({
where: {
guestId: {
in: guestIds,
tx.comment.updateMany({
where: {
guestId: {
in: guestIds,
},
},
},
data: {
guestId: null,
userId: userId,
},
}),
]);
});
};
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,
},
}),
]);
});
data: {
guestId: null,
userId: userId,
},
}),
]);
});
} catch (error) {
Sentry.captureException(error);
}
};