Feature: Suppression de son compte

This commit is contained in:
2026-07-03 19:49:32 +02:00
parent 89190c4561
commit 2281894802
6 changed files with 169 additions and 5 deletions
+70
View File
@@ -252,6 +252,76 @@ router.put('/me', requireAuth, async (req, res, next) => {
} catch (e) { next(e); }
});
// ── Suppression définitive du compte (self-service) ────────────────────────
const DeleteMeSchema = z.object({
password: z.string().min(1),
});
router.delete('/me', requireAuth, (req, res, next) => {
try {
const { password } = DeleteMeSchema.parse(req.body);
const user = db
.prepare('SELECT id, email, display_name, role, password_hash FROM users WHERE id = ?')
.get(req.user.id);
if (!user) throw new HttpError(404, 'Utilisateur introuvable');
const ok = bcrypt.compareSync(password, user.password_hash);
if (!ok) throw new HttpError(401, 'Mot de passe incorrect.');
// Empêche de se retrouver sans aucun administrateur sur l'application
if (user.role === 'admin') {
const { n: adminCount } = db.prepare("SELECT COUNT(*) AS n FROM users WHERE role = 'admin'").get();
if (adminCount <= 1) {
throw new HttpError(400, "Vous êtes le seul administrateur de l'application. Promouvez un autre compte en administrateur avant de supprimer le vôtre.");
}
}
// Log AVANT suppression : target_user_id/actor_id passeront à NULL après le DELETE
// (FK ON DELETE SET NULL), mais les informations restent lisibles dans "details".
audit(req, {
action: 'account_self_deleted',
category: 'account',
actorId: user.id,
targetUserId: user.id,
details: {
email: user.email,
display_name: user.display_name,
role: user.role,
initiated_by: 'self',
note: "Suppression de compte initiée par l'utilisateur lui-même depuis Mon compte.",
},
});
// Notifier les autres administrateurs
const otherAdmins = db.prepare("SELECT id FROM users WHERE role = 'admin' AND id != ?").all(user.id);
if (otherAdmins.length > 0) {
const insertNotif = db.prepare(
'INSERT INTO notifications (user_id, type, title, body, link) VALUES (?, ?, ?, ?, ?)'
);
const notifyTx = db.transaction((rows) => {
for (const admin of rows) {
insertNotif.run(
admin.id,
'security',
'Suppression de compte utilisateur',
`${user.display_name || user.email} (${user.email}) a supprimé définitivement son propre compte.`,
'/admin?section=audit-logs',
);
}
});
notifyTx(otherAdmins);
}
// Suppression définitive — cascade en base sur toutes les données liées
// (investisseurs, plateformes, investissements, remboursements, comptes,
// préférences, notifications, tickets, appareils de confiance, etc.)
db.prepare('DELETE FROM users WHERE id = ?').run(user.id);
res.status(204).end();
} catch (e) { next(e); }
});
// ── Vérification d'adresse email ──────────────────────────────────────────
router.get('/verify-email', (req, res, next) => {
try {