package files import ( "context" "donat-widget/internal/model" "github.com/labstack/echo/v4" "log/slog" "net/http" ) // AddNewFile godoc // @Summary Add new File // @Description Add new File. The entity type defaults to 'widget' if not specified. // @Tags Files // @Accept multipart/form-data // @Produce json // @Security BearerAuth // @Param new_file formData file true "New file to upload" // @Param entity formData string false "Optional entity type (defaults to 'widget')" // @Success 200 {object} model.DataFile "File has been uploaded successfully!" // @Failure 400 {object} echo.HTTPError "Bad request (e.g., missing file, invalid form data)" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error (specific cases, might overlap with 400/500)" // @Failure 500 {object} echo.HTTPError "Internal server error (e.g., failed to save file, DB error)" // @Router /files [post] func AddNewFile(fileService model.FileService, donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() authData, err := fileService.CheckToken(request) if err != nil { slog.Error("Authentication failed", "error", err) return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized: "+err.Error()) } entity := request.FormValue("entity") if entity == "" { entity = "widget" slog.Info("Entity parameter not provided, defaulting to 'widget'") } newFile, err := request.FormFile("new_file") if err != nil { if err == http.ErrMissingFile { slog.Error("Missing 'new_file' in form data", "error", err) return echo.NewHTTPError(http.StatusBadRequest, "Required form field 'new_file' is missing") } slog.Error("Failed to get file from form", "error", err) return echo.NewHTTPError(http.StatusBadRequest, "Cannot process uploaded file: "+err.Error()) } fileId, err := fileService.AddNewFile( ctx, *newFile, authData.AccountID, entity, ) if err != nil { slog.Error("Failed to add new file via service", "entity", entity, "accountID", authData.AccountID, "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to save file: "+err.Error()) } slog.Info("File added successfully", "fileId", fileId, "entity", entity, "accountID", authData.AccountID) fileResponse, err := fileService.GetFileInfo(ctx, fileId) if entity == "avatar" { accessToken := request.Request().Header.Get("Authorization") err := donatService.UpdateAvatarStreamer(accessToken, fileResponse.ID.String()) if err != nil { slog.Error("Failed to update avatar streamer", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update avatar streamer") } } if err != nil { slog.Error("Failed to get file info after adding", "fileId", fileId, "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "File saved, but failed to retrieve info: "+err.Error()) } return request.JSON(http.StatusOK, fileResponse) } } // GetFile godoc // @Summary Get a file // @Description Retrieve a file by its ID // @Tags Files // @Accept json // @Produce octet-stream // @Param file_id path string true "File ID" format:"uuid" // @Success 200 {file} binary "File content" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 404 {object} echo.HTTPError "File not found" // @Router /files/{file_id} [get] func GetFile(fileService model.FileService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() fileID := request.Param("file_id") file, fileType, err := fileService.GetByID(ctx, fileID) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusNotFound, "File not found") } return request.Blob(http.StatusOK, fileType, file) } } // GetWidgetFiles godoc // @Summary Get all widget files // @Description Retrieve all widget files, filtered by type if specified // @Tags Files // @Accept json // @Produce json // @Security BearerAuth // @Param type query string false "File type (audio or image)" Enums(audio, image) // @Success 200 {array} model.DataFile "List of files" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Router /files/widgets [get] func GetWidgetFiles(fileService model.FileService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() fileType := request.QueryParam("type") if fileType != "" && fileType != "audio" && fileType != "image" { return echo.NewHTTPError(http.StatusUnprocessableEntity, "Invalid file type") } authData, err := fileService.CheckToken(request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } widgetFiles, err := fileService.WidgetsFiles( ctx, fileType, authData.AccountID, ) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to retrieve files") } return request.JSON(http.StatusOK, widgetFiles) } }