from typing import Any
from flask import g, redirect, render_template, request, url_for
from werkzeug.wrappers import Response
import auth
import db
import game_engine
from core.flask_app import app
# Choix de PREMIER niveau, avant le catalogue des types de jeu (voir
# db.ONBOARDING_TYPES) : "support" n'y figure jamais (schéma/notions
# entièrement différents, voir document_engine/), posé ici comme une
# carte de plus dans la même grille visuelle (templates/onboarding/
# onboarding_new.html réutilise sa mécanique de sélection existante sans
# aucune modification JS, voir static/js/onboarding/onboarding_new.js).
_SUPPORT_ONBOARDING_CARD: dict[str, Any] = {
"label": "Support de formation",
"tagline": "Un contenu structuré, prêt à publier.",
"icon": "📄",
"description": (
'Un support de formation clair,'
" sans une ligne de code"
'
'
'- ✓'
"Mise en page automatique — dépose tes blocs,"
" l'alignement se fait tout seul
"
'- ✓'
"Formes & mini-jeux — habille et anime ton"
" contenu à volonté
"
'- ✓'
"Aperçu & publication — vois exactement ce que"
" verra l'apprenant
"
"
"
),
}
@app.route("/onboarding", methods=["GET", "POST"])
def onboarding_new() -> str | Response:
"""Point d'entrée UNIQUE pour créer un projet — jeu (environnement 2D)
OU support de formation (voir docs/plan/PLAN.md), deux entités racines
séparées. Un compte peut avoir un projet DE CHAQUE type (project_slug
ET support_slug, voir core/auth_guard.py) : chaque carte du catalogue
n'est proposée que si son slot correspondant n'est pas déjà rempli
(compte "user" restreint — un admin, lui, n'a aucun slot dédié, illimité
des deux côtés)."""
user = g.current_user
restricted = user["role"] != "admin"
has_game = restricted and bool(user.get("project_slug"))
has_support = restricted and bool(user.get("support_slug"))
if has_game and has_support:
# Les deux slots sont déjà remplis — plus rien à créer ici.
return redirect(url_for("index"))
onboarding_types: dict[str, dict[str, Any]] = {}
if not has_support:
onboarding_types["support"] = _SUPPORT_ONBOARDING_CARD
if not has_game:
onboarding_types.update(db.ONBOARDING_TYPES)
error = None
if request.method == "POST":
onboarding_type = request.form.get("onboarding_type", "")
name = request.form.get("name", "").strip()
if onboarding_type not in onboarding_types:
error = "Choisis un type de projet."
elif not name:
error = "Donne un nom à ton projet."
elif onboarding_type == "support":
return redirect(_create_support_for_user(user, name))
else:
return redirect(_create_project_for_user(user, onboarding_type, name))
return render_template(
"onboarding/onboarding_new.html",
onboarding_types=onboarding_types,
error=error,
)
def _create_support_for_user(user: dict[str, Any], name: str) -> str:
slug = db.create_support(name, owner_folder=str(user["id"]))
if user["role"] != "admin":
auth.set_support_slug(user["id"], slug)
return url_for("document_edit", slug=slug)
def _create_project_for_user(user: dict[str, Any], onboarding_type: str, name: str) -> str:
# owner_folder = l'id du compte, jamais son email (voir
# routes/games/games_new.py, même convention).
slug = db.create_game(name, owner_folder=str(user["id"]))
db.set_onboarding_type(slug, onboarding_type)
if user["role"] != "admin":
# project_slug = LE seul environnement 2D d'un compte "user" (voir
# core/auth_guard.py) — un admin n'utilise pas cette colonne, ses
# projets se retrouvent via db.list_games() comme avant.
auth.set_project_slug(user["id"], slug)
screen_kind = db.ONBOARDING_TYPES[onboarding_type]["screen_kind"]
game_engine.create_screen(slug, name, kind=screen_kind)
return url_for("game_dashboard", slug=slug)