ajout des disponibilités de joueurs et ajouts d'un tableau qui montre les dispo des joueurs lors de la création d'un match

This commit is contained in:
cedrick2711
2026-07-14 18:46:45 -04:00
parent 4e7ecf0ab9
commit b19d5db8db
17 changed files with 1706 additions and 218 deletions
Binary file not shown.
Binary file not shown.
+103 -11
View File
@@ -1,8 +1,8 @@
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 User, Tryout, Match, MatchParticipant, Team, TeamMember, OrgTeam, TryoutRegistration
from datetime import datetime, time
from models import User, Tryout, Match, MatchParticipant, Team, TeamMember, OrgTeam, TryoutRegistration, PlayerDisponibility
from datetime import datetime, time, timedelta
matches_bp = Blueprint('matches', __name__, url_prefix='/matches')
@@ -60,7 +60,10 @@ def api_events():
match_desc = participants_str + (f"<br>{match.description}" if match.description else '')
else:
# Player scrim - show all participants
player_names = [p.player.full_name for p in match.participants.all()]
player_names = []
for p in match.participants.all():
player_name = p.player.full_name if p.player else 'Unknown Player'
player_names.append(player_name)
participants_str = ', '.join(player_names) if player_names else 'No players'
match_desc = participants_str + (f"<br>{match.description}" if match.description else '')
@@ -153,14 +156,23 @@ def api_events_for_tryout(tryout_id):
participants_str = f"{' vs '.join(teams)}"
elif match.match_type == 'player_vs_player':
# Get players grouped by team side
team1_players = [p.player.full_name for p in match.participants.filter_by(team_side=1).all()]
team2_players = [p.player.full_name for p in match.participants.filter_by(team_side=2).all()]
team1_players = []
for p in match.participants.filter_by(team_side=1).all():
if p.player:
team1_players.append(p.player.full_name)
team2_players = []
for p in match.participants.filter_by(team_side=2).all():
if p.player:
team2_players.append(p.player.full_name)
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.full_name for p in match.participants.all()]
player_names = []
for p in match.participants.all():
player_name = p.player.full_name if p.player else 'Unknown Player'
player_names.append(player_name)
participants_str = ', '.join(player_names) if player_names else 'No players'
# Include time for calendar display
@@ -244,6 +256,11 @@ def create_match(tryout_id):
location = request.form.get('location')
match_type = request.form.get('match_type')
# Start time is now mandatory
if not start_time_str:
flash('Start time is required. Please select a time slot.', 'danger')
return render_template('pages/create_match.html', tryout=tryout, teams=teams, all_players=all_players)
try:
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else tryout.date
except (ValueError, TypeError):
@@ -253,10 +270,15 @@ def create_match(tryout_id):
start_time = None
end_time = None
try:
if start_time_str:
start_time = datetime.strptime(start_time_str, '%H:%M').time()
start_time = datetime.strptime(start_time_str, '%H:%M').time()
# Auto-calculate end time if not provided (start + 30 minutes)
if end_time_str:
end_time = datetime.strptime(end_time_str, '%H:%M').time()
else:
# Auto-calculate end time as start + 30 minutes
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/create_match.html', tryout=tryout, teams=teams, all_players=all_players)
@@ -340,11 +362,21 @@ def edit_match(match_id):
flash('Invalid date format.', 'danger')
return render_template('pages/edit_match.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids)
# Start time is now mandatory
if not start_time_str:
flash('Start time is required. Please select a time slot.', 'danger')
return render_template('pages/edit_match.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids)
try:
if start_time_str:
match.start_time = datetime.strptime(start_time_str, '%H:%M').time()
match.start_time = datetime.strptime(start_time_str, '%H:%M').time()
# Auto-calculate end time if not provided (start + 30 minutes)
if end_time_str:
match.end_time = datetime.strptime(end_time_str, '%H:%M').time()
else:
# Auto-calculate end time as start + 30 minutes
start_dt = datetime.combine(match.date, match.start_time)
end_dt = start_dt + timedelta(minutes=30)
match.end_time = end_dt.time()
except ValueError:
pass
@@ -400,4 +432,64 @@ def delete_match(match_id):
db.session.delete(match)
db.session.commit()
flash('Match deleted successfully.', 'success')
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
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.
Args:
date_str: Date in YYYY-MM-DD format
time_str: Time in HH:MM format
Returns:
List of player IDs who are available at that 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 []
# Calculate day of week (Python: 0=Monday, 6=Sunday)
# JavaScript: 0=Sunday, 6=Saturday, so we convert
date_parts = date_str.split('-')
date_for_day = datetime(int(date_parts[0]), int(date_parts[1]), int(date_parts[2]))
js_day = date_for_day.weekday()
# Convert Python weekday (Mon=0) to our format (Mon=0)
day_of_week = js_day
# Get all active players
players = User.query.filter_by(role='player', is_active_account=True).all()
available_players = []
for player in players:
# Check if player has disponibility at this time
disponibilities = PlayerDisponibility.query.filter_by(
player_id=player.id,
day_of_week=day_of_week
).all()
for disp in disponibilities:
# Check if time falls within disponibility block
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})
+176 -5
View File
@@ -1,7 +1,8 @@
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
from flask_login import login_required, current_user
from extensions import db, hash_password
from models import User, ROLES, ESPORT_GAMES
from models import User, ROLES, ESPORT_GAMES, PlayerDisponibility
from datetime import datetime, timedelta
users_bp = Blueprint('users', __name__, url_prefix='/users')
@@ -35,7 +36,6 @@ def edit_user(user_id):
flash('Invalid role selected.', 'danger')
return render_template('pages/edit_user.html', user=user, roles=ROLES, esport_games=ESPORT_GAMES)
# E-Sports fields
selected_games = request.form.getlist('games')
trn_username = request.form.get('trn_username', '').strip()
discord_username = request.form.get('discord_username', '').strip()
@@ -134,13 +134,11 @@ def edit_profile():
email = request.form.get('email')
phone = request.form.get('phone')
# E-Sports fields
selected_games = request.form.getlist('games')
trn_username = request.form.get('trn_username', '').strip()
discord_username = request.form.get('discord_username', '').strip()
league_os_profile = request.form.get('league_os_profile', '').strip()
# Check email uniqueness if changed
if email != current_user.email and User.query.filter_by(email=email).first():
flash('Email already in use.', 'danger')
return render_template('pages/edit_profile.html', user=current_user, esport_games=ESPORT_GAMES)
@@ -162,3 +160,176 @@ def edit_profile():
return redirect(url_for('users.profile'))
return render_template('pages/edit_profile.html', user=current_user, esport_games=ESPORT_GAMES)
# Day names for disponibility
DAY_NAMES = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
def add_30_minutes(t):
"""Add 30 minutes to a time object."""
return (datetime.combine(datetime.today(), t) + timedelta(minutes=30)).time()
@users_bp.route('/disponibilities')
@login_required
def get_disponibilities():
"""API endpoint to get all player disponibilities for scheduling."""
# Only managers and above can view disponibilities for scheduling
if not current_user.can_manage_teams() and not current_user.can_schedule_matches():
return jsonify({'error': 'Unauthorized'}), 403
players = User.query.filter_by(role='player', is_active_account=True).order_by(User.full_name).all()
result = {}
for player in players:
disponibilities = list(player.disponibilities)
result[player.id] = {
'full_name': player.full_name,
'disponibilities': [
{
'id': d.id,
'day_of_week': d.day_of_week,
'day_name': DAY_NAMES[d.day_of_week],
'start_time': d.start_time.strftime('%H:%M'),
'end_time': d.end_time.strftime('%H:%M')
}
for d in disponibilities
]
}
return jsonify(result)
@users_bp.route('/disponibilities/my')
@login_required
def get_my_disponibilities():
"""API endpoint for players to get their own disponibilities."""
disponibilities = PlayerDisponibility.query.filter_by(player_id=current_user.id).all()
# Group by day for easier display
result = {}
for d in disponibilities:
day = d.day_of_week
if day not in result:
result[day] = []
result[day].append({
'id': d.id,
'day_of_week': d.day_of_week,
'day_name': DAY_NAMES[d.day_of_week],
'start_time': d.start_time.strftime('%H:%M'),
'end_time': d.end_time.strftime('%H:%M')
})
return jsonify(result)
@users_bp.route('/disponibilities/add', methods=['POST'])
@login_required
def add_disponibility():
"""Add a disponibility block for the current player."""
day_of_week = request.form.get('day_of_week', type=int)
start_time_str = request.form.get('start_time')
if day_of_week is None or day_of_week < 0 or day_of_week > 6:
return jsonify({'error': 'Invalid day of week'}), 400
try:
start_time = datetime.strptime(start_time_str, '%H:%M').time()
except (ValueError, TypeError):
return jsonify({'error': 'Invalid time format'}), 400
end_time = add_30_minutes(start_time)
disponibility = PlayerDisponibility(
player_id=current_user.id,
day_of_week=day_of_week,
start_time=start_time,
end_time=end_time
)
db.session.add(disponibility)
db.session.commit()
return jsonify({
'id': disponibility.id,
'day_of_week': disponibility.day_of_week,
'day_name': DAY_NAMES[disponibility.day_of_week],
'start_time': disponibility.start_time.strftime('%H:%M'),
'end_time': disponibility.end_time.strftime('%H:%M')
})
@users_bp.route('/disponibilities/add_bulk', methods=['POST'])
@login_required
def add_disponibilities_bulk():
"""Add multiple disponibility blocks at once (for grid selection)."""
data = request.get_json()
slots = data.get('slots', []) # List of {day_of_week, start_time}
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 player
existing = PlayerDisponibility.query.filter_by(
player_id=current_user.id,
day_of_week=day_of_week,
start_time=start_time
).first()
if not existing:
disponibility = PlayerDisponibility(
player_id=current_user.id,
day_of_week=day_of_week,
start_time=start_time,
end_time=end_time
)
db.session.add(disponibility)
db.session.flush()
created.append({
'id': disponibility.id,
'day_of_week': disponibility.day_of_week,
'day_name': DAY_NAMES[disponibility.day_of_week],
'start_time': disponibility.start_time.strftime('%H:%M'),
'end_time': disponibility.start_time.strftime('%H:%M')
})
db.session.commit()
return jsonify({'success': True, 'created': created})
@users_bp.route('/disponibilities/clear', methods=['POST'])
@login_required
def clear_disponibilities():
"""Clear all disponibilities for the current player (for resetting)."""
PlayerDisponibility.query.filter_by(player_id=current_user.id).delete()
db.session.commit()
return jsonify({'success': True})
@users_bp.route('/disponibilities/<int:disponibility_id>/delete', methods=['POST'])
@login_required
def delete_disponibility(disponibility_id):
"""Delete a disponibility block."""
disponibility = PlayerDisponibility.query.get_or_404(disponibility_id)
# Only the owner can delete their disponibility
if disponibility.player_id != current_user.id:
return jsonify({'error': 'Unauthorized'}), 403
db.session.delete(disponibility)
db.session.commit()
return jsonify({'success': True})