Structure de dossiers par utilisateur : projects/<propriétaire>/<projet>/
Remplace le rangement plat projects/<slug>/ par une vraie arborescence par compte créateur, sans toucher aux routes existantes (aucune ne déclare de "/" dans son <slug> : le chemin composé "propriétaire_projet" reste un détail interne à db/, décodé par db/games/project_slug.py, seul fichier à modifier si la convention change un jour). - db/game_dir.py, create_game.py, delete_game.py, list_games.py, move_game.py : résolvent/construisent ce chemin composé. Bénéfice direct : deux comptes différents peuvent chacun avoir un projet nommé pareil sans collision (l'unicité ne se vérifie plus que par dossier propriétaire). move_game.py renomme désormais le dossier PROPRIÉTAIRE entier (changement d'email), prêt pour un futur multi-projet. - scripts/migrate_flat_project_slugs.py : migration des projets déjà créés sous l'ancien rangement plat (simulation par défaut, --apply pour exécuter). - routes/auth/profile.py, tests/conftest.py : suppression de compte/jeu de test via db.delete_game (nettoie aussi le dossier propriétaire devenu vide) plutôt qu'un shutil.rmtree direct du seul dossier projet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d5a59bdbd8
commit
0f23024882
+29
-17
@@ -3,30 +3,43 @@ import os
|
||||
from ..connection import connect
|
||||
from ..game_dir import game_dir
|
||||
from ..slugify import slugify
|
||||
from .get_game_type import DEFAULT_GAME_TYPE
|
||||
from .project_slug import build_slug
|
||||
|
||||
|
||||
def create_game(name, slug_override=None, game_type=DEFAULT_GAME_TYPE):
|
||||
def create_game(name, owner_folder=None, project_slug_override=None):
|
||||
"""Feature 1 : crée le dossier du jeu, ses fichiers index.html/css/js
|
||||
reliés entre eux, et sa base de données dédiée (nom du jeu en méta).
|
||||
|
||||
slug_override : impose le nom du dossier au lieu de le dériver de
|
||||
`name` — utilisé par l'inscription (auth/) pour que le dossier d'un
|
||||
compte porte son adresse email (slugifiée), indépendamment du nom
|
||||
donné à son jeu. Toujours rendu unique de la même façon (suffixe
|
||||
-2/-3...) si, par un hasard extrême, le dossier existe déjà.
|
||||
owner_folder : dossier PROPRIÉTAIRE (voir db/games/project_slug.py —
|
||||
structure de dossiers par utilisateur), typiquement
|
||||
slugify(email_du_compte) — le slug final composé
|
||||
"<owner_folder>_<project_part>" résout vers un vrai chemin imbriqué
|
||||
projects/<owner_folder>/<project_part>/. Omis (None) : repli sur
|
||||
l'ancien comportement plat (slug à un seul segment, projects/<slug>/)
|
||||
— utile pour les tests de la couche données qui n'ont pas de compte
|
||||
utilisateur à représenter.
|
||||
|
||||
game_type : "document" (défaut, éditeur générique actuel) ou "jeu_2d"
|
||||
(éditeur de scène — voir get_game_type.py) — choisi une fois pour
|
||||
toutes à la création, gate quel éditeur/quel rendu jouable ce jeu
|
||||
utilise (voir routes/screens/screen_edit.py)."""
|
||||
slug = slugify(slug_override) if slug_override else slugify(name)
|
||||
base = slug
|
||||
project_slug_override : impose le nom du dossier PROJET au lieu de le
|
||||
dériver de `name` — utilisé par l'inscription (auth/, voir
|
||||
routes/onboarding/) pour que le tout premier projet d'un compte porte
|
||||
un nom de dossier prévisible. Le suffixe d'unicité (-2/-3...) ne
|
||||
compare que parmi les projets déjà présents dans CE `owner_folder`
|
||||
(deux comptes différents peuvent donc avoir chacun un projet nommé
|
||||
pareil, sans collision).
|
||||
|
||||
Un projet n'a plus de "type" propre (voir screens/screens_repo/
|
||||
ensure_schema.py — fusion des moteurs, "document"/"jeu_2d" est
|
||||
désormais une propriété PAR ÉCRAN) : un projet fraîchement créé n'a
|
||||
par défaut aucun écran, c'est à l'appelant d'en créer un premier avec
|
||||
le "kind" voulu (voir screens.create_screen)."""
|
||||
project_part = slugify(project_slug_override) if project_slug_override else slugify(name)
|
||||
base = project_part
|
||||
n = 2
|
||||
while os.path.isdir(game_dir(base)):
|
||||
base = f"{slug}-{n}"
|
||||
while os.path.isdir(game_dir(build_slug(owner_folder, base) if owner_folder else base)):
|
||||
base = f"{project_part}-{n}"
|
||||
n += 1
|
||||
slug = base
|
||||
project_part = base
|
||||
slug = build_slug(owner_folder, project_part) if owner_folder else project_part
|
||||
|
||||
os.makedirs(game_dir(slug), exist_ok=True)
|
||||
|
||||
@@ -84,7 +97,6 @@ console.log("Jeu chargé.");
|
||||
"""
|
||||
)
|
||||
conn.execute("INSERT INTO _meta (key, value) VALUES ('name', ?)", (name,))
|
||||
conn.execute("INSERT INTO _meta (key, value) VALUES ('game_type', ?)", (game_type,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return slug
|
||||
|
||||
Reference in New Issue
Block a user