Ajout du statut remplaçant pour les joueurs
Possibilité d'ajouter/enlever coach et manager des équipes
les joueurs peuvent être associés à plusieurs équipes au lieu d'une seule
This commit is contained in:
cedrick2711
2026-07-20 17:41:22 -04:00
parent 027e529885
commit 346229778f
18 changed files with 343 additions and 69 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -2
View File
@@ -6,7 +6,7 @@ This module handles player evaluation creation, management, and viewing.
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 User, Tryout, Evaluation, TryoutRegistration
from models import User, Tryout, Evaluation, TryoutRegistration, GAME_POSITIONS
from sqlalchemy import func
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
@@ -178,7 +178,8 @@ def evaluate_player(tryout_id, player_id):
tryout=tryout,
player=player,
existing_eval=existing_eval,
evaluators=evaluators)
evaluators=evaluators,
game_positions=GAME_POSITIONS)
@evaluations_bp.route('/<int:tryout_id>/players')
+109 -15
View File
@@ -3,10 +3,10 @@
This module handles CRUD operations for organization teams and player assignments.
"""
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
from models import OrgTeam, User, Team, TeamMember, PersonalNote, TeamNote, Tryout
from models import OrgTeam, User, Team, TeamMember, PersonalNote, TeamNote, Tryout, TeamPlayer
teams_bp = Blueprint('teams', __name__, url_prefix='/teams')
@@ -35,8 +35,9 @@ def list_teams():
return redirect(url_for('main.dashboard'))
coaches = User.query.filter_by(role='coach').order_by(User.full_name).all()
managers = User.query.filter_by(role='manager').order_by(User.full_name).all()
all_players = User.query.filter_by(role='player').order_by(User.full_name).all()
return render_template('pages/teams.html', teams=teams, coaches=coaches, all_players=all_players, can_manage=can_manage)
return render_template('pages/teams.html', teams=teams, coaches=coaches, managers=managers, all_players=all_players, can_manage=can_manage)
@teams_bp.route('/create', methods=['POST'])
@@ -47,6 +48,7 @@ def create_team():
Args:
name: Team name from form.
coach_id: Optional coach assignment from form.
manager_id: Optional manager assignment from form.
Returns:
Response: Redirect to teams list with status message.
@@ -57,6 +59,7 @@ def create_team():
name = request.form.get('name')
coach_id = request.form.get('coach_id')
manager_id = request.form.get('manager_id')
if not name:
flash('Team name is required.', 'danger')
@@ -70,6 +73,7 @@ def create_team():
team = OrgTeam(
name=name,
coach_id=int(coach_id) if coach_id else None,
manager_id=int(manager_id) if manager_id else None,
created_by=current_user.id
)
db.session.add(team)
@@ -87,6 +91,7 @@ def edit_team(team_id):
team_id: The ID of the team to edit.
name: New team name from form.
coach_id: New coach assignment from form.
manager_id: New manager assignment from form.
Returns:
Response: Redirect to teams list with status message.
@@ -98,6 +103,7 @@ def edit_team(team_id):
name = request.form.get('name')
coach_id = request.form.get('coach_id')
manager_id = request.form.get('manager_id')
if not name:
flash('Team name is required.', 'danger')
@@ -110,6 +116,7 @@ def edit_team(team_id):
team.name = name
team.coach_id = int(coach_id) if coach_id else None
team.manager_id = int(manager_id) if manager_id else None
db.session.commit()
flash(f'Team "{name}" updated successfully!', 'success')
return redirect(url_for('teams.list_teams'))
@@ -144,22 +151,71 @@ def delete_team(team_id):
t.target_org_team_id = None
db.session.commit()
# Remove all team_players associations
TeamPlayer.query.filter_by(org_team_id=team_id).delete()
db.session.commit()
db.session.delete(team)
db.session.commit()
flash(f'Team "{name}" deleted successfully.', 'success')
return redirect(url_for('teams.list_teams'))
@teams_bp.route('/<int:team_id>/remove_coach', methods=['POST'])
@login_required
def remove_coach(team_id):
"""Remove the coach from an organization team.
Args:
team_id: The ID of the team.
Returns:
Response: Redirect to teams list with status message.
"""
team = OrgTeam.query.get_or_404(team_id)
if not current_user.can_manage_this_org_team(team):
flash('Permission denied.', 'danger')
return redirect(url_for('teams.list_teams'))
team.coach_id = None
db.session.commit()
flash(f'Coach removed from {team.name}.', 'success')
return redirect(url_for('teams.list_teams'))
@teams_bp.route('/<int:team_id>/remove_manager', methods=['POST'])
@login_required
def remove_manager(team_id):
"""Remove the manager from an organization team.
Args:
team_id: The ID of the team.
Returns:
Response: Redirect to teams list with status message.
"""
team = OrgTeam.query.get_or_404(team_id)
if not current_user.can_manage_this_org_team(team):
flash('Permission denied.', 'danger')
return redirect(url_for('teams.list_teams'))
team.manager_id = None
db.session.commit()
flash(f'Manager removed from {team.name}.', 'success')
return redirect(url_for('teams.list_teams'))
@teams_bp.route('/<int:team_id>/add_player', methods=['POST'])
@login_required
def add_player(team_id):
"""Add a player to an organization team.
If player is already on another team, they will be moved.
Players can now be in multiple teams.
Args:
team_id: The ID of the team to add the player to.
player_id: The ID of the player to add.
status: The player's status (starter or substitute).
Returns:
Response: Redirect to teams list with status message.
@@ -169,7 +225,7 @@ def add_player(team_id):
flash('Permission denied.', 'danger')
return redirect(url_for('teams.list_teams'))
player_id = request.form.get('player_id')
position = request.form.get('position', '')
status = request.form.get('status', 'starter')
if not player_id:
flash('Please select a player.', 'danger')
@@ -180,15 +236,19 @@ def add_player(team_id):
flash('Can only assign players to teams.', 'danger')
return redirect(url_for('teams.list_teams'))
# If player already belongs to a different team, remove them first
if player.team_id and player.team_id != team_id:
old_team = OrgTeam.query.get(player.team_id)
flash(f'{player.full_name} was moved from {old_team.name} to {team.name}.', 'info')
elif player.team_id == team_id:
# Check if player is already on this team
existing = TeamPlayer.query.filter_by(player_id=player.id, org_team_id=team.id).first()
if existing:
flash(f'{player.full_name} is already on {team.name}.', 'info')
return redirect(url_for('teams.list_teams'))
player.team_id = team_id
# Add player to the team using TeamPlayer model (allows multiple teams)
tp = TeamPlayer(
player_id=player.id,
org_team_id=team.id,
status=status
)
db.session.add(tp)
db.session.commit()
flash(f'{player.full_name} added to {team.name}!', 'success')
return redirect(url_for('teams.list_teams'))
@@ -213,16 +273,49 @@ def remove_player(team_id, player_id):
player = User.query.get_or_404(player_id)
if player.team_id != team_id:
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=team_id).first()
if not tp:
flash(f'{player.full_name} is not on {team.name}.', 'danger')
return redirect(url_for('teams.list_teams'))
player.team_id = None
db.session.delete(tp)
db.session.commit()
flash(f'{player.full_name} removed from {team.name}.', 'success')
return redirect(url_for('teams.list_teams'))
@teams_bp.route('/<int:team_id>/toggle_status/<int:player_id>', methods=['POST'])
@login_required
def toggle_player_status(team_id, player_id):
"""Toggle a player's status between starter and substitute.
Args:
team_id: The ID of the team.
player_id: The ID of the player.
Returns:
Response: JSON with new status.
"""
team = OrgTeam.query.get_or_404(team_id)
if not current_user.can_manage_this_org_team(team):
return jsonify({'error': 'Permission denied'}), 403
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=team_id).first()
if not tp:
return jsonify({'error': 'Player not found on this team'}), 404
# Toggle status
tp.status = 'substitute' if tp.status == 'starter' else 'starter'
db.session.commit()
return jsonify({
'success': True,
'player_id': player_id,
'new_status': tp.status,
'player_name': tp.player.full_name
})
# Note actions from team page
@@ -284,7 +377,8 @@ def add_player_note(team_id, player_id):
return redirect(url_for('teams.list_teams'))
# Verify player belongs to this team
if player.team_id != team_id:
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=team_id).first()
if not tp:
flash(f'{player.full_name} is not on {team.name}.', 'danger')
return redirect(url_for('teams.list_teams'))
@@ -300,4 +394,4 @@ def add_player_note(team_id, player_id):
db.session.commit()
flash(f'Note added for {player.full_name}!', 'success')
return redirect(url_for('teams.list_teams'))
return redirect(url_for('teams.list_teams'))
+29 -16
View File
@@ -8,7 +8,7 @@ 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, CoachAvailability, TeamNote, PersonalNote, OneOnOneRequest, Match, Team, TeamMember, MatchParticipant, Tryout, TryoutRegistration
from models import User, ROLES, ESPORT_GAMES, PlayerDisponibility, UserGamertag, GAME_PLATFORMS, Contract, OrgTeam, CoachAvailability, TeamNote, PersonalNote, OneOnOneRequest, Match, Team, TeamMember, MatchParticipant, Tryout, TryoutRegistration, TeamPlayer
from werkzeug.utils import secure_filename
from datetime import datetime, timedelta, date as date_type
import requests
@@ -514,8 +514,8 @@ def can_manage_player_contract(user, player_id):
if user.role == 'coach':
org_team = OrgTeam.query.filter_by(coach_id=user.id).first()
if org_team:
player = User.query.get(player_id)
if player and player.team_id == org_team.id:
tp = TeamPlayer.query.filter_by(player_id=player_id, org_team_id=org_team.id).first()
if tp:
return True
return False
@@ -542,7 +542,8 @@ def list_contracts():
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).all()
player_ids = [tp.player_id for tp in TeamPlayer.query.filter_by(org_team_id=org_team.id).all()]
players = User.query.filter(User.id.in_(player_ids)).all() if player_ids else []
else: # president or manager
players = User.query.filter_by(role='player').all()
@@ -571,7 +572,11 @@ def upload_contract():
# Get players this user can manage
if current_user.role == 'coach':
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
players = User.query.filter_by(role='player', team_id=org_team.id).all() if org_team else []
if org_team:
player_ids = [tp.player_id for tp in TeamPlayer.query.filter_by(org_team_id=org_team.id).all()]
players = User.query.filter(User.id.in_(player_ids)).all() if player_ids else []
else:
players = []
else:
players = User.query.filter_by(role='player').all()
@@ -598,7 +603,8 @@ def upload_contract():
# Get player info for folder structure
player = User.query.get_or_404(player_id)
team = OrgTeam.query.get(player.team_id) if player.team_id else None
player_teams = player.get_org_teams()
team = player_teams[0] if player_teams else None
# Create team folder if team exists
if team:
@@ -621,7 +627,7 @@ def upload_contract():
# Create database record
contract = Contract(
player_id=player_id,
team_id=player.team_id,
team_id=team.id if team else None,
uploaded_by_id=current_user.id,
original_filename=original_filename,
stored_filename=stored_filename,
@@ -822,8 +828,9 @@ def one_on_one():
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
# Get player's teams and coach (use the first team the player is on)
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:
@@ -1062,7 +1069,8 @@ def api_get_coach_availability(coach_id):
return jsonify({'error': 'Unauthorized'}), 403
# Players can only view their own coach's availability
org_team = OrgTeam.query.get(current_user.team_id) if current_user.team_id else None
player_teams = current_user.get_org_teams()
org_team = player_teams[0] if player_teams else None
if org_team and org_team.coach_id != coach_id:
return jsonify({'error': 'Unauthorized'}), 403
@@ -1144,7 +1152,8 @@ def manage_personal_notes():
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()
player_ids = [tp.player_id for tp in TeamPlayer.query.filter_by(org_team_id=org_team.id).all()]
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all() if player_ids else []
if request.method == 'POST':
player_id = request.form.get('player_id', type=int)
@@ -1200,7 +1209,8 @@ def notes_dashboard():
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()
player_ids = [tp.player_id for tp in TeamPlayer.query.filter_by(org_team_id=org_team.id).all()]
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all() if player_ids else []
# Get existing team notes
team_notes = []
@@ -1257,8 +1267,9 @@ def my_notes():
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 player's teams and coach (use the first team the player is on)
player_teams = current_user.get_org_teams()
org_team = player_teams[0] if player_teams 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()
@@ -1295,7 +1306,8 @@ def add_personal_note():
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()
player_ids = [tp.player_id for tp in TeamPlayer.query.filter_by(org_team_id=org_team.id).all()]
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all() if player_ids else []
elif current_user.role in ['president', 'manager']:
players = User.query.filter_by(role='player').order_by(User.full_name).all()
@@ -1484,7 +1496,8 @@ def add_note_from_tryout(tryout_id):
# If coach, filter to only their team players; otherwise include all
if org_team:
players = User.query.filter(User.id.in_(player_ids), User.team_id == org_team.id).order_by(User.full_name).all()
team_player_ids = [tp.player_id for tp in TeamPlayer.query.filter_by(org_team_id=org_team.id).all()]
players = User.query.filter(User.id.in_(player_ids), User.id.in_(team_player_ids)).order_by(User.full_name).all()
else:
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all()