Commit Graph
8 Commits
Author SHA1 Message Date
GGThedandClaude Opus 5 8e3865f557 chore(lint): elargir les regles ruff et rendre le format bloquant en CI
QUA-002, seconde moitie. Le depot etant formate, l elargissement porte sur
des defauts et non sur du brassage.

Ajoute a la selection : B (bugbear), C4, RET, SIM, UP. Le lot entier n a
produit que 24 signalements sur 76 fichiers -- le code etait plus propre
que l audit ne le craignait. Neuf corriges automatiquement, quinze a la
main.

SIM108 est ignore : forcer un ternaire se lit moins bien que le if/else
qu il remplace, au seul endroit ou il se declenche.

isort (I) n est PAS active. Il reordonnerait les imports de 48 fichiers,
soit une seconde passe de pur brassage juste apres le commit de formatage.
A faire, mais seul.

Deux vrais defauts trouves par les nouvelles regles
  - team_matches.edit_match faisait `except ValueError: pass` sur l heure de
    debut et l heure de fin, trois lignes sous un champ date qui, lui,
    signale et redirige. Une heure mal saisie etait donc acceptee par le
    formulaire, jetee, l ancienne valeur conservee -- et la page annoncait
    la reussite. Meme traitement que la date desormais.
  - backup.py levait BackupError depuis deux blocs `except` sans `from`,
    ce qui perdait la cause d origine dans la trace.

Ainsi que : un `return` explicite dans force_https, `%`-formatage remplace
dans log_auth_event (operations de chaine avant journalisation, pas des
gabarits de logger -- la redaction n est pas affectee), une compréhension
inutile, un `set(...)` en compréhension d ensemble, `open(..., 'r')`, une
variable de boucle inutilisee, et `contextlib.suppress` dans conftest.

CI : `ruff format --check` remplace le commentaire qui expliquait pourquoi
il etait absent.

263 tests passent. Les deux nouveaux messages sont traduits ; attention,
pybabel les avait apparies en `fuzzy` avec des entrees « date » existantes,
et une entree fuzzy est ignoree a l execution.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-08 15:59:40 -04:00
GGThedandClaude Opus 5 7cec18c139 style: formater le depot avec ruff format
QUA-002, premiere moitie. **Ce commit ne fait que reformater** : aucun
changement de comportement, aucune ligne de logique touchee. 72 fichiers,
4 restaient deja conformes. Il est isole exprès, pour que `git log -p` sur
les commits voisins reste lisible.

`quote-style = "preserve"` etait deja pose dans pyproject.toml, ce qui
evite le brassage guillemets simples / doubles : le diff porte sur les
retours a la ligne, l indentation des appels longs et les virgules
finales, pas sur le style de chaine.

Verification : 263 tests passent avant et apres, ruff check propre.

L activation en CI arrive dans le commit suivant, separement, pour que ce
diff-ci ne contienne rien d autre.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-08 15:53:10 -04:00
GGThedandClaude Opus 5 92d72e4d48 refactor(authz): un seul point de verite pour les autorisations d equipe
ARCH-002. La question "a quelles equipes ce coach est-il rattache ?" etait
posee a huit endroits, de cinq facons differentes, et trois d entre elles
donnaient une mauvaise reponse en production.

Le motif fautif, present tel quel dans six routes :

    OrgTeam.query.filter_by(coach_id=user.id).first()

Il repond au plus une equipe, et seulement par la colonne heritee. Deux
pannes en decoulaient, silencieuses -- les pages s affichaient, vides :

  - un coach rattache uniquement par la relation many-to-many n avait
    aucune equipe, donc aucun joueur, aucun contrat, aucune note d equipe,
    aucun match a venir sur son tableau de bord ;
  - un coach de deux equipes n en voyait qu une. Le formulaire de contrat
    lui proposait la moitie de son effectif, alors que la route POST
    acceptait l autre moitie.

app/permissions.py devient le module ou la question se pose une fois :
coach_org_teams, manager_org_teams, attached_org_teams, visible_org_teams,
can_manage_org_team, org_team_player_ids, coach_player_ids,
can_manage_player_contract, coach_tryouts, coach_manages_tryout. Toutes
lisent les deux rattachements et toutes les equipes.

Le meme ecart existait dans le modele : Coach.get_visible_tryouts ne lisait
que la relation m2m -- calendrier vide pour un coach rattache par la
colonne -- et can_manage_this_tryout ignorait la colonne pour l equipe
cible. Les deux delegent desormais.

Corrections de portee, au passage
  - one_on_one lisait org_team.coach_id : un joueur dont l equipe declare
    ses coachs par la relation etait informe qu il n avait pas de coach, et
    le formulaire de demande restait ferme. Passe par get_coaches(), qui
    retombe deja sur la colonne heritee.
  - notes_dashboard conditionnait les notes personnelles du coach a
    l existence d une equipe : un coach sans equipe ne voyait pas ses
    propres notes.
  - can_manage_team_match reformulait can_manage_this_org_team ; la
    reformulation avait derive. Elle appelle maintenant la regle.

