Commit Graph

3916 Commits

Author SHA1 Message Date
Georges-Antoine Assi
6253b63fca Add test data generator script
Adds backend/scripts/generate_test_data.py, a tool that builds a large,
prod-like RomM library (platforms, users, devices, firmware, roms with
per-provider fake metadata, saves, states, screenshots, collections, sync
data, play sessions) and bulk-inserts it for load and UI testing.

Cover/manual/screenshot path and URL columns are left empty so no asset
files are referenced.

AI assistance: written with Claude Code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 19:20:22 -04:00
Georges-Antoine Assi
e7dd013cfb Merge pull request #3580 from rommapp/claude/youthful-wozniak-ocjhc0
feat(v2): interactive 3D box art on the game detail hero
2026-06-22 21:37:02 -04:00
Georges-Antoine Assi
2631f0e45d Merge pull request #3577 from Spinnich/feature/oidc-allow-registration
feat(auth): add OIDC_ALLOW_REGISTRATION toggle to gate OIDC auto-registration
2026-06-22 18:06:13 -04:00
Georges-Antoine Assi
d38be187f3 Merge branch 'master' into claude/youthful-wozniak-ocjhc0 2026-06-22 18:04:37 -04:00
Georges-Antoine Assi
c4bfbac872 Merge branch 'master' into v2-ui-tweaks-gg 2026-06-22 17:45:59 -04:00
Claude
77980a79ec feat(v2): interactive 3D box art on game detail hero
Adds an RBox3D primitive that builds a rotatable, fake-3D game box from
three flat ScreenScraper scans (front, back, spine) using CSS 3D
transforms. Box proportions derive from the images themselves; it rotates
via pointer drag, arrow keys / gamepad D-pad, and the right analog stick,
drifts gently when idle, and honours prefers-reduced-motion.

The game detail hero (CoverColumn) upgrades to the spinning box when the
"3D box" boxart style is selected and the rom has the full set of faces,
falling back to the flat cover otherwise.

Backend: persist the box-2D-side (spine) scan locally, mirroring the
existing box-2D-back handling — new BOX2D_SIDE media type + box2d_side_path
on ss_metadata, opt-in via scan.media.

- RBox3D primitive + Storybook story (controls + keyboard-rotation play())
- useBoxFaces composable resolving the three faces + a `complete` gate
- box3d-alt i18n key across all locales
- backend BOX2D_SIDE persistence + tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019itLXRfJXGGbhPY3JyqnuN
2026-06-22 21:45:39 +00:00
Georges-Antoine Assi
af4b057894 feat(v2): screenshot-forward covers + cover-art PIP for continue-playing & activity
Show a "where you left off" screenshot on the Home continue-playing rail and
the live-activity board, with a small cover-art thumbnail (PIP) in the corner
so the game stays identifiable. Both render at the image's natural aspect.

Backend:
- New shared util `continue_playing_screenshot(rom, latest_save)` resolving the
  image in priority order: latest save's screenshot, then title screen, then
  first gameplay screenshot (None → frontend falls back to cover art).
- `SimpleRomSchema.screenshot_path` populated only on the `last_played` query;
  `get_latest_saves_for_roms` batch handler (+ tests).
- ActivityEntry / ActivityEntrySchema gain `screenshot_path`, computed from the
  session player's latest save in both the socket and REST heartbeat paths.

Frontend:
- New shared `CoverArtPip.vue` (bottom-right 2D cover thumbnail), reused by
  GameCard and ActivityCard.
- Home continue-playing rail uses `screenshot_path` + PIP, natural aspect (no
  forced hero/style).
- Activity board: screenshot-forward cover + PIP, and a wrapping flex layout so
  cards share a uniform height with natural-ratio widths (gallery-card
  behavior).
- GameCover only keys the measured ratio by rom id for the rom's own cover, so
  a `coverSrc` override (screenshot) never pollutes the gallery's ratio cache.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:40:56 -04:00
Zurdi
b282a4cac7 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 18:03:51 +02:00
zurdi
8c20fd6547 feat(logging): enhance logging module with dynamic module name resolution and add module filtering options 2026-06-22 15:51:22 +00:00
Spinnich
11a81c756f feat(auth): add OIDC_ALLOW_REGISTRATION toggle
Gate automatic account creation on OIDC login behind a new OIDC_ALLOW_REGISTRATION environment variable. Defaults to true, preserving the current auto-provisioning behavior; set it to false to run OIDC in an "existing users only" mode, where a login from an email without an existing RomM account is rejected with a 403 instead of silently creating one. Existing users are unaffected either way.

