The maintenance-page reset used to rotate auth_code immediately. Because the
token also guards the playlist endpoints, that stopped a player from syncing
content the instant the button was pressed -- before the player ever had a
chance to react -- and clients that do not understand the heartbeat's
401 auth_required would have stayed broken until redeployed.
Split the model behaviour:
* request_reauth() -- sets the flag only (used by the admin reset endpoints
and the automatic interval). The current token stays valid, so there is no
outage while the player is being asked to re-authenticate.
* issue_new_token() -- replaces the token now (used by the existing
"regenerate auth code" action, where the admin is shown the new value).
* mark_authenticated() -- if a reset was pending, this is where the old token
is retired: a new token is issued and returned to the player in the
/api/auth/player response.
Net effect: the reset is a request the player acts on, never a forced logout.
A player that ignores it keeps working and shows as "awaiting re-auth" in the
UI; one that handles it gets a fresh token and the old one stops working.
Maintenance page wording updated to match (request vs reset; "awaiting
re-auth" badge), plus a themed info note explaining it is not a forced logout.
Adds docs/player-auth-reset.md describing the protocol and exactly what the
player client (Kiwy-Signage) still needs to implement: detect 401 /
auth_required on the heartbeat (and on the token-guarded endpoints), re-run
POST /api/auth/player with the stored quick-connect code, save the new
auth_code and retry. No password or SSH redeploy required.
Verified end-to-end: token unchanged and still accepted after the request
(200), heartbeat answers 401 auth_required=token_reset, re-auth issues a
different token, the old token is then rejected (403) and the new one accepted
(200), flag cleared; the interval path only flags without rotating.
Follow-up to the player-modal / maintenance-page fix: the same root cause --
colours hard-coded for the light theme -- affected the whole app, in two
places.
1) Inline style attributes (inline outranks the theme rules, so the light
value survives dark mode and the inherited text colour turns
light-on-light). base.html now carries a single, property-scoped
dark-mode override layer that maps every light literal found in the
templates to the theme variables: light backgrounds/whites -> dark
surfaces, semantic pastels -> dark equivalents, dark text -> light text,
light borders -> dark borders, plus .back-link. Scoped to
body.dark-mode, so the light theme is untouched. This covers all
templates, including ones not edited here and any added later.
2) Page-level <style> blocks with no dark support:
* admin/https_config.html hard-coded a light-only palette (blue-tint
panels, dark labels) -- added a body.dark-mode block for it.
* dashboard.html / help.html / manage_player.html coloured text links
with --primary-color (#7c3aed in dark = too dim). Introduced a
dedicated --link-color (#667eea light / #a78bfa dark) and used it for
text links, leaving --primary-color for button/background use.
Verified with an automated luminance scan of all 18 pages in both themes:
dark mode has 0 light backgrounds and 0 dark-on-dark text (the only
remaining light surfaces are the intentional white buttons on the admin
gradient cards), and light mode is unchanged.
Both bugs had the same cause: light colours were set with inline style
attributes, which outrank the theme rules in base.html and so survived the
dark theme. Text that inherits --text-color then became light-on-light.
* manage_player.html: the delete confirmation modal used an inline
background-color of #fefefe with the body's dark-mode text colour, making
the message unreadable in dark mode. Rebuilt it with .modal-* classes
driven by the base.html CSS variables (and dark-mode variants for the
title, warning and player name).
* admin/maintenance.html: the "Automatic reset interval" panel, table
headers and JS-rendered rows/tables hardcoded #f8f9fa/#e2e8f0/#dee2e6.
Switched them to --bg-color / --card-bg / --border-color /
--text-secondary and added a themed .maint-badge-pending.
Verified with computed styles in both themes; light mode is unchanged.
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.
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.
- Content model: add url column + is_weblink() for web page content items
- Player model: add deployment tracking fields (status, timestamps, message)
- Content blueprint: add add_weblink and add_weblink_to_playlist routes;
weblinks auto-deleted when removed from playlist
- Players blueprint: add SSH deploy mode in add_player; weblink-aware playlist
- API blueprint: weblink URL served directly in playlist response;
add /api/deploy/test-ssh and /api/deploy/player endpoints
- Admin blueprint: add build-player page (clone from Gitea, write base config);
replace nginx status card with Caddy status on HTTPS config page
- caddy_manager: rewritten to generate proper HTTPS/internal-CA Caddyfiles
and reload Caddy via admin API (/load) for live config updates
- ssh_deploy, background_tasks, player_build: new utils for SSH deployment
- background_tasks: push Flask app context into background thread so DB
updates after deployment complete correctly
- ssh_deploy: robust install script detection with passwordless sudo injection
(uses SSH credentials, cleaned up after install)
- Dockerfile: add git, sshpass, openssh-client, rsync
- docker-compose: switch nginx to Caddy on ports 80/443; add port 5000 for dev
- Templates: add_player deploy mode UI, weblink form in playlist/upload pages,
build_player admin page, Caddy status on HTTPS config page
- Migrations: add_url_to_content, add_deployment_fields_to_player
- app.py: call db.create_all() on startup for schema bootstrap
- config.py: add PLAYER_CODE_DIR and PLAYER_REPO_URL settings
- Changed ownership of all files to scheianu:scheianu
- Set directories to 755 permissions (rwxr-xr-x)
- Set files to 644 permissions (rw-r--r--)
- Made shell scripts executable (755)
- Allows development without requiring sudo for file modifications
- Improves development workflow and security
- Detect actual HTTPS status from current request (scheme + X-Forwarded-Proto)
- Auto-sync database when HTTPS status mismatch is detected
- Show real-time connection info (protocol, host, port)
- Display helpful message when accessing via HTTPS but config shows disabled
- Add CSS styling for detection status display
- Users now see accurate HTTPS status even if database wasn't in sync
- Added auto-creation of PlayerUser records from player metadata (user_card_data)
- Fixed player_user table schema (removed player_id, made user_code unique globally)
- Created admin page for managing editing users (view, update names, delete)
- Updated permissions: normal users can now access admin panel, editing users, and leftover media
- Admin-only access: user management, system dependencies, logo customization
- Fixed edited media workflow to preserve original files
- Content.filename now points to edited_media folder, keeping originals intact
- Added user display names in edited media page (shows name if set, code otherwise)
- Fixed leftover media file size calculation (handle None values)
- Split editing users into separate card on admin panel with description
Features added:
- Leftover media management page in admin panel with delete functionality for images and videos
- Individual file delete buttons for leftover media
- PDF to PNG conversion (each page becomes a separate image at Full HD resolution)
- Delete functionality for leftover video files
- Enhanced playlist management with duration editing for all content types
- Improved dark mode support for playlist management page
- Content type badges with color coding
- Better styling for duration input fields with save functionality
- Fixed URL generation for duration update endpoint
- Added comprehensive dark mode styling to all pages:
* Dashboard (workflow guide, secondary text, log items)
* Admin panel with user management system
* Content/playlist management page
* Upload media page
* Add player page
- Implemented user management system:
* Create/edit/delete users
* Two role types (user/admin)
* Reset password functionality
* Role-based permissions
- Replaced group assignment with playlist assignment:
* Players now directly assigned to playlists
* Updated add player form and backend
* Removed group selection from player creation
- Fixed bugs:
* Updated instance_path configuration for SQLite
* Fixed import path in app factory
* Updated dependencies (Pillow 11.0.0, removed gevent)
- Added start.sh script for easy development server launch