| Age | Commit message (Collapse) | Author |
|
Existing databases created before the finished column was added to the
base schema still satisfied CREATE TABLE IF NOT EXISTS and never got the
column, causing GET /api/v1/media/{id} to fail with
"SQL logic error: no such column: finished" and break media detail view.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- escapeLike() helper in repository/media.go for LIKE search safety
- ErrWeakPassword sentinel in service.go (min 8 chars, HTTP 400)
- CreateUser rejects empty/short passwords in service/user.go
- ErrWeakPassword auto-dispatched via HTTPStatuser (no switch needed)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
Several per-service Store interfaces declared the same four-repo
block (UserRepo + SetRepo + SetPermissionRepo + MediaRepo) verbatim.
Extract that into a CoreStore interface and have MediaServiceStore,
AdminServiceStore, AccessHelperStore, BrowseServiceStore, and
WriteServiceStore embed it. Repository structurally still satisfies
every interface; tests unaffected.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
1. tagService.AssignTag and RemoveTag now use verifyModifyAccess
(owner role required) instead of verifyAccess. Tags are global
state visible to every user with access to a media item, so a
viewer must not be able to add or remove them. Favorites and
notes stay on verifyAccess because they're per-user data
(favorites.user_id, media_notes.user_id) and don't affect anyone
else. Verified via curl: viewer POST /media/{id}/tags now 403,
admin still 200.
2. serveFileResult now emits a strong ETag header
("<size>-<mtime-nanos>") before calling http.ServeContent. Go's
ServeContent honours If-None-Match when ETag is set, so iOS
audio clients and podcast apps can revalidate cached downloads
with conditional GETs. Verified via curl: ETag present on
/stream; If-None-Match matching the ETag returns 304.
3. MediaFilter gains IncludeDeleted flag; ListMedia skips the
implicit `deleted_at IS NULL` predicate when it is set.
FSScanner.loadExistingMedia now passes IncludeDeleted=true so
the dedup map includes soft-deleted rows. Previously a re-scan
of a soft-deleted file tried to CreateMedia and hit the
UNIQUE(set_id, rel_path) constraint, failing the whole scan and
setting progress.last_error. Now the rescan skips the row
cleanly; soft-delete sticks.
4. FSScanner.reconcileOrphans soft-deletes media rows whose
underlying file disappeared between scans. The scanner used to
only walk files that exist and never compare against the DB,
leaving phantom rows in GET /api/v1/media that 404'd on stream.
Verified via curl: rm /testdata/.../orphan.mp3, rescan, row
now has deleted_at != NULL.
Scenarios updated to lock in the fixed behaviour:
S19 step 15 — viewer tag-add now asserts 403, not 200.
S20 step 14 — asserts ETag is present and If-None-Match → 304.
S24 step 13 — asserts clean rescan (no last_error from UNIQUE).
S24 step 20 — asserts orphan rows are soft-deleted by rescan.
Verified: full Go unit suite passes; 25/25 LLM e2e scenarios;
22/22 Playwright e2e-web.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|