fix(web): une erreur sur un point JSON ne renvoie plus une page HTML

STD-09, trouve en recroisant l'audit anterieur -- celui mene sur le miroir
GitHub, jamais repasse depuis qu'on a decouvert que ce n'etait pas la bonne
source.

Sept gestionnaires d'erreur portaient chacun leur copie d'une liste de
prefixes d'URL decidant "JSON ou page HTML". Les copies avaient derive --
trois testaient /users/coach-availability, quatre non -- et toutes
manquaient les memes points. Un fetch() qui recoit une page d'erreur HTML
leve en la parsant : sur le calendrier, les listes de selections et
d'equipes restaient vides, sans message dans la page et sans rien dans le
journal.

Deux choses apprises en ecrivant le test, aucune n'etait dans le constat.

L'approche par prefixe ne pouvait pas etre reparee. Trois des seize vues
JSON sont a des chemins qu'aucun prefixe ne distingue des pages HTML
voisines -- /matches/<id>/toggle-presence/<id> et ses deux cousins, que les
gabarits appellent justement en fetch(). Les vues se declarent donc
elles-memes (@json_endpoint, app/api.py), et un test parcourt la carte des
URL pour verifier qu'aucune vue appelant jsonify n'a ete oubliee.

Et surtout : @login_required n'atteint jamais le gestionnaire 401.
Flask-Login intercepte avant et redirige. Les seize points JSON repondaient
donc a une session expiree par une 302 vers un formulaire HTML, quoi que
dise la liste de prefixes. Reecrire la liste seule aurait eu l'air d'un
correctif sans rien changer.

Au passage, le message flash de ce gestionnaire etait la seule chaine de
l'application qui n'avait jamais ete traduite.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
GGThed
2026-08-11 19:36:25 -04:00
co-authored by Claude Opus 5
parent 8d7de75e99
commit ad3dea6a15
11 changed files with 436 additions and 153 deletions
+3
View File
@@ -10,6 +10,7 @@ from flask_babel import gettext as _
from flask_login import current_user, login_required
from marshmallow import ValidationError
from app.api import json_endpoint
from app.extensions import db
from app.forms import flash_validation_errors, form_payload
from app.models import (
@@ -262,6 +263,7 @@ def delete_match(match_id):
@team_matches_bp.route('/api/manageable-teams')
@json_endpoint
@login_required
def api_manageable_teams():
"""API endpoint returning teams the current user can schedule matches for."""
@@ -279,6 +281,7 @@ def api_manageable_teams():
@team_matches_bp.route('/<int:match_id>/toggle-presence/<int:participant_id>', methods=['POST'])
@json_endpoint
@login_required
def toggle_presence(match_id, participant_id):
"""Toggle is_confirmed for a team match participant."""