package handlers import ( "fmt" "net/http" "os" "path/filepath" "strings" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type UploadHandler struct{} func NewUploadHandler() *UploadHandler { return &UploadHandler{} } func (h *UploadHandler) UploadImage(c *gin.Context) { file, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "No file uploaded"}) return } ext := strings.ToLower(filepath.Ext(file.Filename)) allowedExts := map[string]bool{".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true} if !allowedExts[ext] { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid file type. Only jpg, jpeg, png, gif, webp are allowed"}) return } uploadDir := "uploads/images" if err := os.MkdirAll(uploadDir, 0755); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create upload directory"}) return } filename := fmt.Sprintf("%s%s", uuid.New().String(), ext) filepath := filepath.Join(uploadDir, filename) if err := c.SaveUploadedFile(file, filepath); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"}) return } url := fmt.Sprintf("/uploads/images/%s", filename) c.JSON(http.StatusOK, gin.H{ "url": url, "filename": filename, }) } func (h *UploadHandler) UploadMultiple(c *gin.Context) { form, err := c.MultipartForm() if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "No files uploaded"}) return } files := form.File["files"] if len(files) == 0 { c.JSON(http.StatusBadRequest, gin.H{"error": "No files uploaded"}) return } uploadDir := "uploads/images" if err := os.MkdirAll(uploadDir, 0755); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create upload directory"}) return } allowedExts := map[string]bool{".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true} var urls []string for _, file := range files { ext := strings.ToLower(filepath.Ext(file.Filename)) if !allowedExts[ext] { continue } filename := fmt.Sprintf("%s%s", uuid.New().String(), ext) filepath := filepath.Join(uploadDir, filename) if err := c.SaveUploadedFile(file, filepath); err != nil { continue } urls = append(urls, fmt.Sprintf("/uploads/images/%s", filename)) } c.JSON(http.StatusOK, gin.H{ "urls": urls, }) } func (h *UploadHandler) DeleteImage(c *gin.Context) { filename := c.Param("filename") if filename == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "Filename is required"}) return } if strings.Contains(filename, "..") || strings.Contains(filename, "/") || strings.Contains(filename, "\\") { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid filename"}) return } filePath := filepath.Join("uploads/images", filename) filePath, err := filepath.Abs(filePath) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid file path"}) return } absUploadDir, _ := filepath.Abs("uploads/images") if !strings.HasPrefix(filePath, absUploadDir) { c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"}) return } if _, err := os.Stat(filePath); os.IsNotExist(err) { c.JSON(http.StatusNotFound, gin.H{"error": "File not found"}) return } if err := os.Remove(filePath); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete file"}) return } c.JSON(http.StatusOK, gin.H{"message": "File deleted successfully"}) }