changement de l'affichage des tryouts et des matchs

This commit is contained in:
cedrick2711
2026-07-22 22:19:58 -04:00
parent 346229778f
commit 5e909014f8
14 changed files with 573 additions and 326 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -21,7 +21,7 @@ def is_safe_url(url):
"""
if not url:
return False
parsed = url_parse(url)
parsed = urlparse(url)
# Allow relative URLs (no netloc) or same-origin URLs
return not parsed.netloc or parsed.netloc == request.host
+59 -6
View File
@@ -6,8 +6,9 @@ This module handles player evaluation creation, management, and viewing.
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_required, current_user
from extensions import db
from models import User, Tryout, Evaluation, TryoutRegistration, GAME_POSITIONS
from models import User, Tryout, Evaluation, TryoutRegistration, GAME_POSITIONS, OrgTeam
from sqlalchemy import func
from sqlalchemy.orm import aliased
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
@@ -41,13 +42,55 @@ def list_evaluations():
Evaluators (coach/manager): Their given evaluations.
Players: Their received evaluations.
Supports sorting by any column header via 'sort' and 'order' query parameters.
Returns:
Response: Rendered evaluations list template.
"""
user = current_user
# Get sort parameters
sort_column = request.args.get('sort', 'created_at')
sort_order = request.args.get('order', 'desc')
# Validate sort_order
if sort_order not in ('asc', 'desc'):
sort_order = 'desc'
# Map sort columns to SQLAlchemy expressions using aliased User models for relationship sorting
player_alias = aliased(User, name='eval_player')
evaluator_alias = aliased(User, name='eval_evaluator')
sort_map = {
'tryout': Tryout.title,
'player': player_alias.full_name,
'evaluator': evaluator_alias.full_name,
'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 user.role == 'president':
evaluations = Evaluation.query.order_by(Evaluation.created_at.desc()).all()
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'),
@@ -60,13 +103,23 @@ def list_evaluations():
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.filter_by(evaluator_id=user.id).order_by(Evaluation.created_at.desc()).all()
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.filter_by(player_id=user.id).order_by(Evaluation.created_at.desc()).all()
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)
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'])
@@ -219,4 +272,4 @@ def players_to_evaluate(tryout_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)
return render_template('pages/players_to_evaluate.html', tryout=tryout, players=players)
+41 -39
View File
@@ -14,7 +14,7 @@ tryouts_bp = Blueprint('tryouts', __name__, url_prefix='/tryouts')
def can_manage():
"""Check if current user can manage tryouts.
Returns:
bool: True if user is president or manager.
"""
@@ -25,13 +25,13 @@ def can_manage():
@login_required
def list_tryouts():
"""List all tryouts visible to the current user.
Shows tryouts filtered by user's role:
- President: All tryouts
- Manager: Only their created tryouts
- Coach: Tryouts targeting their org team
- Player: Upcoming and in-progress tryouts
- Player: Only tryouts they are registered for or participating in
Returns:
Response: Rendered tryouts list template.
"""
@@ -47,7 +47,9 @@ def list_tryouts():
else:
tryouts = []
elif current_user.role == 'player':
tryouts = Tryout.query.filter(Tryout.status.in_(['upcoming', 'in_progress'])).order_by(Tryout.date.desc()).all()
# Players only see tryouts they are registered for or participating in matches
from routes.matches import get_visible_tryouts_for_user
tryouts = get_visible_tryouts_for_user()
else:
tryouts = Tryout.query.order_by(Tryout.date.desc()).all()
return render_template('pages/tryouts.html', tryouts=tryouts, now=datetime.utcnow())
@@ -57,12 +59,12 @@ def list_tryouts():
@login_required
def create_tryout():
"""Create a new tryout event.
GET: Render the tryout creation form.
POST: Create a tryout with the submitted details.
Requires president or manager role.
Returns:
Response: Create form or redirect to the new tryout.
"""
@@ -110,15 +112,15 @@ def create_tryout():
@login_required
def edit_tryout(tryout_id):
"""Edit an existing tryout event.
GET: Render the tryout edit form with current data.
POST: Update the tryout with submitted changes.
Permission based on can_manage_this_tryout check.
Args:
tryout_id: The ID of the tryout to edit.
Returns:
Response: Edit form or redirect to tryout view.
"""
@@ -164,18 +166,18 @@ def edit_tryout(tryout_id):
@login_required
def view_tryout(tryout_id):
"""View a specific tryout with all details.
Displays tryout information, registered players, evaluations, teams,
matches, and evaluation status information.
Args:
tryout_id: The ID of the tryout to view.
Returns:
Response: Rendered tryout detail template.
"""
tryout = Tryout.query.get_or_404(tryout_id)
# Check if user has permission to view this tryout
can_view = False
if current_user.role == 'president':
@@ -197,11 +199,11 @@ def view_tryout(tryout_id):
can_view = is_registered or player_in_match
elif current_user.role == 'scout':
can_view = True
if not can_view:
flash('You do not have permission to view this tryout.', 'danger')
return redirect(url_for('tryouts.list_tryouts'))
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all()
registered_players = [User.query.get(r.player_id) for r in registrations if r.player_id]
evaluations = Evaluation.query.filter_by(tryout_id=tryout_id).all()
@@ -235,7 +237,7 @@ def view_tryout(tryout_id):
# Determine if current user can edit this tryout
can_edit = current_user.can_manage_this_tryout(tryout)
# Determine if current user can view the calendar (managers/coaches can always see it)
# Players need to be registered or participating in a match
can_view_calendar = can_edit
@@ -245,16 +247,16 @@ def view_tryout(tryout_id):
MatchParticipant.player_id == current_user.id,
Match.tryout_id == tryout_id
).first() is not None
can_view_calendar = is_registered or player_in_match
# Only expose all_players to users who can manage players in this tryout
all_players = None
if can_edit:
all_players = User.query.filter_by(role='player').order_by(User.full_name).all()
# Get matches for this tryout with participant info
matches = Match.query.filter_by(tryout_id=tryout_id).order_by(Match.date).all()
matches = Match.query.filter_by(tryout_id=tryout_id).order_by(Match.date, Match.start_time).all()
match_data = []
for match in matches:
if match.match_type == 'team_vs_team':
@@ -279,7 +281,7 @@ def view_tryout(tryout_id):
'match': match,
'participants': participants
})
return render_template('pages/view_tryout.html',
tryout=tryout,
registered_players=registered_players,
@@ -301,13 +303,13 @@ def view_tryout(tryout_id):
@login_required
def register_for_tryout(tryout_id):
"""Register a player for a tryout.
Allows players to register for tryouts. Validates that the tryout
is accepting registrations and not at capacity.
Args:
tryout_id: The ID of the tryout to register for.
Returns:
Response: Redirect to tryout view with status message.
"""
@@ -342,12 +344,12 @@ def register_for_tryout(tryout_id):
@login_required
def update_status(tryout_id):
"""Update the status of a tryout.
Changes tryout status between upcoming, in_progress, and completed.
Args:
tryout_id: The ID of the tryout to update.
Returns:
Response: Redirect to tryout view.
"""
@@ -367,11 +369,11 @@ def update_status(tryout_id):
@login_required
def update_registration_status(tryout_id, player_id):
"""Update the attendance status of a tryout registration.
Args:
tryout_id: The ID of the tryout.
player_id: The ID of the player whose status to update.
Returns:
Response: Redirect to tryout view.
"""
@@ -393,12 +395,12 @@ def update_registration_status(tryout_id, player_id):
@login_required
def register_player(tryout_id):
"""Manually register a player for a tryout (by managers/coaches).
Allows authorized users to register players on their behalf.
Args:
tryout_id: The ID of the tryout.
Returns:
Response: Redirect to tryout view with status message.
"""
@@ -439,10 +441,10 @@ def register_player(tryout_id):
@login_required
def create_team(tryout_id):
"""Create a tryout-specific team.
Args:
tryout_id: The ID of the tryout to create the team for.
Returns:
Response: Redirect to tryout view with status message.
"""
@@ -464,11 +466,11 @@ def create_team(tryout_id):
@login_required
def add_to_team(tryout_id, team_id):
"""Add a player to a tryout team.
Args:
tryout_id: The ID of the tryout.
team_id: The ID of the team to add the player to.
Returns:
Response: Redirect to tryout view with status message.
"""
@@ -490,4 +492,4 @@ def add_to_team(tryout_id, team_id):
db.session.commit()
flash('Player added to team!', 'success')
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))