Ajout du statut remplaçant pour les joueurs Possibilité d'ajouter/enlever coach et manager des équipes les joueurs peuvent être associés à plusieurs équipes au lieu d'une seule
397 lines
13 KiB
Python
397 lines
13 KiB
Python
"""Organization team management routes.
|
|
|
|
This module handles CRUD operations for organization teams and player assignments.
|
|
"""
|
|
|
|
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
|
|
from flask_login import login_required, current_user
|
|
from extensions import db
|
|
from models import OrgTeam, User, Team, TeamMember, PersonalNote, TeamNote, Tryout, TeamPlayer
|
|
|
|
teams_bp = Blueprint('teams', __name__, url_prefix='/teams')
|
|
|
|
|
|
@teams_bp.route('')
|
|
@login_required
|
|
def list_teams():
|
|
"""List all organization teams visible to the current user.
|
|
|
|
Coaches see only their assigned team. Players and scouts see all teams.
|
|
Managers and presidents see all teams and can manage them.
|
|
|
|
Returns:
|
|
Response: Rendered teams list template.
|
|
"""
|
|
can_manage = current_user.can_manage_teams()
|
|
|
|
if current_user.role == 'coach':
|
|
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
|
teams = [org_team] if org_team else []
|
|
elif current_user.role in ['player', 'scout'] or can_manage:
|
|
# Players and scouts can view all teams; managers/presidents can manage
|
|
teams = OrgTeam.query.order_by(OrgTeam.name).all()
|
|
else:
|
|
flash('You do not have permission to view teams.', 'danger')
|
|
return redirect(url_for('main.dashboard'))
|
|
|
|
coaches = User.query.filter_by(role='coach').order_by(User.full_name).all()
|
|
managers = User.query.filter_by(role='manager').order_by(User.full_name).all()
|
|
all_players = User.query.filter_by(role='player').order_by(User.full_name).all()
|
|
return render_template('pages/teams.html', teams=teams, coaches=coaches, managers=managers, all_players=all_players, can_manage=can_manage)
|
|
|
|
|
|
@teams_bp.route('/create', methods=['POST'])
|
|
@login_required
|
|
def create_team():
|
|
"""Create a new organization team.
|
|
|
|
Args:
|
|
name: Team name from form.
|
|
coach_id: Optional coach assignment from form.
|
|
manager_id: Optional manager assignment from form.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
if not current_user.can_manage_teams():
|
|
flash('You do not have permission to create teams.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
name = request.form.get('name')
|
|
coach_id = request.form.get('coach_id')
|
|
manager_id = request.form.get('manager_id')
|
|
|
|
if not name:
|
|
flash('Team name is required.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
existing = OrgTeam.query.filter_by(name=name).first()
|
|
if existing:
|
|
flash(f'Team "{name}" already exists.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
team = OrgTeam(
|
|
name=name,
|
|
coach_id=int(coach_id) if coach_id else None,
|
|
manager_id=int(manager_id) if manager_id else None,
|
|
created_by=current_user.id
|
|
)
|
|
db.session.add(team)
|
|
db.session.commit()
|
|
flash(f'Team "{name}" created successfully!', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/edit', methods=['POST'])
|
|
@login_required
|
|
def edit_team(team_id):
|
|
"""Edit an existing organization team.
|
|
|
|
Args:
|
|
team_id: The ID of the team to edit.
|
|
name: New team name from form.
|
|
coach_id: New coach assignment from form.
|
|
manager_id: New manager assignment from form.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('You do not have permission to edit this team.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
name = request.form.get('name')
|
|
coach_id = request.form.get('coach_id')
|
|
manager_id = request.form.get('manager_id')
|
|
|
|
if not name:
|
|
flash('Team name is required.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
existing = OrgTeam.query.filter(OrgTeam.name == name, OrgTeam.id != team_id).first()
|
|
if existing:
|
|
flash(f'Team "{name}" already exists.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
team.name = name
|
|
team.coach_id = int(coach_id) if coach_id else None
|
|
team.manager_id = int(manager_id) if manager_id else None
|
|
db.session.commit()
|
|
flash(f'Team "{name}" updated successfully!', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/delete', methods=['POST'])
|
|
@login_required
|
|
def delete_team(team_id):
|
|
"""Delete an organization team.
|
|
|
|
Removes the team and clears its target_org_team_id reference from
|
|
any linked tryouts before deletion.
|
|
|
|
Args:
|
|
team_id: The ID of the team to delete.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
if not current_user.can_manage_teams():
|
|
flash('You do not have permission to delete teams.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
name = team.name
|
|
|
|
# Check if any tryouts are targeting this team
|
|
from models import Tryout
|
|
tryouts = Tryout.query.filter_by(target_org_team_id=team_id).all()
|
|
if tryouts:
|
|
for t in tryouts:
|
|
t.target_org_team_id = None
|
|
db.session.commit()
|
|
|
|
# Remove all team_players associations
|
|
TeamPlayer.query.filter_by(org_team_id=team_id).delete()
|
|
db.session.commit()
|
|
|
|
db.session.delete(team)
|
|
db.session.commit()
|
|
flash(f'Team "{name}" deleted successfully.', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/remove_coach', methods=['POST'])
|
|
@login_required
|
|
def remove_coach(team_id):
|
|
"""Remove the coach from an organization team.
|
|
|
|
Args:
|
|
team_id: The ID of the team.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
team.coach_id = None
|
|
db.session.commit()
|
|
flash(f'Coach removed from {team.name}.', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/remove_manager', methods=['POST'])
|
|
@login_required
|
|
def remove_manager(team_id):
|
|
"""Remove the manager from an organization team.
|
|
|
|
Args:
|
|
team_id: The ID of the team.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
team.manager_id = None
|
|
db.session.commit()
|
|
flash(f'Manager removed from {team.name}.', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/add_player', methods=['POST'])
|
|
@login_required
|
|
def add_player(team_id):
|
|
"""Add a player to an organization team.
|
|
|
|
Players can now be in multiple teams.
|
|
|
|
Args:
|
|
team_id: The ID of the team to add the player to.
|
|
player_id: The ID of the player to add.
|
|
status: The player's status (starter or substitute).
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
player_id = request.form.get('player_id')
|
|
status = request.form.get('status', 'starter')
|
|
|
|
if not player_id:
|
|
flash('Please select a player.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
player = User.query.get_or_404(int(player_id))
|
|
if player.role != 'player':
|
|
flash('Can only assign players to teams.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
# Check if player is already on this team
|
|
existing = TeamPlayer.query.filter_by(player_id=player.id, org_team_id=team.id).first()
|
|
if existing:
|
|
flash(f'{player.full_name} is already on {team.name}.', 'info')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
# Add player to the team using TeamPlayer model (allows multiple teams)
|
|
tp = TeamPlayer(
|
|
player_id=player.id,
|
|
org_team_id=team.id,
|
|
status=status
|
|
)
|
|
db.session.add(tp)
|
|
db.session.commit()
|
|
flash(f'{player.full_name} added to {team.name}!', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/remove_player/<int:player_id>', methods=['POST'])
|
|
@login_required
|
|
def remove_player(team_id, player_id):
|
|
"""Remove a player from an organization team.
|
|
|
|
Args:
|
|
team_id: The ID of the team.
|
|
player_id: The ID of the player to remove.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('Permission denied.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
player = User.query.get_or_404(player_id)
|
|
|
|
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=team_id).first()
|
|
if not tp:
|
|
flash(f'{player.full_name} is not on {team.name}.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
db.session.delete(tp)
|
|
db.session.commit()
|
|
flash(f'{player.full_name} removed from {team.name}.', 'success')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/toggle_status/<int:player_id>', methods=['POST'])
|
|
@login_required
|
|
def toggle_player_status(team_id, player_id):
|
|
"""Toggle a player's status between starter and substitute.
|
|
|
|
Args:
|
|
team_id: The ID of the team.
|
|
player_id: The ID of the player.
|
|
|
|
Returns:
|
|
Response: JSON with new status.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
return jsonify({'error': 'Permission denied'}), 403
|
|
|
|
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=team_id).first()
|
|
if not tp:
|
|
return jsonify({'error': 'Player not found on this team'}), 404
|
|
|
|
# Toggle status
|
|
tp.status = 'substitute' if tp.status == 'starter' else 'starter'
|
|
db.session.commit()
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'player_id': player_id,
|
|
'new_status': tp.status,
|
|
'player_name': tp.player.full_name
|
|
})
|
|
|
|
|
|
# Note actions from team page
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/add-team-note', methods=['POST'])
|
|
@login_required
|
|
def add_team_note(team_id):
|
|
"""Add a team improvement note from the team page (for coaches).
|
|
|
|
Args:
|
|
team_id: The ID of the team to add notes for.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
|
|
# Check if user can manage this team (president, manager, or coach)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('You do not have permission to add notes to this team.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
content = request.form.get('content', '').strip()
|
|
|
|
if content:
|
|
note = TeamNote(
|
|
org_team_id=team_id,
|
|
coach_id=current_user.id,
|
|
content=content
|
|
)
|
|
db.session.add(note)
|
|
db.session.commit()
|
|
flash('Team notes added successfully!', 'success')
|
|
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
|
|
@teams_bp.route('/<int:team_id>/add-player-note/<int:player_id>', methods=['POST'])
|
|
@login_required
|
|
def add_player_note(team_id, player_id):
|
|
"""Add a personal note for a player from the team page (for coaches).
|
|
|
|
Args:
|
|
team_id: The ID of the team.
|
|
player_id: The ID of the player to add note for.
|
|
|
|
Returns:
|
|
Response: Redirect to teams list with status message.
|
|
"""
|
|
team = OrgTeam.query.get_or_404(team_id)
|
|
|
|
# Check if user can manage this team (president, manager, or coach)
|
|
if not current_user.can_manage_this_org_team(team):
|
|
flash('You do not have permission to add notes to this team.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
player = User.query.get_or_404(player_id)
|
|
if player.role != 'player':
|
|
flash('Can only add notes for players.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
# Verify player belongs to this team
|
|
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=team_id).first()
|
|
if not tp:
|
|
flash(f'{player.full_name} is not on {team.name}.', 'danger')
|
|
return redirect(url_for('teams.list_teams'))
|
|
|
|
content = request.form.get('content', '').strip()
|
|
|
|
if content:
|
|
note = PersonalNote(
|
|
player_id=player_id,
|
|
coach_id=current_user.id,
|
|
content=content
|
|
)
|
|
db.session.add(note)
|
|
db.session.commit()
|
|
flash(f'Note added for {player.full_name}!', 'success')
|
|
|
|
return redirect(url_for('teams.list_teams')) |