156 lines
5.6 KiB
Python
156 lines
5.6 KiB
Python
"""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 |