package donat import ( "context" "donat-widget/internal/model" _ "donat-widget/internal/model/api" "donat-widget/pkg/custom_response" "donat-widget/pkg/validator" "github.com/labstack/echo/v4" "log/slog" "mime/multipart" "net/http" "strconv" ) // CreateDonat godoc // @Summary Create donat // @Description Create donat // @Tags Donate // @Accept json // @Produce json // @Param streamer-login path string true "Login стримера" // @Param request body model.CreateDonatBody true "Create donat body json" // @Success 200 {object} model.CreateDonatResponse "Donat page updated successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /donat/{streamer-login} [post] func CreateDonat(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.CreateDonatBody err := validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } streamerLogin := request.Param("streamer-login") order, err := donatService.CreateDonat( ctx, streamerLogin, body.Text, body.DonatUser, body.TargetID, body.Amount, ) if err != nil { return request.JSON(http.StatusInternalServerError, err.Error()) } return request.JSON(http.StatusCreated, order) } } // GetDonat godoc // @Summary Get donats // @Description Получает список донатов для указанного стримера с пагинацией // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Param page query int false "Номер страницы (по умолчанию 1)" default(1) // @Param limit query int false "Количество элементов на странице (по умолчанию 10)" default(10) // @Success 200 {array} model.Donat "Успешный возврат списка донатов" // @Failure 400 {object} echo.HTTPError "Некорректный формат streamerID" // @Failure 500 {object} echo.HTTPError "Внутренняя ошибка сервера" // @Router /donat [get] func GetDonat(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() page, err := strconv.Atoi(request.QueryParam("page")) if page == 0 || err != nil { page = 1 } limit, err := strconv.Atoi(request.QueryParam("limit")) if limit == 0 || err != nil { limit = 20 } authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } if err != nil { slog.Error(err.Error()) return request.JSON(http.StatusInternalServerError, err.Error()) } donats, err := donatService.GetDonatsByStreamerID( ctx, authData.AccountID, page, limit, ) if err != nil { slog.Error(err.Error()) return request.JSON(http.StatusInternalServerError, err.Error()) } slog.Info("get donat successfully") return request.JSON(200, donats) } } // MarkDonatPaid godoc // @Summary Mark donat as paid // @Description Mark donat as paid // @Tags Donate // @Accept json // @Produce json // @Param request body model.MarkDonatPaidBody true "order id body" // @Success 200 {string} string "Ok" // @Failure 400 {object} echo.HTTPError "Некорректный формат streamerID" // @Failure 500 {object} echo.HTTPError "Внутренняя ошибка сервера" // @Router /donat/paid [post] func MarkDonatPaid(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.MarkDonatPaidBody err := validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } err = donatService.MarkDonatPaid(ctx, body.OrderID) if err != nil { slog.Error(err.Error()) return request.JSON(http.StatusInternalServerError, err.Error()) } slog.Info("mark donat paid successfully") return request.String(200, "Donat paid success") } } // MarkDonatView godoc // @Summary Mark donat as viewed // @Description Mark donat as viewed // @Tags Donate // @Accept json // @Produce json // @Param request body model.MarkDonatViewed true "order id body" // @Success 200 {string} string "Ok" // @Failure 500 {object} echo.HTTPError "Внутренняя ошибка сервера" // @Router /donat/viewed [post] func MarkDonatView(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.MarkDonatViewed err := validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } err = donatService.MarkDonatView( ctx, body.OrderID, ) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Interaction Error") } slog.Info("Donat viewed successfully") return request.JSON(http.StatusOK, "donat view success") } } // GetInnerDonatePage godoc // @Summary Get inner donate page info // @Description Get inner donate page info // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} model.InnerDonatePageResponse "Current donate page state" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /inner-donate-page [get] func GetInnerDonatePage(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } ctx := context.Background() var innerPage model.InnerDonatePageResponse accessToken := model.Token(request.Request().Header.Get("Authorization")) innerPage, err = donatService.GetInnerDonatPage(ctx, authData.AccountID, string(accessToken)) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } return request.JSON(http.StatusOK, innerPage) } } // GetOuterDonatePage godoc // @Summary Get outer donate page info // @Description Get outer donate page info // @Tags Donate // @Accept json // @Produce json // @Param streamer-login path string true "Login стримера" // @Success 200 {object} model.OuterDonatePageResponse "Current donate page state" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /outer-donate-page/{streamer-login} [get] func GetOuterDonatePage(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() streamerLogin := request.Param("streamer-login") outerPageResponse, err := donatService.GetOuterDonatPage( ctx, streamerLogin, ) if outerPageResponse.Login == "" { return echo.NewHTTPError(http.StatusNotFound, "Пользователь не найден!") } if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, custom_response.InternalError) } return request.JSON(http.StatusOK, outerPageResponse) } } // UpdateDonatePage godoc // @Summary Update personal streamer donate page // @Description Update personal streamer donate page with optional background and head image files. // @Tags Donate // @Consumes multipart/form-data // @Produces json // @Security BearerAuth // @Param metadata formData model.UpdateDonatPage false "Update fields" // @Param background formData file false "Background image" // @Param head_img formData file false "Head image" // @Param avatar formData file false "Avatar image" // @Success 200 {string} string "Donat page updated successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /donat-page [patch] func UpdateDonatePage(donatService model.DonatService, fileService model.FileService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.UpdateDonatPage err := validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } authData, err := donatService.CheckToken(request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnauthorized, custom_response.Unauthorized) } bgFile, err := request.FormFile("background") if err != nil { bgFile = &multipart.FileHeader{ Filename: "", Size: 0, Header: nil, } } headImgFile, err := request.FormFile("head_img") if err != nil { headImgFile = &multipart.FileHeader{ Filename: "", Size: 0, Header: nil, } } avatarFile, err := request.FormFile("avatar") if err != nil { avatarFile = &multipart.FileHeader{ Filename: "", Size: 0, Header: nil, } } err = donatService.UpdateDonatePage( ctx, authData.AccountID, body, *bgFile, *headImgFile, *avatarFile, ) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, custom_response.InternalError) } return request.JSON(http.StatusOK, "Success") } } // GetVoiceSettings godoc // @Summary Get donat voice settings // @Description Get donat voice settings // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} model.VoiceSettingsResponse "Current voice settings" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /voice-settings [get] func GetVoiceSettings(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } voiceSettings, err := donatService.GetVoiceSettings(ctx, authData.AccountID) if err != nil { slog.Error("Failed to get voice settings", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Internal server error") } // Возвращаем настройки голоса в JSON return request.JSON(http.StatusOK, voiceSettings) } } // UpdateVoiceSettings godoc // @Summary Update donat voice settings. // @Description Update donat voice settings. // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Param request body model.UpdateVoiceSettings true "Update fields" // @Success 200 {string} string "Voice settings updated successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /voice-settings [patch] func UpdateVoiceSettings(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } var body model.UpdateVoiceSettings err = validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } err = donatService.UpdateVoiceSettings(ctx, authData.AccountID, body) if err != nil { slog.Error("Failed to update voice settings", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update voice settings") } return request.JSON(http.StatusOK, "Voice settings updated successfully") } } // GetFiltersSettings godoc // @Summary Get donat filters settings // @Description Get donat filters settings // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} model.FilterSettingResponse "Current filters settings" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /filters-settings [get] func GetFiltersSettings(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } filtersSettings, err := donatService.GetFiltersSettings(ctx, authData.AccountID) if err != nil { slog.Error("Failed to get filters settings", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Internal server error") } return request.JSON(http.StatusOK, filtersSettings) } } // UpdateFiltersSettings godoc // @Summary Update donat filters settings. // @Description Update donat filters settings. // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Param request body model.UpdateFilterSettings true "Update fields" // @Success 200 {string} string "Voice settings updated successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /filters-settings [patch] func UpdateFiltersSettings(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.UpdateFilterSettings err := validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } err = donatService.UpdateFiltersSettings( ctx, authData.AccountID, body, ) return request.JSON(http.StatusOK, "Success update") } } // GetModerationSettings godoc // @Summary Get donat moderation settings // @Description Get donat moderation settings // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} model.ModerationResponse "Current moderation settings" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /moderation-settings [get] func GetModerationSettings(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } moderationSettings, err := donatService.GetModerationSettings(ctx, authData.AccountID) if err != nil { slog.Error("Failed to get moderation settings", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Internal server error") } return request.JSON(http.StatusOK, moderationSettings) } } // UpdateModerationSettings godoc // @Summary Update donat moderation settings // @Description Update donat moderation settings // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Param request body model.UpdateModeration true "Update fields" // @Success 200 {string} string "Moderation settings updated successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /moderation-settings [patch] func UpdateModerationSettings(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.UpdateModeration err := validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } err = donatService.UpdateModerationSettings( ctx, authData.AccountID, body, ) if err != nil { slog.Error("Failed to update moderation settings", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update moderation settings") } return request.JSON(http.StatusOK, "Success update") } } // GetDonationsStats godoc // @Summary Get donations statistics // @Description Get donations statistics for a given period // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Param period query string true "Period for statistics" Enums(24h, 7d, 1m, 1y) // @Success 200 {array} model.DonationSummaryResponse "Donations statistics" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /donat/period-stat [get] func GetDonationsStats(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } ctx := context.Background() period := request.QueryParam("period") if period == "" { return echo.NewHTTPError(http.StatusBadRequest, "period is required") } stats, err := donatService.GetDonationsStats(ctx, authData.AccountID, period) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } return request.JSON(http.StatusOK, stats) } } // GetDonateModeration godoc // @Summary Get the latest donation in moderation // @Description Get the latest donation with status 'moderation' sorted by updated_at // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} model.DonationModeration "Latest donation in moderation" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 404 {object} echo.HTTPError "No donations in moderation found" // @Failure 500 {object} echo.HTTPError "Internal server error" // @Router /donat-moderate/latest-moderation [get] func GetDonateModeration(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } ctx := context.Background() donation, err := donatService.GetDonatModeration(ctx, authData.AccountID) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } if donation.ID == 0 { // Если донат не найден return request.JSON(http.StatusOK, map[string]interface{}{}) } return request.JSON(http.StatusOK, donation) } } // ModerateDonat godoc // @Summary Update donat settings // @Description Update donat settings such as accepted, show_text, play_content, show_name // @Tags Donate // @Accept json // @Produce json // @Security BearerAuth // @Param donat-id path int true "ID доната" // @Param request body model.ModerationDonat true "Update fields" // @Success 200 {string} string "Donat settings updated successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /donat-moderate/{donat-id} [patch] func ModerateDonat(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() donatID, err := strconv.Atoi(request.Param("donat-id")) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Incorrect donat id") } var body model.ModerationDonat err = validator.ParseAndValidate(&body, request) if err != nil { slog.Error(err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") } authData, err := donatService.CheckToken(request) if err != nil { slog.Error("Unauthorized") return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } err = donatService.ModerateDonation( ctx, donatID, authData.AccountID, body, ) if err != nil { slog.Error("Failed to update donat settings", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update donat settings") } return request.JSON(http.StatusOK, "Donat settings updated successfully") } } // InitNewStreamer godoc // @Summary Initialize new streamer // @Description Creates initial records for new streamer in related tables // @Tags Donate // @Accept json // @Produce json // @Param request body model.InitNewStreamerBody true "Streamer initialization data" // @Success 200 {string} string "Streamer initialized successfully" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /init-streamer [post] func InitNewStreamer(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.InitNewStreamerBody if err := validator.ParseAndValidate(&body, request); err != nil { slog.Error("Validation error", "error", err) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Invalid request body") } if err := donatService.InitNewStreamer( ctx, body.StreamerID, body.Login, ); err != nil { slog.Error("Initialization failed", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Initialization failed") } return request.JSON(http.StatusCreated, "Streamer initialized successfully") } } // GetDonatForPlaying godoc // @Summary Initialize new streamer // @Description Creates initial records for new streamer in related tables // @Tags Donate // @Accept json // @Produce json // @Param streamer-id path string true "Login стримера" // @Success 200 {object} model.PlayingDonatResponse "Donat data" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 422 {object} echo.HTTPError "Validation error" // @Router /get-donat-for-playing/{streamer-id} [get] func GetDonatForPlaying(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() streamerLogin := request.Param("streamer-id") login, err := strconv.Atoi(streamerLogin) playingDonat, err := donatService.GetPlayingDonat(ctx, login) if err != nil { slog.Error("Failed to get playing donat", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get playing donat") } if playingDonat.OrderID == "" { return echo.NewHTTPError(http.StatusNotFound, "Not found active donat!") } return request.JSON(http.StatusOK, playingDonat) } } // UpdateLoginDonatePage godoc // @Summary Update streamer login // @Description Updates the streamer login associated with the donate page // @Tags Donate // @Accept json // @Produce json // @Param request body model.UpdateLoginBody true "Update data" // @Success 200 {object} string "Successfully updated streamer login" // @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 500 {object} echo.HTTPError "Internal server error" // @Router /update-login-donate [post] func UpdateLoginDonatePage(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() var body model.UpdateLoginBody if err := validator.ParseAndValidate(&body, request); err != nil { slog.Error("Validation error", "error", err) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Invalid request body") } err := donatService.UpdateStreamerLogin(ctx, body.Login, body.AccountID) if err != nil { slog.Error("Failed to update streamer login", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update streamer login") } return request.JSON(http.StatusOK, "Successfully updated streamer login") } }