119 lines
4.1 KiB
Python
119 lines
4.1 KiB
Python
"""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 |