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:
@@ -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)
|
||||
|
||||
@@ -43,6 +43,11 @@ func NewRouter(h *Handlers) *chi.Mux {
|
||||
|
||||
r.Post("/sync", h.Sync)
|
||||
|
||||
r.Route("/artists", func(r chi.Router) {
|
||||
r.Post("/{id}/refresh", h.RefreshArtist)
|
||||
r.Delete("/{id}", h.DeleteArtist)
|
||||
})
|
||||
|
||||
r.Route("/library", func(r chi.Router) {
|
||||
r.Get("/artists", h.ListLibraryArtists)
|
||||
r.Get("/albums", h.ListLibraryAlbums)
|
||||
|
||||
Reference in New Issue
Block a user