feat(api): add /api/requests user-facing CRUD

Implements POST/GET/GET:id/DELETE /api/requests handlers delegating to
lidarrrequests.Service; wires routes in RequireUser group and threads
the service through Mount and server.go.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-29 17:40:49 -04:00
parent 9192eb9f0a
commit 03cbd4d0c1
6 changed files with 583 additions and 11 deletions
+15 -8
View File
@@ -14,15 +14,16 @@ import (
"git.fabledsword.com/bvandeusen/minstrel/internal/auth"
"git.fabledsword.com/bvandeusen/minstrel/internal/config"
"git.fabledsword.com/bvandeusen/minstrel/internal/lidarrconfig"
"git.fabledsword.com/bvandeusen/minstrel/internal/lidarrrequests"
"git.fabledsword.com/bvandeusen/minstrel/internal/playevents"
)
// Mount attaches /api/* handlers to r. Public endpoints (login) are outside
// RequireUser; everything else is gated by the middleware. The events writer
// is shared with the Subsonic mount so /rest/scrobble feeds the same store.
func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playevents.Writer, recCfg config.RecommendationConfig, lidarrCfg *lidarrconfig.Service) {
func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playevents.Writer, recCfg config.RecommendationConfig, lidarrCfg *lidarrconfig.Service, lidarrReqs *lidarrrequests.Service) {
rng := rand.New(rand.NewSource(rand.Int63()))
h := &handlers{pool: pool, logger: logger, events: events, recCfg: recCfg, rng: rng.Float64, lidarrCfg: lidarrCfg}
h := &handlers{pool: pool, logger: logger, events: events, recCfg: recCfg, rng: rng.Float64, lidarrCfg: lidarrCfg, lidarrRequests: lidarrReqs}
r.Route("/api", func(api chi.Router) {
api.Post("/auth/login", h.handleLogin)
@@ -54,15 +55,21 @@ func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playev
authed.Get("/likes/ids", h.handleGetLikedIDs)
authed.Get("/lidarr/search", h.handleLidarrSearch)
authed.Post("/requests", h.handleCreateRequest)
authed.Get("/requests", h.handleListRequests)
authed.Get("/requests/{id}", h.handleGetRequest)
authed.Delete("/requests/{id}", h.handleCancelRequest)
})
})
}
type handlers struct {
pool *pgxpool.Pool
logger *slog.Logger
events *playevents.Writer
recCfg config.RecommendationConfig
rng func() float64
lidarrCfg *lidarrconfig.Service
pool *pgxpool.Pool
logger *slog.Logger
events *playevents.Writer
recCfg config.RecommendationConfig
rng func() float64
lidarrCfg *lidarrconfig.Service
lidarrRequests *lidarrrequests.Service
}