ajout d'un paneau admin
This commit is contained in:
+95
-51
@@ -708,6 +708,70 @@ def send_discord_notification(player_name, points, date_str, start_time_str, end
|
||||
logger.warning(f"Failed to send Discord notification: {e}")
|
||||
|
||||
|
||||
def _get_player_coach_options(player):
|
||||
"""Build a deduplicated list of coaches (with their teams) for a player.
|
||||
|
||||
Returns a list of dicts:
|
||||
[{'coach_id': int, 'coach_name': str, 'teams': [{'team_id': int, 'team_name': str}]}]
|
||||
"""
|
||||
coach_map = {}
|
||||
for org_team in player.get_org_teams():
|
||||
for coach in org_team.get_coaches():
|
||||
entry = coach_map.setdefault(coach.id, {
|
||||
'coach_id': coach.id,
|
||||
'coach_name': coach.full_name or coach.username,
|
||||
'teams': [],
|
||||
})
|
||||
entry['teams'].append({
|
||||
'team_id': org_team.id,
|
||||
'team_name': org_team.name,
|
||||
})
|
||||
return list(coach_map.values())
|
||||
|
||||
|
||||
def _get_player_coach_ids(player):
|
||||
"""Return the set of coach ids the player is allowed to request."""
|
||||
return {c['coach_id'] for c in _get_player_coach_options(player)}
|
||||
|
||||
|
||||
@users_bp.route('/one-on-one/coaches')
|
||||
@login_required
|
||||
def one_on_one_coaches():
|
||||
"""API: list coaches (and their teams) available to the current player."""
|
||||
if not isinstance(current_user, Player):
|
||||
return jsonify({'error': 'Only players can request One on One sessions.'}), 403
|
||||
|
||||
coaches = _get_player_coach_options(current_user)
|
||||
return jsonify({'coaches': coaches})
|
||||
|
||||
|
||||
@users_bp.route('/one-on-one/coaches/<int:coach_id>/availability')
|
||||
@login_required
|
||||
def one_on_one_coach_availability(coach_id):
|
||||
"""API: return a single coach's availability for the current player."""
|
||||
if not isinstance(current_user, Player):
|
||||
return jsonify({'error': 'Only players can request One on One sessions.'}), 403
|
||||
|
||||
if coach_id not in _get_player_coach_ids(current_user):
|
||||
return jsonify({'error': 'Coach is not assigned to any of your teams.'}), 403
|
||||
|
||||
coach = User.query.get_or_404(coach_id)
|
||||
availabilities = CoachAvailability.query.filter_by(coach_id=coach_id).all()
|
||||
availability = [
|
||||
{
|
||||
'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 availabilities
|
||||
]
|
||||
return jsonify({
|
||||
'coach_id': coach.id,
|
||||
'coach_name': coach.full_name or coach.username,
|
||||
'availability': availability,
|
||||
})
|
||||
|
||||
|
||||
@users_bp.route('/one-on-one', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def one_on_one():
|
||||
@@ -716,41 +780,37 @@ def one_on_one():
|
||||
flash('Only players can request One on One sessions.', 'danger')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
org_teams = current_user.get_org_teams()
|
||||
org_team = org_teams[0] if org_teams 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')
|
||||
|
||||
team_notes = []
|
||||
if org_team:
|
||||
team_notes = TeamNote.query.filter_by(org_team_id=org_team.id).order_by(TeamNote.created_at.desc()).all()
|
||||
|
||||
personal_notes = PersonalNote.query.filter_by(player_id=current_user.id).order_by(PersonalNote.created_at.desc()).all()
|
||||
|
||||
coach_availability = []
|
||||
if coach:
|
||||
availabilities = CoachAvailability.query.filter_by(coach_id=coach.id).all()
|
||||
coach_availability = [
|
||||
{
|
||||
'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 availabilities
|
||||
]
|
||||
coach_options = _get_player_coach_options(current_user)
|
||||
|
||||
if request.method == 'POST':
|
||||
coach_id = request.form.get('coach_id', type=int)
|
||||
org_team_id = request.form.get('org_team_id', type=int)
|
||||
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:
|
||||
if not coach_options:
|
||||
flash('Cannot request One on One - no coach assigned.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
if coach_id not in _get_player_coach_ids(current_user):
|
||||
flash('Selected coach is not assigned to any of your teams.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
coach = User.query.get_or_404(coach_id)
|
||||
|
||||
# Validate org_team_id belongs to the player and includes this coach
|
||||
org_team = None
|
||||
if org_team_id:
|
||||
org_team = OrgTeam.query.get(org_team_id)
|
||||
if not org_team or org_team not in current_user.get_org_teams():
|
||||
flash('Invalid team selection.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
if coach not in org_team.get_coaches():
|
||||
flash('Selected coach is not part of the selected team.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
try:
|
||||
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
||||
start_time = datetime.strptime(start_time_str, '%H:%M').time()
|
||||
@@ -759,14 +819,14 @@ def one_on_one():
|
||||
flash('Invalid date or time format.', 'danger')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
check_date = datetime.strptime(date_str, '%Y-%m-%d')
|
||||
day_of_week = check_date.weekday()
|
||||
day_of_week = date_obj.weekday()
|
||||
|
||||
availabilities = CoachAvailability.query.filter_by(coach_id=coach.id).all()
|
||||
is_available = any(
|
||||
av['day_of_week'] == day_of_week
|
||||
and av['start_time'] <= start_time_str
|
||||
and av['end_time'] >= end_time_str
|
||||
for av in coach_availability
|
||||
av.day_of_week == day_of_week
|
||||
and av.start_time <= start_time
|
||||
and av.end_time >= end_time
|
||||
for av in availabilities
|
||||
)
|
||||
|
||||
if not is_available:
|
||||
@@ -796,30 +856,13 @@ def one_on_one():
|
||||
flash('Your One on One request has been submitted!', 'success')
|
||||
return redirect(url_for('users.one_on_one'))
|
||||
|
||||
# Build list of upcoming dates that have coach availability
|
||||
from datetime import date as date_cls, timedelta as td
|
||||
today = date_cls.today()
|
||||
available_days = {av['day_of_week'] for av in coach_availability}
|
||||
dates = []
|
||||
for i in range(14): # Next 14 days
|
||||
d = today + td(days=i)
|
||||
if d.weekday() in available_days:
|
||||
dates.append({
|
||||
'value': d.strftime('%Y-%m-%d'),
|
||||
'day_of_week': d.weekday(),
|
||||
'display': d.strftime('%B %d, %Y (%A)'),
|
||||
})
|
||||
|
||||
# Player's own One on One request history
|
||||
my_requests = OneOnOneRequest.query.filter_by(
|
||||
player_id=current_user.id
|
||||
).order_by(OneOnOneRequest.created_at.desc()).all()
|
||||
|
||||
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,
|
||||
dates=dates,
|
||||
coach_options=coach_options,
|
||||
my_requests=my_requests)
|
||||
|
||||
|
||||
@@ -1031,12 +1074,13 @@ def notes_dashboard():
|
||||
coach_id=current_user.id,
|
||||
).order_by(PersonalNote.created_at.desc()).all()
|
||||
|
||||
# One on One requests from team players
|
||||
# One on One requests addressed to this coach from their team players
|
||||
one_on_one_requests = []
|
||||
if org_team and players:
|
||||
player_ids_list = [p.id for p in players]
|
||||
one_on_one_requests = OneOnOneRequest.query.filter(
|
||||
OneOnOneRequest.player_id.in_(player_ids_list)
|
||||
OneOnOneRequest.player_id.in_(player_ids_list),
|
||||
OneOnOneRequest.coach_id == current_user.id,
|
||||
).order_by(OneOnOneRequest.created_at.desc()).all()
|
||||
|
||||
# For context selectors in the form
|
||||
|
||||
Reference in New Issue
Block a user