23 Commits

Author SHA1 Message Date
nendo
edb5d15420 Fix save-sync hash drift, archival save leak, and dedupe scoping
Cleanup pass on save-sync addressing three independent failure modes
that interact in production data: content_hash drift between client
and server, null-slot archival saves leaking into sync flows, and
content-hash dedupe collapsing legitimately-distinct slots.

Bug fixes
- compute_content_hash dispatched on zipfile.is_zipfile(relative_path),
  which silently returned False whenever the process's CWD wasn't
  ASSETS_BASE_PATH. Every zip save fell through to the raw-MD5 branch,
  persisting hashes that disagreed with clients computing the intended
  per-entry zip-hash. Resolve to a full path before the dispatch.
- _build_negotiate_plan, sync_push_pull_task, and sync_watcher all
  treated null-slot saves as sync-eligible. Null-slot saves represent
  web-UI / archival uploads; including them in negotiate plans matched
  them against device pushes by filename and overwrote archival data.
  Filter null-slot saves at all three call sites.
- get_save_by_content_hash matched on (rom_id, user_id, content_hash)
  only, so identical bytes uploaded to different slots collapsed into
  one record. Scope the lookup by slot when provided so clone-save-
  to-new-slot creates a distinct row per slot.
- get_save_by_filename matched on (rom_id, user_id, file_name) only.
  When two uploads to different slots happened in the same wall-clock
  second (the datetime tag is per-second), the second upload UPDATED
  the first record's slot instead of creating a distinct row. Scope
  the filename lookup by slot too.

One-shot recovery
- New recompute_save_content_hashes manual task walks every Save row,
  recomputes via the fixed dispatch, and updates rows whose values
  differ. Idempotent; safe to re-run.
- Backend startup runs a COUNT(content_hash IS NULL) query and, if
  any rows exist, enqueues the recompute task on the low-priority
  RQ queue. The API process moves on; the worker handles the
  recompute out-of-band. Subsequent restarts find zero NULL hashes
  and skip. Admins can also trigger the task manually.

Test infrastructure
- Added tests/_zipfile_shim.reload_zipfile() mirroring the pattern
  from utils/zip_cache.py for the same zipfile-inflate64 + CPython
  3.13.5 incompatibility. Test fixtures that build ZIPs call it
  immediately before opening the archive.
2026-05-29 17:00:01 +09:00
Georges-Antoine Assi
aee17e51d5 fix 2026-04-29 14:43:37 -04:00
copilot-swe-agent[bot]
80b5fdf21f fix: add periodic janitor to clean up orphaned upload tmp directories
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/2e55dd7f-d99d-48a2-ae15-0b8c4817cc6e

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-04-29 16:42:12 +00:00
Georges-Antoine Assi
4928041593 manual cleanu 2026-04-12 11:04:12 -04:00
Georges-Antoine Assi
4c97eddfc3 fix trunk check 2026-03-22 16:30:14 -04:00
Georges-Antoine Assi
55ca39cacb fix deprecations in pydantic 2026-03-15 09:34:48 -04:00
Georges-Antoine Assi
b3fbbf59fb add tests 2026-03-14 23:35:04 -04:00
Georges-Antoine Assi
72e884a83c run fmt 2026-03-12 19:02:24 -04:00
copilot-swe-agent[bot]
4234ca3953 fix: always update rom_user status from RA award on each sync run
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-03-12 22:59:47 +00:00
copilot-swe-agent[bot]
da30e4daf1 feat: auto-update game status from RetroAchievements award kind
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-03-11 02:27:38 +00:00
Georges-Antoine Assi
b4f3df57b3 get tests to finish 2026-03-07 22:37:06 -05:00
Georges-Antoine Assi
eda88b70d1 get claude to refactor launchbox_handler 2026-03-07 16:02:39 -05:00
Georges-Antoine Assi
38ce9897d4 [HOTFIX] Dont schedule tasks if already queued 2026-01-09 17:55:16 -05:00
zurdi
95b8a839cc fix: unit test 2025-12-17 15:30:09 +00:00
Georges-Antoine Assi
f30f0bfd75 Smarter detection of whether to scan roms 2025-10-26 13:21:56 -04:00
Georges-Antoine Assi
9fa15d20f0 totally refactor scan types 2025-10-23 16:57:40 -04:00
Georges-Antoine Assi
9a8899f678 use explicit kwargs on scan 2025-10-19 12:43:03 -04:00
Georges-Antoine Assi
c43c1041a3 fix tests 2025-10-16 14:20:38 -04:00
Michael Manganiello
e4e3928d1b misc: Apply import sorting 2025-09-04 11:17:00 -03:00
Michael Manganiello
d216bad78b misc: Add MetadataHandler's is_enabled method
Convert `MetadataHandler` to an abstract base class and add an
`is_enabled` class method that allows every metadata handler to
independently report whether it is enabled based on its configuration.

This avoids the need for global variables in the config module, allowing
us to change the enabled state of a metadata handler at runtime if
needed.
2025-09-03 22:13:28 -03:00
Michael Manganiello
a31a8504c2 feat: Add scheduled task to sync RetroAchievements progress
Add a new scheduled task that syncs RetroAchievements progress for all
users with a RetroAchievements username.

Environment variables:
- `ENABLE_SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC`: Enable or disable
  the task (default: `false`)
- `SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC_CRON`: Cron string to
  schedule the task (default: "0 4 * * *" - daily at 4 AM)
2025-08-31 01:57:26 -03:00
Georges-Antoine Assi
2e690f49bb fix tests 2025-08-26 21:17:27 -04:00
Michael Manganiello
ba21cbc1e1 misc: Separate tests folder from backend code
Create separate `tests/` folder for all tests. This will also simplify
not copying tests code into the Docker image.
2025-08-08 12:49:13 -03:00