Ajoute la régénération des codes de récupération et le changement d'email
Depuis /profile : - "Codes de récupération 2FA" : régénère les 10 codes (invalide les 10 précédents d'un coup, voir auth.generate_recovery_codes) et les affiche une seule fois via le même modal qu'à l'inscription (session flash, core/recovery_codes_flash.py) — mot de passe actuel requis. - "Adresse email" : change l'adresse (mêmes règles qu'à l'inscription — format valide, unicité — voir auth/email_validation.py, désormais partagé avec create_user.py au lieu d'être dupliqué). Pour un compte "user", le dossier de son unique projet porte le nom de son adresse (project_slug = slugify(email)) : il est renommé pour suivre le changement (db/games/move_game.py, même logique d'unicité par suffixe que create_game()), sans quoi project_slug ne correspondrait plus à aucun dossier réel. Un "admin" n'a pas de project_slug dédié : rien n'est renommé pour ce rôle. 18 nouveaux tests (tests/test_profile.py) : mauvais mot de passe refusé pour les deux actions, mauvais format/email déjà pris refusés, dossier bien renommé et project_slug mis à jour, connexion possible avec la nouvelle adresse, anciens codes de récupération bien invalidés après régénération, modal jamais réaffiché deux fois. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5c2d7c49cd
commit
c8c949c430
+2
-1
@@ -32,6 +32,7 @@ from .games.game_meta import game_meta
|
||||
from .games.create_game import create_game
|
||||
from .games.update_game_name import update_game_name
|
||||
from .games.delete_game import delete_game
|
||||
from .games.move_game import move_game
|
||||
|
||||
from .definitions.list_definitions import list_definitions
|
||||
from .definitions.get_definition import get_definition
|
||||
@@ -63,7 +64,7 @@ from .global_vars.delete_global_variable_by_id import delete_global_variable_by_
|
||||
__all__ = [
|
||||
"PROJECTS_DIR", "FIELD_TYPES", "GLOBAL_VARIABLE_TYPES",
|
||||
"slugify", "table_name_for", "game_dir", "db_path", "connect",
|
||||
"list_games", "game_meta", "create_game", "update_game_name", "delete_game",
|
||||
"list_games", "game_meta", "create_game", "update_game_name", "delete_game", "move_game",
|
||||
"list_definitions", "get_definition", "create_definition", "rename_definition",
|
||||
"definitions_referencing", "add_field_to_definition", "update_field", "delete_field",
|
||||
"delete_definition",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import os
|
||||
|
||||
from ..game_dir import game_dir
|
||||
|
||||
|
||||
def move_game(old_slug, new_slug):
|
||||
"""Renomme le dossier d'un jeu vers un nouveau slug — utilisé quand un
|
||||
utilisateur change son adresse email (voir routes/auth/profile.py,
|
||||
project_slug = slugify(email) pour un compte "user") : le dossier
|
||||
physique du jeu doit suivre. Rend le nouveau slug unique de la même
|
||||
façon que create_game() si, par un hasard extrême, il correspond déjà
|
||||
à un dossier existant. Renvoie le slug FINAL (potentiellement suffixé),
|
||||
à enregistrer comme nouveau project_slug."""
|
||||
if old_slug == new_slug:
|
||||
return old_slug
|
||||
base = new_slug
|
||||
n = 2
|
||||
while os.path.isdir(game_dir(base)):
|
||||
base = f"{new_slug}-{n}"
|
||||
n += 1
|
||||
new_slug = base
|
||||
os.rename(game_dir(old_slug), game_dir(new_slug))
|
||||
return new_slug
|
||||
Reference in New Issue
Block a user