- Nouveau db/assert_not_none.py : centralise l'unique suppression
Bandit/Ruff (# nosec B101 / # noqa: S101) de narrowing de type dans
tout le moteur. Remplace 11 sites disperses (ai/chat.py, ai/tools.py,
routes/scenes/scene_object_{add,collision,geometry,personnage_data,
quiz_config}.py, screens/payload/full_game_payload.py,
scripts/build_demo_dialogues.py) qui repetaient chacun le meme
commentaire empile - Sonar (python:S7632) ne parse pas deux
commentaires # sur une ligne, meme si Ruff et Bandit les acceptent
chacun tres bien (contrainte structurelle documentee dans
CODE_QUALITY.md : chaque outil exige son propre mot-cle immediatement
apres un #, aucun format a un seul # ne peut satisfaire les deux a la
fois). Les 6 sites # nosec B608 (SQL dynamique) restent inchanges,
nature differente, hors perimetre de ce refactor.
Verifie : mypy --strict propre (389 fichiers), ruff/bandit/import-linter
clean, suite complete verte (591 tests), scan SonarQube local relance
confirmant S7632 a 7 (1 seul site restant dans le helper lui-meme + les
6 B608), 0 bug (une regression S8371 trouvee et corrigee en route).
- 4 sites |safe repositionnes sur leur ligne exacte (scene_edit.html,
register_2fa.html, onboarding_new.html, play.html) - le marqueur
NOSONAR etait sur la ligne precedente par erreur (meme piege que celui
documente pour S8371 ci-dessus). Confirme par scan que meme corrige,
l'analyseur Web de Sonar ne supporte aucune syntaxe de suppression
inline testee pour la regle Web:S5247 - documente comme limitation
technique connue dans CODE_QUALITY.md plutot que force.
- CODE_QUALITY.md (nouveau) : reference complete du dispositif qualite -
vue d'ensemble par outil, configuration de chacun, commandes de lancement
local, procedure de justification d'une exception (avec le format exact
attendu par Bandit/Ruff/Sonar, verifie empiriquement), table des 10
exceptions documentees, backlog (djLint H021, code smells Sonar).
djLint (H021, styles inline) volontairement saute pour ce commit - meme
backlog assume que les commits precedents, aucun rapport avec ce changement.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
44 lines
2.2 KiB
Python
44 lines
2.2 KiB
Python
from flask import jsonify, request
|
|
from werkzeug.wrappers import Response
|
|
|
|
import db
|
|
import screens
|
|
from core.flask_app import app
|
|
|
|
|
|
@app.route("/game/<slug>/scene-objects/<int:object_id>/geometry", methods=["POST"])
|
|
def scene_object_geometry(slug: str, object_id: int) -> Response | tuple[Response, int]:
|
|
"""Mirror exact de routes/elements/element_geometry.py, mais en pixels
|
|
(voir screens/scenes/update_scene_object_geometry.py) — appelé en AJAX
|
|
pendant/à la fin d'un glisser-déposer sur la scène."""
|
|
# Vérifié AVANT l'update (pas seulement après) : update_scene_object_geometry
|
|
# ne valide pas object_id elle-même (simple UPDATE ... WHERE id = ?, sans
|
|
# effet silencieux si la ligne n'existe plus) — un objet supprimé entre
|
|
# temps (ex. course avec un autre onglet/une suppression concurrente)
|
|
# aurait sinon fait planter obj["scene_id"] plus bas sur un obj devenu None.
|
|
obj = screens.get_scene_object(slug, object_id)
|
|
if obj is None:
|
|
return jsonify({"error": "objet introuvable"}), 404
|
|
data = request.get_json(force=True)
|
|
screens.update_scene_object_geometry(
|
|
slug,
|
|
object_id,
|
|
x=float(data["x"]),
|
|
y=float(data["y"]),
|
|
width=float(data["width"]),
|
|
height=float(data["height"]),
|
|
)
|
|
# Un "fond" agrandi manuellement au-delà du champ de la caméra doit
|
|
# élargir le "monde" tout de suite (voir screens.resolve_scene_world_size)
|
|
# — sans ça, rien ne rafraîchissait window.SCENE_WIDTH/SCENE_HEIGHT côté
|
|
# JS après un redimensionnement manuel (contrairement au tour de Ruby,
|
|
# voir iaChatRefreshAfterTurn() dans static/js/ia/ia-chat.js), rendant
|
|
# injoignable à la souris tout ce qui dépassait la scène nominale.
|
|
screen = screens.get_screen(slug, obj["scene_id"])
|
|
screen = db.assert_not_none(
|
|
screen, "obj existe (verifie plus haut) et _scene_objects.scene_id a ON DELETE CASCADE vers _screens"
|
|
)
|
|
objects = screens.list_scene_objects(slug, obj["scene_id"])
|
|
world_width, world_height = screens.resolve_scene_world_size(screen, objects)
|
|
return jsonify({"ok": True, "world_width": world_width, "world_height": world_height})
|