Feature: Suppression de son compte
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user