88827be7be
Admin-only page reachable from a new card on the admin panel (replacing the Quick Actions card) that centralises housekeeping operations: * Database integrity: PRAGMA integrity_check / quick_check / foreign_key_check, plus VACUUM + ANALYZE to reclaim free space. * Leftover records: detects and removes orphaned rows left behind by deleted players/content (player_feedback, player_edit, playlist_content, dangling player.playlist_id) and orphaned edited-media folders on disk. * Player authentication tokens: manual reset (single or all), a configurable automatic reset interval, and cancellation of a pending reset. Resetting a token rotates player.auth_code and sets auth_reset_required, so the next heartbeat (POST /api/player-feedback) answers 401 + auth_required and the client restarts its authentication flow. A successful authentication clears the flag and stamps auth_token_issued_at, from which the interval is measured. New: PlayerAuthConfig model, add_player_auth_reset migration (registered in docker-entrypoint.sh), admin/maintenance.html.
69 lines
2.4 KiB
Python
69 lines
2.4 KiB
Python
"""Add player authentication token reset support.
|
|
|
|
Adds:
|
|
* ``player.auth_token_issued_at`` — when the current auth token was issued
|
|
* ``player.auth_reset_required`` — force re-authentication on next heartbeat
|
|
* ``player_auth_config`` — single-row token reset interval policy
|
|
|
|
Idempotent: safe to run on every container start.
|
|
"""
|
|
import sys
|
|
sys.path.insert(0, '/app')
|
|
|
|
from app.app import create_app
|
|
from app.extensions import db
|
|
from sqlalchemy import text
|
|
|
|
app = create_app()
|
|
|
|
with app.app_context():
|
|
print("Adding player authentication token reset support...")
|
|
|
|
# 1. New columns on the player table.
|
|
columns = [
|
|
("auth_token_issued_at", "DATETIME"),
|
|
("auth_reset_required", "BOOLEAN DEFAULT 0"),
|
|
]
|
|
for col_name, col_type in columns:
|
|
try:
|
|
db.session.execute(text(f"ALTER TABLE player ADD COLUMN {col_name} {col_type}"))
|
|
db.session.commit()
|
|
print(f"✓ '{col_name}' column added to player table.")
|
|
except Exception as e:
|
|
if 'duplicate column' in str(e).lower() or 'already exists' in str(e).lower():
|
|
print(f"✓ '{col_name}' column already exists, skipping.")
|
|
else:
|
|
print(f"✗ Error adding '{col_name}': {e}")
|
|
raise
|
|
|
|
# 2. Settings table holding the automatic reset interval.
|
|
try:
|
|
db.session.execute(text("""
|
|
CREATE TABLE IF NOT EXISTS player_auth_config (
|
|
id INTEGER PRIMARY KEY,
|
|
reset_interval_days INTEGER NOT NULL DEFAULT 0,
|
|
updated_at DATETIME,
|
|
updated_by VARCHAR(255)
|
|
)
|
|
"""))
|
|
db.session.commit()
|
|
print("✓ 'player_auth_config' table ready.")
|
|
except Exception as e:
|
|
print(f"✗ Error creating 'player_auth_config': {e}")
|
|
raise
|
|
|
|
# 3. Backfill: treat existing tokens as issued now so the interval starts
|
|
# counting from the migration rather than expiring every player at once.
|
|
try:
|
|
result = db.session.execute(text(
|
|
"UPDATE player SET auth_token_issued_at = CURRENT_TIMESTAMP "
|
|
"WHERE auth_token_issued_at IS NULL"
|
|
))
|
|
db.session.commit()
|
|
print(f"✓ Backfilled auth_token_issued_at for {result.rowcount} player(s).")
|
|
except Exception as e:
|
|
print(f"⚠ Could not backfill auth_token_issued_at: {e}")
|
|
db.session.rollback()
|
|
|
|
print("Done.")
|