Files
team-tryouts/routes/teams.py

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.username).all()
managers = User.query.filter_by(role='manager').order_by(User.username).all()
all_players = User.query.filter_by(role='player').order_by(User.username).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.username} 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.username} 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.username} is not on {team.name}.', 'danger')
return redirect(url_for('teams.list_teams'))
db.session.delete(tp)
db.session.commit()
flash(f'{player.username} 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.username
})
# 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.username} 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.username}!', 'success')
return redirect(url_for('teams.list_teams'))