Build and deploy / test-python (push) Successful in 11m5s
Build and deploy / test-js (push) Successful in 55s
Build and deploy / lint-python (push) Successful in 6m29s
Build and deploy / lint-js (push) Failing after 1m39s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 5m18s
Bug reel constate le 21/09/2026 : un element Scenario cree avant la refonte en arbre de decision (ancien schema plat "situation"/"choices"/ "correct_index") faisait planter silencieusement le panneau Proprietes cote client des la selection - scenario.nodes etait inexistant sur l'ancienne forme, aucune erreur visible, juste "il ne se passe rien". Cause : document_edit.py et document_render.py renvoyaient les attributs BRUTS de la base au client, jamais revalides - contrairement a la route d'ecriture qui, elle, sanitize deja avant de persister. Ajoute document_engine.sanitize_element_attributes(kind, attributes), point d'entree unique de dispatch kind -> sanitize_X_config, utilise desormais a la fois en ecriture (document_element_update.py, qui reutilise ce nouveau dispatch au lieu de son if/elif duplique) ET en lecture (document_edit.py/document_render.py). Elimine toute la classe de bug "schema devenu obsolete apres une evolution du modele de donnees d'un mini-jeu, donnee jamais retouchee depuis" - present et futur, pas seulement pour Scenario. Migre les donnees reelles deja affectees (support de test, element 46) vers le nouveau schema en arbre, en preservant integralement le contenu deja redige par l'utilisateur (situation + 3 choix/consequences du scenario "chat sur la route"). Ajoute un test de non-regression qui ecrit delibirement l'ancien schema en base (en contournant le sanitize de la route d'ecriture, pour simuler une donnee reellement ancienne jamais nettoyee) puis verifie que /edit et /render renvoient une structure saine au client. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
2.3 KiB
Python
49 lines
2.3 KiB
Python
from typing import Any
|
|
|
|
from flask import jsonify, request
|
|
from werkzeug.wrappers import Response
|
|
|
|
import db
|
|
import document_engine
|
|
from core.flask_app import app
|
|
|
|
|
|
@app.route("/document/<slug>/elements/<int:element_id>/update", methods=["POST"])
|
|
def document_element_update(slug: str, element_id: int) -> Response | tuple[Response, int]:
|
|
"""Remplace les attributs d'un élément — un formulaire du panneau
|
|
Propriétés (voir static/document/js/document-editor.js) envoie
|
|
systématiquement l'état complet de ses champs.
|
|
|
|
Quiz, Association, Memory, Mots mêlés et Scénario sont les seuls
|
|
kinds revalidés côté serveur (document_engine.sanitize_element_attributes,
|
|
même convention que game_engine/rendering/quiz_box_config.py côté
|
|
jeu) : leur forme (liste de questions/choix, liste de paires, liste
|
|
de cartes, liste de mots, arbre de scénarios) doit rester
|
|
structurellement correcte pour que le rendu ne plante jamais,
|
|
contrairement aux autres kinds (texte/forme/image...) dont les
|
|
attributs sont de simples valeurs scalaires sans structure à
|
|
garantir. Même sanitizer utilisé en LECTURE par document_edit.py/
|
|
document_render.py — un élément dont les attributs stockés datent
|
|
d'un schéma devenu obsolète est ainsi normalisé partout, jamais
|
|
seulement à l'écriture."""
|
|
element = document_engine.get_document_element(slug, element_id)
|
|
if element is None:
|
|
return jsonify({"error": "élément introuvable"}), 404
|
|
attributes: dict[str, Any] = request.get_json(force=True) or {}
|
|
attributes = document_engine.sanitize_element_attributes(element["kind"], attributes)
|
|
document_engine.update_document_element_attributes(slug, element_id, attributes)
|
|
element = db.assert_not_none(
|
|
document_engine.get_document_element(slug, element_id),
|
|
"element_id verifie present juste au-dessus, aucune suppression concurrente possible entre-temps ici",
|
|
)
|
|
elements_by_parent: dict[int | None, list[dict[str, Any]]] = {}
|
|
for el in document_engine.list_document_elements(slug):
|
|
elements_by_parent.setdefault(el["parent_id"], []).append(el)
|
|
return jsonify(
|
|
{
|
|
"ok": True,
|
|
"attributes": element["attributes"],
|
|
"rendered_html": document_engine.render_document_element(element, elements_by_parent),
|
|
}
|
|
)
|