feat: add refresh and delete artist endpoints (sections 1.2, 1.3)

- Add POST /api/artists/{id}/refresh to re-fetch metadata from gRPC service
- Add DELETE /api/artists/{id} with cascade delete via PostgreSQL
- Add e2e tests for both flows covering happy path, not found, idempotency
- Extend testutil with GetArtistUpdatedAt, CountAlbumsByArtist, DELETE helper
This commit is contained in:
Alexander
2026-04-29 13:08:53 +02:00
parent 25deaf4621
commit b08a0b1646
7 changed files with 717 additions and 0 deletions
+54
View File
@@ -269,6 +269,60 @@ func (h *Handlers) LibraryStats(w http.ResponseWriter, r *http.Request) {
})
}
func (h *Handlers) RefreshArtist(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
artistID := chi.URLParam(r, "id")
if artistID == "" {
writeError(w, http.StatusBadRequest, "artist ID required")
return
}
result, err := services.RefreshArtist(r.Context(), artistID, h.MetadataClient, h.DB)
if err != nil {
if _, ok := err.(*services.NotFoundError); ok {
writeError(w, http.StatusNotFound, err.Error())
return
}
writeError(w, http.StatusInternalServerError, err.Error())
return
}
writeJSON(w, http.StatusOK, result)
}
func (h *Handlers) DeleteArtist(w http.ResponseWriter, r *http.Request) {
if h.DB == nil {
writeError(w, http.StatusServiceUnavailable, "database not connected")
return
}
artistID := chi.URLParam(r, "id")
if artistID == "" {
writeError(w, http.StatusBadRequest, "artist ID required")
return
}
deleted, err := h.DB.DeleteArtistByForeignID(r.Context(), artistID)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if !deleted {
writeError(w, http.StatusNotFound, "artist not found: "+artistID)
return
}
writeJSON(w, http.StatusOK, map[string]any{
"deleted": true,
"message": "artist and related data deleted",
})
}
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)