package routes import ( "encoding/base64" "os" "path/filepath" "strings" "time" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "stereo.cat/backend/internal/auth" "stereo.cat/backend/internal/types" ) func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { api.POST("/upload", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) { claims := c.MustGet("claims").(jwt.MapClaims) user := claims["user"].(auth.User) uid := user.ID if uid == "" { c.JSON(401, gin.H{"error": "unauthorized"}) return } file, err := c.FormFile("file") if err != nil { c.JSON(400, gin.H{"error": "file is required"}) return } filePath := filepath.Join(cfg.ImagePath, uid, file.Filename) if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { c.JSON(500, gin.H{"error": "failed to create directory"}) return } if err := c.SaveUploadedFile(file, filePath); err != nil { c.JSON(500, gin.H{"error": "failed to save file"}) return } b64, err := convertToBase64(filePath) if err != nil { } fileMeta := types.File{ ID: uid + "_" + file.Filename, Path: filePath, Owner: uid, CreatedAt: time.Now(), Base64: b64, } if err := cfg.Database.Create(&fileMeta).Error; err != nil { c.JSON(500, gin.H{"error": "failed to save file metadata"}) return } c.JSON(200, gin.H{"message": "file uploaded successfully", "file_id": fileMeta.ID}) }) api.DELETE("/delete", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) { claims := c.MustGet("claims").(jwt.MapClaims) user := claims["user"].(auth.User) uid := user.ID if uid == "" { c.JSON(401, gin.H{"error": "unauthorized"}) return } var response struct { FileID string `json:"file_id" binding:"required"` } if err := c.ShouldBindJSON(&response); err != nil { c.JSON(400, gin.H{"error": "file_id is required"}) return } resfID := response.FileID if resfID == "" { c.JSON(400, gin.H{"error": "file_id cannot be empty"}) return } parts := strings.SplitN(resfID, "_", 2) if len(parts) != 2 { c.JSON(400, gin.H{"error": "invalid file_id format"}) return } fileID, filename := parts[0], parts[1] if fileID != uid { c.JSON(403, gin.H{"error": "you can only delete your own files"}) return } filePath := filepath.Join(cfg.ImagePath, uid, filename) if err := os.Remove(filePath); err != nil { c.JSON(500, gin.H{"error": "failed to delete file"}) return } if err := cfg.Database.Where("id = ?", resfID).Delete(&types.File{}).Error; err != nil { c.JSON(500, gin.H{"error": "failed to delete file metadata"}) return } c.JSON(200, gin.H{"message": "file deleted successfully"}) }) api.GET("/:name", func(c *gin.Context) { name := c.Param("name") parts := strings.SplitN(name, "_", 2) if len(parts) != 2 { c.JSON(400, gin.H{"error": "invalid file name"}) return } uid, filename := parts[0], parts[1] path := filepath.Join(cfg.ImagePath, uid, filename) if _, err := os.Stat(path); err != nil { c.JSON(404, gin.H{"error": "file not found"}) return } c.File(path) }) api.GET("/list", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) { claims := c.MustGet("claims").(jwt.MapClaims) user := claims["user"].(auth.User) var files []types.File if err := cfg.Database.Where("owner = ?", user.ID).Find(&files).Error; err != nil { c.JSON(500, gin.H{"error": "failed to retrieve files"}) return } c.JSON(200, files) }) } func convertToBase64(filePath string) (string, error) { file, err := os.ReadFile(filePath) if err != nil { return "", err } b64 := base64.StdEncoding.EncodeToString(file) return b64, nil }