334 Commits

Author SHA1 Message Date
Spinnich
15b485b118 fix(collections): address reviewer feedback on types and concurrency
- Use CollectionSchema instead of ReturnType<typeof collectionsStore.getCollection>
  in AddRoms.vue and RemoveRoms.vue (simpler, per gantoine review)
- Wrap bulk INSERT in a savepoint so a concurrent duplicate-key violation
  is caught via IntegrityError and ignored rather than aborting the transaction
- Only bump Collection.updated_at in remove_roms_from_collection when rows
  were actually deleted (rowcount > 0), matching add_roms_to_collection behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 06:46:12 -04:00
Spinnich
2ecefa3d3f Fix race condition in collection and favorite rom membership updates
Replace full rom_ids list replacement with atomic POST/DELETE endpoints
that add or remove individual ROMs from a collection. This prevents
concurrent rapid clicks from overwriting each other (last-write-wins).

Also fix missing session.flush() in add_rom_user() and add collection
endpoint tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:08:53 -04:00
Georges-Antoine Assi
abc69c790f
fix scanning 2026-04-12 09:35:34 -04:00
Georges-Antoine Assi
85f9444b57
fix: restore get_roms_by_fs_name after stripped @with_details
Commit 3991e1b6e removed `@with_details` from `get_roms_by_fs_name` but
left the body using the `query` parameter that decorator was supposed
to inject, so every scan hit `'NoneType' object has no attribute
'filter'` and crashed the platform identification task.

Make the function self-contained: build `select(Rom)` directly and
eager-load only `Rom.platform`, the one relationship the scan loop
actually needs (via `rom.platform_slug` / `rom.platform.fs_slug`).
Keeps the prior commit's intent of avoiding the heavy `with_details`
eager-load on every batch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:10:27 -04:00
Georges-Antoine Assi
de9efb3da8
refactor: simplify mark_missing_roms with a single flips dict
Collapse the two parallel id lists and their mirrored chunked-update
loops into a `flips: dict[bool, list[int]]` keyed by desired state, and
drop unused rom assignments in the related tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:13:33 -04:00
Georges-Antoine Assi
3991e1b6ed
fix: scan stalls on platforms with 10k+ already-scanned ROMs
The scan was spending excessive time on large platforms even when all ROMs
were already scanned. Root causes: per-ROM UPDATE queries for skipped ROMs
(10k individual writes), missing composite index on (platform_id, fs_name)
causing full table scans, NOT IN clauses with 10k+ values in
mark_missing_roms(), and redundant filesystem reads.

Changes:
- Add bulk_mark_present() for batch-updating skipped ROMs in one query
- Move skip detection from _identify_rom to the batch loop so skipped ROMs
  never enter the async scan pipeline, and report progress for them
- Add composite index idx_roms_platform_id_fs_name via migration 0077
- Rewrite mark_missing_roms() with flip-based approach: mark all missing,
  then un-mark present ones in chunks of 1000
- Cache filesystem reads in scan_platforms() to avoid double directory
  traversal (precounting + scanning)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:20:40 -04:00
Georges-Antoine Assi
4e5ee69343
more simplify 2026-04-06 22:29:55 -04:00
Georges-Antoine Assi
b2e1e094f7
some simplification 2026-04-06 21:53:49 -04:00
Georges-Antoine Assi
e5cb29ae80
Merge branch 'master' into feature/play-session-ingest 2026-04-06 12:42:15 -04:00
Georges-Antoine Assi
f2e8e337b2
Merge branch 'master' into save-sync 2026-04-05 21:47:53 -04:00
Georges-Antoine Assi
8664f6203f
bad removal 2026-04-05 19:19:06 -04:00
Georges-Antoine Assi
e0214f100d
more bot cleanup 2026-04-05 19:15:33 -04:00
Georges-Antoine Assi
7c41fb5bac
revert fs_name sibling roms 2026-04-05 17:57:48 -04:00
Georges-Antoine Assi
a3ebe16a39
run fmt 2026-03-24 15:32:48 -04:00
copilot-swe-agent[bot]
a5954590ec Fix IntegrityError when updating favourites with stale ROM IDs
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rommapp/romm/sessions/8a6fd3fe-77ab-4f7b-a0e9-1c55e7096e88
2026-03-23 22:19:06 +00:00
Georges-Antoine Assi
f107dc2752
changes from bot rview 2026-03-22 17:17:14 -04:00
nendo
719b98faaf Batch session inserts into single transaction
Replace per-item add_session with add_sessions using add_all.
No fallback on IntegrityError -- duplicate concurrent submissions
are the client's responsibility.
2026-03-22 21:21:27 +09:00
nendo
75302ed59a Add play session ingest for game time tracking
Backend API for collecting and querying play sessions, modeled after
the Argosy session data format. Clients submit batches per device,
recording both the session window and screen-on time.
2026-03-22 20:22:55 +09:00
nendo
4edb1710a5 fix: address review feedback on session handler and counter
- Restore NoResultFound behavior on update_session, complete_session,
  fail_session when row is missing (scalar returns None, old .one()
  raised -- silent None is a semantic regression)
