import { PrismaPg } from '@prisma/adapter-pg'; import { PrismaClient } from '@prisma/client'; /** * Accès direct à la base, pour la mise en place des tests seulement. * * Certains états ne se posent pas par l'interface — retirer un second facteur * dont on a perdu le secret, par exemple. Les fabriquer ici garde la suite * rejouable sans ajouter au produit une porte qui n'aurait pas lieu d'exister. */ let client: PrismaClient | null = null; function db(): PrismaClient { // Prisma 7 exige un adaptateur : le client applicatif n'est pas réutilisable // ici, il vit derrière `server-only`. client ??= new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), }); return client; } /** Remet un compte à l'état « aucun second facteur », sans effet s'il n'en a pas. */ export async function resetMfa(email: string): Promise { const user = await db().user.findUnique({ where: { email }, select: { id: true }, }); if (!user) return; await db().user.update({ where: { id: user.id }, data: { mfaSecretEnc: null, mfaEnrolledAt: null, mfaLastStep: null }, }); await db().mfaRecoveryCode.deleteMany({ where: { userId: user.id } }); } /** * Recule la date de dépôt d'une pièce. * * Aucune interface ne permet d'antidater, et c'est bien ainsi. Sans ce levier, * la moitié utile de la purge — celle qui efface — resterait invérifiable : * seule l'échéance atteinte la déclenche, et elle se compte en mois. * * La transaction pose `app.account_id` : la table est protégée par RLS, et une * mise à jour sans compte courant ne toucherait aucune ligne — en silence. */ export async function backdateDocument( name: string, months: number, ): Promise { const document = await db().$queryRaw>` SELECT id, "accountId" FROM "Document" WHERE name = ${name} LIMIT 1 `; const found = document[0]; if (!found) throw new Error(`Pièce introuvable : ${name}`); const uploadedAt = new Date(); uploadedAt.setMonth(uploadedAt.getMonth() - months); await db().$transaction(async (tx) => { await tx.$executeRaw`SELECT set_config('app.account_id', ${found.accountId}, true)`; await tx.$executeRaw`UPDATE "Document" SET "uploadedAt" = ${uploadedAt} WHERE id = ${found.id}`; }); }