Limite assumee : le panneau de notes d equipe reste ecrit pour une seule
equipe et affiche donc la premiere. La resolution est corrigee, la mise en
page multi-equipes ne l est pas -- c est un choix produit, pas un bug.

14 tests ajoutes. Cinq echouent sur le code d avant, verifie en remettant
les routes et le modele a leur etat precedent.

ARCH-001 fera disparaitre la colonne heritee ; cela demande une migration
de donnees, donc Alembic. D ici la, ce module est ce qui rend la
duplication inoffensive.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-08 14:08:02 -04:00
GGThedandClaude Opus 5 37f70c89e3 feat(i18n): traduire les messages flash et de validation
198 appels flash dans les sept modules de routes, plus les 23 messages de
validation de app/validators.py. Le catalogue compte desormais 631 chaines,
aucune non traduite.

validators.py utilise lazy_gettext : les champs de schema sont construits a
l'import, donc avant qu'une requete existe. Un gettext ordinaire s'y
resoudrait une seule fois, dans la langue active au demarrage.

Un bug introduit par la conversion, puis corrige
  Le convertisseur automatique ne voyait que le premier litteral d'un appel
  flash, ce qui a casse deux chaines concatenees sur plusieurs lignes dans
  users.py -- le resultat n'etait meme pas du Python valide. Ma premiere
  verification ne l'a pas vu : elle enchainait py_compile sur head, or head
  reussit toujours, donc le "OK" s'affichait quoi qu'il arrive. Les deux
  appels sont reecrits et la verification refaite correctement.

Un bug plus interessant, revele par le test de fumee
  La langue choisie ne survivait pas a la connexion. login() et logout()
  appellent tous deux session.clear() -- l'un contre la fixation de session,
  l'autre pour terminer la session -- et le choix de langue partait avec le
  reste. Concretement : quelqu'un qui lisait la page de connexion en anglais
  se retrouvait en francais des qu'il se connectait.

  La langue est une preference d'affichage, pas un etat appartenant au
  compte. Les deux endroits la reportent maintenant explicitement, a cote du
  jeton CSRF. Quatre tests couvrent le cas, dont un qui verifie que corriger
  une cle preservee n'a pas fait tomber l'autre.

Detail de nommage : le convertisseur avait genere %(value)s pour une
expression conditionnelle, ce qui n'aide pas un traducteur. Renomme en
%(player)s.

Les 14 traductions ecrites avec une apostrophe droite sont normalisees en
apostrophe typographique. Sans consequence en HTML, ou &#39; s'affiche
correctement -- mais les blocs <script> ne decodent pas les entites, et
autant que le catalogue soit homogene.

200 tests.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-07 22:12:27 -04:00
GGThedandClaude Opus 5 a793b7ed0d fix(authz): verifier le rattachement equipe/tryout, et nettoyer le code mort
SEC-AUTHZ-002. add_to_team recevait tryout_id et team_id independamment
dans l'URL, controlait l'autorisation sur le tryout, puis operait sur
l'equipe sans jamais etablir de lien entre les deux. Un gestionnaire du
tryout A pouvait donc modifier une equipe du tryout B.

Le lint pointait exactement dessus : `team` etait charge ligne 463 puis
jamais utilise. La correction automatique proposee etait de supprimer la
variable, ce qui aurait fait taire l'avertissement en cimentant la faille.
Elle est desormais utilisee pour ce a quoi elle servait.

Trois defauts sur la meme route, corriges ensemble :
  - team.tryout_id != tryout_id repond maintenant 404
  - seuls les joueurs inscrits au tryout peuvent rejoindre ses equipes
  - int(player_id) sur une entree de formulaire brute levait ValueError,
    donc une erreur 500, sur toute valeur non numerique

Nettoyage automatique par ruff : 34 imports et variables morts retires
sur l'ensemble du paquet. La suite de tests a servi de filet, elle passe
a l'identique avant et apres. Aucun changement de comportement.

A noter, OneOnOneRequestSchema figurait aussi parmi les imports morts :
c'est un quatrieme schema jamais appele, la route one_on_one validant ses
dates a la main. Unifier la validation reste a faire (ARCH-005).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-07 19:47:00 -04:00
cedrick2711 fc1bdc57c4 régler les imports des fichiers après redistribution 2026-07-29 14:16:01 -04:00
cedrick2711 b69eaabbba remodulation du projet en POO et changement de l'organisation des fichiers 2026-07-29 13:57:06 -04:00
cedrick2711 3feae80767 remodulation du projet et des classes 2026-07-28 23:33:31 -04:00