2026-07-16 01:47:11 +00:00
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2026-07-16 02:29:11 +00:00
|
|
|
func Upload(w http.ResponseWriter, r *http.Request) {
|
2026-07-16 01:47:11 +00:00
|
|
|
if r.Method != http.MethodPost {
|
|
|
|
|
writeErr(w, 405, "Method not allowed")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := r.ParseMultipartForm(20 << 20); err != nil {
|
|
|
|
|
writeErr(w, 400, "image too large (max 20MB)")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
file, _, err := r.FormFile("image")
|
|
|
|
|
if err != nil {
|
|
|
|
|
writeErr(w, 400, "missing image file")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
data, err := io.ReadAll(file)
|
|
|
|
|
if err != nil || len(data) == 0 {
|
|
|
|
|
writeErr(w, 400, "failed to read image")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ct := http.DetectContentType(data)
|
|
|
|
|
if !strings.HasPrefix(ct, "image/") {
|
|
|
|
|
writeErr(w, 400, "file is not an image")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hash := sha256.Sum256(data)
|
|
|
|
|
name := hex.EncodeToString(hash[:])[:16] + "_" + fmt.Sprintf("%d", time.Now().UnixNano())
|
|
|
|
|
dir := "static/images"
|
|
|
|
|
os.MkdirAll(dir, 0755)
|
|
|
|
|
|
|
|
|
|
// Determine extension from content type
|
|
|
|
|
ext := ".jpg"
|
|
|
|
|
switch {
|
|
|
|
|
case strings.Contains(ct, "png"):
|
|
|
|
|
ext = ".png"
|
|
|
|
|
case strings.Contains(ct, "webp"):
|
|
|
|
|
ext = ".webp"
|
|
|
|
|
case strings.Contains(ct, "gif"):
|
|
|
|
|
ext = ".gif"
|
|
|
|
|
case strings.Contains(ct, "svg"):
|
|
|
|
|
ext = ".svg"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
filePath := filepath.Join(dir, name+ext)
|
|
|
|
|
if err := os.WriteFile(filePath, data, 0644); err != nil {
|
|
|
|
|
writeErr(w, 500, "failed to save image")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
url := "/static/images/" + name + ext
|
|
|
|
|
writeJSON(w, 200, map[string]string{"url": url, "filename": name + ext})
|
|
|
|
|
}
|