5 Commits

Author SHA1 Message Date
bvandeusen c81491164a refactor(server/api/test): withUser helper; migrate 51 context-value sites (A3) 2026-05-08 10:40:03 -04:00
bvandeusen 0a1e76564d feat(server/m7-352): 403 system_playlist_readonly on playlist edit endpoints
Push kind='system' guard into each of the five Service edit methods
(Update, Delete, AppendTracks, RemoveTrack, Reorder) immediately after
the ownership check; map the typed error to 403 in writePlaylistErr;
add table-driven test covering all five verbs against a seeded system
playlist.
2026-05-04 09:29:37 -04:00
bvandeusen a90ff11f0f feat(server/m7-352): kind filter on GET /api/playlists + lazy fallback
Adds ?kind= filter (user|system|all, default user) to GET /api/playlists
so system mixes don't leak into slice-1 SPA views. Lazy background build
fires when kind=system|all and the caller's run row is stale (>24h).
Propagates Kind/SystemVariant/SeedArtistID through PlaylistRow and
playlistRowView wire types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 09:24:27 -04:00
bvandeusen a8fd33d4ed chore(lint): clear pre-existing CI lint debt
Nine golangci-lint failures accumulated across M7 #352, #372, and
6d1709c that were never surfaced because test-go never ran green long
enough to reach the lint step. The first push to land cleanly through
vet (the M7 #363 slice) ran lint and exposed them.

- errcheck: discard the error on defer Close() in collage.go,
  collage_test.go, and server_test.go.
- gofmt -s: re-run on config.go and playlists_test.go.
- goimports: move the stray "time" import from the local-module group
  to stdlib in server_test.go.
- revive unused-parameter: rename ctx to _ on stubScanner.Scan and
  fakeLidarrUnmonitorer.UnmonitorTrack (test stubs); on
  tracks.Service's adminID, add //nolint:revive directive rather than
  renaming because the HTTP handler passes admin.ID (a real authed-user
  UUID) and the existing comment already flags it as reserved for the
  audit-log follow-up.
2026-05-03 18:59:58 -04:00
bvandeusen c331168d3b feat(api): /api/playlists* handlers for M7 #352 slice 1
9 handlers covering create / get / list / update / delete / append /
remove / reorder / cover. Permissions enforced in the service layer
(ErrForbidden -> 403 not_authorized) so the handler is a thin
HTTP-shape adapter. /cover serves the cached collage from disk via
http.ServeFile; 404 when cover_path is nil.

Server gained a DataDir field so the playlists service can find the
collage cache; api.Mount picks up two new params (playlistsSvc and
dataDir). The stale TestRoutesRegisteredInMount Mount() call in
library_test.go was missing the tracks.Service argument added by an
earlier slice — fixed in passing.

Wire codes follow the project's existing nested errorBody envelope:
not_found, not_authorized, unauthenticated, bad_request, server_error.
The plan called for a flat envelope, but the api package's writeErr
already produces {"error":{"code":"...","message":"..."}} and
deviating here would break every existing client.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 11:10:21 -04:00