- Remove redundant get_session call from _increment_session_counter;
  the atomic SQL increment is already a no-op on missing rows
- Log warning when passed session_id is not found in _sync_device
  instead of silently creating an orphan session
2026-03-16 10:59:49 +09:00
nendo
55638d15dc fix: address bugs, security issues, and convention violations in save-sync
- Fix broken path construction in FSSyncHandler: build_* methods now
  return relative paths; sync_watcher uses paths relative to sync base
  instead of CWD (was completely non-functional in production)
- Fix SSH connection leak in push-pull task: conn.close() now in finally
- Add log.warning for disabled SSH host key verification
- Fix race condition in session operation counter: use atomic SQL
  increment instead of read-then-write
- Extract _increment_session_counter helper, add exc_info to warnings
- Replace legacy session.query() with select() in sync_sessions_handler
- Fix orphaned session: trigger_push_pull now passes session_id to job
- Fix wasteful SSH download when no matched_save exists
- Fix BaseModel import collision in sync.py (pydantic -> project base)
- Fix ORM mutation in UserSchema.from_orm_with_request: set field on
  schema instance instead of mutating live ORM object
- Mask ssh_password and ssh_key_path in DeviceSchema API response
- Fix migration PostgreSQL compatibility: condition ON UPDATE clause
  on MySQL, drop enum in downgrade
- Rename copy-paste artifact rom_user_status_enum
2026-03-16 10:56:43 +09:00
Georges-Antoine Assi
e1b07cacfc
make devices actually unique 2026-03-15 20:09:33 -04:00
Georges-Antoine Assi
e6ddc5da11
bot attempt at save sync 2026-03-14 22:13:38 -04:00
Georges-Antoine Assi
997e2c44aa
start pre-4.8 cleanup 2026-03-12 23:02:12 -04:00
Zurdi
4c680f4919
Merge pull request #3121 from Bergbok/playable-filter-fix
fix: add missing platforms to playable game filter
2026-03-11 16:24:00 +01:00
Bergbok
99e41cecc2
refactor: create list for playable platforms that don't use EJS 2026-03-11 17:18:13 +02:00
Bergbok
ed61158aee
fix: include DOS, Game Boy Color and Sega 32X games in playable filter 2026-03-11 16:40:39 +02:00
Bergbok
cad510a0b0
refactor: remove duplicate C64 entry from EJS_SUPPORTED_PLATFORMS 2026-03-11 16:37:49 +02:00
Bergbok
8517fb9aca
fix: include browser games in playable filter 2026-03-11 16:11:08 +02:00
Georges-Antoine Assi
6f02a4beff
Merge pull request #3114 from tmgast/feature/client-api-tokens
Add client API tokens with QR pairing flow
2026-03-10 22:17:05 -04:00
nendo
e0b25fbc6c feat(client-tokens): add client API tokens with QR pairing flow
Long-lived, revocable, scope-restricted tokens for external clients
(mobile apps, retro handhelds, third-party tools). Includes:

- Backend: model, migration, DB handler, auth integration (rmm_ prefix
  routing in HybridAuthBackend), CRUD + pairing + exchange endpoints,
  rate limiting, scope intersection enforcement, admin oversight
