package routes import ( "errors" "log/slog" "orbits-server/internal/server/api/assets" "orbits-server/internal/server/bootstrap" "orbits-server/internal/server/service" "path/filepath" "github.com/gin-gonic/gin" "gorm.io/gorm" ) func RegisterFileRoutes(file *gin.RouterGroup, env bootstrap.Environment, db *gorm.DB) { fileService := service.NewFileService(db, env) // prefix: file // for example: /file/ // file download route / display contents file.GET("/:fileName", func(c *gin.Context) { fileParam := c.Param("fileName") fp := filepath.Join(env.ContentDirectory, fileParam) assets.FileDownloadResponse(c, fp) }) // upload route file.POST("/upload", func(c *gin.Context) { fileHeader, err := c.FormFile("file") if err != nil { slog.Debug("no file or file headers provided on the request", "error", err) assets.BadRequestResponse(c) return } stream, err := fileHeader.Open() if err != nil { slog.Error("failed to a reader stream") assets.InternalErrorResponse(c) return } defer stream.Close() fileResponse, err := fileService.Create(stream, fileHeader.Filename) if err != nil { slog.Error("failed to enroll file to the database", "error", err) if errors.Is(err, gorm.ErrDuplicatedKey) { assets.DuplicateResponse(c) return } assets.InternalErrorResponse(c) return } // save to filesystem after everything has given a green light if err := c.SaveUploadedFile(fileHeader, fileResponse.FilePath); err != nil { slog.Error("failed to save to disk, rolling back database", "error", err) // rollback db if the write has failed fileService.DeleteRecordByID(fileResponse.ID) // give the response to the client assets.InternalErrorResponse(c) return } slog.Info("saved file to local filesystem and database") assets.CreationResponse(c, fileResponse) }) // delete route file.DELETE("/:filename", func(c *gin.Context) { fileParam := c.Param("filename") if err := fileService.DeleteByName(fileParam); err != nil { slog.Error("file not found", "error", err) assets.NotFoundResponse(c) return } slog.Info("received a delete request for a file", "fileName", fileParam) assets.DeletionResponse(c) }) // define a route to check what is registered file.GET("/list", func(c *gin.Context) { files, err := fileService.ListFiles() if err != nil { slog.Error("failed to retrieve available files", "error", err) assets.InternalErrorResponse(c) return } assets.BasicResponse(c, files) }) }