nyanimedb/modules/backend/handlers/images.go
Iron_Felix 5acc53ec9d
All checks were successful
Build and Deploy Go App / build (push) Successful in 5m59s
Build and Deploy Go App / deploy (push) Successful in 37s
fix
2025-12-06 04:34:18 +03:00

141 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handlers
import (
"bytes"
"context"
"fmt"
"image"
"image/jpeg"
"image/png"
"io"
"net/http"
oapi "nyanimedb/api"
"os"
"path/filepath"
"strings"
"github.com/disintegration/imaging"
log "github.com/sirupsen/logrus"
"golang.org/x/image/webp"
)
// PostMediaUpload implements oapi.StrictServerInterface.
func (s *Server) PostMediaUpload(ctx context.Context, request oapi.PostMediaUploadRequestObject) (oapi.PostMediaUploadResponseObject, error) {
// Получаем multipart body
mp := request.MultipartBody
if mp == nil {
log.Errorf("PostMedia without body")
return oapi.PostMediaUpload400JSONResponse("Multipart body is required"), nil
}
// Парсим первую часть (предполагаем, что файл в поле "file")
part, err := mp.NextPart()
if err != nil {
log.Errorf("PostMedia without file")
return oapi.PostMediaUpload400JSONResponse("File required"), nil
}
defer part.Close()
// Читаем ВЕСЬ файл в память (для небольших изображений — нормально)
// Если файлы могут быть большими — используйте лимитированный буфер (см. ниже)
data, err := io.ReadAll(part)
if err != nil {
log.Errorf("PostMedia cannot read file")
return oapi.PostMediaUpload400JSONResponse("File required"), nil
}
if len(data) == 0 {
log.Errorf("PostMedia empty file")
return oapi.PostMediaUpload400JSONResponse("Empty file"), nil
}
// Проверка MIME по первым 512 байтам
mimeType := http.DetectContentType(data)
if mimeType != "image/jpeg" && mimeType != "image/png" && mimeType != "image/webp" {
log.Errorf("PostMedia bad type")
return oapi.PostMediaUpload400JSONResponse("Bad data type"), nil
}
// Декодируем изображение из буфера
var img image.Image
switch mimeType {
case "image/jpeg":
{
img, err = jpeg.Decode(bytes.NewReader(data))
if err != nil {
log.Errorf("PostMedia cannot decode file: %v", err)
return oapi.PostMediaUpload500Response{}, nil
}
}
case "image/png":
{
img, err = png.Decode(bytes.NewReader(data))
if err != nil {
log.Errorf("PostMedia cannot decode file: %v", err)
return oapi.PostMediaUpload500Response{}, nil
}
}
case "image/webp":
{
img, err = webp.Decode(bytes.NewReader(data))
if err != nil {
log.Errorf("PostMedia cannot decode file: %v", err)
return oapi.PostMediaUpload500Response{}, nil
}
}
}
var buf bytes.Buffer
err = imaging.Encode(&buf, img, imaging.PNG)
if err != nil {
log.Errorf("PostMedia failed to re-encode JPEG: %v", err)
return oapi.PostMediaUpload500Response{}, nil
}
// TODO: to delete
filename := part.FileName()
if filename == "" {
filename = "upload_" + generateRandomHex(8) + ".jpg"
} else {
filename = sanitizeFilename(filename)
if !strings.HasSuffix(strings.ToLower(filename), ".png") {
filename += ".png"
}
}
// TODO: пойти на хуй ( вызвать файловую помойку)
os.Mkdir("uploads", 0644)
err = os.WriteFile(filepath.Join("./uploads", filename), buf.Bytes(), 0644)
if err != nil {
log.Errorf("PostMedia failed to write: %v", err)
return oapi.PostMediaUpload500Response{}, nil
}
return oapi.PostMediaUpload200JSONResponse{}, nil
}
// Вспомогательные функции — как раньше
func generateRandomHex(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = byte('a' + (i % 16))
}
return fmt.Sprintf("%x", b)
}
func sanitizeFilename(name string) string {
var clean strings.Builder
for _, r := range name {
if (r >= 'a' && r <= 'z') ||
(r >= 'A' && r <= 'Z') ||
(r >= '0' && r <= '9') ||
r == '.' || r == '_' || r == '-' {
clean.WriteRune(r)
}
}
s := clean.String()
if s == "" {
return "file"
}
return s
}