c53bcb6c99
POST /api/admin/cover-sources/research bumps cover_art_sources_meta. current_version unconditionally; the next enrichment pass re-eligibles every 'none' row. Existing positively-sourced rows are not affected — the version-mismatch eligibility rule only kicks in for 'none'. Admin Cover Art panel gains a "Re-search missing art" button that calls the endpoint and shows a confirmation toast. Operator's escape hatch when: - They've added a Last.fm key and want to retry failed rows immediately rather than waiting for the next scheduled scan. - An upstream provider's catalog has updated (e.g. Deezer added a back-catalog import). - They want to verify a fix end-to-end before the next scheduled scan fires. SettingsService.BumpVersion (the unconditional version of T5's BumpVersionIfProvidersChanged) is the single-call DB writer; both endpoints route through it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
75 lines
2.1 KiB
Go
75 lines
2.1 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/auth"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/coverart"
|
|
)
|
|
|
|
func newResearchRouter(h *handlers) chi.Router {
|
|
r := chi.NewRouter()
|
|
r.Route("/api/admin", func(admin chi.Router) {
|
|
admin.Use(auth.RequireAdmin())
|
|
admin.Post("/cover-sources/research", h.handleResearchMissingArt)
|
|
})
|
|
return r
|
|
}
|
|
|
|
func TestAdminResearchMissingArt_BumpsAndReturnsVersion(t *testing.T) {
|
|
if os.Getenv("MINSTREL_TEST_DATABASE_URL") == "" {
|
|
t.Skip("MINSTREL_TEST_DATABASE_URL not set")
|
|
}
|
|
coverart.ResetRegistryForTests()
|
|
t.Cleanup(coverart.ResetRegistryForTests)
|
|
|
|
coverart.Register(&apiTestAlbumProvider{id: "research-prov", display: "Research Provider"})
|
|
|
|
h, _ := testHandlersWithCoverSettings(t)
|
|
admin := seedUser(t, h.pool, "researchadmin", "pw", true)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/admin/cover-sources/research", nil)
|
|
req = withUser(req, admin)
|
|
rec := httptest.NewRecorder()
|
|
newResearchRouter(h).ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200; body=%s", rec.Code, rec.Body.String())
|
|
}
|
|
var resp map[string]any
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("decode: %v", err)
|
|
}
|
|
if _, ok := resp["version"]; !ok {
|
|
t.Errorf("response missing 'version' field; got %v", resp)
|
|
}
|
|
}
|
|
|
|
func TestAdminResearchMissingArt_NonAdmin_403(t *testing.T) {
|
|
if os.Getenv("MINSTREL_TEST_DATABASE_URL") == "" {
|
|
t.Skip("MINSTREL_TEST_DATABASE_URL not set")
|
|
}
|
|
coverart.ResetRegistryForTests()
|
|
t.Cleanup(coverart.ResetRegistryForTests)
|
|
|
|
coverart.Register(&apiTestAlbumProvider{id: "research-prov2", display: "Research Provider 2"})
|
|
|
|
h, _ := testHandlersWithCoverSettings(t)
|
|
user := seedUser(t, h.pool, "researchnonadmin", "pw", false)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/admin/cover-sources/research", nil)
|
|
req = withUser(req, user)
|
|
rec := httptest.NewRecorder()
|
|
newResearchRouter(h).ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusForbidden {
|
|
t.Errorf("status = %d, want 403", rec.Code)
|
|
}
|
|
}
|