refactor(validation): un schema aux frontieres tryout et evaluation
ARCH-005, seconde moitie. Meme forme que pour les matchs : des champs lus a la main sur request.form, deux verifies et le reste cru sur parole. Cote tryout : - game pilote la liste des postes et les champs de gamertag montres au joueur qui s inscrit. Il etait accepte tel quel : une faute de frappe produisait une selection pour laquelle personne ne pouvait etre evalue ; - max_players etait int(x) if x else None — un 500 sur « twelve », et un -3 accepte sans broncher ; - coach_ids etait charge par User.id.in_(...) sans filtre de role. Une soumission fabriquee a la main pouvait donc nommer un joueur coach d une selection, ce qui est une attribution de droits : gerer la selection et evaluer ses joueurs. Ce n est pas un formulaire que l interface propose, et ca marchait. Cote evaluation, validate_score transformait tout ce qui sortait de 1..10 — 11, 0, « bien » — en None. Le critere disparaissait de la moyenne et la page annoncait l evaluation enregistree. Rien ne distinguait « non evalue » de « evalue, refuse, et oublie ». Le calcul de la moyenne remonte sur le modele, en Evaluation.overall_from et apply_scores. Il vivait dans la route, additionnant neuf variables locales, et ne pouvait pas etre exerce sans requete HTTP, session authentifiee et base — c est TEST-002, et c est pourquoi le calcul des scores n avait aucun test. Il en a maintenant six, sans rien monter. Une precision qui compte : aucun critere rempli donne None, pas 0. La grille commence a 1, donc un zero serait une note qu aucun joueur ne peut recevoir, et qui le classerait sous tout le monde dans la liste. Les neuf criteres sont ecrits en toutes lettres dans le schema plutot que generes depuis le modele — un schema se lit — et un test verifie que les deux listes coincident. C est la garde qui empeche la derive, pas l astuce. Douze chaines traduites, dont trois que pybabel avait devinees en fuzzy : une entree fuzzy est ignoree a l execution, le piege est consigne dans docs/translations.md. 30 tests neufs. 477 au total.
This commit is contained in:
@@ -31,3 +31,49 @@ class Evaluation(db.Model):
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint('tryout_id', 'player_id', 'evaluator_id', name='unique_evaluation'),
|
||||
)
|
||||
|
||||
#: The nine criteria, in the order the form shows them. The overall score
|
||||
#: is their mean; a criterion left blank is left out of the mean rather
|
||||
#: than counted as a zero, which is why this list exists rather than the
|
||||
#: route summing nine named variables (ARCH-005, QUA-003).
|
||||
CRITERIA = (
|
||||
'mecanics_score',
|
||||
'cohesion_score',
|
||||
'communication_score',
|
||||
'gamesense_score',
|
||||
'versatility_score',
|
||||
'discipline_score',
|
||||
'analysis_score',
|
||||
'sport_ethics_score',
|
||||
'mental_score',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def overall_from(cls, scores):
|
||||
"""Mean of the criteria that were actually filled in.
|
||||
|
||||
Args:
|
||||
scores: Mapping of criterion name to score or None.
|
||||
|
||||
Returns:
|
||||
float | None: None when nothing was scored — which is not the
|
||||
same as zero, and must not become one. A player nobody could
|
||||
assess has no overall score; a player who scored zero on
|
||||
everything cannot exist, the scale starts at one.
|
||||
"""
|
||||
given = [scores.get(name) for name in cls.CRITERIA]
|
||||
given = [score for score in given if score is not None]
|
||||
if not given:
|
||||
return None
|
||||
return sum(given) / len(given)
|
||||
|
||||
def apply_scores(self, scores):
|
||||
"""Write these criteria onto the record and recompute the overall.
|
||||
|
||||
Every criterion is assigned, including the ones left blank: an edit
|
||||
that clears a score has to clear it, and the mean has to be the mean
|
||||
of what is on the record afterwards.
|
||||
"""
|
||||
for name in self.CRITERIA:
|
||||
setattr(self, name, scores.get(name))
|
||||
self.overall_score = self.overall_from(scores)
|
||||
|
||||
Reference in New Issue
Block a user