diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc index 8b8238c..a023f1b 100644 Binary files a/__pycache__/models.cpython-313.pyc and b/__pycache__/models.cpython-313.pyc differ diff --git a/instance/team_tryouts.db b/instance/team_tryouts.db index 283fc39..cd70a18 100644 Binary files a/instance/team_tryouts.db and b/instance/team_tryouts.db differ diff --git a/models.py b/models.py index 82d761a..eedd70e 100644 --- a/models.py +++ b/models.py @@ -212,7 +212,7 @@ GAME_PLATFORMS = { 'League of Legends': [], 'Counter-Strike 2': [], 'Apex Legends': ['PC', 'PlayStation', 'Xbox', 'Nintendo Switch'], - 'Overwatch 2': ['PC', 'PlayStation', 'Xbox', 'Nintendo Switch'], + 'Overwatch 2': [], 'Rainbow Six Siege': ['Ubisoft', 'PlayStation', 'Xbox'], # Ubisoft = Uplay/Steam 'Rocket League': ['Epic', 'PlayStation', 'Xbox', 'Nintendo Switch'], # Epic uses EpicID, others use username 'Super Smash Bros.': ['Nintendo Switch'], @@ -236,7 +236,7 @@ TRN_URLS = { 'League of Legends': 'https://tracker.gg/lol/profile/{username}', 'Counter-Strike 2': 'https://tracker.gg/cs2/profile/steam/{username}', 'Apex Legends': 'https://tracker.gg/apex/profile/{platform}/{username}', - 'Overwatch 2': 'https://tracker.gg/overwatch/profile/{platform}/{username}', + 'Overwatch 2': 'https://tracker.gg/overwatch/profile/battlenet/{username}', 'Rainbow Six Siege': 'https://r6.tracker.network/r6siege/profile/{platform_code}/{username}', 'Rocket League': 'https://rocketleague.tracker.network/rocket-league/profile/{platform_code}/{username}', 'Super Smash Bros.': 'https://tracker.gg/smash/profile/{username}', diff --git a/routes/__pycache__/evaluations.cpython-313.pyc b/routes/__pycache__/evaluations.cpython-313.pyc index 817648e..a6d2ad9 100644 Binary files a/routes/__pycache__/evaluations.cpython-313.pyc and b/routes/__pycache__/evaluations.cpython-313.pyc differ diff --git a/routes/__pycache__/matches.cpython-313.pyc b/routes/__pycache__/matches.cpython-313.pyc index 6ee2ed9..16fa6af 100644 Binary files a/routes/__pycache__/matches.cpython-313.pyc and b/routes/__pycache__/matches.cpython-313.pyc differ diff --git a/routes/__pycache__/teams.cpython-313.pyc b/routes/__pycache__/teams.cpython-313.pyc index beb6f71..a704ba9 100644 Binary files a/routes/__pycache__/teams.cpython-313.pyc and b/routes/__pycache__/teams.cpython-313.pyc differ diff --git a/routes/__pycache__/tryouts.cpython-313.pyc b/routes/__pycache__/tryouts.cpython-313.pyc index 3087a17..8e5775c 100644 Binary files a/routes/__pycache__/tryouts.cpython-313.pyc and b/routes/__pycache__/tryouts.cpython-313.pyc differ diff --git a/routes/__pycache__/users.cpython-313.pyc b/routes/__pycache__/users.cpython-313.pyc index e0b6b5c..76615e3 100644 Binary files a/routes/__pycache__/users.cpython-313.pyc and b/routes/__pycache__/users.cpython-313.pyc differ diff --git a/routes/evaluations.py b/routes/evaluations.py index d887fdc..99c5bb2 100644 --- a/routes/evaluations.py +++ b/routes/evaluations.py @@ -69,6 +69,12 @@ def evaluate_player(tryout_id, player_id): return redirect(url_for('main.dashboard')) tryout = Tryout.query.get_or_404(tryout_id) + + # Check if user has permission to evaluate players in this tryout + if not current_user.can_manage_this_tryout(tryout): + flash('You do not have permission to evaluate players in this tryout.', 'danger') + return redirect(url_for('tryouts.list_tryouts')) + player = User.query.get_or_404(player_id) if player.role != 'player': @@ -176,6 +182,12 @@ def players_to_evaluate(tryout_id): return redirect(url_for('main.dashboard')) tryout = Tryout.query.get_or_404(tryout_id) + + # Check if user has permission to evaluate players in this tryout + if not current_user.can_manage_this_tryout(tryout): + flash('You do not have permission to evaluate players in this tryout.', 'danger') + return redirect(url_for('tryouts.list_tryouts')) + registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all() players = [] for reg in registrations: diff --git a/routes/matches.py b/routes/matches.py index 3b8255a..1d1b2c3 100644 --- a/routes/matches.py +++ b/routes/matches.py @@ -45,7 +45,7 @@ def api_events(): """ events = [] - # Get tryouts based on user permissions + # Get tryouts based on user permissions (this already filters by user's role) tryouts = get_visible_tryouts_for_user() for tryout in tryouts: diff --git a/routes/teams.py b/routes/teams.py index 5fdb422..208d2be 100644 --- a/routes/teams.py +++ b/routes/teams.py @@ -238,8 +238,10 @@ def add_team_note(team_id): 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') + + # Check if user can manage this team (president, manager, or coach) + if not current_user.can_manage_this_org_team(team): + flash('You do not have permission to add notes to this team.', 'danger') return redirect(url_for('teams.list_teams')) content = request.form.get('content', '').strip() @@ -270,10 +272,12 @@ def add_player_note(team_id, player_id): 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') + + # Check if user can manage this team (president, manager, or coach) + if not current_user.can_manage_this_org_team(team): + flash('You do not have permission to add notes to this team.', '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') diff --git a/routes/tryouts.py b/routes/tryouts.py index e650eae..c634332 100644 --- a/routes/tryouts.py +++ b/routes/tryouts.py @@ -175,6 +175,33 @@ def view_tryout(tryout_id): Response: Rendered tryout detail template. """ tryout = Tryout.query.get_or_404(tryout_id) + + # Check if user has permission to view this tryout + can_view = False + if current_user.role == 'president': + can_view = True + elif current_user.role == 'manager' and tryout.created_by == current_user.id: + can_view = True + elif current_user.role == 'coach': + org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first() + if org_team and tryout.target_org_team_id == org_team.id: + can_view = True + elif current_user.role == 'player': + is_registered = TryoutRegistration.query.filter_by( + tryout_id=tryout_id, player_id=current_user.id + ).first() is not None + player_in_match = MatchParticipant.query.join(Match).filter( + MatchParticipant.player_id == current_user.id, + Match.tryout_id == tryout_id + ).first() is not None + can_view = is_registered or player_in_match + elif current_user.role == 'scout': + can_view = True + + if not can_view: + flash('You do not have permission to view this tryout.', 'danger') + return redirect(url_for('tryouts.list_tryouts')) + registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all() registered_players = [User.query.get(r.player_id) for r in registrations if r.player_id] evaluations = Evaluation.query.filter_by(tryout_id=tryout_id).all() diff --git a/routes/users.py b/routes/users.py index 0453ff7..5632dd4 100644 --- a/routes/users.py +++ b/routes/users.py @@ -19,7 +19,7 @@ users_bp = Blueprint('users', __name__, url_prefix='/users') def update_user_gamertags(user, selected_games): """Update gamertags for a user based on form input. - + Handles creating, updating, and deleting gamertag records for the specified games. Used by both edit_user and edit_profile routes to avoid code duplication. @@ -1050,15 +1050,20 @@ def delete_coach_availability(availability_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 + + # 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 + if org_team and org_team.coach_id != coach_id: + return jsonify({'error': 'Unauthorized'}), 403 availability = CoachAvailability.query.filter_by(coach_id=coach_id).all() @@ -1324,24 +1329,29 @@ def 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: + # For coaches, verify the match is in their team's tryout + if current_user.role == 'coach' and org_team: + 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: 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) + # For coaches, verify the tryout targets their team + if current_user.role == 'coach' and org_team: 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: + team = Team.query.get(team_id) + if team: + team_tryout = Tryout.query.get(team.tryout_id) + # For coaches, verify the team is in their tryout + if current_user.role == 'coach' and org_team: + if team_tryout and team_tryout.target_org_team_id and team_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,