|
|
@@ -3,6 +3,8 @@ package handlers
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "io"
|
|
|
"net/http"
|
|
|
"net/url"
|
|
|
"time"
|
|
|
@@ -12,6 +14,8 @@ import (
|
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
|
)
|
|
|
|
|
|
+const maxUploadSize = 10 << 20 // 10 MB
|
|
|
+
|
|
|
type UploadHandler struct {
|
|
|
minioClient *minio.Client
|
|
|
bucket string
|
|
|
@@ -47,6 +51,55 @@ type presignedURLResponse struct {
|
|
|
Fields map[string]string `json:"fields"`
|
|
|
}
|
|
|
|
|
|
+func (h *UploadHandler) UploadFile(w http.ResponseWriter, r *http.Request) {
|
|
|
+ r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
|
|
|
+ if err := r.ParseMultipartForm(maxUploadSize); err != nil {
|
|
|
+ writeError(w, http.StatusBadRequest, "file too large or invalid multipart", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ file, header, err := r.FormFile("file")
|
|
|
+ if err != nil {
|
|
|
+ writeError(w, http.StatusBadRequest, "file is required", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer file.Close()
|
|
|
+
|
|
|
+ contentType := header.Header.Get("Content-Type")
|
|
|
+ validContentTypes := map[string]bool{
|
|
|
+ "image/jpeg": true, "image/png": true, "image/webp": true, "image/heic": true,
|
|
|
+ }
|
|
|
+ if !validContentTypes[contentType] {
|
|
|
+ writeError(w, http.StatusBadRequest, "unsupported content type", nil)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ ext := ".jpg"
|
|
|
+ switch contentType {
|
|
|
+ case "image/png":
|
|
|
+ ext = ".png"
|
|
|
+ case "image/webp":
|
|
|
+ ext = ".webp"
|
|
|
+ case "image/heic":
|
|
|
+ ext = ".heic"
|
|
|
+ }
|
|
|
+ objectName := "uploads/" + uuid.New().String() + ext
|
|
|
+
|
|
|
+ _, err = h.minioClient.PutObject(r.Context(), h.bucket, objectName, file, header.Size,
|
|
|
+ minio.PutObjectOptions{ContentType: contentType},
|
|
|
+ )
|
|
|
+ if err != nil {
|
|
|
+ writeError(w, http.StatusInternalServerError, "failed to upload file", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ fileURL := fmt.Sprintf("%s/%s/%s", h.publicEndpoint, h.bucket, objectName)
|
|
|
+
|
|
|
+ writeJSON(w, http.StatusOK, map[string]string{
|
|
|
+ "file_url": fileURL,
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
func (h *UploadHandler) PresignedURL(w http.ResponseWriter, r *http.Request) {
|
|
|
var req presignedURLRequest
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|