"""Admin team wipe — confirmation flow, data removal, and safety backup. ADMIN-009. The "Wipe Team Rosters" button must require typing WIPE, create a safety backup, and remove TeamPlayer + TeamMatch records while preserving OrgTeam structures. """ import pytest from app.extensions import db from app.models import ( AuditLog, BackupRecord, OrgTeam, TeamMatch, TeamMatchParticipant, TeamPlayer, ) def _redirected(response): return response.status_code in (301, 302) class TestWipeConfirmation: def test_wipe_without_confirmation_fails(self, app, client, as_role): as_role('admin') response = client.post( '/admin/teams/wipe', data={}, follow_redirects=True, ) html = response.data.decode() assert 'WIPE' in html def test_wipe_with_wrong_confirmation_fails(self, app, client, as_role): as_role('admin') response = client.post( '/admin/teams/wipe', data={'confirm': 'yes'}, follow_redirects=True, ) html = response.data.decode() assert 'WIPE' in html class TestWipeDataRemoval: @pytest.fixture def seeded_teams(self, app, client, as_role, make_user, monkeypatch): import app.routes.admin as admin_module # Mock the backup so the wipe proceeds without a real pg_dump. def fake_create_backup_record(backup_type='pre_wipe', notes=None): from app.models import BackupRecord record = BackupRecord( filename='db_backup_pre_wipe.dump', file_path='/tmp/db_backup_pre_wipe.dump', size_bytes=100, backup_type=backup_type, notes=notes, created_by_id=1, ) db.session.add(record) db.session.commit() return record monkeypatch.setattr(admin_module, '_create_backup_record', fake_create_backup_record) as_role('admin') # Create an org team client.post('/teams/create', data={'name': 'Wipe Team'}, follow_redirects=False) with app.app_context(): team_id = OrgTeam.query.filter_by(name='Wipe Team').first().id # Add a player to the team player_id = make_user('player') client.post( f'/teams/{team_id}/add_player', data={'player_id': str(player_id)}, follow_redirects=False, ) # Create a team match client.post( f'/team-matches/{team_id}/create', data={'title': 'Wipe Match', 'date': '2026-10-01', 'start_time': '10:00'}, follow_redirects=False, ) return team_id def test_wipe_removes_team_players(self, app, client, as_role, seeded_teams): as_role('admin') client.post('/admin/teams/wipe', data={'confirm': 'WIPE'}, follow_redirects=False) with app.app_context(): assert TeamPlayer.query.count() == 0 def test_wipe_removes_team_matches(self, app, client, as_role, seeded_teams): as_role('admin') client.post('/admin/teams/wipe', data={'confirm': 'WIPE'}, follow_redirects=False) with app.app_context(): assert TeamMatch.query.count() == 0 def test_wipe_preserves_org_team_structures(self, app, client, as_role, seeded_teams): as_role('admin') client.post('/admin/teams/wipe', data={'confirm': 'WIPE'}, follow_redirects=False) with app.app_context(): assert OrgTeam.query.filter_by(name='Wipe Team').first() is not None def test_wipe_creates_safety_backup(self, app, client, as_role, seeded_teams): as_role('admin') client.post('/admin/teams/wipe', data={'confirm': 'WIPE'}, follow_redirects=False) with app.app_context(): safety = BackupRecord.query.filter_by(backup_type='pre_wipe').first() assert safety is not None def test_wipe_creates_audit_log(self, app, client, as_role, seeded_teams): as_role('admin') client.post('/admin/teams/wipe', data={'confirm': 'WIPE'}, follow_redirects=False) with app.app_context(): entry = AuditLog.query.filter_by(action='teams_wiped').first() assert entry is not None