mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-30 12:33:01 +00:00
* feat(web): add config backup & restore UI Adds a Backup & Restore tab to the v3 web UI that packages user config, secrets, WiFi, user-uploaded fonts, plugin image uploads, and the installed plugin list into a single ZIP for safe reinstall recovery. Restore extracts the bundle, snapshots current state via the existing atomic config manager (so rollback stays available), reapplies the selected sections, and optionally reinstalls missing plugins from the store. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backup): address PR review findings - backup_manager: read plugin state from "states" key (not "plugins") to match the actual plugin_state.json format written by state_manager - backup_manager: stream ZIP directly to a temp file instead of building it in an io.BytesIO buffer to avoid OOM on Raspberry Pi - backup_manager: tighten plugin-uploads path validation in validate_backup and restore_backup to require "/uploads/" in the path, rejecting any non-uploads files smuggled under assets/plugins/ - api_v3: enforce 200 MB upload limit by streaming in chunks rather than relying on validate_file_upload (which only checks the filename) - api_v3: replace bool() with _coerce_to_bool() for RestoreOptions fields so string "false" is not treated as truthy - api_v3: capture and log _save_config_atomic return value instead of discarding it; log rather than silence font-cache and config-reload errors - backup_restore.html: track inspectedFile so runRestore always applies to the file the user inspected, not a subsequently selected file; clear on input change or clearRestore() - backup_restore.html: throw on non-success restore payload so errors are surfaced via the error notification path instead of yellow "warnings" - test: update fixture to use correct "states" key structure; import SCHEMA_VERSION constant instead of hardcoding 1; rename unused err -> _err Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(backup): address second round of PR review findings - api_v3: guard opts_dict with isinstance check after json.loads so a non-object JSON payload (null, array, etc.) returns a 400 instead of a 500 AttributeError - backup_manager: wrap tmp ZIP creation and os.replace in try/except so the .zip.tmp temp file is always removed on any failure - backup_manager: replace hardcoded Path("/tmp/_zip_check") sentinel in validate_backup with a proper tempfile.TemporaryDirectory() so path traversal checks are portable and leave no artifacts - backup_restore.html: detect partial-success responses (plugins_failed or errors non-empty) even when status is 'success' and render yellow/warning styling and notify instead of green Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(backup): add post-install steps for restored plugins; conditional restart hint - api_v3: after a successful plugin reinstall during restore, run the same post-install sequence used by the normal /plugins/install flow: invalidate schema cache, discover_plugins()/load_plugin(), and set_plugin_installed() so restored plugins are immediately available - backup_restore.html: only show the "restart the display service" hint when at least one item was restored or at least one plugin was installed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(backup): address Codacy findings - api_v3: replace 'fonts' in ' '.join(result.restored) substring check with any(r.startswith("fonts") for r in result.restored) to avoid fragile joined-string membership testing - api_v3: replace deprecated datetime.utcnow() and utcfromtimestamp() with datetime.now(timezone.utc) and fromtimestamp(..., timezone.utc); add timezone to import - test: remove unused import io (backup_manager no longer uses BytesIO) - src/backup_manager.py hardcoded /tmp sentinel was already fixed in a prior commit (tempfile.TemporaryDirectory) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Chuck <chuck@example.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
351 KiB
351 KiB