package handlers import ( "encoding/json" "net/http" "time" "github.com/google/uuid" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) type UploadHandler struct { minioClient *minio.Client bucket string endpoint string } func NewUploadHandler(endpoint, accessKey, secretKey, bucket string, useSSL bool) (*UploadHandler, error) { client, err := minio.New(endpoint, &minio.Options{ Creds: credentials.NewStaticV4(accessKey, secretKey, ""), Secure: useSSL, }) if err != nil { return nil, err } return &UploadHandler{ minioClient: client, bucket: bucket, endpoint: endpoint, }, nil } type presignedURLRequest struct { ContentType string `json:"content_type"` MaxSizeMB int `json:"max_size_mb"` } type presignedURLResponse struct { UploadURL string `json:"upload_url"` FileURL string `json:"file_url"` Fields map[string]string `json:"fields"` } func (h *UploadHandler) PresignedURL(w http.ResponseWriter, r *http.Request) { var req presignedURLRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if req.MaxSizeMB <= 0 || req.MaxSizeMB > 50 { req.MaxSizeMB = 10 } validContentTypes := map[string]bool{ "image/jpeg": true, "image/png": true, "image/webp": true, "image/heic": true, } if !validContentTypes[req.ContentType] { writeError(w, http.StatusBadRequest, "unsupported content type") return } fileID := uuid.New().String() ext := ".jpg" switch req.ContentType { case "image/png": ext = ".png" case "image/webp": ext = ".webp" case "image/heic": ext = ".heic" } objectName := "uploads/" + fileID + ext policy := minio.NewPostPolicy() policy.SetBucket(h.bucket) policy.SetKey(objectName) policy.SetExpires(time.Now().Add(15 * time.Minute)) policy.SetContentType(req.ContentType) policy.SetContentLengthRange(1, int64(req.MaxSizeMB)*1024*1024) url, formData, err := h.minioClient.PresignedPostPolicy(r.Context(), policy) if err != nil { writeError(w, http.StatusInternalServerError, "failed to generate upload URL") return } fileURL := "http://" + h.endpoint + "/" + h.bucket + "/" + objectName writeJSON(w, http.StatusOK, presignedURLResponse{ UploadURL: url.String(), FileURL: fileURL, Fields: formData, }) }