remodulation du projet et des classes
This commit is contained in:
@@ -0,0 +1,551 @@
|
||||
"""Match scheduling routes for managing scrimmages and matches within tryouts.
|
||||
|
||||
Uses polymorphic isinstance checks instead of role-string comparisons.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
|
||||
from flask_login import login_required, current_user
|
||||
from app.extensions import db
|
||||
from app.models import (
|
||||
Admin, Manager, Coach, Player, Scout,
|
||||
User, Tryout, Match, MatchParticipant, Team, TeamMember,
|
||||
OrgTeam, TryoutRegistration, PlayerDisponibility,
|
||||
)
|
||||
from datetime import datetime, time, timedelta
|
||||
from app.discord_bot import send_schedule_notification
|
||||
|
||||
matches_bp = Blueprint('matches', __name__, url_prefix='/matches')
|
||||
|
||||
|
||||
def can_schedule_match():
|
||||
"""Check if user can schedule matches (Admin, Manager, Coach, Scout)."""
|
||||
return isinstance(current_user, (Admin, Manager, Coach, Scout))
|
||||
|
||||
|
||||
def get_visible_tryouts_for_user():
|
||||
"""Get tryouts that the current user can see based on their role.
|
||||
|
||||
Delegates to the polymorphic User subclass.
|
||||
"""
|
||||
return current_user.get_visible_tryouts()
|
||||
|
||||
|
||||
@matches_bp.route('/calendar')
|
||||
@login_required
|
||||
def calendar():
|
||||
"""Render the calendar view."""
|
||||
return render_template('pages/calendar.html')
|
||||
|
||||
|
||||
@matches_bp.route('/api/events')
|
||||
@login_required
|
||||
def api_events():
|
||||
"""API endpoint returning calendar events for FullCalendar."""
|
||||
events = []
|
||||
tryouts = get_visible_tryouts_for_user()
|
||||
|
||||
for tryout in tryouts:
|
||||
events.append({
|
||||
'id': f'tryout_{tryout.id}',
|
||||
'title': tryout.title,
|
||||
'date': tryout.date.strftime('%Y-%m-%d'),
|
||||
'type': 'tryout', 'color': '#3b82f6',
|
||||
'extendedProps': {
|
||||
'location': tryout.location or 'TBD',
|
||||
'status': tryout.status,
|
||||
'description': tryout.description or '',
|
||||
'tryout_id': tryout.id,
|
||||
},
|
||||
})
|
||||
|
||||
for match in tryout.matches:
|
||||
match_color = '#10b981' if match.match_type == 'team_vs_team' else '#f59e0b'
|
||||
match_desc = match.description or ''
|
||||
participants_str = ''
|
||||
if match.match_type == 'team_vs_team':
|
||||
teams = []
|
||||
if match.team1:
|
||||
teams.append(match.team1.name)
|
||||
if match.team2:
|
||||
teams.append(match.team2.name)
|
||||
participants_str = f"{' vs '.join(teams)}"
|
||||
match_desc = participants_str + (f"<br>{match.description}" if match.description else '')
|
||||
else:
|
||||
player_names = []
|
||||
for p in match.participants.all():
|
||||
player_names.append(p.player.username if p.player else 'Unknown Player')
|
||||
participants_str = ', '.join(player_names) if player_names else 'No players'
|
||||
match_desc = participants_str + (f"<br>{match.description}" if match.description else '')
|
||||
|
||||
start_time_str = match.start_time.strftime('%H:%M') if match.start_time else None
|
||||
end_time_str = match.end_time.strftime('%H:%M') if match.end_time else None
|
||||
|
||||
user_participant = MatchParticipant.query.filter_by(
|
||||
match_id=match.id, player_id=current_user.id,
|
||||
).first()
|
||||
|
||||
events.append({
|
||||
'id': f'match_{match.id}',
|
||||
'title': match.title,
|
||||
'date': match.date.strftime('%Y-%m-%d'),
|
||||
'type': 'match', 'color': match_color,
|
||||
'extendedProps': {
|
||||
'location': match.location or tryout.location or 'TBD',
|
||||
'status': match.status, 'description': match_desc,
|
||||
'match_type': match.match_type,
|
||||
'tryout_id': tryout.id, 'match_id': match.id,
|
||||
'start_time': start_time_str, 'end_time': end_time_str,
|
||||
'participants': participants_str,
|
||||
'user_participant_id': user_participant.id if user_participant else None,
|
||||
'user_attendance_confirmed': user_participant.attendance_confirmed if user_participant else False,
|
||||
},
|
||||
})
|
||||
|
||||
return jsonify(events)
|
||||
|
||||
|
||||
@matches_bp.route('/api/events/<int:tryout_id>')
|
||||
@login_required
|
||||
def api_events_for_tryout(tryout_id):
|
||||
"""API endpoint returning calendar events for a specific tryout."""
|
||||
tryout = Tryout.query.get_or_404(tryout_id)
|
||||
can_view = current_user.can_manage_this_tryout(tryout)
|
||||
|
||||
is_registered = False
|
||||
player_in_match = False
|
||||
if isinstance(current_user, Player):
|
||||
is_registered = TryoutRegistration.query.filter_by(
|
||||
tryout_id=tryout_id, player_id=current_user.id,
|
||||
).first() is not None
|
||||
player_matches = Match.query.join(MatchParticipant).filter(
|
||||
MatchParticipant.player_id == current_user.id,
|
||||
Match.tryout_id == tryout_id,
|
||||
).all()
|
||||
player_in_match = len(player_matches) > 0
|
||||
|
||||
if not can_view and not is_registered and not player_in_match:
|
||||
return jsonify([])
|
||||
|
||||
events = [{
|
||||
'id': f'tryout_{tryout.id}',
|
||||
'title': f'Tryout: {tryout.title}',
|
||||
'date': tryout.date.strftime('%Y-%m-%d'),
|
||||
'type': 'tryout', 'color': '#3b82f6',
|
||||
'extendedProps': {
|
||||
'location': tryout.location or 'TBD',
|
||||
'status': tryout.status,
|
||||
'description': tryout.description or '',
|
||||
'tryout_id': tryout.id,
|
||||
},
|
||||
}]
|
||||
|
||||
for match in tryout.matches:
|
||||
match_color = '#10b981' if match.match_type in ('team_vs_team', 'player_vs_player') else '#f59e0b'
|
||||
participants_str = ''
|
||||
if match.match_type == 'team_vs_team':
|
||||
teams = []
|
||||
if match.team1:
|
||||
teams.append(match.team1.name)
|
||||
if match.team2:
|
||||
teams.append(match.team2.name)
|
||||
participants_str = f"{' vs '.join(teams)}"
|
||||
elif match.match_type == 'player_vs_player':
|
||||
team1_players = [p.player.username for p in match.participants.filter_by(team_side=1).all() if p.player]
|
||||
team2_players = [p.player.username for p in match.participants.filter_by(team_side=2).all() if p.player]
|
||||
if team1_players and team2_players:
|
||||
participants_str = f"{', '.join(team1_players)} vs {', '.join(team2_players)}"
|
||||
else:
|
||||
participants_str = 'TBD vs TBD'
|
||||
else:
|
||||
player_names = [p.player.username for p in match.participants.all() if p.player]
|
||||
participants_str = ', '.join(player_names) if player_names else 'No players'
|
||||
|
||||
start_time_str = match.start_time.strftime('%H:%M') if match.start_time else None
|
||||
end_time_str = match.end_time.strftime('%H:%M') if match.end_time else None
|
||||
|
||||
events.append({
|
||||
'id': f'match_{match.id}',
|
||||
'title': match.title,
|
||||
'date': match.date.strftime('%Y-%m-%d'),
|
||||
'type': 'match', 'color': match_color,
|
||||
'extendedProps': {
|
||||
'location': match.location or tryout.location or 'TBD',
|
||||
'status': match.status, 'match_type': match.match_type,
|
||||
'tryout_id': tryout.id, 'match_id': match.id,
|
||||
'participants': participants_str,
|
||||
'start_time': start_time_str, 'end_time': end_time_str,
|
||||
},
|
||||
})
|
||||
|
||||
return jsonify(events)
|
||||
|
||||
|
||||
@matches_bp.route('/create/<int:tryout_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def create_match(tryout_id):
|
||||
"""Create a new match / scrimmage within a tryout."""
|
||||
tryout = Tryout.query.get_or_404(tryout_id)
|
||||
if not current_user.can_manage_this_tryout(tryout):
|
||||
flash('You do not have permission to schedule matches for this tryout.', 'danger')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||
|
||||
teams = Team.query.filter_by(tryout_id=tryout_id).all()
|
||||
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all()
|
||||
all_players = [User.query.get(r.player_id) for r in registrations if User.query.get(r.player_id)]
|
||||
all_players = sorted([p for p in all_players if p], key=lambda x: x.username)
|
||||
prefill_date = request.args.get('date', '')
|
||||
|
||||
if request.method == 'POST':
|
||||
title = request.form.get('title')
|
||||
description = request.form.get('description')
|
||||
date_str = request.form.get('date')
|
||||
start_time_str = request.form.get('start_time')
|
||||
end_time_str = request.form.get('end_time')
|
||||
location = request.form.get('location')
|
||||
match_type = request.form.get('match_type')
|
||||
|
||||
if not start_time_str:
|
||||
flash('Start time is required. Please select a time slot.', 'danger')
|
||||
return render_template('pages/match_form.html', tryout=tryout, teams=teams,
|
||||
all_players=all_players, prefill_date=prefill_date)
|
||||
|
||||
try:
|
||||
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else tryout.date
|
||||
except (ValueError, TypeError):
|
||||
flash('Invalid date format.', 'danger')
|
||||
return render_template('pages/match_form.html', tryout=tryout, teams=teams,
|
||||
all_players=all_players, prefill_date=prefill_date)
|
||||
|
||||
start_time = None
|
||||
end_time = None
|
||||
try:
|
||||
start_time = datetime.strptime(start_time_str, '%H:%M').time()
|
||||
if end_time_str:
|
||||
end_time = datetime.strptime(end_time_str, '%H:%M').time()
|
||||
else:
|
||||
start_dt = datetime.combine(date_obj, start_time)
|
||||
end_dt = start_dt + timedelta(minutes=30)
|
||||
end_time = end_dt.time()
|
||||
except ValueError:
|
||||
flash('Invalid time format.', 'danger')
|
||||
return render_template('pages/match_form.html', tryout=tryout, teams=teams, all_players=all_players)
|
||||
|
||||
match = Match(
|
||||
tryout_id=tryout_id, title=title, description=description,
|
||||
date=date_obj, start_time=start_time, end_time=end_time,
|
||||
location=location, match_type=match_type, created_by=current_user.id,
|
||||
)
|
||||
db.session.add(match)
|
||||
db.session.flush()
|
||||
|
||||
notified_player_ids = []
|
||||
notified_participant_ids = []
|
||||
|
||||
if match_type == 'team_vs_team':
|
||||
team1_id = request.form.get('team1_id')
|
||||
team2_id = request.form.get('team2_id')
|
||||
match.team1_id = int(team1_id) if team1_id else None
|
||||
match.team2_id = int(team2_id) if team2_id else None
|
||||
if match.team1_id:
|
||||
for m in TeamMember.query.filter_by(team_id=match.team1_id).all():
|
||||
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=1)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids.append(m.player_id)
|
||||
if match.team2_id:
|
||||
for m in TeamMember.query.filter_by(team_id=match.team2_id).all():
|
||||
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=2)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids.append(m.player_id)
|
||||
elif match_type == 'player_vs_player':
|
||||
team1_player_ids = request.form.get('team1_player_ids', '')
|
||||
team2_player_ids = request.form.get('team2_player_ids', '')
|
||||
team1_ids = [int(p) for p in team1_player_ids.split(',') if p] if team1_player_ids else []
|
||||
team2_ids = [int(p) for p in team2_player_ids.split(',') if p] if team2_player_ids else []
|
||||
for pid in team1_ids:
|
||||
participant = MatchParticipant(match_id=match.id, player_id=pid, team_side=1)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
for pid in team2_ids:
|
||||
participant = MatchParticipant(match_id=match.id, player_id=pid, team_side=2)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids = team1_ids + team2_ids
|
||||
elif match_type == 'player_scrim':
|
||||
player_ids = request.form.getlist('player_ids')
|
||||
for pid in player_ids:
|
||||
participant = MatchParticipant(match_id=match.id, player_id=int(pid))
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids = [int(p) for p in player_ids]
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Discord notifications
|
||||
event_date_str = date_obj.strftime('%Y-%m-%d')
|
||||
event_time_str = f"{start_time.strftime('%I:%M %p')} - {end_time.strftime('%I:%M %p')}" if start_time and end_time else 'TBD'
|
||||
for i, player_id in enumerate(notified_player_ids):
|
||||
reference_id = notified_participant_ids[i] if i < len(notified_participant_ids) else match.id
|
||||
send_schedule_notification(
|
||||
user_id=player_id, event_type='match', event_title=match.title,
|
||||
event_date=event_date_str, event_time=event_time_str,
|
||||
reference_id=reference_id,
|
||||
)
|
||||
|
||||
flash('Match scheduled successfully!', 'success')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||
|
||||
return render_template('pages/match_form.html', tryout=tryout, teams=teams,
|
||||
all_players=all_players, prefill_date=prefill_date)
|
||||
|
||||
|
||||
@matches_bp.route('/<int:match_id>/edit', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_match(match_id):
|
||||
"""Edit an existing match."""
|
||||
match = Match.query.get_or_404(match_id)
|
||||
tryout = match.tryout
|
||||
|
||||
if not current_user.can_manage_this_tryout(tryout):
|
||||
flash('You do not have permission to edit this match.', 'danger')
|
||||
return redirect(url_for('matches.calendar'))
|
||||
|
||||
teams = Team.query.filter_by(tryout_id=tryout.id).all()
|
||||
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout.id).all()
|
||||
all_players = [User.query.get(r.player_id) for r in registrations if r.player_id]
|
||||
all_players = sorted([p for p in all_players if p], key=lambda x: x.username)
|
||||
current_player_ids = [p.player_id for p in match.participants.all()]
|
||||
team1_player_ids = [p.player_id for p in match.participants.filter_by(team_side=1).all()]
|
||||
team2_player_ids = [p.player_id for p in match.participants.filter_by(team_side=2).all()]
|
||||
|
||||
if request.method == 'POST':
|
||||
match.title = request.form.get('title')
|
||||
match.description = request.form.get('description')
|
||||
date_str = request.form.get('date')
|
||||
start_time_str = request.form.get('start_time')
|
||||
end_time_str = request.form.get('end_time')
|
||||
location = request.form.get('location')
|
||||
status = request.form.get('status')
|
||||
|
||||
try:
|
||||
match.date = datetime.strptime(date_str, '%Y-%m-%d').date()
|
||||
except (ValueError, TypeError):
|
||||
flash('Invalid date format.', 'danger')
|
||||
return render_template('pages/match_form.html', match=match, tryout=tryout,
|
||||
teams=teams, all_players=all_players,
|
||||
current_player_ids=current_player_ids)
|
||||
|
||||
if not start_time_str:
|
||||
flash('Start time is required.', 'danger')
|
||||
return render_template('pages/match_form.html', match=match, tryout=tryout,
|
||||
teams=teams, all_players=all_players,
|
||||
current_player_ids=current_player_ids)
|
||||
|
||||
try:
|
||||
match.start_time = datetime.strptime(start_time_str, '%H:%M').time()
|
||||
if end_time_str:
|
||||
match.end_time = datetime.strptime(end_time_str, '%H:%M').time()
|
||||
else:
|
||||
start_dt = datetime.combine(match.date, match.start_time)
|
||||
end_dt = start_dt + timedelta(minutes=30)
|
||||
match.end_time = end_dt.time()
|
||||
except ValueError:
|
||||
match.start_time = None
|
||||
|
||||
match.location = location
|
||||
if status in ['scheduled', 'completed', 'cancelled']:
|
||||
match.status = status
|
||||
|
||||
notified_player_ids = []
|
||||
notified_participant_ids = []
|
||||
|
||||
if match.match_type == 'team_vs_team':
|
||||
team1_id = request.form.get('team1_id')
|
||||
team2_id = request.form.get('team2_id')
|
||||
new_team1_id = int(team1_id) if team1_id else None
|
||||
new_team2_id = int(team2_id) if team2_id else None
|
||||
|
||||
if new_team1_id != match.team1_id or new_team2_id != match.team2_id:
|
||||
MatchParticipant.query.filter_by(match_id=match.id).delete()
|
||||
match.team1_id = new_team1_id
|
||||
match.team2_id = new_team2_id
|
||||
if match.team1_id:
|
||||
for m in TeamMember.query.filter_by(team_id=match.team1_id).all():
|
||||
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=1)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids.append(m.player_id)
|
||||
if match.team2_id:
|
||||
for m in TeamMember.query.filter_by(team_id=match.team2_id).all():
|
||||
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=2)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids.append(m.player_id)
|
||||
else:
|
||||
if match.team1_id:
|
||||
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team1_id).all()])
|
||||
if match.team2_id:
|
||||
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team2_id).all()])
|
||||
elif match.match_type == 'player_vs_player':
|
||||
MatchParticipant.query.filter_by(match_id=match.id).delete()
|
||||
team1_str = request.form.get('team1_player_ids', '')
|
||||
team2_str = request.form.get('team2_player_ids', '')
|
||||
t1_ids = [p for p in team1_str.split(',') if p.strip()] if team1_str else []
|
||||
t2_ids = [p for p in team2_str.split(',') if p.strip()] if team2_str else []
|
||||
for pid in t1_ids:
|
||||
participant = MatchParticipant(match_id=match.id, player_id=int(pid), team_side=1)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
for pid in t2_ids:
|
||||
participant = MatchParticipant(match_id=match.id, player_id=int(pid), team_side=2)
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids = [int(p) for p in t1_ids] + [int(p) for p in t2_ids]
|
||||
elif match.match_type == 'player_scrim':
|
||||
MatchParticipant.query.filter_by(match_id=match.id).delete()
|
||||
player_ids = request.form.getlist('player_ids')
|
||||
for pid in player_ids:
|
||||
participant = MatchParticipant(match_id=match.id, player_id=int(pid))
|
||||
db.session.add(participant)
|
||||
db.session.flush()
|
||||
notified_participant_ids.append(participant.id)
|
||||
notified_player_ids = [int(p) for p in player_ids]
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Discord notifications
|
||||
end_time_val = match.end_time or (match.start_time if match.start_time else None)
|
||||
if match.start_time and end_time_val:
|
||||
event_time_str = f"{match.start_time.strftime('%I:%M %p')} - {end_time_val.strftime('%I:%M %p')}"
|
||||
else:
|
||||
event_time_str = 'TBD'
|
||||
event_date_str = match.date.strftime('%Y-%m-%d')
|
||||
for i, player_id in enumerate(notified_player_ids):
|
||||
reference_id = notified_participant_ids[i] if i < len(notified_participant_ids) else match.id
|
||||
send_schedule_notification(
|
||||
user_id=player_id, event_type='match', event_title=match.title,
|
||||
event_date=event_date_str, event_time=event_time_str,
|
||||
reference_id=reference_id,
|
||||
)
|
||||
|
||||
flash('Match updated successfully!', 'success')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
||||
|
||||
participants_map = {}
|
||||
for p in match.participants.all():
|
||||
participants_map[p.player_id] = {
|
||||
'participant_id': p.id,
|
||||
'attendance_confirmed': p.attendance_confirmed,
|
||||
'team_side': p.team_side,
|
||||
}
|
||||
|
||||
return render_template('pages/match_form.html', match=match, tryout=tryout,
|
||||
teams=teams, all_players=all_players,
|
||||
current_player_ids=current_player_ids,
|
||||
team1_player_ids=team1_player_ids,
|
||||
team2_player_ids=team2_player_ids,
|
||||
participants_map=participants_map)
|
||||
|
||||
|
||||
@matches_bp.route('/api/manageable-tryouts')
|
||||
@login_required
|
||||
def api_manageable_tryouts():
|
||||
"""API endpoint returning tryouts the current user can manage."""
|
||||
if not can_schedule_match():
|
||||
return jsonify([])
|
||||
|
||||
tryouts = get_visible_tryouts_for_user()
|
||||
manageable = []
|
||||
for t in tryouts:
|
||||
if current_user.can_manage_this_tryout(t):
|
||||
manageable.append({
|
||||
'id': t.id, 'title': t.title,
|
||||
'date': t.date.strftime('%Y-%m-%d'),
|
||||
})
|
||||
return jsonify(manageable)
|
||||
|
||||
|
||||
@matches_bp.route('/<int:match_id>/delete', methods=['POST'])
|
||||
@login_required
|
||||
def delete_match(match_id):
|
||||
"""Delete a match."""
|
||||
match = Match.query.get_or_404(match_id)
|
||||
tryout = match.tryout
|
||||
if not current_user.can_manage_this_tryout(tryout):
|
||||
flash('You do not have permission to delete this match.', 'danger')
|
||||
return redirect(url_for('matches.calendar'))
|
||||
db.session.delete(match)
|
||||
db.session.commit()
|
||||
flash('Match deleted successfully.', 'success')
|
||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
||||
|
||||
|
||||
def get_players_available_at_time(date_str, time_str):
|
||||
"""Get list of player IDs available at a specific date and time."""
|
||||
try:
|
||||
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
||||
time_obj = datetime.strptime(time_str, '%H:%M').time()
|
||||
except (ValueError, TypeError):
|
||||
return []
|
||||
|
||||
date_for_day = datetime.strptime(date_str, '%Y-%m-%d')
|
||||
day_of_week = date_for_day.weekday()
|
||||
|
||||
players = User.query.filter_by(role='player', is_active_account=True).all()
|
||||
available_players = []
|
||||
for player in players:
|
||||
disponibilities = PlayerDisponibility.query.filter_by(
|
||||
player_id=player.id, day_of_week=day_of_week,
|
||||
).all()
|
||||
for disp in disponibilities:
|
||||
disp_start = disp.start_time.hour * 60 + disp.start_time.minute
|
||||
disp_end = disp.end_time.hour * 60 + disp.end_time.minute
|
||||
match_time = time_obj.hour * 60 + time_obj.minute
|
||||
if disp_start <= match_time < disp_end:
|
||||
available_players.append(player.id)
|
||||
break
|
||||
return available_players
|
||||
|
||||
|
||||
@matches_bp.route('/api/available_players/<date>/<time>')
|
||||
@login_required
|
||||
def api_available_players(date, time):
|
||||
"""API endpoint to get players available at a specific date/time slot."""
|
||||
if not current_user.can_manage_teams() and not current_user.can_schedule_matches():
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
player_ids = get_players_available_at_time(date, time)
|
||||
return jsonify({'available_player_ids': player_ids})
|
||||
|
||||
|
||||
@matches_bp.route('/<int:match_id>/toggle-presence/<int:participant_id>', methods=['POST'])
|
||||
@login_required
|
||||
def toggle_presence(match_id, participant_id):
|
||||
"""Toggle attendance_confirmed for a match participant."""
|
||||
match = Match.query.get_or_404(match_id)
|
||||
tryout = match.tryout
|
||||
|
||||
participant = MatchParticipant.query.get_or_404(participant_id)
|
||||
if participant.match_id != match_id:
|
||||
return jsonify({'error': 'Participant does not belong to this match'}), 400
|
||||
|
||||
is_self = participant.player_id == current_user.id
|
||||
if not is_self and not current_user.can_manage_this_tryout(tryout):
|
||||
return jsonify({'error': 'Unauthorized'}), 403
|
||||
|
||||
participant.attendance_confirmed = not participant.attendance_confirmed
|
||||
db.session.commit()
|
||||
return jsonify({
|
||||
'participant_id': participant.id,
|
||||
'attendance_confirmed': participant.attendance_confirmed,
|
||||
'player_name': participant.player.username if participant.player else 'Unknown',
|
||||
})
|
||||
Reference in New Issue
Block a user