Ajout des match qui arrivent pour les coach, president et manager Légèrement alléger la quantité de pages (merge certaines ensembles)
508 lines
20 KiB
Python
508 lines
20 KiB
Python
"""Tryout management routes for creating, viewing, and managing tryout events.
|
|
|
|
This module handles CRUD operations for tryouts and player registrations.
|
|
"""
|
|
|
|
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, TryoutRegistration, Evaluation, Team, TeamMember, OrgTeam, Match, MatchParticipant, ESPORT_GAMES, GAME_POSITIONS
|
|
from datetime import datetime
|
|
|
|
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.
|
|
"""
|
|
return current_user.role in ['president', 'manager']
|
|
|
|
|
|
@tryouts_bp.route('')
|
|
@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: Only tryouts they are registered for or participating in
|
|
|
|
Returns:
|
|
Response: Rendered tryouts list template.
|
|
"""
|
|
if current_user.role == 'president':
|
|
tryouts = Tryout.query.order_by(Tryout.date.desc()).all()
|
|
elif current_user.role == 'manager':
|
|
tryouts = Tryout.query.filter_by(created_by=current_user.id).order_by(Tryout.date.desc()).all()
|
|
elif current_user.role == 'coach':
|
|
# Coaches see tryouts targeting their org team
|
|
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
|
if org_team:
|
|
tryouts = Tryout.query.filter_by(target_org_team_id=org_team.id).order_by(Tryout.date.desc()).all()
|
|
else:
|
|
tryouts = []
|
|
elif current_user.role == 'player':
|
|
# 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())
|
|
|
|
|
|
@tryouts_bp.route('/create', methods=['GET', 'POST'])
|
|
@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.
|
|
"""
|
|
if not can_manage():
|
|
flash('You do not have permission to create tryouts.', 'danger')
|
|
return redirect(url_for('tryouts.list_tryouts'))
|
|
|
|
org_teams = OrgTeam.query.order_by(OrgTeam.name).all()
|
|
managers = User.query.filter_by(role='manager', is_active_account=True).order_by(User.full_name).all()
|
|
coaches = User.query.filter_by(role='coach', is_active_account=True).order_by(User.full_name).all()
|
|
|
|
if request.method == 'POST':
|
|
title = request.form.get('title')
|
|
description = request.form.get('description')
|
|
game = request.form.get('game')
|
|
date_str = request.form.get('date')
|
|
location = request.form.get('location')
|
|
max_players = request.form.get('max_players')
|
|
target_org_team_id = request.form.get('target_org_team_id')
|
|
manager_id = request.form.get('manager_id')
|
|
coach_id = request.form.get('coach_id')
|
|
|
|
try:
|
|
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
|
except (ValueError, TypeError):
|
|
flash('Invalid date format.', 'danger')
|
|
return render_template('pages/tryout_form.html', tryout=None, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES)
|
|
|
|
tryout = Tryout(
|
|
title=title,
|
|
description=description,
|
|
game=game,
|
|
date=date_obj,
|
|
location=location,
|
|
max_players=int(max_players) if max_players else None,
|
|
created_by=current_user.id,
|
|
status='upcoming',
|
|
target_org_team_id=int(target_org_team_id) if target_org_team_id else None,
|
|
manager_id=int(manager_id) if manager_id else None,
|
|
coach_id=int(coach_id) if coach_id else None
|
|
)
|
|
db.session.add(tryout)
|
|
db.session.commit()
|
|
flash('Tryout created successfully!', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
|
|
|
return render_template('pages/tryout_form.html', tryout=None, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES)
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/edit', methods=['GET', 'POST'])
|
|
@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.
|
|
"""
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
|
|
# Permission: president, manager (own tryouts), or coach (targets their team)
|
|
if not current_user.can_manage_this_tryout(tryout):
|
|
flash('You do not have permission to edit this tryout.', 'danger')
|
|
return redirect(url_for('tryouts.list_tryouts'))
|
|
|
|
org_teams = OrgTeam.query.order_by(OrgTeam.name).all()
|
|
managers = User.query.filter_by(role='manager', is_active_account=True).order_by(User.full_name).all()
|
|
coaches = User.query.filter_by(role='coach', is_active_account=True).order_by(User.full_name).all()
|
|
|
|
if request.method == 'POST':
|
|
title = request.form.get('title')
|
|
description = request.form.get('description')
|
|
game = request.form.get('game')
|
|
date_str = request.form.get('date')
|
|
location = request.form.get('location')
|
|
max_players = request.form.get('max_players')
|
|
target_org_team_id = request.form.get('target_org_team_id')
|
|
manager_id = request.form.get('manager_id')
|
|
coach_id = request.form.get('coach_id')
|
|
|
|
try:
|
|
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
|
except (ValueError, TypeError):
|
|
flash('Invalid date format.', 'danger')
|
|
return render_template('pages/tryout_form.html', tryout=tryout, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES)
|
|
|
|
tryout.title = title
|
|
tryout.description = description
|
|
tryout.game = game
|
|
tryout.date = date_obj
|
|
tryout.location = location
|
|
tryout.max_players = int(max_players) if max_players else None
|
|
tryout.target_org_team_id = int(target_org_team_id) if target_org_team_id else None
|
|
tryout.manager_id = int(manager_id) if manager_id else None
|
|
tryout.coach_id = int(coach_id) if coach_id else None
|
|
db.session.commit()
|
|
flash('Tryout updated successfully!', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
|
|
|
return render_template('pages/tryout_form.html', tryout=tryout, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES)
|
|
|
|
|
|
@tryouts_bp.route('/<int: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':
|
|
can_view = True
|
|
elif current_user.role == 'manager' and tryout.created_by == current_user.id:
|
|
can_view = True
|
|
elif current_user.role == 'coach':
|
|
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
|
if org_team and tryout.target_org_team_id == org_team.id:
|
|
can_view = True
|
|
elif current_user.role == 'player':
|
|
is_registered = TryoutRegistration.query.filter_by(
|
|
tryout_id=tryout_id, player_id=current_user.id
|
|
).first() is not None
|
|
player_in_match = MatchParticipant.query.join(Match).filter(
|
|
MatchParticipant.player_id == current_user.id,
|
|
Match.tryout_id == tryout_id
|
|
).first() is not None
|
|
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()
|
|
|
|
evaluator_ids = set(e.evaluator_id for e in evaluations)
|
|
player_ids_with_eval = set(e.player_id for e in evaluations)
|
|
|
|
# Check if current user has evaluated each player
|
|
player_eval_status = {}
|
|
if current_user.can_evaluate():
|
|
for p in registered_players:
|
|
existing = Evaluation.query.filter_by(
|
|
tryout_id=tryout_id,
|
|
player_id=p.id,
|
|
evaluator_id=current_user.id
|
|
).first()
|
|
player_eval_status[p.id] = existing is not None
|
|
|
|
is_registered = TryoutRegistration.query.filter_by(
|
|
tryout_id=tryout_id, player_id=current_user.id
|
|
).first() is not None
|
|
|
|
teams = Team.query.filter_by(tryout_id=tryout_id).all()
|
|
team_data = []
|
|
for team in teams:
|
|
members = TeamMember.query.filter_by(team_id=team.id).all()
|
|
team_data.append({
|
|
'team': team,
|
|
'members': [{'player': User.query.get(m.player_id), 'position': m.position} for m in members]
|
|
})
|
|
|
|
# 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
|
|
if current_user.role == 'player':
|
|
# Check if player is participating in any matches for this tryout
|
|
player_in_match = MatchParticipant.query.join(Match).filter(
|
|
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, Match.start_time).all()
|
|
match_data = []
|
|
for match in matches:
|
|
if match.match_type == 'team_vs_team':
|
|
participants = {
|
|
'team1': match.team1.name if match.team1 else 'TBD',
|
|
'team2': match.team2.name if match.team2 else 'TBD',
|
|
'team1_players': [{'name': m.player.full_name, 'position': m.position} for m in match.team1.members.all()] if match.team1 else [],
|
|
'team2_players': [{'name': m.player.full_name, 'position': m.position} for m in match.team2.members.all()] if match.team2 else []
|
|
}
|
|
elif match.match_type == 'player_vs_player':
|
|
team1_players = [{'name': p.player.full_name, 'position': p.position} for p in match.participants.filter_by(team_side=1).all() if p.player]
|
|
team2_players = [{'name': p.player.full_name, 'position': p.position} for p in match.participants.filter_by(team_side=2).all() if p.player]
|
|
participants = {
|
|
'team1': 'Team 1',
|
|
'team2': 'Team 2',
|
|
'team1_players': team1_players,
|
|
'team2_players': team2_players
|
|
}
|
|
else:
|
|
participants = [p.player.full_name for p in match.participants.all()]
|
|
match_data.append({
|
|
'match': match,
|
|
'participants': participants
|
|
})
|
|
|
|
return render_template('pages/view_tryout.html',
|
|
tryout=tryout,
|
|
registered_players=registered_players,
|
|
evaluations=evaluations,
|
|
player_eval_status=player_eval_status,
|
|
is_registered=is_registered,
|
|
registrations=registrations,
|
|
team_data=team_data,
|
|
can_edit=can_edit,
|
|
can_view_calendar=can_view_calendar,
|
|
all_players=all_players,
|
|
matches=matches,
|
|
match_data=match_data,
|
|
game_positions=GAME_POSITIONS,
|
|
now=datetime.utcnow())
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/register', methods=['POST'])
|
|
@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.
|
|
"""
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
if current_user.role != 'player':
|
|
flash('Only players can register for tryouts.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
if tryout.status not in ['upcoming', 'in_progress']:
|
|
flash('This tryout is not accepting registrations.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
existing = TryoutRegistration.query.filter_by(tryout_id=tryout_id, player_id=current_user.id).first()
|
|
if existing:
|
|
flash('You are already registered for this tryout.', 'info')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
if tryout.max_players:
|
|
count = TryoutRegistration.query.filter_by(tryout_id=tryout_id).count()
|
|
if count >= tryout.max_players:
|
|
flash('This tryout is full.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
registration = TryoutRegistration(tryout_id=tryout_id, player_id=current_user.id)
|
|
db.session.add(registration)
|
|
db.session.commit()
|
|
flash('Successfully registered for tryout!', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/status', methods=['POST'])
|
|
@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.
|
|
"""
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
if not current_user.can_manage_this_tryout(tryout):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('tryouts.list_tryouts'))
|
|
new_status = request.form.get('status')
|
|
if new_status in ['upcoming', 'in_progress', 'completed']:
|
|
tryout.status = new_status
|
|
db.session.commit()
|
|
flash(f'Tryout status updated to {new_status}.', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/registration/<int:player_id>/status', methods=['POST'])
|
|
@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.
|
|
"""
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
if not current_user.can_manage_this_tryout(tryout):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('tryouts.list_tryouts'))
|
|
|
|
registration = TryoutRegistration.query.filter_by(tryout_id=tryout_id, player_id=player_id).first_or_404()
|
|
new_status = request.form.get('status')
|
|
if new_status in ['registered', 'attended', 'no_show']:
|
|
registration.status = new_status
|
|
db.session.commit()
|
|
flash('Registration status updated.', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/register_player', methods=['POST'])
|
|
@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.
|
|
"""
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
if not current_user.can_manage_this_tryout(tryout):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
player_id = request.form.get('player_id')
|
|
|
|
if not player_id:
|
|
flash('Please select a player.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
player = User.query.get_or_404(int(player_id))
|
|
if player.role != 'player':
|
|
flash('Can only register players.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
existing = TryoutRegistration.query.filter_by(tryout_id=tryout_id, player_id=player.id).first()
|
|
if existing:
|
|
flash(f'{player.full_name} is already registered for this tryout.', 'info')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
if tryout.max_players:
|
|
count = TryoutRegistration.query.filter_by(tryout_id=tryout_id).count()
|
|
if count >= tryout.max_players:
|
|
flash('This tryout is full.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
registration = TryoutRegistration(tryout_id=tryout_id, player_id=player.id)
|
|
db.session.add(registration)
|
|
db.session.commit()
|
|
flash(f'{player.full_name} registered for tryout!', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/team/create', methods=['POST'])
|
|
@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.
|
|
"""
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
if not current_user.can_manage_this_tryout(tryout):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
team_name = request.form.get('team_name')
|
|
if team_name:
|
|
team = Team(tryout_id=tryout_id, name=team_name, created_by=current_user.id)
|
|
db.session.add(team)
|
|
db.session.commit()
|
|
flash(f'Team "{team_name}" created!', 'success')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
|
|
@tryouts_bp.route('/<int:tryout_id>/team/<int:team_id>/add', methods=['POST'])
|
|
@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.
|
|
"""
|
|
team = Team.query.get_or_404(team_id)
|
|
tryout = Tryout.query.get_or_404(tryout_id)
|
|
if not current_user.can_manage_this_tryout(tryout):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
|
|
|
player_id = request.form.get('player_id')
|
|
position = request.form.get('position', '')
|
|
|
|
existing = TeamMember.query.filter_by(team_id=team_id, player_id=player_id).first()
|
|
if existing:
|
|
flash('Player is already on this team.', 'info')
|
|
else:
|
|
member = TeamMember(team_id=team_id, player_id=int(player_id), position=position)
|
|
db.session.add(member)
|
|
db.session.commit()
|
|
flash('Player added to team!', 'success')
|
|
|
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|