Ajoute une page de profil (modifier ses infos, mot de passe, supprimer son compte)
Le nom affiché dans la barre de navigation (base.html) devient un lien vers /profile : informations du compte (email en lecture seule, nom/ prénom modifiables), changement de mot de passe (mot de passe actuel requis + mêmes règles de force qu'à l'inscription/la réinitialisation), et une section "danger" pour demander la suppression du compte. La suppression exige le mot de passe actuel ET la saisie exacte de "SUPPRIMER" (deux confirmations distinctes pour une action irréversible) — routes/auth/profile.py. Pour un compte "user" (limité à un seul projet, créé automatiquement et impossible à supprimer autrement, voir core/auth_guard.py), supprimer le compte supprime aussi son unique projet sur le disque, faute de quoi il resterait orphelin sans plus aucun propriétaire. Un compte "admin" peut posséder plusieurs jeux qui ne lui sont pas dédiés de la même façon : ses projets ne sont jamais touchés. L'unique compte administrateur ne peut pas être supprimé (auth/ count_admins.py) — le supprimer bloquerait la création d'un nouveau compte admin (réservée au tout premier compte jamais créé, base vide). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d5a84413d1
commit
0d46abe193
@@ -1 +1 @@
|
||||
from . import register, register_2fa, login, login_2fa, logout, forgot_password, reset_password
|
||||
from . import register, register_2fa, login, login_2fa, logout, forgot_password, reset_password, profile
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from flask import g, redirect, render_template, request, session, url_for
|
||||
|
||||
import auth
|
||||
import db
|
||||
|
||||
from core.flask_app import app
|
||||
|
||||
|
||||
def _render(error=None, success=None):
|
||||
user = auth.get_user_by_id(g.current_user["id"])
|
||||
return render_template(
|
||||
"auth/profile.html", user=user, error=error, success=success,
|
||||
min_score_required=auth.MIN_SCORE_REQUIRED,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/profile", methods=["GET"])
|
||||
def profile():
|
||||
return _render()
|
||||
|
||||
|
||||
@app.route("/profile/update-name", methods=["POST"])
|
||||
def profile_update_name():
|
||||
nom = request.form.get("nom", "").strip()
|
||||
prenom = request.form.get("prenom", "").strip()
|
||||
if not nom or not prenom:
|
||||
return _render(error="Nom et prénom sont requis.")
|
||||
auth.update_profile(g.current_user["id"], nom, prenom)
|
||||
return _render(success="Informations mises à jour.")
|
||||
|
||||
|
||||
@app.route("/profile/change-password", methods=["POST"])
|
||||
def profile_change_password():
|
||||
user = g.current_user
|
||||
current_password = request.form.get("current_password", "")
|
||||
new_password = request.form.get("new_password", "")
|
||||
new_password_confirm = request.form.get("new_password_confirm", "")
|
||||
if not auth.verify_password(user, current_password):
|
||||
return _render(error="Mot de passe actuel incorrect.")
|
||||
if new_password != new_password_confirm:
|
||||
return _render(error="Les nouveaux mots de passe ne correspondent pas.")
|
||||
if not auth.password_strength(new_password)["valid"]:
|
||||
return _render(error="Nouveau mot de passe trop faible — respecte les critères affichés.")
|
||||
auth.set_password(user["id"], new_password)
|
||||
return _render(success="Mot de passe modifié.")
|
||||
|
||||
|
||||
@app.route("/profile/delete", methods=["POST"])
|
||||
def profile_delete():
|
||||
user = g.current_user
|
||||
current_password = request.form.get("current_password", "")
|
||||
confirm_text = request.form.get("confirm_text", "").strip().upper()
|
||||
if not auth.verify_password(user, current_password):
|
||||
return _render(error="Mot de passe incorrect — suppression annulée.")
|
||||
if confirm_text != "SUPPRIMER":
|
||||
return _render(error='Tape "SUPPRIMER" pour confirmer — suppression annulée.')
|
||||
if user["role"] == "admin" and auth.count_admins() <= 1:
|
||||
return _render(error="Impossible de supprimer l'unique compte administrateur.")
|
||||
|
||||
# Un compte "user" ne possède qu'UN SEUL projet, créé automatiquement
|
||||
# pour lui et impossible à supprimer autrement (voir core/auth_guard.py,
|
||||
# game_delete bloqué pour ce rôle) — supprimer le compte est donc la
|
||||
# seule façon de s'en débarrasser aussi, sans quoi il resterait orphelin
|
||||
# sur le disque sans plus aucun propriétaire. Un "admin" peut posséder
|
||||
# plusieurs jeux qui ne lui sont pas dédiés de la même façon : ses
|
||||
# projets restent intacts.
|
||||
if user["role"] != "admin" and user.get("project_slug"):
|
||||
game_dir = db.game_dir(user["project_slug"])
|
||||
if os.path.isdir(game_dir):
|
||||
shutil.rmtree(game_dir)
|
||||
|
||||
auth.delete_user(user["id"])
|
||||
session.clear()
|
||||
return redirect(url_for("login"))
|
||||
Reference in New Issue
Block a user