Ajout de fonctionnalités:
Ajout de notes personnels et de notes d'équipe avec historique. Ajout de prise de rendez-vous avec un coach selon ses disponibilités
This commit is contained in:
Binary file not shown.
Binary file not shown.
+73
-2
@@ -6,7 +6,7 @@ This module handles CRUD operations for organization teams and player assignment
|
||||
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 OrgTeam, User
|
||||
from models import OrgTeam, User, Team, TeamMember, PersonalNote, TeamNote, Tryout
|
||||
|
||||
teams_bp = Blueprint('teams', __name__, url_prefix='/teams')
|
||||
|
||||
@@ -220,4 +220,75 @@ def remove_player(team_id, player_id):
|
||||
player.team_id = None
|
||||
db.session.commit()
|
||||
flash(f'{player.full_name} removed from {team.name}.', 'success')
|
||||
return redirect(url_for('teams.list_teams'))
|
||||
return redirect(url_for('teams.list_teams'))
|
||||
|
||||
|
||||
# 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)
|
||||
if current_user.role == 'coach' and team.coach_id != current_user.id:
|
||||
flash('Only the coach of this team can add notes.', '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)
|
||||
if current_user.role == 'coach' and team.coach_id != current_user.id:
|
||||
flash('Only the coach of this team can add notes.', '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'))
|
||||
|
||||
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'))
|
||||
|
||||
+693
-3
@@ -8,9 +8,10 @@ import os
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, send_file
|
||||
from flask_login import login_required, current_user
|
||||
from extensions import db, hash_password
|
||||
from models import User, ROLES, ESPORT_GAMES, PlayerDisponibility, UserGamertag, GAME_PLATFORMS, Contract, OrgTeam
|
||||
from models import User, ROLES, ESPORT_GAMES, PlayerDisponibility, UserGamertag, GAME_PLATFORMS, Contract, OrgTeam, CoachAvailability, TeamNote, PersonalNote, OneOnOneRequest, Match, Team, TeamMember, MatchParticipant, Tryout
|
||||
from werkzeug.utils import secure_filename
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, date as date_type
|
||||
import requests
|
||||
|
||||
|
||||
users_bp = Blueprint('users', __name__, url_prefix='/users')
|
||||
@@ -716,4 +717,693 @@ def download_signed_contract(contract_id):
|
||||
flash('No signed contract available.', 'danger')
|
||||
return redirect(url_for('users.list_contracts'))
|
||||
|
||||
return send_file(contract.signed_file_path, as_attachment=True, download_name=contract.signed_filename)
|
||||
return send_file(contract.signed_file_path, as_attachment=True, download_name=contract.signed_filename)
|
||||
|
||||
|
||||
# One on One Functions
|
||||
|
||||
|
||||
DISCORD_WEBHOOK_URL = os.environ.get('DISCORD_WEBHOOK_URL', '')
|
||||
|
||||
|
||||
def send_discord_notification(player_name, points, date_str, start_time_str, end_time_str, team_name, coach_name, coach_discord):
|
||||
"""Send a Discord webhook notification for a One on One request.
|
||||
|
||||
Args:
|
||||
player_name: Name of the player making the request.
|
||||
points: Discussion points from the player.
|
||||
date_str: Date of the requested session.
|
||||
start_time_str: Start time of the requested session.
|
||||
end_time_str: End time of the requested session.
|
||||
team_name: Name of the player's team.
|
||||
coach_name: Name of the coach.
|
||||
coach_discord: Coach's Discord username.
|
||||
"""
|
||||
if not DISCORD_WEBHOOK_URL:
|
||||
return # No webhook configured, skip notification
|
||||
|
||||
embed = {
|
||||
"embeds": [{
|
||||
"title": "One on One Request",
|
||||
"color": 3447003, # Blue color
|
||||
"fields": [
|
||||
{"name": "Player", "value": player_name, "inline": True},
|
||||
{"name": "Team", "value": team_name or "Unknown Team", "inline": True},
|
||||
{"name": "Date", "value": date_str, "inline": True},
|
||||
{"name": "Time", "value": f"{start_time_str} - {end_time_str}", "inline": True},
|
||||
{"name": "Discussion Points", "value": points or "No specific points provided", "inline": False}
|
||||
],
|
||||
"footer": {
|
||||
"text": f"Coach: {coach_name}" + (f" (Discord: {coach_discord})" if coach_discord else "")
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
try:
|
||||
requests.post(DISCORD_WEBHOOK_URL, json=embed, timeout=5)
|
||||
except Exception:
|
||||
pass # Silently fail if webhook doesn't work
|
||||
|
||||
|
||||
@users_bp.route('/one-on-one', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def one_on_one():
|
||||
"""One on One request page for players.
|
||||
|
||||
Players can view team notes, personal notes, and request One on One sessions.
|
||||
|
||||
Returns:
|
||||
Response: Rendered One on One page.
|
||||
"""
|
||||
if current_user.role != 'player':
|
||||
flash('Only players can request One on One sessions.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get player's team and coach
|
||||
org_team = OrgTeam.query.get(current_user.team_id) if current_user.team_id else None
|
||||
coach = User.query.get(org_team.coach_id) if org_team and org_team.coach_id else None
|
||||
|
||||
if not coach:
|
||||
flash('You do not have a coach assigned to your team.', 'info')
|
||||
|
||||
# Get team notes for this player's team
|
||||
team_notes = []
|
||||
if org_team:
|
||||
team_notes = TeamNote.query.filter_by(org_team_id=org_team.id).order_by(TeamNote.created_at.desc()).all()
|
||||
|
||||
# Get personal notes for this player
|
||||
personal_notes = PersonalNote.query.filter_by(player_id=current_user.id).order_by(PersonalNote.created_at.desc()).all()
|
||||
|
||||
# Get coach's availability for the next 7 days
|
||||
coach_availability = []
|
||||
if coach:
|
||||
coach_availability = CoachAvailability.query.filter_by(coach_id=coach.id).all()
|
||||
|
||||
if request.method == 'POST':
|
||||
# Handle One on One request submission
|
||||
date_str = request.form.get('date')
|
||||
start_time_str = request.form.get('start_time')
|
||||
end_time_str = request.form.get('end_time')
|
||||
points = request.form.get('points', '').strip()
|
||||
|
||||
if not coach:
|
||||
flash('Cannot request One on One - no coach assigned.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
# Validate date and time
|
||||
try:
|
||||
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
||||
start_time = datetime.strptime(start_time_str, '%H:%M').time()
|
||||
end_time = datetime.strptime(end_time_str, '%H:%M').time()
|
||||
except (ValueError, TypeError):
|
||||
flash('Invalid date or time format.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
# Check if the requested slot is within coach's availability
|
||||
date_parts = date_str.split('-')
|
||||
check_date = datetime(int(date_parts[0]), int(date_parts[1]), int(date_parts[2]))
|
||||
# Python weekday: Monday=0, Sunday=6
|
||||
day_of_week = check_date.weekday()
|
||||
|
||||
is_available = any(
|
||||
av.day_of_week == day_of_week and
|
||||
av.start_time <= start_time and
|
||||
av.end_time >= end_time
|
||||
for av in coach_availability
|
||||
)
|
||||
|
||||
if not is_available:
|
||||
flash('The requested time is not within the coach\'s availability.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
# Create the request
|
||||
request_obj = OneOnOneRequest(
|
||||
player_id=current_user.id,
|
||||
coach_id=coach.id,
|
||||
org_team_id=org_team.id if org_team else None,
|
||||
date=date_obj,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
points=points if points else None
|
||||
)
|
||||
db.session.add(request_obj)
|
||||
db.session.commit()
|
||||
|
||||
# Send Discord notification
|
||||
send_discord_notification(
|
||||
player_name=current_user.full_name,
|
||||
points=points,
|
||||
date_str=date_str,
|
||||
start_time_str=start_time_str,
|
||||
end_time_str=end_time_str,
|
||||
team_name=org_team.name if org_team else None,
|
||||
coach_name=coach.full_name,
|
||||
coach_discord=coach.discord_username
|
||||
)
|
||||
|
||||
flash('One on One request sent to your coach!', 'success')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
# Calculate dates for the next week (starting from today)
|
||||
dates = []
|
||||
for i in range(7):
|
||||
d = date_type.today() + timedelta(days=i)
|
||||
dates.append({
|
||||
'value': d.strftime('%Y-%m-%d'),
|
||||
'display': d.strftime('%A, %b %d'),
|
||||
'day_of_week': d.weekday()
|
||||
})
|
||||
|
||||
# Serialize coach availability for JavaScript
|
||||
coach_availability_serialized = [
|
||||
{
|
||||
'id': av.id,
|
||||
'day_of_week': av.day_of_week,
|
||||
'start_time': av.start_time.strftime('%H:%M'),
|
||||
'end_time': av.end_time.strftime('%H:%M')
|
||||
}
|
||||
for av in coach_availability
|
||||
]
|
||||
|
||||
return render_template('pages/one_on_one.html',
|
||||
org_team=org_team,
|
||||
coach=coach,
|
||||
team_notes=team_notes,
|
||||
personal_notes=personal_notes,
|
||||
coach_availability=coach_availability_serialized,
|
||||
dates=dates)
|
||||
|
||||
|
||||
@users_bp.route('/coach-availability', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def manage_coach_availability():
|
||||
"""Manage coach availability (for coaches).
|
||||
|
||||
GET: Render the availability management page.
|
||||
POST: Add availability slots via bulk.
|
||||
|
||||
Returns:
|
||||
Response: Rendered management page or redirect.
|
||||
"""
|
||||
if current_user.role != 'coach':
|
||||
flash('Only coaches can manage availability.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
if request.method == 'POST':
|
||||
data = request.get_json()
|
||||
slots = data.get('slots', [])
|
||||
|
||||
created = []
|
||||
for slot in slots:
|
||||
day_of_week = slot.get('day_of_week')
|
||||
start_time_str = slot.get('start_time')
|
||||
|
||||
if day_of_week is None or day_of_week < 0 or day_of_week > 6:
|
||||
continue
|
||||
|
||||
try:
|
||||
start_time = datetime.strptime(start_time_str, '%H:%M').time()
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
|
||||
end_time = add_30_minutes(start_time)
|
||||
|
||||
# Check if this slot already exists for this coach
|
||||
existing = CoachAvailability.query.filter_by(
|
||||
coach_id=current_user.id,
|
||||
day_of_week=day_of_week,
|
||||
start_time=start_time
|
||||
).first()
|
||||
|
||||
if not existing:
|
||||
availability = CoachAvailability(
|
||||
coach_id=current_user.id,
|
||||
day_of_week=day_of_week,
|
||||
start_time=start_time,
|
||||
end_time=end_time
|
||||
)
|
||||
db.session.add(availability)
|
||||
db.session.flush()
|
||||
created.append({
|
||||
'id': availability.id,
|
||||
'day_of_week': availability.day_of_week,
|
||||
'day_name': DAY_NAMES[availability.day_of_week],
|
||||
'start_time': availability.start_time.strftime('%H:%M'),
|
||||
'end_time': availability.end_time.strftime('%H:%M')
|
||||
})
|
||||
|
||||
db.session.commit()
|
||||
return jsonify({'success': True, 'created': created})
|
||||
|
||||
# Get existing availability
|
||||
existing_availability = CoachAvailability.query.filter_by(coach_id=current_user.id).all()
|
||||
|
||||
return render_template('pages/coach_availability.html',
|
||||
existing_availability=existing_availability)
|
||||
|
||||
|
||||
@users_bp.route('/coach-availability/clear', methods=['POST'])
|
||||
@login_required
|
||||
def clear_coach_availability():
|
||||
"""Clear all coach availability slots.
|
||||
|
||||
Returns:
|
||||
Response: JSON with success status.
|
||||
"""
|
||||
if current_user.role != 'coach':
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
|
||||
CoachAvailability.query.filter_by(coach_id=current_user.id).delete()
|
||||
db.session.commit()
|
||||
return jsonify({'success': True})
|
||||
|
||||
|
||||
@users_bp.route('/coach-availability/<int:availability_id>/delete', methods=['POST'])
|
||||
@login_required
|
||||
def delete_coach_availability(availability_id):
|
||||
"""Delete a coach availability slot.
|
||||
|
||||
Args:
|
||||
availability_id: The ID of the availability slot to delete.
|
||||
|
||||
Returns:
|
||||
Response: JSON with success status or error.
|
||||
"""
|
||||
if current_user.role != 'coach':
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
|
||||
availability = CoachAvailability.query.get_or_404(availability_id)
|
||||
|
||||
if availability.coach_id != current_user.id:
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
|
||||
db.session.delete(availability)
|
||||
db.session.commit()
|
||||
return jsonify({'success': True})
|
||||
|
||||
|
||||
@users_bp.route('/api/coach-availability/<int:coach_id>')
|
||||
@login_required
|
||||
def api_get_coach_availability(coach_id):
|
||||
"""API endpoint to get coach availability.
|
||||
|
||||
Args:
|
||||
coach_id: The ID of the coach.
|
||||
|
||||
Returns:
|
||||
Response: JSON with availability data.
|
||||
"""
|
||||
if current_user.role != 'player':
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
|
||||
availability = CoachAvailability.query.filter_by(coach_id=coach_id).all()
|
||||
|
||||
result = {}
|
||||
for av in availability:
|
||||
if av.day_of_week not in result:
|
||||
result[av.day_of_week] = []
|
||||
result[av.day_of_week].append({
|
||||
'id': av.id,
|
||||
'start_time': av.start_time.strftime('%H:%M'),
|
||||
'end_time': av.end_time.strftime('%H:%M')
|
||||
})
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@users_bp.route('/team-notes', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def manage_team_notes():
|
||||
"""Manage team improvement notes (for coaches).
|
||||
|
||||
GET: Render the team notes management page.
|
||||
POST: Create or update team notes.
|
||||
|
||||
Returns:
|
||||
Response: Rendered management page or redirect.
|
||||
"""
|
||||
if current_user.role != 'coach':
|
||||
flash('Only coaches can manage team notes.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get the coach's team
|
||||
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||
if not org_team:
|
||||
flash('You are not assigned to coach any team.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get existing team notes
|
||||
team_notes = TeamNote.query.filter_by(org_team_id=org_team.id).order_by(TeamNote.created_at.desc()).all()
|
||||
|
||||
if request.method == 'POST':
|
||||
content = request.form.get('content', '').strip()
|
||||
|
||||
if content:
|
||||
# Create new team note entry (keeps history)
|
||||
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 added successfully!', 'success')
|
||||
return redirect(url_for('users.manage_team_notes'))
|
||||
|
||||
return render_template('pages/team_notes.html',
|
||||
org_team=org_team,
|
||||
team_notes=team_notes)
|
||||
|
||||
|
||||
@users_bp.route('/personal-notes', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def manage_personal_notes():
|
||||
"""Manage personal notes for players (for coaches).
|
||||
|
||||
GET: Render the personal notes management page.
|
||||
POST: Create a personal note for a player.
|
||||
|
||||
Returns:
|
||||
Response: Rendered management page or redirect.
|
||||
"""
|
||||
if current_user.role != 'coach':
|
||||
flash('Only coaches can manage personal notes.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get players on the coach's team
|
||||
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||
players = []
|
||||
if org_team:
|
||||
players = User.query.filter_by(role='player', team_id=org_team.id).order_by(User.full_name).all()
|
||||
|
||||
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('Please select a player and enter note content.', 'danger')
|
||||
return redirect(url_for('users.manage_personal_notes'))
|
||||
|
||||
# Verify player is on coach's team
|
||||
if org_team and player_id not in [p.id for p in players]:
|
||||
flash('You can only add notes for players on your team.', 'danger')
|
||||
return redirect(url_for('users.manage_personal_notes'))
|
||||
|
||||
note = PersonalNote(
|
||||
player_id=player_id,
|
||||
coach_id=current_user.id,
|
||||
content=content
|
||||
)
|
||||
db.session.add(note)
|
||||
db.session.commit()
|
||||
flash('Personal note added successfully!', 'success')
|
||||
return redirect(url_for('users.manage_personal_notes'))
|
||||
|
||||
# Get all personal notes for players on this team
|
||||
personal_notes = []
|
||||
if org_team:
|
||||
personal_notes = PersonalNote.query.filter(
|
||||
PersonalNote.player_id.in_([p.id for p in players])
|
||||
).order_by(PersonalNote.created_at.desc()).all()
|
||||
|
||||
return render_template('pages/personal_notes.html',
|
||||
players=players,
|
||||
personal_notes=personal_notes,
|
||||
org_team=org_team)
|
||||
|
||||
|
||||
# Note source types for filtering
|
||||
NOTE_SOURCE_MATCH = 'match'
|
||||
NOTE_SOURCE_TRYOUT = 'tryout'
|
||||
NOTE_SOURCE_TEAM = 'team'
|
||||
|
||||
|
||||
@users_bp.route('/my-notes')
|
||||
@login_required
|
||||
def my_notes():
|
||||
"""View all notes for the current player.
|
||||
|
||||
Shows both personal notes and team notes that the player has received.
|
||||
Personal notes are grouped by source (match, tryout, team).
|
||||
|
||||
Returns:
|
||||
Response: Rendered my notes template.
|
||||
"""
|
||||
if current_user.role != 'player':
|
||||
flash('Only players can view their notes.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get player's team and coach
|
||||
org_team = OrgTeam.query.get(current_user.team_id) if current_user.team_id else None
|
||||
|
||||
# Get all personal notes for this player with eager loading for relationships
|
||||
personal_notes = PersonalNote.query.filter_by(player_id=current_user.id).order_by(PersonalNote.created_at.desc()).all()
|
||||
|
||||
# Get team notes for this player's team
|
||||
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/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_personal_note():
|
||||
"""Add a personal note with optional context (for coaches and managers).
|
||||
|
||||
GET: Render the note creation form.
|
||||
POST: Create a personal note, optionally linked to match/tryout/team.
|
||||
|
||||
Returns:
|
||||
Response: Create form or redirect to notes view.
|
||||
"""
|
||||
if current_user.role not in ['coach', 'manager', 'president']:
|
||||
flash('Only coaches and managers can add notes.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get players this user can manage
|
||||
players = []
|
||||
org_team = None
|
||||
if current_user.role == 'coach':
|
||||
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||
if org_team:
|
||||
players = User.query.filter_by(role='player', team_id=org_team.id).order_by(User.full_name).all()
|
||||
elif current_user.role in ['president', 'manager']:
|
||||
players = User.query.filter_by(role='player').order_by(User.full_name).all()
|
||||
|
||||
# Get available matches and tryouts for context
|
||||
matches = []
|
||||
tryouts = []
|
||||
teams = []
|
||||
if current_user.role == 'coach' and org_team:
|
||||
tryouts = Tryout.query.filter_by(target_org_team_id=org_team.id).order_by(Tryout.date.desc()).all()
|
||||
matches = Match.query.join(Tryout).filter(Tryout.target_org_team_id == org_team.id).order_by(Match.date.desc()).all()
|
||||
elif current_user.role in ['president', 'manager']:
|
||||
tryouts = Tryout.query.order_by(Tryout.date.desc()).all()
|
||||
matches = Match.query.order_by(Match.date.desc()).all()
|
||||
teams = Team.query.order_by(Team.name).all()
|
||||
|
||||
if request.method == 'POST':
|
||||
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 = request.form.get('team_id', type=int)
|
||||
|
||||
if not player_id or not content:
|
||||
flash('Please select a player and enter note content.', 'danger')
|
||||
return redirect(url_for('users.add_personal_note'))
|
||||
|
||||
# Verify player is on coach's team (if coach)
|
||||
if current_user.role == 'coach' and org_team and player_id not in [p.id for p in players]:
|
||||
flash('You can only add notes for players on your team.', 'danger')
|
||||
return redirect(url_for('users.add_personal_note'))
|
||||
|
||||
# Validate context - ensure coach can access the match/tryout/team
|
||||
if match_id:
|
||||
match = Match.query.get(match_id)
|
||||
match_tryout = None
|
||||
if match:
|
||||
match_tryout = Tryout.query.get(match.tryout_id)
|
||||
if match_tryout and match_tryout.target_org_team_id and match_tryout.target_org_team_id != org_team.id:
|
||||
flash('You can only add notes for matches in your team\'s tryouts.', 'danger')
|
||||
return redirect(url_for('users.add_personal_note'))
|
||||
if tryout_id and org_team:
|
||||
tryout = Tryout.query.get(tryout_id)
|
||||
if tryout and tryout.target_org_team_id and tryout.target_org_team_id != org_team.id:
|
||||
flash('You can only add notes for your team\'s tryouts.', 'danger')
|
||||
return redirect(url_for('users.add_personal_note'))
|
||||
if team_id and org_team:
|
||||
team = Team.query.get(team_id)
|
||||
if team:
|
||||
tryout = Tryout.query.get(team.tryout_id)
|
||||
if tryout and tryout.target_org_team_id and tryout.target_org_team_id != org_team.id:
|
||||
flash('You can only add notes for your team\'s tryouts.', 'danger')
|
||||
return redirect(url_for('users.add_personal_note'))
|
||||
|
||||
note = PersonalNote(
|
||||
player_id=player_id,
|
||||
coach_id=current_user.id,
|
||||
content=content,
|
||||
match_id=match_id if match_id else None,
|
||||
team_id=team_id if team_id else None,
|
||||
tryout_id=tryout_id if tryout_id else None
|
||||
)
|
||||
db.session.add(note)
|
||||
db.session.commit()
|
||||
flash('Personal note added successfully!', 'success')
|
||||
return redirect(url_for('users.my_notes'))
|
||||
|
||||
return render_template('pages/add_personal_note.html',
|
||||
players=players,
|
||||
matches=matches,
|
||||
tryouts=tryouts,
|
||||
teams=teams,
|
||||
org_team=org_team)
|
||||
|
||||
|
||||
@users_bp.route('/match/<int:match_id>/add-note', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_note_from_match(match_id):
|
||||
"""Add a personal note from a match view context (for coaches).
|
||||
|
||||
GET: Render the note creation form pre-filled with match info.
|
||||
POST: Create a personal note linked to the match.
|
||||
|
||||
Args:
|
||||
match_id: The ID of the match to create note for.
|
||||
|
||||
Returns:
|
||||
Response: Create form or redirect.
|
||||
"""
|
||||
if current_user.role not in ['coach', 'manager', 'president']:
|
||||
flash('Only coaches can add notes from matches.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
match = Match.query.get_or_404(match_id)
|
||||
tryout = Tryout.query.get(match.tryout_id)
|
||||
|
||||
# Check permissions
|
||||
if current_user.role == 'coach':
|
||||
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||
if not org_team or (tryout.target_org_team_id and tryout.target_org_team_id != org_team.id):
|
||||
flash('You do not have permission for this match.', 'danger')
|
||||
return redirect(url_for('matches.calendar'))
|
||||
|
||||
# Get all participants for this match
|
||||
participant_ids = []
|
||||
if match.match_type == 'team_vs_team':
|
||||
if match.team1_id:
|
||||
team_members = TeamMember.query.filter_by(team_id=match.team1_id).all()
|
||||
participant_ids.extend([m.player_id for m in team_members])
|
||||
if match.team2_id:
|
||||
team_members = TeamMember.query.filter_by(team_id=match.team2_id).all()
|
||||
participant_ids.extend([m.player_id for m in team_members])
|
||||
else:
|
||||
participants = MatchParticipant.query.filter_by(match_id=match_id).all()
|
||||
participant_ids = [p.player_id for p in participants]
|
||||
|
||||
players = User.query.filter(User.id.in_(participant_ids)).order_by(User.full_name).all() if participant_ids else []
|
||||
|
||||
# Get team notes for context
|
||||
team_notes = []
|
||||
if tryout and tryout.target_org_team_id:
|
||||
team_notes = TeamNote.query.filter_by(org_team_id=tryout.target_org_team_id).order_by(TeamNote.created_at.desc()).all()
|
||||
|
||||
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('Please select a player and enter note content.', 'danger')
|
||||
elif player_id not in participant_ids:
|
||||
flash('Selected player is not in this match.', 'danger')
|
||||
else:
|
||||
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('Personal note added successfully!', 'success')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
||||
|
||||
return render_template('pages/add_note_from_match.html',
|
||||
match=match,
|
||||
tryout=tryout,
|
||||
players=players,
|
||||
team_notes=team_notes)
|
||||
|
||||
|
||||
@users_bp.route('/tryout/<int:tryout_id>/add-note', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_note_from_tryout(tryout_id):
|
||||
"""Add a personal note from a tryout view context (for coaches).
|
||||
|
||||
GET: Render the note creation form pre-filled with tryout info.
|
||||
POST: Create a personal note linked to the tryout.
|
||||
|
||||
Args:
|
||||
tryout_id: The ID of the tryout to create note for.
|
||||
|
||||
Returns:
|
||||
Response: Create form or redirect.
|
||||
"""
|
||||
if current_user.role not in ['coach', 'manager', 'president']:
|
||||
flash('Only coaches can add notes from tryouts.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
tryout = Tryout.query.get_or_404(tryout_id)
|
||||
|
||||
# Check permissions
|
||||
if current_user.role == 'coach':
|
||||
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||
if not org_team or (tryout.target_org_team_id and tryout.target_org_team_id != org_team.id):
|
||||
flash('You do not have permission for this tryout.', 'danger')
|
||||
return redirect(url_for('tryouts.list_tryouts'))
|
||||
|
||||
# Get all registered players in this tryout
|
||||
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all()
|
||||
player_ids = [r.player_id for r in registrations]
|
||||
|
||||
# If coach, filter to only their team players
|
||||
if current_user.role == 'coach' and org_team:
|
||||
players = User.query.filter(User.id.in_(player_ids), User.team_id == org_team.id).order_by(User.full_name).all()
|
||||
else:
|
||||
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all()
|
||||
|
||||
# Get team notes for context
|
||||
team_notes = []
|
||||
if tryout.target_org_team_id:
|
||||
team_notes = TeamNote.query.filter_by(org_team_id=tryout.target_org_team_id).order_by(TeamNote.created_at.desc()).all()
|
||||
|
||||
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('Please select a player and enter note content.', 'danger')
|
||||
elif player_id not in [p.id for p in players]:
|
||||
flash('Selected player is not registered for this tryout.', 'danger')
|
||||
else:
|
||||
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('Personal note added successfully!', 'success')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||
|
||||
return render_template('pages/add_note_from_tryout.html',
|
||||
tryout=tryout,
|
||||
players=players,
|
||||
team_notes=team_notes)
|
||||
|
||||
Reference in New Issue
Block a user