import { prisma } from "@/lib/api/db"; import bcrypt from "bcrypt"; import removeFolder from "@/lib/api/storage/removeFolder"; import Stripe from "stripe"; import { DeleteUserBody } from "@/types/global"; import removeFile from "@/lib/api/storage/removeFile"; export default async function deleteUserById( userId: number, body: DeleteUserBody, isServerAdmin?: boolean ) { // First, we retrieve the user from the database const user = await prisma.user.findUnique({ where: { id: userId }, }); if (!user) { return { response: "Invalid credentials.", status: 404, }; } if (!isServerAdmin) { if (user.password) { const isPasswordValid = bcrypt.compareSync( body.password, user.password as string ); if (!isPasswordValid && !isServerAdmin) { return { response: "Invalid credentials.", status: 401, // Unauthorized }; } } else { return { response: "User has no password. Please reset your password from the forgot password page.", status: 401, // Unauthorized }; } } // Delete the user and all related data within a transaction await prisma .$transaction( async (prisma) => { // Delete Access Tokens await prisma.accessToken.deleteMany({ where: { userId }, }); // Delete whitelisted users await prisma.whitelistedUser.deleteMany({ where: { userId }, }); // Delete links await prisma.link.deleteMany({ where: { collection: { ownerId: userId } }, }); // Delete tags await prisma.tag.deleteMany({ where: { ownerId: userId }, }); // Find collections that the user owns const collections = await prisma.collection.findMany({ where: { ownerId: userId }, }); for (const collection of collections) { // Delete related users and collections relations await prisma.usersAndCollections.deleteMany({ where: { collectionId: collection.id }, }); // Delete archive folders removeFolder({ filePath: `archives/${collection.id}` }); await removeFolder({ filePath: `archives/preview/${collection.id}`, }); } // Delete collections after cleaning up related data await prisma.collection.deleteMany({ where: { ownerId: userId }, }); // Delete subscription if (process.env.STRIPE_SECRET_KEY) await prisma.subscription.delete({ where: { userId }, }); // .catch((err) => console.log(err)); await prisma.usersAndCollections.deleteMany({ where: { OR: [{ userId: userId }, { collection: { ownerId: userId } }], }, }); // Delete user's avatar await removeFile({ filePath: `uploads/avatar/${userId}.jpg` }); // Finally, delete the user await prisma.user.delete({ where: { id: userId }, }); }, { timeout: 20000 } ) .catch((err) => console.log(err)); if (process.env.STRIPE_SECRET_KEY) { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: "2022-11-15", }); try { const listByEmail = await stripe.customers.list({ email: user.email?.toLowerCase(), expand: ["data.subscriptions"], }); if (listByEmail.data[0].subscriptions?.data[0].id) { const deleted = await stripe.subscriptions.cancel( listByEmail.data[0].subscriptions?.data[0].id, { cancellation_details: { comment: body.cancellation_details?.comment, feedback: body.cancellation_details?.feedback, }, } ); return { response: deleted, status: 200, }; } } catch (err) { console.log(err); } } return { response: "User account and all related data deleted successfully.", status: 200, }; }