- Auto-crop thumbnails on image upload (Go stdlib, no external deps): find non-background bounding box, pad 5px, scale to ≤300px, encode JPEG - Add thumbnail_data BYTEA column to fruit_images and publication_fruit_images - New GET /api/v1/fruits/:id/images/:imageId/thumbnail endpoint (fallback to full data) - New GET /api/v1/publications/:id/fruit-images/:imgId/thumbnail endpoint - New POST /api/v1/admin/backfill-thumbnails to retroactively generate thumbnails - ListFruits response now includes synonyms and thumbnail_url per fruit - Replace FruitList table with responsive FruitCard grid (thumbnail + name + OSDB ID + type + synonyms) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
45 lines
1.1 KiB
Go
45 lines
1.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
type FruitBackfiller interface {
|
|
BackfillThumbnails(ctx context.Context) (int, error)
|
|
}
|
|
|
|
type PubBackfiller interface {
|
|
BackfillThumbnails(ctx context.Context) (int, error)
|
|
}
|
|
|
|
type AdminHandler struct {
|
|
fruitRepo FruitBackfiller
|
|
pubRepo PubBackfiller
|
|
}
|
|
|
|
func NewAdminHandler(fruitRepo FruitBackfiller, pubRepo PubBackfiller) *AdminHandler {
|
|
return &AdminHandler{fruitRepo: fruitRepo, pubRepo: pubRepo}
|
|
}
|
|
|
|
func (h *AdminHandler) BackfillThumbnails(c echo.Context) error {
|
|
ctx := c.Request().Context()
|
|
|
|
fruitCount, err := h.fruitRepo.BackfillThumbnails(ctx)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "backfill failed: " + err.Error()})
|
|
}
|
|
|
|
pubCount, err := h.pubRepo.BackfillThumbnails(ctx)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "backfill failed: " + err.Error()})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, map[string]int{
|
|
"fruit_images_processed": fruitCount,
|
|
"pub_fruit_images_processed": pubCount,
|
|
})
|
|
}
|