Retire l'export exécutable (.exe) et la partie publique en ligne (/jouer)
Décision produit : seul l'export Web/SCORM (LMS) est pertinent — l'export exécutable Windows autonome (publish/build_package.py, bouton "Publier") et la partie publique par joueur (/jouer/<slug>, routes/public_play/, "Publier en ligne") sont jugés redondants et retirés. Conserve le mécanisme d'état "par joueur" (db/global_vars, db/rows, per_player) : infrastructure générique déjà utilisée par Score/Progression et testée indépendamment de toute route publique (voir tests/test_player_state.py), aucune raison de la retirer. _STATIC_ITEMS/_copy_characters (copie sélective des sprites CraftPix réellement utilisés) migrent de build_package.py vers build_scorm_package.py, seul appelant restant. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
82d00b3800
commit
e82eb7ce88
+1
-1
@@ -1 +1 @@
|
||||
from . import auth, games, objects, screens, elements, legacy_actions, flow, element_types, uploads, play, animations, global_vars, publish, custom_events, flow_blocks, public_play, scenes, onboarding
|
||||
from . import auth, games, objects, screens, elements, legacy_actions, flow, element_types, uploads, play, animations, global_vars, publish, custom_events, flow_blocks, scenes, onboarding
|
||||
|
||||
@@ -1 +1 @@
|
||||
from . import index, games_new, game_dashboard, game_rename, game_delete, game_toggle_public_played, game_scoring_view
|
||||
from . import index, games_new, game_dashboard, game_rename, game_delete, game_scoring_view
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
from flask import request, redirect, url_for
|
||||
|
||||
import db
|
||||
|
||||
from core.flask_app import app
|
||||
|
||||
|
||||
@app.route("/game/<slug>/toggle-public-played", methods=["POST"])
|
||||
def game_toggle_public_played(slug):
|
||||
"""Bascule "Publier en ligne" (voir db/games/is_public_played.py) —
|
||||
active/désactive la route publique /jouer/<slug> (routes/public_play/),
|
||||
jouable par n'importe quel visiteur anonyme avec sa propre partie
|
||||
(état par joueur, Phase 1). Distinct de "Publier" (export .zip
|
||||
exécutable mono-joueur, voir routes/publish/publish_game.py)."""
|
||||
db.set_public_played(slug, request.form.get("value") == "1")
|
||||
return redirect(request.referrer or url_for("game_dashboard", slug=slug))
|
||||
@@ -1,9 +0,0 @@
|
||||
from . import (
|
||||
game_play_public,
|
||||
runtime_payload_public,
|
||||
flow_node_run_data_public,
|
||||
flow_node_run_variable_public,
|
||||
flow_node_run_score_public,
|
||||
flow_node_run_status_public,
|
||||
flow_node_run_add_row_public,
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
from flask import jsonify, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>/flow/nodes/<int:node_id>/run-add-row", methods=["POST"])
|
||||
def flow_node_run_add_row_public(slug, node_id):
|
||||
"""Miroir public de routes/flow/flow_node_run_add_row.py (aperçu
|
||||
créateur) — voir routes/public_play/game_play_public.py pour le
|
||||
principe général."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
node = screens.get_flow_node(slug, node_id)
|
||||
if not node or node.get("node_type") != "action" or node.get("action_type") != "ajouter_ligne":
|
||||
return jsonify({"ok": False}), 400
|
||||
row_id = screens.apply_add_row_action(slug, node, player_id)
|
||||
resp = app.make_response(jsonify({"ok": row_id is not None, "row_id": row_id}))
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1,33 +0,0 @@
|
||||
from flask import jsonify, request, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>/flow/nodes/<int:node_id>/run-data", methods=["POST"])
|
||||
def flow_node_run_data_public(slug, node_id):
|
||||
"""Miroir public de routes/flow/flow_node_run_data.py (aperçu créateur)
|
||||
— voir routes/public_play/game_play_public.py pour le principe
|
||||
général. `player_id` (le cookie du visiteur) est passé à
|
||||
apply_data_action pour qu'un objet per_player agisse sur SA ligne."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
node = screens.get_flow_node(slug, node_id)
|
||||
if not node or node.get("node_type") != "action" or node.get("action_type") != "modifier_donnee":
|
||||
return jsonify({"ok": False}), 400
|
||||
if node.get("target_row_id") == screens.CLICKED_ROW_ID:
|
||||
body = request.get_json(silent=True) or {}
|
||||
node = {**node, "target_row_id": body.get("clicked_row_id")}
|
||||
elif node.get("target_row_id") == screens.LAST_INSERTED_ROW_ID:
|
||||
# Phase 4 — voir routes/flow/flow_node_run_data.py.
|
||||
body = request.get_json(silent=True) or {}
|
||||
node = {**node, "target_row_id": body.get("last_inserted_row_id")}
|
||||
ok = screens.apply_data_action(slug, node, player_id)
|
||||
resp = app.make_response(jsonify({"ok": ok}))
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1,25 +0,0 @@
|
||||
from flask import jsonify, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>/flow/nodes/<int:node_id>/run-score", methods=["POST"])
|
||||
def flow_node_run_score_public(slug, node_id):
|
||||
"""Miroir public de routes/flow/flow_node_run_score.py (aperçu
|
||||
créateur) — voir routes/public_play/game_play_public.py pour le
|
||||
principe général."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
node = screens.get_flow_node(slug, node_id)
|
||||
if not node or node.get("node_type") != "action" or node.get("action_type") != "modifier_score":
|
||||
return jsonify({"ok": False}), 400
|
||||
ok = screens.apply_score_action(slug, node, player_id)
|
||||
resp = app.make_response(jsonify({"ok": ok}))
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1,25 +0,0 @@
|
||||
from flask import jsonify, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>/flow/nodes/<int:node_id>/run-status", methods=["POST"])
|
||||
def flow_node_run_status_public(slug, node_id):
|
||||
"""Miroir public de routes/flow/flow_node_run_status.py (aperçu
|
||||
créateur) — voir routes/public_play/game_play_public.py pour le
|
||||
principe général."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
node = screens.get_flow_node(slug, node_id)
|
||||
if not node or node.get("node_type") != "action" or node.get("action_type") != "definir_statut_partie":
|
||||
return jsonify({"ok": False}), 400
|
||||
ok = screens.apply_status_action(slug, node, player_id)
|
||||
resp = app.make_response(jsonify({"ok": ok}))
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1,25 +0,0 @@
|
||||
from flask import jsonify, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>/flow/nodes/<int:node_id>/run-variable", methods=["POST"])
|
||||
def flow_node_run_variable_public(slug, node_id):
|
||||
"""Miroir public de routes/flow/flow_node_run_variable.py (aperçu
|
||||
créateur) — voir routes/public_play/game_play_public.py pour le
|
||||
principe général."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
node = screens.get_flow_node(slug, node_id)
|
||||
if not node or node.get("node_type") != "action" or node.get("action_type") != "modifier_variable":
|
||||
return jsonify({"ok": False}), 400
|
||||
ok = screens.apply_variable_action(slug, node, player_id)
|
||||
resp = app.make_response(jsonify({"ok": ok}))
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1,40 +0,0 @@
|
||||
import json
|
||||
|
||||
from flask import render_template, url_for, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>")
|
||||
def game_play_public(slug):
|
||||
"""Route PUBLIQUE, non authentifiée (voir core/auth_guard.py) —
|
||||
distincte de /game/<slug>/play (aperçu créateur, connecté, INCHANGÉE) :
|
||||
un vrai visiteur anonyme, identifié par un cookie (voir
|
||||
core/player_identity.py), avec sa propre partie (variables/objets
|
||||
per_player, voir db/global_vars/, db/rows/). 404 si le créateur n'a
|
||||
pas explicitement basculé "Publier en ligne" dans son tableau de bord
|
||||
— jamais exposé par défaut."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
game = db.game_meta(slug)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
payload = screens.full_game_payload(slug, player_id)
|
||||
resp = app.make_response(
|
||||
render_template(
|
||||
"play.html", game=game, screens_data=payload["screens"], payload_json=json.dumps(payload),
|
||||
asset_url=lambda filename: url_for("static", filename=filename),
|
||||
runtime_payload_url=url_for("runtime_payload_public", slug=slug),
|
||||
flow_node_run_data_url=url_for("flow_node_run_data_public", slug=slug, node_id=999999),
|
||||
flow_node_run_variable_url=url_for("flow_node_run_variable_public", slug=slug, node_id=999999),
|
||||
flow_node_run_score_url=url_for("flow_node_run_score_public", slug=slug, node_id=999999),
|
||||
flow_node_run_status_url=url_for("flow_node_run_status_public", slug=slug, node_id=999999),
|
||||
flow_node_run_add_row_url=url_for("flow_node_run_add_row_public", slug=slug, node_id=999999),
|
||||
)
|
||||
)
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1,20 +0,0 @@
|
||||
from flask import jsonify, abort
|
||||
|
||||
import db
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
from core.player_identity import get_or_create_player_id, set_player_id_cookie
|
||||
|
||||
|
||||
@app.route("/jouer/<slug>/runtime-payload")
|
||||
def runtime_payload_public(slug):
|
||||
"""Miroir public de routes/flow/runtime_payload.py (aperçu créateur) —
|
||||
voir routes/public_play/game_play_public.py pour le principe général."""
|
||||
if not db.is_public_played(slug):
|
||||
abort(404)
|
||||
player_id, is_new = get_or_create_player_id()
|
||||
resp = app.make_response(jsonify(screens.full_game_payload(slug, player_id)))
|
||||
if is_new:
|
||||
set_player_id_cookie(resp, player_id)
|
||||
return resp
|
||||
@@ -1 +1 @@
|
||||
from . import publish_game, export_scorm
|
||||
from . import export_scorm
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import os
|
||||
|
||||
from flask import after_this_request, send_file
|
||||
|
||||
import db
|
||||
from publish.build_package import build_game_zip
|
||||
|
||||
from core.flask_app import app
|
||||
|
||||
|
||||
@app.route("/game/<slug>/publish", methods=["POST"])
|
||||
def publish_game(slug):
|
||||
"""Construit et renvoie le zip exécutable autonome du jeu (voir
|
||||
publish/build_package.py) — protégée par la même garde d'accès que
|
||||
toutes les autres routes /game/<slug>/... (core/auth_guard.py),
|
||||
aucune vérification supplémentaire nécessaire ici."""
|
||||
zip_path, game_name = build_game_zip(slug)
|
||||
|
||||
@after_this_request
|
||||
def _cleanup(response):
|
||||
try:
|
||||
os.remove(zip_path)
|
||||
except OSError:
|
||||
pass
|
||||
return response
|
||||
|
||||
download_name = f"{db.slugify(game_name)}.zip"
|
||||
return send_file(zip_path, as_attachment=True, download_name=download_name, mimetype="application/zip")
|
||||
Reference in New Issue
Block a user