Files
ske087 46602f1933 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.
2026-09-11 12:18:34 +03:00

109 lines
4.0 KiB
Python

"""Post-sanitization verification smoke test.
Boots the app on a fresh DB, registers a player/playlist/content, and exercises
every API endpoint plus key UI routes. Fails loudly on any 5xx.
"""
import os
import tempfile
tmpdir = tempfile.mkdtemp()
db_path = os.path.join(tmpdir, 'smoke.db')
os.environ['DATABASE_URL'] = f'sqlite:///{db_path}'
from app.app import create_app
from app.extensions import db, bcrypt
from app.models import Player, Playlist, Content, User, PlayerUser, HTTPSConfig
app = create_app('testing')
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
app.config['CACHE_TYPE'] = 'simple'
with app.app_context():
db.create_all()
# prove Group/group_content are gone from metadata
tables = sorted(db.metadata.tables.keys())
print('registered tables:', tables)
assert 'group' not in tables, 'group table still registered!'
assert 'group_content' not in tables, 'group_content still registered!'
admin = User(username='smoke',
password=bcrypt.generate_password_hash('smokepw').decode('utf-8'),
role='admin')
pl = Playlist(name='Smoke PL')
db.session.add_all([admin, pl])
db.session.flush()
c = Content(filename='s.png', content_type='image', duration=5)
db.session.add(c)
db.session.flush()
pl.contents.append(c)
p = Player(name='Smoke', hostname='smoke-host', auth_code='smoke-code')
p.set_password('pw')
p.set_quickconnect_code('qc')
p.playlist_id = pl.id
db.session.add(p)
db.session.commit()
pid = p.id
code = p.auth_code
auth = {'Authorization': f'Bearer {code}'}
with app.test_client() as cl:
# public api
for url in ['/api/health', '/api/system-info', '/api/content', '/api/logs',
f'/api/player-status/{pid}',
'/api/playlists?hostname=smoke-host&quickconnect_code=qc']:
r = cl.get(url)
print(f'{r.status_code} GET {url}')
assert r.status_code < 500, f'{url} -> {r.status_code}'
# system-info must no longer expose a groups key
if url == '/api/system-info':
body = r.get_json()
assert 'groups' not in body, f'groups key still present: {body}'
print(' system-info keys:', sorted(body.keys()))
# authed api
for url in [f'/api/playlists/{pid}', f'/api/playlist-version/{pid}']:
r = cl.get(url, headers=auth)
print(f'{r.status_code} GET {url} (bearer)')
assert r.status_code < 500
r = cl.post('/api/auth/verify', json={'auth_code': code})
print(f'{r.status_code} POST /api/auth/verify')
assert r.status_code < 500
r = cl.post('/api/player-feedback', json={
'hostname': 'smoke-host', 'quickconnect_code': 'qc',
'status': 'playing', 'message': 'ok'})
print(f'{r.status_code} POST /api/player-feedback')
assert r.status_code < 500
# content listing must no longer contain group_count
body = cl.get('/api/content').get_json()
assert body['content'], 'expected seeded content'
assert 'group_count' not in body['content'][0], body['content'][0]
print(' /api/content item keys:', sorted(body['content'][0].keys()))
# login then hit UI pages
r = cl.post('/login', data={'username': 'smoke', 'password': 'smokepw'},
follow_redirects=True)
print(f'{r.status_code} POST /login')
for url in ['/', '/content/', '/content/media-library', '/players/',
'/admin/', '/admin/users', '/admin/system/info']:
r = cl.get(url, follow_redirects=True)
print(f'{r.status_code} GET {url}')
assert r.status_code < 500, f'{url} -> {r.status_code}'
# import checks
import app.utils as u
print('utils exports ok:', hasattr(u, 'get_player_status_info'))
assert not hasattr(u, 'get_group_statistics')
assert not hasattr(u, 'assign_player_to_group')
import importlib
for mod in ['app.blueprints.content', 'app.blueprints.api', 'app.utils.group_player_management',
'app.blueprints.players']:
importlib.import_module(mod)
print(f'imported {mod}')
print('\n🎉 SMOKE TEST PASSED')