Add admin maintenance console
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.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""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.")
|
||||
Reference in New Issue
Block a user