feat(server/m7-recurring-scans): admin schedule HTTP handlers
Two new endpoints under existing RequireAdmin middleware: - GET /api/admin/scan/schedule — returns config + computed next_scheduled_at (ISO 8601; null when mode='off') - PATCH /api/admin/scan/schedule — validates per-mode required fields, normalizes mode='off' to NULL the per-mode fields, writes via UpdateScanSchedule, calls scheduler.Refresh(), returns the updated record. server.New + api.Mount gain a *library.Scheduler parameter; handlers struct + Server struct gain the scheduler field. Test stubs (server_test.go, library_test.go's Mount call) updated to pass nil. Tests gated on MINSTREL_TEST_DATABASE_URL: GET default is mode=off with null next; PATCH daily produces a 03:00 next-fire; PATCH weekly without weekly_day → 400; PATCH off normalizes lingering per-mode fields to NULL; non-admin → 403. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -26,7 +26,7 @@ import (
|
||||
// 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, lidarrReqs *lidarrrequests.Service, lidarrQuar *lidarrquarantine.Service, tracksSvc *tracks.Service, playlistsSvc *playlists.Service, coverEnricher *coverart.Enricher, coverBackfillCap int, coverSettings *coverart.SettingsService, scanner *library.Scanner, scanCfg library.RunScanConfig, dataDir string) {
|
||||
func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playevents.Writer, recCfg config.RecommendationConfig, lidarrCfg *lidarrconfig.Service, lidarrReqs *lidarrrequests.Service, lidarrQuar *lidarrquarantine.Service, tracksSvc *tracks.Service, playlistsSvc *playlists.Service, coverEnricher *coverart.Enricher, coverBackfillCap int, coverSettings *coverart.SettingsService, scanner *library.Scanner, scanCfg library.RunScanConfig, scheduler *library.Scheduler, dataDir string) {
|
||||
rng := rand.New(rand.NewSource(rand.Int63()))
|
||||
h := &handlers{
|
||||
pool: pool, logger: logger, events: events, recCfg: recCfg,
|
||||
@@ -41,6 +41,7 @@ func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playev
|
||||
coverSettings: coverSettings,
|
||||
scanner: scanner,
|
||||
scanCfg: scanCfg,
|
||||
scheduler: scheduler,
|
||||
dataDir: dataDir,
|
||||
}
|
||||
|
||||
@@ -115,6 +116,8 @@ func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playev
|
||||
|
||||
admin.Get("/scan/status", h.handleGetScanStatus)
|
||||
admin.Post("/scan/run", h.handleTriggerScan)
|
||||
admin.Get("/scan/schedule", h.handleGetScanSchedule)
|
||||
admin.Patch("/scan/schedule", h.handlePatchScanSchedule)
|
||||
|
||||
admin.Get("/library/coverage", h.handleGetLibraryCoverage)
|
||||
|
||||
@@ -152,5 +155,6 @@ type handlers struct {
|
||||
coverSettings *coverart.SettingsService
|
||||
scanner *library.Scanner
|
||||
scanCfg library.RunScanConfig
|
||||
scheduler *library.Scheduler
|
||||
dataDir string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user