package handlers import ( "crypto/rand" "encoding/hex" "net/http" "os" "path/filepath" "strings" "github.com/gin-gonic/gin" ) var allowedExtensions = map[string]bool{ ".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true, ".mp4": true, ".webm": true, ".mp3": true, ".ogg": true, ".pdf": true, ".txt": true, } func (store *Store) UploadMessageFile(ctx *gin.Context) { file, err := ctx.FormFile("file") if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": "file is required"}) return } const maxSize = 10 << 20 // 10MB if file.Size > maxSize { ctx.JSON(http.StatusBadRequest, gin.H{"error": "file too large"}) return } ext := strings.ToLower(filepath.Ext(file.Filename)) if !allowedExtensions[ext] { ctx.JSON(http.StatusBadRequest, gin.H{"error": "file type not allowed"}) return } b := make([]byte, 16) if _, err := rand.Read(b); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate filename"}) return } filename := hex.EncodeToString(b) + ext uploadDir := "/backend/uploads" if err := os.MkdirAll(uploadDir, 0755); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create upload directory"}) return } // Ensure directory is world-readable so nginx can serve files if err := os.Chmod(uploadDir, 0755); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create upload directory"}) return } dest := filepath.Join(uploadDir, filename) if err := ctx.SaveUploadedFile(file, dest); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save file"}) return } if err := os.Chmod(dest, 0644); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to set file permissions"}) return } ctx.JSON(http.StatusOK, gin.H{"url": "/uploads/" + filename}) }