remodulation du projet et des classes
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
"""Evaluation routes for assessing player performance during tryouts.
|
||||
|
||||
Uses polymorphic isinstance checks instead of role-string comparisons.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, current_user
|
||||
from app.extensions import db
|
||||
from app.models import (
|
||||
Admin, Coach, Manager, Player,
|
||||
User, Tryout, Evaluation, TryoutRegistration,
|
||||
OrgTeam, GAME_POSITIONS,
|
||||
)
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
|
||||
|
||||
|
||||
def validate_score(score_value):
|
||||
"""Validate that a score is between 1 and 10."""
|
||||
if score_value is None:
|
||||
return None
|
||||
try:
|
||||
score = int(score_value)
|
||||
if 1 <= score <= 10:
|
||||
return score
|
||||
return None
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
|
||||
@evaluations_bp.route('')
|
||||
@login_required
|
||||
def list_evaluations():
|
||||
"""List all evaluations accessible to the current user."""
|
||||
user = current_user
|
||||
|
||||
if isinstance(user, Player):
|
||||
flash('You do not have permission to view evaluations.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
sort_column = request.args.get('sort', 'created_at')
|
||||
sort_order = request.args.get('order', 'desc')
|
||||
if sort_order not in ('asc', 'desc'):
|
||||
sort_order = 'desc'
|
||||
|
||||
player_alias = aliased(User, name='eval_player')
|
||||
evaluator_alias = aliased(User, name='eval_evaluator')
|
||||
|
||||
sort_map = {
|
||||
'tryout': Tryout.title,
|
||||
'player': player_alias.username,
|
||||
'evaluator': evaluator_alias.username,
|
||||
'mecanics_score': Evaluation.mecanics_score,
|
||||
'cohesion_score': Evaluation.cohesion_score,
|
||||
'communication_score': Evaluation.communication_score,
|
||||
'gamesense_score': Evaluation.gamesense_score,
|
||||
'versatility_score': Evaluation.versatility_score,
|
||||
'discipline_score': Evaluation.discipline_score,
|
||||
'analysis_score': Evaluation.analysis_score,
|
||||
'sport_ethics_score': Evaluation.sport_ethics_score,
|
||||
'mental_score': Evaluation.mental_score,
|
||||
'overall_score': Evaluation.overall_score,
|
||||
'position_recommendation': Evaluation.position_recommendation,
|
||||
'created_at': Evaluation.created_at,
|
||||
}
|
||||
|
||||
sort_expr = sort_map.get(sort_column, Evaluation.created_at)
|
||||
if sort_order == 'asc':
|
||||
sort_expr = sort_expr.asc()
|
||||
else:
|
||||
sort_expr = sort_expr.desc()
|
||||
|
||||
if isinstance(user, Admin):
|
||||
evaluations = Evaluation.query \
|
||||
.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id) \
|
||||
.outerjoin(player_alias, Evaluation.player_id == player_alias.id) \
|
||||
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id) \
|
||||
.order_by(sort_expr).all()
|
||||
avg_scores = db.session.query(
|
||||
Evaluation.player_id,
|
||||
func.count(Evaluation.id).label('eval_count'),
|
||||
func.avg(Evaluation.overall_score).label('avg_score'),
|
||||
).group_by(Evaluation.player_id).all()
|
||||
player_scores = {}
|
||||
for row in avg_scores:
|
||||
p = User.query.get(row.player_id)
|
||||
if p:
|
||||
player_scores[p.id] = {
|
||||
'player': p, 'count': row.eval_count,
|
||||
'avg': round(row.avg_score, 1) if row.avg_score else 0,
|
||||
}
|
||||
elif user.can_evaluate():
|
||||
evaluations = Evaluation.query \
|
||||
.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id) \
|
||||
.outerjoin(player_alias, Evaluation.player_id == player_alias.id) \
|
||||
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id) \
|
||||
.filter(Evaluation.evaluator_id == user.id) \
|
||||
.order_by(sort_expr).all()
|
||||
player_scores = {}
|
||||
else:
|
||||
evaluations = Evaluation.query \
|
||||
.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id) \
|
||||
.outerjoin(player_alias, Evaluation.player_id == player_alias.id) \
|
||||
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id) \
|
||||
.filter(Evaluation.player_id == user.id) \
|
||||
.order_by(sort_expr).all()
|
||||
player_scores = {}
|
||||
|
||||
return render_template('pages/evaluations.html',
|
||||
evaluations=evaluations, player_scores=player_scores,
|
||||
sort_column=sort_column, sort_order=sort_order)
|
||||
|
||||
|
||||
@evaluations_bp.route('/<int:tryout_id>/<int:player_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def evaluate_player(tryout_id, player_id):
|
||||
"""Evaluate a specific player in a tryout."""
|
||||
if not current_user.can_evaluate():
|
||||
flash('You do not have permission to evaluate players.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
tryout = Tryout.query.get_or_404(tryout_id)
|
||||
if not current_user.can_manage_this_tryout(tryout):
|
||||
flash('You do not have permission to evaluate players in this tryout.', 'danger')
|
||||
return redirect(url_for('tryouts.list_tryouts'))
|
||||
|
||||
is_registered = TryoutRegistration.query.filter_by(
|
||||
tryout_id=tryout_id, player_id=player_id,
|
||||
).first() is not None
|
||||
if not is_registered:
|
||||
flash('Player is not registered for this tryout.', 'danger')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||
|
||||
player = User.query.get_or_404(player_id)
|
||||
if not isinstance(player, Player):
|
||||
flash('Can only evaluate players.', 'danger')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||
|
||||
existing_eval = Evaluation.query.filter_by(
|
||||
tryout_id=tryout_id, player_id=player_id, evaluator_id=current_user.id,
|
||||
).first()
|
||||
|
||||
if request.method == 'POST':
|
||||
mecanics = validate_score(request.form.get('mecanics_score'))
|
||||
cohesion = validate_score(request.form.get('cohesion_score'))
|
||||
communication = validate_score(request.form.get('communication_score'))
|
||||
gamesense = validate_score(request.form.get('gamesense_score'))
|
||||
versatility = validate_score(request.form.get('versatility_score'))
|
||||
discipline = validate_score(request.form.get('discipline_score'))
|
||||
analysis = validate_score(request.form.get('analysis_score'))
|
||||
sport_ethics = validate_score(request.form.get('sport_ethics_score'))
|
||||
mental = validate_score(request.form.get('mental_score'))
|
||||
comments = request.form.get('comments')
|
||||
position = request.form.get('position_recommendation')
|
||||
|
||||
scores = [s for s in [mecanics, cohesion, communication, gamesense,
|
||||
versatility, discipline, analysis, sport_ethics, mental]
|
||||
if s is not None]
|
||||
overall = sum(scores) / len(scores) if scores else None
|
||||
|
||||
if existing_eval:
|
||||
existing_eval.mecanics_score = mecanics
|
||||
existing_eval.cohesion_score = cohesion
|
||||
existing_eval.communication_score = communication
|
||||
existing_eval.gamesense_score = gamesense
|
||||
existing_eval.versatility_score = versatility
|
||||
existing_eval.discipline_score = discipline
|
||||
existing_eval.analysis_score = analysis
|
||||
existing_eval.sport_ethics_score = sport_ethics
|
||||
existing_eval.mental_score = mental
|
||||
existing_eval.overall_score = overall
|
||||
existing_eval.comments = comments
|
||||
existing_eval.position_recommendation = position
|
||||
flash('Evaluation updated!', 'success')
|
||||
else:
|
||||
evaluation = Evaluation(
|
||||
tryout_id=tryout_id, player_id=player_id,
|
||||
evaluator_id=current_user.id,
|
||||
mecanics_score=mecanics, cohesion_score=cohesion,
|
||||
communication_score=communication, gamesense_score=gamesense,
|
||||
versatility_score=versatility, discipline_score=discipline,
|
||||
analysis_score=analysis, sport_ethics_score=sport_ethics,
|
||||
mental_score=mental, overall_score=overall,
|
||||
comments=comments, position_recommendation=position,
|
||||
)
|
||||
db.session.add(evaluation)
|
||||
flash('Evaluation submitted successfully!', 'success')
|
||||
|
||||
db.session.commit()
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||
|
||||
evaluators = None
|
||||
if isinstance(current_user, Admin):
|
||||
all_evaluations = Evaluation.query.filter_by(
|
||||
tryout_id=tryout_id, player_id=player_id,
|
||||
).all()
|
||||
evaluators = [{'evaluator': User.query.get(e.evaluator_id), 'eval': e}
|
||||
for e in all_evaluations]
|
||||
|
||||
return render_template('pages/evaluate_player.html',
|
||||
tryout=tryout, player=player,
|
||||
existing_eval=existing_eval,
|
||||
evaluators=evaluators,
|
||||
game_positions=GAME_POSITIONS)
|
||||
|
||||
|
||||
@evaluations_bp.route('/<int:tryout_id>/players')
|
||||
@login_required
|
||||
def players_to_evaluate(tryout_id):
|
||||
"""List players that need evaluation in a specific tryout."""
|
||||
if not current_user.can_evaluate():
|
||||
flash('Permission denied.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
tryout = Tryout.query.get_or_404(tryout_id)
|
||||
if not current_user.can_manage_this_tryout(tryout):
|
||||
flash('You do not have permission to evaluate players in this tryout.', 'danger')
|
||||
return redirect(url_for('tryouts.list_tryouts'))
|
||||
|
||||
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all()
|
||||
players = []
|
||||
for reg in registrations:
|
||||
p = User.query.get(reg.player_id)
|
||||
if p and isinstance(p, Player):
|
||||
existing = Evaluation.query.filter_by(
|
||||
tryout_id=tryout_id, player_id=p.id, evaluator_id=current_user.id,
|
||||
).first()
|
||||
players.append({'player': p, 'evaluated': existing is not None,
|
||||
'registration': reg})
|
||||
|
||||
return render_template('pages/players_to_evaluate.html', tryout=tryout, players=players)
|
||||
Reference in New Issue
Block a user