Files
silo-server/internal/api/handlers/sections_preview.go

91 lines
2.8 KiB
Go

package handlers
import (
"context"
"encoding/json"
"net/http"
apimw "github.com/Silo-Server/silo-server/internal/api/middleware"
"github.com/Silo-Server/silo-server/internal/catalog"
"github.com/Silo-Server/silo-server/internal/models"
"github.com/Silo-Server/silo-server/internal/sections"
"github.com/Silo-Server/silo-server/internal/sections/recipes"
)
// sectionPreviewFetcher is the minimal interface needed by HandlePreview.
// *sections.Fetcher satisfies this interface.
type sectionPreviewFetcher interface {
FetchOne(ctx context.Context, resolved sections.ResolvedSection, libraryID *int, libraryIDs []int, userID int, profileID string, filter catalog.AccessFilter) (sections.SectionWithItems, error)
}
// previewRequest is the request body for POST /api/admin/sections/preview.
type previewRequest struct {
SectionType string `json:"section_type"`
Config json.RawMessage `json:"config"`
ItemLimit int `json:"item_limit"`
LibraryID *int `json:"library_id,omitempty"`
LibraryIDs []int `json:"library_ids,omitempty"`
}
// previewResponse is the response body for POST /api/admin/sections/preview.
type previewResponse struct {
Items []*models.MediaItem `json:"items"`
TotalCount int `json:"total_count"`
}
// HandlePreview is POST /api/admin/sections/preview. Returns a sample of items without persisting.
func (h *SectionHandler) HandlePreview(w http.ResponseWriter, r *http.Request) {
var req previewRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "bad_json", err.Error())
return
}
rec, ok := recipes.Get(req.SectionType)
if !ok {
writeError(w, http.StatusBadRequest, "unknown_type", "section_type not registered")
return
}
if err := rec.Validate(req.Config); err != nil {
writeError(w, http.StatusBadRequest, "invalid_config", err.Error())
return
}
limit := req.ItemLimit
if limit <= 0 || limit > 50 {
limit = 10
}
resolved := sections.ResolvedSection{
SectionType: sections.SectionType(req.SectionType),
Title: "preview",
ItemLimit: limit,
Config: req.Config,
}
fetcher := h.previewFetcher
if fetcher == nil {
fetcher = h.fetcher
}
if fetcher == nil {
writeError(w, http.StatusInternalServerError, "preview_unavailable", "section fetcher not configured")
return
}
userID := apimw.GetUserID(r.Context())
profileID := apimw.GetProfileID(r.Context())
filter := requestAccessFilter(r)
result, err := fetcher.FetchOne(r.Context(), resolved, req.LibraryID, req.LibraryIDs, userID, profileID, filter)
if err != nil {
writeError(w, http.StatusInternalServerError, "preview_failed", err.Error())
return
}
items := result.Items
if items == nil {
items = []*models.MediaItem{}
}
writeJSON(w, http.StatusOK, previewResponse{Items: items, TotalCount: result.TotalCount})
}