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 }