Renaming a rom via PUT /roms/{id} only updated fs_name and its
derivatives, leaving regions/languages/tags/revision/version stale
against the new filename. Re-parse them whenever fs_name changes so
edits like "patapon (Fr En)" -> "Patapon (Fr, En)" are reflected in
the database.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pytest-asyncio 0.23 is incompatible with pytest 9 (it calls the removed
Package.obj attribute, causing an INTERNALERROR during collection).
Bump to ~= 1.1 and set asyncio_default_fixture_loop_scope to silence the
1.x deprecation warning.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The .gitattributes file was stored with CRLF endings, which prevents
git from parsing its rules reliably on Linux/macOS. Add a self-referential
eol=lf rule and renormalize the file to LF in the index.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Windows developers with core.autocrlf=true (or the default) will have
git check out shell scripts with CRLF endings. When those files are
copied into a Linux Docker container they fail to execute:
exec /entrypoint.sh: no such file or directory
Adding eol=lf attributes for *.sh, entrypoint.sh, and
docker/init_scripts/init ensures the repository always stores and checks
out these files with Unix line endings, regardless of platform or
git config.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
Starlette's TestClient (httpx-based) does not expose body kwargs on the
delete() convenience method; client.request(\"DELETE\", ..., json=...) is
the correct approach. Also switch datetime.utcnow() to
datetime.now(timezone.utc) to silence Python 3.13 deprecation warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch content= to data= for DELETE requests (Starlette TestClient is
requests-based and does not accept content= keyword argument)
- Fix test_bumps_updated_at to record time before the API call and use >=
comparison, avoiding false failures when MariaDB truncates DATETIME to
whole seconds and creation/update land in the same second
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace client.delete(json=...) with content=json.dumps()+Content-Type header
(Starlette TestClient does not forward json= on DELETE requests)
- Adjust duplicate-name test to expect HTTP 500 matching CollectionAlreadyExistsException
- Add description="" to collections created without it to satisfy Pydantic schema
- Strip tzinfo before comparing updated_at to avoid offset-naive/aware TypeError
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>