Files
Forge-Engine/db/games/project_slug.py
T
williamandClaude Sonnet 5 0f23024882
Build and deploy / test-python (push) Failing after 3m14s
Build and deploy / test-js (push) Successful in 53s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
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>
2026-09-02 06:22:03 +02:00

33 lines
1.5 KiB
Python

"""Convention du slug composé "propriétaire_projet" (voir le plan
"Structure de dossiers propriétaire/projet") : un slug encode en réalité
deux segments — le dossier PROPRIÉTAIRE (slugifié depuis l'email du
compte qui a créé le projet) et le dossier PROJET à l'intérieur — pour
que projects/ soit une vraie arborescence par utilisateur
(projects/<propriétaire>/<projet>/), sans jamais toucher aux ~40 fichiers
de routes qui déclarent <slug> dans leur URL : le slug reste, pour elles,
un seul segment plat et opaque.
"_" comme séparateur est sûr et non ambigu : slugify() (voir
db/slugify.py) ne produit jamais de "_", seulement [a-z0-9-]+ — un slug
composé peut donc toujours être découpé sans collision sur la PREMIÈRE
occurrence de "_" (le dossier propriétaire, lui, n'en contient jamais).
Seule une poignée de fonctions dans db/games/ (game_dir, create_game,
move_game, list_games) savent que le slug encode ce chemin composé — si
la convention change un jour, ce fichier est le seul à modifier."""
def build_slug(owner_folder, project_part):
return f"{owner_folder}_{project_part}"
def split_slug(slug):
"""(owner_folder, project_part) si `slug` est bien composé, sinon
(slug, None) — un slug "plat" (créé avant cette convention, pas encore
migré par scripts/migrate_flat_project_slugs.py) reste lisible tel
quel par le code appelant (repli sur l'ancien comportement)."""
owner_folder, sep, project_part = slug.partition("_")
if not sep:
return slug, None
return owner_folder, project_part