Files
tp/main_dc/yalarba/api_yal/internal/domain/upload/handler.go
T
valitovgaziz 90a96b4125 Migrate easysite from api_es to api_yal
- Remove api_es service, Dockerfile, all Go source files
- Remove api_es from docker-compose.yml, nginx-ssl.conf, .env, Makefile
- Replace nginx /api/ proxy with /api/v1/ → api_yal:8787
- Add amenity/upload domains, AuthResponse, GET /auth/me, GET /objects/my to api_yal
- Rewrite easysite frontend: types, composables, and all 5 pages to use api_yal DTOs
- Wire nuxt.config public.apiBase, add useObjects CRUD composable
- Update docs references from api_es to api_yal
2026-06-12 10:14:38 +05:00

151 lines
3.6 KiB
Go

package upload
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"time"
"api_yal/internal/logger"
"api_yal/internal/middleware"
"api_yal/internal/models"
"go.uber.org/zap"
"gorm.io/gorm"
)
type UploadHandler struct {
db *gorm.DB
uploadPath string
}
func NewHandler(db *gorm.DB, uploadPath string) *UploadHandler {
if err := os.MkdirAll(uploadPath, 0755); err != nil {
logger.Get().Warn("failed to create upload directory", zap.String("path", uploadPath), zap.Error(err))
}
return &UploadHandler{db: db, uploadPath: uploadPath}
}
func (h *UploadHandler) Upload(w http.ResponseWriter, r *http.Request) {
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
if err := r.ParseMultipartForm(32 << 20); err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, "File is required", http.StatusBadRequest)
return
}
defer file.Close()
objectIDStr := r.FormValue("object_id")
if objectIDStr == "" {
http.Error(w, "object_id is required", http.StatusBadRequest)
return
}
var objectID uint
if _, err := fmt.Sscan(objectIDStr, &objectID); err != nil {
http.Error(w, "Invalid object_id", http.StatusBadRequest)
return
}
ext := filepath.Ext(header.Filename)
filename := fmt.Sprintf("%d_%d%s", userID, time.Now().UnixNano(), ext)
filePath := filepath.Join(h.uploadPath, filename)
dst, err := os.Create(filePath)
if err != nil {
logger.Get().Error("failed to create file", zap.Error(err))
http.Error(w, "Failed to save file", http.StatusInternalServerError)
return
}
defer dst.Close()
if _, err := io.Copy(dst, file); err != nil {
logger.Get().Error("failed to write file", zap.Error(err))
http.Error(w, "Failed to save file", http.StatusInternalServerError)
return
}
isPrimary := false
if r.FormValue("is_primary") == "true" {
isPrimary = true
}
image := models.ObjectImage{
ObjectID: objectID,
URL: "/uploads/" + filename,
IsPrimary: isPrimary,
}
if err := h.db.Create(&image).Error; err != nil {
logger.Get().Error("failed to save image record", zap.Error(err))
http.Error(w, "Failed to save image", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]interface{}{
"id": image.ID,
"url": image.URL,
"object_id": image.ObjectID,
"is_primary": image.IsPrimary,
})
}
func (h *UploadHandler) DeleteImage(w http.ResponseWriter, r *http.Request) {
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
imageIDStr := r.URL.Query().Get("id")
if imageIDStr == "" {
http.Error(w, "id is required", http.StatusBadRequest)
return
}
var imageID uint
if _, err := fmt.Sscan(imageIDStr, &imageID); err != nil {
http.Error(w, "Invalid id", http.StatusBadRequest)
return
}
var image models.ObjectImage
if err := h.db.First(&image, imageID).Error; err != nil {
http.Error(w, "Image not found", http.StatusNotFound)
return
}
var object models.Object
if err := h.db.First(&object, image.ObjectID).Error; err != nil {
http.Error(w, "Object not found", http.StatusNotFound)
return
}
if object.OwnerID != userID {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
filePath := filepath.Join(h.uploadPath, filepath.Base(image.URL))
os.Remove(filePath)
h.db.Delete(&image)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"message": "Image deleted"})
}