Sanitize codebase, reorganize docs, and add missing deploy files
Remove dead code identified in docs/SANITIZATION-REVIEW.md:
- app/blueprints/content_old.py and app/blueprints/playlist.py
- app/models/group.py, app/utils/nginx_config_reader.py
- orphaned templates (content_list, edit_content, upload_content,
player_page) and the related group/Template references
Result: 6 blueprints, 82 routes, no dead modules or orphan templates.
Add files that deploy.sh and docker-entrypoint.sh already require but
which were never tracked:
- https_manager.py (referenced by deploy.sh, migrate_network.sh,
docker-entrypoint.sh)
- Caddyfile.example (seeded by deploy.sh; its absence aborts deploy)
Relocate generated Graphify artifacts from graphify-out/ to
docs/graphify-out/ (110 files, no content change) and archive the
superseded docs under docs/.
Ignore hygiene:
- ignore ad-hoc .env backups (.env.bak*) — they contain live secrets
- keep the pre-sanitization snapshots (docs/legacy code/,
docs/old_code_documentation/) on disk but out of the repo
Fix .env.example: drop a duplicated config block, genericize the
hardcoded host IP, and document HOSTNAME_INTERNAL.
This commit is contained in:
+36
-51
@@ -8,7 +8,9 @@ import bcrypt
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
from app.extensions import db, cache
|
||||
from app.models import Player, Content, PlayerFeedback, ServerLog
|
||||
from app.models import (
|
||||
Player, Playlist, Content, PlayerFeedback, ServerLog,
|
||||
)
|
||||
from app.utils.logger import log_action
|
||||
|
||||
api_bp = Blueprint('api', __name__, url_prefix='/api')
|
||||
@@ -86,6 +88,25 @@ def verify_player_auth(f):
|
||||
return decorated_function
|
||||
|
||||
|
||||
def get_assigned_playlist(player: Player) -> Optional[Playlist]:
|
||||
"""Return the playlist assigned to *player*, or ``None`` if unassigned.
|
||||
|
||||
Centralises playlist lookup so every endpoint reports the same sync
|
||||
version. Playlist edits bump ``Playlist.version``; players poll that
|
||||
value to decide whether their cached content is stale. A player with no
|
||||
assigned playlist has nothing to sync and resolves to version 0.
|
||||
|
||||
Args:
|
||||
player: The player whose assigned playlist should be resolved.
|
||||
|
||||
Returns:
|
||||
The assigned ``Playlist`` instance, or ``None`` when unassigned.
|
||||
"""
|
||||
if not player.playlist_id:
|
||||
return None
|
||||
return db.session.get(Playlist, player.playlist_id)
|
||||
|
||||
|
||||
@api_bp.route('/health', methods=['GET'])
|
||||
def health_check():
|
||||
"""API health check endpoint."""
|
||||
@@ -113,7 +134,7 @@ def authenticate_player():
|
||||
quickconnect_code: Quick connect code (optional if using password)
|
||||
|
||||
Returns:
|
||||
JSON with auth_code, player_id, group_id, and configuration
|
||||
JSON with auth_code, player_id, playlist_id, and configuration
|
||||
"""
|
||||
data = request.get_json()
|
||||
|
||||
@@ -265,12 +286,8 @@ def get_playlist_by_quickconnect():
|
||||
db.session.commit()
|
||||
|
||||
# Get playlist version from the assigned playlist
|
||||
playlist_version = 1
|
||||
if player.playlist_id:
|
||||
from app.models import Playlist
|
||||
assigned_playlist = Playlist.query.get(player.playlist_id)
|
||||
if assigned_playlist:
|
||||
playlist_version = assigned_playlist.version
|
||||
assigned_playlist = get_assigned_playlist(player)
|
||||
playlist_version = assigned_playlist.version if assigned_playlist else 0
|
||||
|
||||
# Hash the quickconnect code for validation on client side
|
||||
hashed_quickconnect = bcrypt.hashpw(
|
||||
@@ -322,12 +339,8 @@ def get_player_playlist(player_id: int):
|
||||
db.session.commit()
|
||||
|
||||
# Get playlist version from the assigned playlist
|
||||
playlist_version = 1
|
||||
if player.playlist_id:
|
||||
from app.models import Playlist
|
||||
assigned_playlist = Playlist.query.get(player.playlist_id)
|
||||
if assigned_playlist:
|
||||
playlist_version = assigned_playlist.version
|
||||
assigned_playlist = get_assigned_playlist(player)
|
||||
playlist_version = assigned_playlist.version if assigned_playlist else 0
|
||||
|
||||
return jsonify({
|
||||
'player_id': player_id,
|
||||
@@ -363,10 +376,16 @@ def get_playlist_version(player_id: int):
|
||||
player.last_seen = datetime.utcnow()
|
||||
db.session.commit()
|
||||
|
||||
# Player syncs against the version of its assigned playlist; the
|
||||
# content count comes from that same playlist (Content has no
|
||||
# player_id column - it reaches players through the playlist).
|
||||
assigned_playlist = get_assigned_playlist(player)
|
||||
|
||||
return jsonify({
|
||||
'player_id': player_id,
|
||||
'playlist_version': player.playlist_version,
|
||||
'content_count': Content.query.filter_by(player_id=player_id).count()
|
||||
'playlist_id': player.playlist_id,
|
||||
'playlist_version': assigned_playlist.version if assigned_playlist else 0,
|
||||
'content_count': assigned_playlist.contents.count() if assigned_playlist else 0
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
@@ -378,7 +397,6 @@ def get_playlist_version(player_id: int):
|
||||
def get_cached_playlist(player_id: int) -> List[Dict]:
|
||||
"""Get cached playlist for a player based on assigned playlist."""
|
||||
from flask import url_for
|
||||
from app.models import Playlist
|
||||
|
||||
player = Player.query.get(player_id)
|
||||
if not player or not player.playlist_id:
|
||||
@@ -556,7 +574,6 @@ def get_player_status(player_id: int):
|
||||
'player_id': player_id,
|
||||
'name': player.name,
|
||||
'location': player.location,
|
||||
'group_id': player.group_id,
|
||||
'status': player.status,
|
||||
'is_online': is_online,
|
||||
'last_seen': player.last_seen.isoformat() if player.last_seen else None,
|
||||
@@ -593,7 +610,6 @@ def system_info():
|
||||
try:
|
||||
# Get counts
|
||||
total_players = Player.query.count()
|
||||
total_groups = Group.query.count()
|
||||
total_content = Content.query.count()
|
||||
|
||||
# Count online players (seen in last 5 minutes)
|
||||
@@ -610,7 +626,6 @@ def system_info():
|
||||
'total': total_players,
|
||||
'online': online_players
|
||||
},
|
||||
'groups': total_groups,
|
||||
'content': total_content,
|
||||
'logs_24h': recent_logs,
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
@@ -621,35 +636,6 @@ def system_info():
|
||||
return jsonify({'error': 'Internal server error'}), 500
|
||||
|
||||
|
||||
|
||||
# DEPRECATED: Groups functionality has been archived
|
||||
# @api_bp.route('/groups', methods=['GET'])
|
||||
# @rate_limit(max_requests=60, window=60)
|
||||
# def list_groups():
|
||||
# """List all groups with basic information."""
|
||||
# try:
|
||||
# groups = Group.query.order_by(Group.name).all()
|
||||
#
|
||||
# groups_data = []
|
||||
# for group in groups:
|
||||
# groups_data.append({
|
||||
# 'id': group.id,
|
||||
# 'name': group.name,
|
||||
# 'description': group.description,
|
||||
# 'player_count': group.players.count(),
|
||||
# 'content_count': group.contents.count()
|
||||
# })
|
||||
#
|
||||
# return jsonify({
|
||||
# 'groups': groups_data,
|
||||
# 'count': len(groups_data)
|
||||
# })
|
||||
#
|
||||
# except Exception as e:
|
||||
# log_action('error', f'Error listing groups: {str(e)}')
|
||||
# return jsonify({'error': 'Internal server error'}), 500
|
||||
|
||||
|
||||
@api_bp.route('/content', methods=['GET'])
|
||||
@rate_limit(max_requests=60, window=60)
|
||||
def list_content():
|
||||
@@ -665,8 +651,7 @@ def list_content():
|
||||
'type': content.content_type,
|
||||
'duration': content.duration,
|
||||
'size': content.file_size,
|
||||
'uploaded_at': content.uploaded_at.isoformat(),
|
||||
'group_count': content.groups.count()
|
||||
'uploaded_at': content.uploaded_at.isoformat()
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
|
||||
Reference in New Issue
Block a user