"""Admin tryout toggle — open/close gate and enforcement on tryout routes. ADMIN-006. The tryouts_open setting gates every tryout mutation route for non-admins. Admins always bypass the lock. These tests verify the toggle itself and the gate on each affected route. """ import pytest from app.extensions import db from app.models import AppSettings, Tryout, User NON_ADMIN_ROLES = ['manager', 'coach'] def _redirected(response): return response.status_code in (301, 302) # --------------------------------------------------------------------------- # Toggle logic # --------------------------------------------------------------------------- class TestTryoutToggle: def test_toggle_from_open_to_closed(self, client, as_role): as_role('admin') # Default is open client.post('/admin/toggle-tryouts', data={}, follow_redirects=False) # Now should be closed with client.application.app_context(): assert not AppSettings.get_bool('tryouts_open', default=True) def test_toggle_from_closed_to_open(self, client, as_role): as_role('admin') # Close first client.post('/admin/toggle-tryouts', data={}, follow_redirects=False) # Open again client.post('/admin/toggle-tryouts', data={}, follow_redirects=False) with client.application.app_context(): assert AppSettings.get_bool('tryouts_open', default=True) def test_toggle_creates_audit_log(self, client, as_role): from app.models import AuditLog as_role('admin') client.post('/admin/toggle-tryouts', data={}, follow_redirects=False) with client.application.app_context(): entry = AuditLog.query.filter_by(action='tryouts_toggled').first() assert entry is not None def test_default_is_open(self, app): with app.app_context(): assert AppSettings.get_bool('tryouts_open', default=True) # --------------------------------------------------------------------------- # Gate enforcement on tryout routes # --------------------------------------------------------------------------- class TestTryoutGateEnforcement: @pytest.mark.parametrize('role', NON_ADMIN_ROLES) def test_non_admin_cannot_create_tryout_when_closed(self, client, as_role, role): as_role('admin') client.post('/admin/toggle-tryouts', data={}) # close as_role(role) response = client.post( '/tryouts/create', data={'title': 'Test', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=True, ) html = response.data.decode() assert 'closed' in html.lower() or 'open tryouts' in html.lower() @pytest.mark.parametrize('role', NON_ADMIN_ROLES) def test_non_admin_cannot_edit_tryout_when_closed( self, app, client, as_role, make_user, role ): # Create a tryout as admin first as_role('admin') client.post( '/tryouts/create', data={'title': 'Edit Test', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=False, ) with app.app_context(): tryout_id = Tryout.query.filter_by(title='Edit Test').first().id # Close tryouts client.post('/admin/toggle-tryouts', data={}) # Try to edit as non-admin as_role(role) response = client.post( f'/tryouts/{tryout_id}/edit', data={'title': 'Hacked', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=True, ) html = response.data.decode() assert 'closed' in html.lower() or 'open tryouts' in html.lower() @pytest.mark.parametrize('role', NON_ADMIN_ROLES) def test_non_admin_cannot_delete_tryout_when_closed( self, app, client, as_role, make_user, role ): as_role('admin') client.post( '/tryouts/create', data={'title': 'Delete Test', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=False, ) with app.app_context(): tryout_id = Tryout.query.filter_by(title='Delete Test').first().id client.post('/admin/toggle-tryouts', data={}) # close as_role(role) response = client.post( f'/tryouts/{tryout_id}/delete', data={}, follow_redirects=True, ) html = response.data.decode() assert 'closed' in html.lower() or 'open tryouts' in html.lower() def test_admin_can_always_create_tryout(self, client, as_role): as_role('admin') # Close tryouts client.post('/admin/toggle-tryouts', data={}) # Admin should still be able to create response = client.post( '/tryouts/create', data={'title': 'Admin Test', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=False, ) assert _redirected(response) # success redirect, not blocked def test_admin_can_always_edit_tryout(self, app, client, as_role): as_role('admin') client.post( '/tryouts/create', data={'title': 'Admin Edit', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=False, ) with app.app_context(): tryout_id = Tryout.query.filter_by(title='Admin Edit').first().id client.post('/admin/toggle-tryouts', data={}) # close response = client.post( f'/tryouts/{tryout_id}/edit', data={'title': 'Admin Edited', 'game': 'Valorant', 'date': '2026-12-01'}, follow_redirects=False, ) assert _redirected(response) # success, not blocked