86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"Yimaru-Backend/internal/domain"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/google/uuid"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func (h *Handler) processAndSaveThumbnail(c *fiber.Ctx, subDir string) (string, error) {
|
|
fileHeader, err := c.FormFile("file")
|
|
if err != nil {
|
|
return "", c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Image file is required", Error: err.Error()})
|
|
}
|
|
if fileHeader.Size > 10*1024*1024 {
|
|
return "", c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "File too large", Error: "Thumbnail image must be <= 10MB"})
|
|
}
|
|
|
|
fh, err := fileHeader.Open()
|
|
if err != nil {
|
|
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to read file", Error: err.Error()})
|
|
}
|
|
defer fh.Close()
|
|
|
|
head := make([]byte, 512)
|
|
n, _ := fh.Read(head)
|
|
contentType := http.DetectContentType(head[:n])
|
|
if contentType != "image/jpeg" && contentType != "image/png" && contentType != "image/webp" {
|
|
return "", c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid file type", Error: "Only jpg, png and webp images are allowed"})
|
|
}
|
|
|
|
rest, err := io.ReadAll(fh)
|
|
if err != nil {
|
|
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to read file", Error: err.Error()})
|
|
}
|
|
data := append(head[:n], rest...)
|
|
|
|
if h.cloudConvertSvc != nil {
|
|
optimized, optErr := h.cloudConvertSvc.OptimizeImage(c.Context(), fileHeader.Filename, bytes.NewReader(data), int64(len(data)), 1200, 80)
|
|
if optErr != nil {
|
|
h.mongoLoggerSvc.Warn("CloudConvert thumbnail optimization failed, using original", zap.Error(optErr))
|
|
} else {
|
|
optimizedData, readErr := io.ReadAll(optimized.Data)
|
|
optimized.Data.Close()
|
|
if readErr == nil {
|
|
data = optimizedData
|
|
contentType = "image/webp"
|
|
}
|
|
}
|
|
}
|
|
|
|
if h.minioSvc != nil {
|
|
result, uploadErr := h.minioSvc.Upload(c.Context(), subDir, fileHeader.Filename, bytes.NewReader(data), int64(len(data)), contentType)
|
|
if uploadErr != nil {
|
|
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to upload file to storage", Error: uploadErr.Error()})
|
|
}
|
|
return "minio://" + result.ObjectKey, nil
|
|
}
|
|
|
|
ext := ".jpg"
|
|
if contentType == "image/png" {
|
|
ext = ".png"
|
|
}
|
|
if contentType == "image/webp" {
|
|
ext = ".webp"
|
|
}
|
|
dir := filepath.Join(".", "static", subDir)
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to create storage directory", Error: err.Error()})
|
|
}
|
|
filename := uuid.New().String() + ext
|
|
fullpath := filepath.Join(dir, filename)
|
|
if err := os.WriteFile(fullpath, data, 0o644); err != nil {
|
|
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to save file", Error: err.Error()})
|
|
}
|
|
return "/static/" + subDir + "/" + filename, nil
|
|
}
|
|
|