Adds the config constant, env.template and docs entries, and tests covering the enabled/disabled and existing-user paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 12:33:00 +00:00
Georges-Antoine Assi
662dc89a24 Merge branch 'master' into aspect-ratio-no-no 2026-06-21 19:20:09 -04:00
Georges-Antoine Assi
1f98b2df14 run fmt 2026-06-21 17:47:06 -04:00
Georges-Antoine Assi
4724361f6d refactor: remove per-platform cover aspect-ratio setting
The platform aspect_ratio setting is dropped from the UI and the API
(platform update body + response schema) — nothing consumed it for
rendering, and covers now size to their image's natural aspect.

- SettingsTab: remove the cover-style / aspect-ratio picker (and its
  now-dead helpers, CSS, and unused imports); collapse to a single column.
- update_platform: drop the `aspect_ratio` body field; PlatformSchema no
  longer returns it; utils/platforms stops seeding the default.
- Regenerate the affected frontend types (PlatformSchema, update body).

The DB column stays (out of the update/response scope; dropping it would
be a separate destructive migration) but is no longer read or written
through the API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:43:40 -04:00
Georges-Antoine Assi
389025942f changes from bot review 2026-06-21 17:42:25 -04:00
Georges-Antoine Assi
77970f6379 Merge branch 'master' into feature/device-flow-authorization 2026-06-21 16:25:39 -04:00
Zurdi
ee33bf1b71 Merge pull request #3569 from rommapp/feat/share-savestates
feat: share saves & states with other users
2026-06-21 21:18:34 +02:00
Georges-Antoine Assi
0460133992 Secure activity identity, cut Redis churn, remove v1 activity
Backend:
- Resolve the acting user from the authenticated socket session on
  connect instead of trusting the client-supplied user_id, so a client
  can no longer spoof a "now playing" session for another user. Only
  rom_id/device_id come from the payload.
- Emit activity:update/clear through the already-initialised socket
  server instead of opening (and leaking) a fresh AsyncRedisManager per
  REST heartbeat.
- Collapse get_all_active's per-key GET into a single MGET.
- Drop the pure pass-through _build_activity_entry helper.

Frontend:
- Remove all activity emits from the v1 EmulatorJS Player; the v2 shell
  is the single driver of the activity lifecycle.
- Remove activity from the v1 UI entirely (Activity view, ActivityBtn,
  ActivePlayers on game details, navigation, and the now-v2-only route).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:12:18 -04:00
zurdi
9106c3721e feat: add visibility toggle for saves and states, enhance community sections
- Introduced new API endpoints for updating visibility of saves and states.
- Added `is_public` property to `SaveSchema` and `StateSchema`.
- Created new models for user saves and states with visibility attributes.
- Updated the `SaveDataTab` component to differentiate between "Mine" and "Community" sections.
- Implemented visibility toggle functionality for user saves and states.
- Enhanced localization files to include new strings for visibility actions.
2026-06-21 14:00:02 +00:00
nendo
812491f68c Refine device authorization flow
- device/init returns a relative verification_path; the client joins it
  with its own origin
- Render the v2 approval screen via the named v2 router outlet (was blank)
- DevicePair: RSpinner, keyboard-accessible scope chips, scrollable scopes;
  DevicePairShell uses always-light overlay tokens (no hex)