- Frontend: settings page with token management table, stepped
  create/deliver dialog (config -> copy/pair), QR code with RomM logo,
  admin token table, standalone /pair page for QR scan landing
- /pair page supports custom-scheme callbacks for app deep linking,
  falls back to displaying code for manual entry
- 33 backend tests across 5 classes (CRUD, auth, isolation, pairing,
  admin)
2026-03-11 10:56:35 +09:00
Georges-Antoine Assi
0c18c2588c
run fmt 2026-03-10 21:47:27 -04:00
cc
a4e8d9df49 fix: sort without mutating store, move constants to module scope
- Spread allPlatforms before sorting to avoid mutating Pinia store
- Move _METADATA_SOURCE_COLUMNS to module level
- Add optional chain on sourceInfo v-img src

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:09:19 -04:00
cc
52c53505a1 refactor: address review feedback
- Derive metadata source columns from Rom model instead of hardcoded list
- Replace getOrderedCoverage() function calls with a computed map to avoid
  redundant sorting on each render

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:27:50 -04:00
cc
778097f4a0 feat: add per-platform metadata coverage and region breakdown to server stats
Enhances the server stats page with two new per-platform statistics:
- Metadata coverage: shows which sources matched ROMs (ordered by user's scan priority config)
- Region breakdown: shows ROM counts per region with flag emojis

Backend adds two new efficient queries (single GROUP BY for metadata, Python-side aggregation for regions).
Frontend redesigns platform cards with a tabular detail layout, size bar visualization, and expandable region chips.

> This PR was developed with AI assistance (Claude Code) per CONTRIBUTING.md disclosure requirements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:15:08 -04:00
Georges-Antoine Assi
e3d9bfe9fa
fix migration 2026-03-08 20:14:14 -04:00
copilot-swe-agent[bot]
ae73da7c27 Fix 500 error from empty fs_name_no_tags causing mass sibling matching and incorrect ROM grouping
- Add migration 0071 to fix sibling_roms view: add guard against empty string matching for fs_name_no_tags
- Fix group_by_meta_id in filter_roms: use func.nullif to treat empty fs_name_no_tags as NULL in grouping key
- Add group_by_meta_id support to get_roms_scalar
- Add tests for sibling matching behavior with empty/non-empty fs_name_no_tags

Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-03-08 23:17:51 +00:00
Georges-Antoine Assi
2905328c9e
update comments 2026-03-08 11:39:41 -04:00
Georges-Antoine Assi
29a5b8edf2
fix on mariadb 2026-03-08 10:15:08 -04:00
Georges-Antoine Assi
72d04b1ec7
fixes 2026-03-08 10:08:50 -04:00
Georges-Antoine Assi
708105aabd
Hack for natural sorting of roms 2026-03-08 09:51:51 -04:00
Georges-Antoine Assi
2706927cbc
fix bug with exclusion criteria 2026-02-19 10:32:55 -05:00
Georges-Antoine Assi
d3aa1b7c44
prefer exact stem matches first 2026-02-19 10:27:17 -05:00
Georges-Antoine Assi
6461078721
loosen rules around fetch matching screenshots 2026-02-19 10:18:56 -05:00
Georges-Antoine Assi
fe5b831afc
Add Rom.ra_hash and RomFile.ra_hash fields to API 2026-02-13 11:11:02 -05:00
Georges-Antoine Assi
66ee72431e
fix bot comment 2026-02-08 21:23:42 -05:00
Georges-Antoine Assi
16cac7cf64
[ROMM-2972] Fix /props returning stale data 2026-02-08 21:10:12 -05:00
Georges-Antoine Assi
5596999a3b
one last regression 2026-02-07 22:46:09 -05:00
Georges-Antoine Assi
cb85d70b83
extract filter into own block 2026-02-07 22:27:44 -05:00
Georges-Antoine Assi
3e86e55994
changes from bot review 2026-02-07 22:02:15 -05:00
Georges-Antoine Assi
2d678ef19f
[ROMM-2976] Fix no games displayed for status filter 2026-02-07 21:27:24 -05:00