"""Notes a coach keeps: about a team, and about individual players. The player-facing view of the same notes lives here too — my_notes — since it reads exactly what the coach routes write. """ from flask import flash, redirect, render_template, request, url_for from flask_babel import gettext as _ from flask_login import current_user, login_required from app.extensions import db from app.models import ( Coach, Match, MatchParticipant, OneOnOneRequest, OrgTeam, PersonalNote, Player, TeamNote, Tryout, TryoutRegistration, User, ) from app.permissions import coach_can_access_player, coach_org_teams, coach_player_ids from app.routes.users.blueprint import users_bp @users_bp.route('/my-notes') @login_required def my_notes(): """View personal and team notes for the current player.""" if not isinstance(current_user, Player): flash(_('This page is for players only.'), 'info') return redirect(url_for('main.dashboard')) org_teams = current_user.get_org_teams() org_team = org_teams[0] if org_teams else None personal_notes = ( PersonalNote.query.filter_by( player_id=current_user.id, ) .order_by(PersonalNote.created_at.desc()) .all() ) team_notes = [] if org_team: team_notes = ( TeamNote.query.filter_by( org_team_id=org_team.id, ) .order_by(TeamNote.created_at.desc()) .all() ) return render_template( 'pages/player_personal_notes.html', org_team=org_team, personal_notes=personal_notes, team_notes=team_notes, ) @users_bp.route('/notes-dashboard') @login_required def notes_dashboard(): """Notes and One on One dashboard for coaches.""" if not isinstance(current_user, Coach): flash(_('Only coaches can access the notes dashboard.'), 'danger') return redirect(url_for('main.dashboard')) # The team-notes panel is still written against a single team; the # player list is not, and used to be narrowed to one team's squad while # the POST routes accepted every player the coach works with. The form # offered fewer players than the handler would take. org_teams = coach_org_teams(current_user) org_team = org_teams[0] if org_teams else None player_ids = coach_player_ids(current_user) players = ( User.query.filter(User.id.in_(player_ids)).order_by(User.username).all() if player_ids else [] ) team_notes = [] latest_team_note = None if org_team: team_notes = ( TeamNote.query.filter_by( org_team_id=org_team.id, ) .order_by(TeamNote.created_at.desc()) .all() ) latest_team_note = team_notes[0] if team_notes else None # A coach's own notes belong to them whether or not they hold a team; # this list was gated on org_team and came back empty without one. personal_notes = ( PersonalNote.query.filter_by( coach_id=current_user.id, ) .order_by(PersonalNote.created_at.desc()) .all() ) one_on_one_requests = [] if player_ids: one_on_one_requests = ( OneOnOneRequest.query.filter(OneOnOneRequest.player_id.in_(player_ids)) .order_by(OneOnOneRequest.created_at.desc()) .all() ) # For context selectors in the form matches = ( Match.query.filter( db.or_(Match.created_by == current_user.id, Match.status == 'scheduled'), ) .order_by(Match.date.desc()) .limit(20) .all() ) tryouts = ( Tryout.query.filter_by( created_by=current_user.id, ) .order_by(Tryout.date.desc()) .limit(20) .all() ) teams = OrgTeam.query.order_by(OrgTeam.name).all() return render_template( 'pages/notes.html', org_team=org_team, players=players, team_notes=team_notes, latest_team_note=latest_team_note, personal_notes=personal_notes, one_on_one_requests=one_on_one_requests, matches=matches, tryouts=tryouts, teams=teams, ) # --------------------------------------------------------------------------- # Manage Team Notes (POST) # --------------------------------------------------------------------------- @users_bp.route('/team-notes/manage', methods=['POST']) @login_required def manage_team_notes(): """Create or update team notes for the coach's org team.""" if not isinstance(current_user, Coach): flash(_('Only coaches can manage team notes.'), 'danger') return redirect(url_for('main.dashboard')) # Same team the dashboard displays notes for, resolved the same way. org_teams = coach_org_teams(current_user) if not org_teams: flash(_('You are not assigned to a team.'), 'danger') return redirect(url_for('users.notes_dashboard')) org_team = org_teams[0] content = request.form.get('content', '').strip() if content: note = TeamNote( org_team_id=org_team.id, coach_id=current_user.id, content=content, ) db.session.add(note) db.session.commit() flash(_('Team notes saved successfully!'), 'success') return redirect(url_for('users.notes_dashboard')) # --------------------------------------------------------------------------- # Manage Personal Notes (POST, simple form) # --------------------------------------------------------------------------- @users_bp.route('/personal-notes/manage', methods=['POST']) @login_required def manage_personal_notes(): """Create a personal note for a player (coach only, simple form).""" if not isinstance(current_user, Coach): flash(_('Only coaches can manage personal notes.'), 'danger') return redirect(url_for('main.dashboard')) player_id = request.form.get('player_id', type=int) content = request.form.get('content', '').strip() if not player_id or not content: flash(_('Player and content are required.'), 'danger') return redirect(url_for('users.notes_dashboard')) player = User.query.get_or_404(player_id) if not isinstance(player, Player): flash(_('Can only add notes for players.'), 'danger') return redirect(url_for('users.notes_dashboard')) if not coach_can_access_player(current_user, player_id): flash(_('You can only write notes about players you work with.'), 'danger') return redirect(url_for('users.notes_dashboard')) note = PersonalNote( player_id=player_id, coach_id=current_user.id, content=content, ) db.session.add(note) db.session.commit() flash(_('Note added for %(username)s.', username=player.username), 'success') return redirect(url_for('users.notes_dashboard')) # --------------------------------------------------------------------------- # Add Personal Note (POST, full form with context) # --------------------------------------------------------------------------- @users_bp.route('/personal-notes/add', methods=['POST']) @login_required def add_personal_note(): """Create a personal note for a player with optional context (coach only).""" if not isinstance(current_user, Coach): flash(_('Only coaches can add personal notes.'), 'danger') return redirect(url_for('main.dashboard')) player_id = request.form.get('player_id', type=int) content = request.form.get('content', '').strip() match_id = request.form.get('match_id', type=int) tryout_id = request.form.get('tryout_id', type=int) team_id_str = request.form.get('team_id') if not player_id or not content: flash(_('Player and content are required.'), 'danger') return redirect(url_for('users.notes_dashboard')) player = User.query.get_or_404(player_id) if not isinstance(player, Player): flash(_('Can only add notes for players.'), 'danger') return redirect(url_for('users.notes_dashboard')) if not coach_can_access_player(current_user, player_id): flash(_('You can only write notes about players you work with.'), 'danger') return redirect(url_for('users.notes_dashboard')) note = PersonalNote( player_id=player_id, coach_id=current_user.id, content=content, match_id=match_id if match_id else None, tryout_id=tryout_id if tryout_id else None, team_id=int(team_id_str) if team_id_str and team_id_str.isdigit() else None, ) db.session.add(note) db.session.commit() flash(_('Note added for %(username)s.', username=player.username), 'success') return redirect(url_for('users.notes_dashboard')) # --------------------------------------------------------------------------- # Add Note from Tryout context (GET + POST) # --------------------------------------------------------------------------- @users_bp.route('/personal-notes/tryout/', methods=['GET', 'POST']) @login_required def add_note_from_tryout(tryout_id): """Add a personal note for a player in the context of a tryout.""" if not isinstance(current_user, Coach): flash(_('Only coaches can add personal notes.'), 'danger') return redirect(url_for('main.dashboard')) tryout = Tryout.query.get_or_404(tryout_id) preselected_player_id = request.args.get('player_id', type=int) # Get registrations as players for the select list registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all() players = [r.player for r in registrations if r.player] if request.method == 'POST': player_id = request.form.get('player_id', type=int) content = request.form.get('content', '').strip() if not player_id or not content: flash(_('Player and content are required.'), 'danger') return redirect(url_for('users.add_note_from_tryout', tryout_id=tryout_id)) if not coach_can_access_player(current_user, player_id): flash(_('You can only write notes about players you work with.'), 'danger') return redirect(url_for('users.add_note_from_tryout', tryout_id=tryout_id)) note = PersonalNote( player_id=player_id, coach_id=current_user.id, content=content, tryout_id=tryout_id, ) db.session.add(note) db.session.commit() flash(_('Note added successfully.'), 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id)) return render_template( 'pages/add_note.html', context_type='tryout', tryout=tryout, players=players, preselected_player_id=preselected_player_id, team_notes=[], ) # --------------------------------------------------------------------------- # Add Note from Match context (GET + POST) # --------------------------------------------------------------------------- @users_bp.route('/personal-notes/match/', methods=['GET', 'POST']) @login_required def add_note_from_match(match_id): """Add a personal note for a player in the context of a match.""" if not isinstance(current_user, Coach): flash(_('Only coaches can add personal notes.'), 'danger') return redirect(url_for('main.dashboard')) match_obj = Match.query.get_or_404(match_id) # Get participants as players for the select list participants = MatchParticipant.query.filter_by(match_id=match_id).all() players = [p.player for p in participants if p.player] preselected_player_id = request.args.get('player_id', type=int) if request.method == 'POST': player_id = request.form.get('player_id', type=int) content = request.form.get('content', '').strip() if not player_id or not content: flash(_('Player and content are required.'), 'danger') return redirect(url_for('users.add_note_from_match', match_id=match_id)) if not coach_can_access_player(current_user, player_id): flash(_('You can only write notes about players you work with.'), 'danger') return redirect(url_for('users.add_note_from_match', match_id=match_id)) note = PersonalNote( player_id=player_id, coach_id=current_user.id, content=content, match_id=match_id, ) db.session.add(note) db.session.commit() flash(_('Note added successfully.'), 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=match_obj.tryout_id)) return render_template( 'pages/add_note.html', context_type='match', tryout=match_obj, match=match_obj, players=players, preselected_player_id=preselected_player_id, team_notes=[], )