2026-06-21 10:57:48 +09:00
Georges-Antoine Assi
429e718a14 add ui for v2 2026-06-20 21:09:11 -04:00
Georges-Antoine Assi
4b091bfb34 Resolve activity device_type from the device record
Instead of always inferring "web" for browser-emitted activity events, look
the device up by device_id and use its client type, falling back to "web"
(the browser default) when no device record exists. Mirrors the REST
heartbeat endpoint, which derives device_type from device.client.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 18:56:03 -04:00
Georges-Antoine Assi
892a1b18e1 Merge branch 'master' into claude/user-game-activity-monitoring-Mqb1v 2026-06-20 13:42:11 -04:00
Zurdi
dd3f9d0496 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-20 18:33:54 +02:00
copilot-swe-agent[bot]
bd0bc65e92 fix: allow ROM deletion when file is missing
Co-authored-by: zurdi15 <34356590+zurdi15@users.noreply.github.com>
2026-06-20 16:23:24 +00:00
Zurdi
cce2587024 Merge pull request #3557 from rommapp/feat/logs-view
feat: real-time backend logs view
2026-06-20 17:54:23 +02:00
zurdi
78cac11913 feat: add DISABLE_LOGS_VIEWER configuration and implement checks in logs endpoints and frontend 2026-06-20 15:48:58 +00:00
zurdi
78eef900b9 feat: update logs endpoint to require 'logs.read' scope and adjust related authorization checks 2026-06-20 09:55:10 +00:00
Georges-Antoine Assi
b8450add5f Validate test database name before CREATE DATABASE
Addresses review feedback: `db_name` is interpolated into CREATE DATABASE
statements via f-strings (identifiers can't be bind parameters), so validate
it up-front against a plain-identifier allowlist ([A-Za-z0-9_]+) and refuse
anything containing quoting/other characters, rather than rely on quoting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 21:38:50 -04:00
Georges-Antoine Assi
26cf4b36f8 Scope test-user grant to the romm_test namespace
Addresses review feedback: granting ALL PRIVILEGES on *.* is overly broad,
especially against a shared DB instance. A database-level grant on the
`romm\_test%` wildcard pattern still lets the user CREATE the per-worker
databases (romm_test_gw0, ...) needed by pytest-xdist, while confining it to
that namespace — verified that out-of-namespace CREATE DATABASE is denied.

PostgreSQL needs no equivalent change: its CI service user (POSTGRES_USER)
is the container superuser.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 21:34:46 -04:00
Georges-Antoine Assi
0e016eca9b Merge branch 'master' into claude/user-game-activity-monitoring-Mqb1v 2026-06-19 21:11:05 -04:00
Georges-Antoine Assi
02815ec403 Run backend tests in parallel with pytest-xdist
Add pytest-xdist and run the backend test suite across multiple workers
(`-n 4` in CI). Each worker gets its own database so the autouse
`clear_database` fixture can't wipe rows another worker is mid-test with:

- Rootdir `backend/conftest.py` sets a per-worker `DB_NAME`
  (`romm_test_gw0`, ...) before any app module is imported, so each
  worker's engine binds to its own database.
- `tests/conftest.py` creates the per-worker database on demand (mariadb/
  mysql and postgresql paths) just before migrations run.
- The test user's grant is widened to `*.*` (setup.sql + CI) so it can
  `CREATE DATABASE` for the workers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 21:02:47 -04:00
zurdi
8b70e31828 refactor: address Copilot review on logs feature
- main.py: await the cancelled log-forwarder task (suppressing
  CancelledError) so its pubsub/lock cleanup finishes before shutdown.
- forwarder: only heartbeat the Redis lock while we still own it; if a
  stall let another worker take it, relinquish forwarding to avoid
  duplicate lines (the outer loop re-contends).
- endpoints/logs.py: derive MAX_LOG_LIMIT from LOG_BUFFER_SIZE so the
  REST backfill never drifts from the producer's ring buffer.
- Logs.vue: append the download <a> to the DOM before click() (matches
  the Patcher pattern) for cross-browser reliability.
- Add tests/endpoints/test_logs.py: non-admin 403, limit clamping to
  [1, MAX_LOG_LIMIT], oldest-first ordering, and malformed-entry skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 20:53:58 +00:00
zurdi
02c6fc8d3f fix: suppress bandit B110/B112 on intentional log-stream swallows
The log-stream handler and forwarder deliberately swallow exceptions: the
handler is a best-effort mirror that must never raise into the app, and the
forwarder can't log its own failures without feeding back into the stream.
Annotate these with `# nosec` (with justification) so Trunk's bandit check
passes, keeping lines within black's width.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 16:17:45 +00:00
zurdi
ad543d93ee feat: add logs feature with internationalization support
- Introduced a new logs view for admin users, allowing real-time monitoring of backend logs.
- Implemented a log entry streaming mechanism using Socket.IO.
- Added filtering and searching capabilities for log entries.
- Created localized log messages in Spanish, French, Hungarian, Italian, Japanese, Korean, Polish, Portuguese, Romanian, Russian, Simplified Chinese, and Traditional Chinese.
- Updated router and sidebar components to include the new logs route.
- Enhanced user interface with tooltips and buttons for copying and downloading logs.
2026-06-19 16:06:50 +00:00
zurdi
54b403a38e Merge remote-tracking branch 'origin/master' into feat/add-user-avatar-to-notes 2026-06-19 07:48:36 +00:00
zurdi
e974e3b451 fix: correct down_revision reference in migration script 2026-06-19 07:39:00 +00:00
zurdi
d5c985f634 Merge remote-tracking branch 'origin/master' into feat/screenshot-CRUD-endpoints 2026-06-19 07:35:07 +00:00
zurdi
5714ba3cec refactor: move screenshot file validation logic to utils and clean up endpoints 2026-06-19 07:30:07 +00:00
Georges-Antoine Assi
e657948bba fix trunk 2026-06-18 21:17:47 -04:00
Georges-Antoine Assi
13007b36df cleanup tests 2026-06-18 21:12:13 -04:00
Georges-Antoine Assi
1e78a2ed59 Merge branch 'master' into claude/exciting-heisenberg-61PF9 2026-06-18 19:59:00 -04:00
Georges-Antoine Assi
8922c2dd12 changes forom bot review 2026-06-18 13:27:41 -04:00
Georges-Antoine Assi
892f870d0d fix migration 2026-06-18 11:51:11 -04:00
Georges-Antoine Assi
c98fd39adb Merge branch 'master' into copilot/support-sortname-tag-es-de 2026-06-18 11:49:43 -04:00
Georges-Antoine Assi
8bf7d18afe cleanup 2026-06-18 11:48:51 -04:00
Georges-Antoine Assi
a38ebe29b5 Preserve custom name_sort_key; gate derivation on "still derived"
Drop the name_sort_key_custom flag/migration in favour of a flagless rule: a
key is "custom" when it no longer equals compute(name). Apply that consistently
across all three write paths so a manual sort key survives renames while a
derived key keeps following the name:

- @validates re-derives on name assignment only when the stored key still
  matches the derived value; direct name_sort_key assignment stores a
  normalized custom key (or reverts to derived when cleared). Handles both
  kwarg orders at construction.
- update_rom mirrors the same check for the bulk update() path it bypasses.
- The edit endpoint only writes the key when the user actually changed the
  field, delegating the untouched case to update_rom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:30:40 -04:00
Georges-Antoine Assi
cd19d723fa Merge sort_name into name_sort_key with custom-override flag
Collapse the separate `sort_name` column into `name_sort_key`, which is now
the single user-settable sort field: always normalized and indexed for fast
ordering, derived from `name` by default, and overridable. A new
`name_sort_key_custom` boolean marks user/metadata overrides so they survive
renames and rescans.

- Drop the `roms.sort_name` column; repurpose migration 0085 to add
  `name_sort_key_custom`.
- Derive the key via `@validates("name")` unless pinned custom; the edit
  dialog, unmatch flow, and ES-DE gamelist <sortname> set custom keys.
- update_rom / scan_rom keep the columns in sync explicitly (bulk update and
  construction bypass / reorder the validator).
- Frontend: edit field drives name_sort_key (empty when auto), api sends the
  override only when custom, regenerated types updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 10:34:21 -04:00
zurdi
d4a6d97acb feat: add user avatar and updated timestamp to community screenshots 2026-06-18 14:20:54 +00:00
zurdi
c0b44cd2ef Merge branch 'feat/screenshot-CRUD-endpoints' into feat/add-user-avatar-to-notes 2026-06-18 14:17:32 +00:00
zurdi
7ef3cba02a fix(migrations): shorten 0084 revision id to fit alembic_version column
The revision id '0084_add_roms_search_and_sort_indexes' (37 chars)
exceeded alembic_version.version_num VARCHAR(32), so every migration
run and test setup failed with 'Data too long for column version_num'
when stamping the revision. Rename it to '0084_roms_search_sort_indexes'
(29 chars) and update the 0085 down_revision link to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 14:06:32 +00:00