2025-03-26 19:40:04 +05:00

604 lines
15 KiB
Go

package donat
import (
"context"
"donat-widget/internal/model"
"donat-widget/internal/model/api"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"log/slog"
"mime/multipart"
"net/http"
)
type ServiceDonat struct {
donatRepo model.DonatRepo
widgetRepo model.WidgetRepo
authClient model.AuthClient
paymentClient model.PaymentClient
fileRepo model.FileRepo
fileService model.FileService
storage model.Storage
defaultAvatar string
defaultBackground string
defaultHead string
}
func New(
donatRepo model.DonatRepo,
widgetRepo model.WidgetRepo,
paymentClient model.PaymentClient,
authClient model.AuthClient,
fileRepo model.FileRepo,
fileService model.FileService,
storage model.Storage,
) *ServiceDonat {
var defaultAvatar = "25b2b94c-e5e6-49e4-9f40-d8814f632847"
var defaultBackground = "56527f54-87c0-4f4d-92b5-df6cb61b27d4"
var defaultHead = "fef345e0-ec9a-4c68-8f2a-dcccf660e640"
return &ServiceDonat{
donatRepo: donatRepo,
widgetRepo: widgetRepo,
paymentClient: paymentClient,
authClient: authClient,
fileRepo: fileRepo,
fileService: fileService,
storage: storage,
defaultAvatar: defaultAvatar,
defaultBackground: defaultBackground,
defaultHead: defaultHead,
}
}
func (donatService *ServiceDonat) CheckToken(
request echo.Context,
) (api.CheckTokenResponse, error) {
accessToken := model.Token(request.Request().Header.Get("Authorization"))
checkTokenResponse, err := donatService.authClient.CheckToken(accessToken)
if err != nil {
slog.Error("Failed to check token", "error", err.Error())
return api.CheckTokenResponse{}, echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}
if checkTokenResponse.AccountID == 0 {
slog.Error("Unauthorized account")
return api.CheckTokenResponse{}, echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized account")
}
if checkTokenResponse.AccountID == -1 {
slog.Error("Expired token")
return api.CheckTokenResponse{}, echo.NewHTTPError(http.StatusUnauthorized, "Expired token")
}
return checkTokenResponse, nil
}
func (donatService *ServiceDonat) CreateDonat(
ctx context.Context,
streamerLogin string,
text string,
donatUser string,
targetID int,
amount int,
) (api.CreatePaymentResponse, error) {
donatePage, err := donatService.donatRepo.GetDonatPageByLogin(ctx, streamerLogin)
if err != nil {
slog.Error("Failed to get donate page", "error", err.Error())
return api.CreatePaymentResponse{}, err
}
widgets, err := donatService.widgetRepo.GetWidgetsByStreamerID(ctx, donatePage.StreamerID)
if err != nil {
slog.Error(err.Error())
return api.CreatePaymentResponse{}, err
}
orderID := uuid.New()
var widgetID int
for _, widget := range widgets {
if widget.MinAmount <= amount && widget.MaxAmount <= amount {
widgetID = widget.ID
}
}
err = donatService.donatRepo.CreateDonat(
ctx, donatePage.StreamerID, targetID, widgetID, orderID, amount, text, donatUser,
)
if err != nil {
slog.Error(err.Error())
return api.CreatePaymentResponse{}, err
}
createPaymentResponse, err := donatService.paymentClient.CreatePayment(donatePage.StreamerID, amount, orderID)
if err != nil {
slog.Error(err.Error())
return api.CreatePaymentResponse{}, err
}
return createPaymentResponse, err
}
func (donatService *ServiceDonat) GetDonatsByStreamerID(
ctx context.Context,
streamerID int,
page int,
limit int,
) ([]*model.Donat, error) {
donats, err := donatService.donatRepo.GetDonatsByStreamerID(
ctx,
streamerID,
page,
limit,
)
if len(donats) == 0 {
return []*model.Donat{}, nil
}
if err != nil {
slog.Error(err.Error())
return nil, err
}
return donats, nil
}
func (donatService *ServiceDonat) GetDonatByOrderID(
ctx context.Context,
orderID string,
) (*model.Donat, error) {
donat, err := donatService.donatRepo.GetDonatByOrderID(ctx, orderID)
if err != nil {
slog.Error(err.Error())
return nil, err
}
return donat, nil
}
func (donatService *ServiceDonat) MarkDonatPaid(
ctx context.Context,
orderID string,
) error {
err := donatService.donatRepo.MarkDonatPaid(
ctx,
orderID,
)
if err != nil {
slog.Error(err.Error())
return err
}
return nil
}
func (donatService *ServiceDonat) MarkDonatView(
ctx context.Context,
donatID int,
) error {
err := donatService.donatRepo.MarkDonatView(
ctx,
donatID,
)
if err != nil {
slog.Error("donatService.donatRepo.MarkDonatView: " + err.Error())
return err
}
return nil
}
func (donatService *ServiceDonat) GetInnerDonatPage(
ctx context.Context,
streamerID int,
) (model.InnerDonatePageResponse, error) {
// Получаем данные страницы доната из репозитория
donatePage, err := donatService.donatRepo.GetDonatPage(ctx, streamerID)
if err != nil {
slog.Error(err.Error())
return model.InnerDonatePageResponse{}, err
}
// Создаем объекты InnerFile для каждого изображения
headImgFile := model.InnerFile{
FileID: donatePage.HeadImgFileId,
FileName: donatePage.HeadImgFileName,
FileType: donatePage.HeadImgType,
FileLink: donatService.storage.DownloadLink(donatePage.HeadImgFileId),
FileSize: donatePage.HeadImgSize,
}
avatarFile := model.InnerFile{
FileID: donatePage.AvatarFileId,
FileName: donatePage.AvatarFileName,
FileType: donatePage.AvatarType,
FileLink: donatService.storage.DownloadLink(donatePage.AvatarFileId),
FileSize: donatePage.AvatarImgSize,
}
backgroundImgFile := model.InnerFile{
FileID: donatePage.BackgroundImgFileId,
FileName: donatePage.BackgroundImgFileName,
FileType: donatePage.BackgroundImgType,
FileLink: donatService.storage.DownloadLink(donatePage.BackgroundImgFileId),
FileSize: donatePage.BackgroundImgSize,
}
// Создаем объект InnerDonatePageResponse
innerDonatePageResponse := model.InnerDonatePageResponse{
Description: donatePage.Description,
TextAfterDonat: donatePage.TextAfterDonat,
HeadImg: headImgFile,
Avatar: avatarFile,
BackgroundImg: backgroundImgFile,
}
return innerDonatePageResponse, nil
}
func (donatService *ServiceDonat) GetOuterDonatPage(
ctx context.Context,
streamerLogin string,
) (model.OuterDonatePageResponse, error) {
donatePage, err := donatService.donatRepo.GetDonatPageByLogin(ctx, streamerLogin)
if err != nil {
slog.Error(err.Error())
return model.OuterDonatePageResponse{}, err
}
var outerDonatePageResponse = model.OuterDonatePageResponse{
Description: donatePage.Description,
Login: donatePage.StreamerLogin,
OnLine: "online",
BackgroundImg: donatService.storage.DownloadLink(donatePage.BackgroundImgFileId),
HeadImg: donatService.storage.DownloadLink(donatePage.HeadImgFileId),
AvatarImg: donatService.storage.DownloadLink(donatePage.AvatarFileId),
}
return outerDonatePageResponse, nil
}
func (donatService *ServiceDonat) UpdateDonatePage(
ctx context.Context,
streamerID int,
updateModel model.UpdateDonatPage,
background multipart.FileHeader,
headImg multipart.FileHeader,
) error {
var backgroundFileID *string
var headImgFileID *string
if background.Size > 0 {
fileID, err := donatService.fileService.AddNewFile(
ctx,
background,
streamerID,
"donat_page",
)
if err != nil {
slog.Error(err.Error())
return err
}
backgroundFileID = &fileID
}
if headImg.Size > 0 {
fileID, err := donatService.fileService.AddNewFile(
ctx,
headImg,
streamerID,
"donat_page",
)
if err != nil {
slog.Error(err.Error())
return err
}
headImgFileID = &fileID
}
err := donatService.donatRepo.UpdateDonatePage(
ctx,
streamerID,
backgroundFileID,
headImgFileID,
updateModel.Description,
updateModel.TextAfterDonat,
)
if err != nil {
slog.Error(err.Error())
return err
}
return nil
}
func (donatService *ServiceDonat) GetVoiceSettings(
ctx context.Context,
streamerID int,
) (model.VoiceSettingsResponse, error) {
voiceSettings, err := donatService.donatRepo.GetVoiceSettingsByStreamerID(ctx, streamerID)
if err != nil {
slog.Error("Failed to get voice settings", "error", err)
return model.VoiceSettingsResponse{}, err
}
languages, err := donatService.donatRepo.GetLanguagesByStreamerID(ctx, streamerID)
if err != nil {
slog.Error("Failed to get languages", "error", err)
return model.VoiceSettingsResponse{}, err
}
// Расширяем структуру VoiceSettingsResponse
response := model.VoiceSettingsResponse{
VoiceSpeed: voiceSettings.VoiceSpeed,
Scenery: voiceSettings.Scenery,
VoiceSoundPercent: voiceSettings.VoiceSoundPercent,
MinPrice: voiceSettings.MinPrice,
Enable: voiceSettings.Enable,
Languages: languages,
}
return response, nil
}
func (donatService *ServiceDonat) UpdateVoiceSettings(
ctx context.Context,
streamerID int,
updateModel model.UpdateVoiceSettings,
) error {
// Получаем voice_setting_id для streamerID
voiceSettingID, err := donatService.donatRepo.GetVoiceSettingIDByStreamerID(ctx, streamerID)
if err != nil {
slog.Error("Failed to get voice setting ID", "error", err)
return err
}
// Удаляем старые языки
err = donatService.donatRepo.DeleteLanguagesByVoiceSettingID(ctx, voiceSettingID)
if err != nil {
slog.Error("Failed to delete old languages", "error", err)
return err
}
// Получаем ID всех языков по их ISO-кодам
languageIDs, err := donatService.donatRepo.GetLanguageIDsByISOCodes(ctx, updateModel.Languages)
if err != nil {
slog.Error("Failed to get language IDs by ISO codes", "error", err)
return err
}
// Добавляем новые языки (пакетная вставка)
err = donatService.donatRepo.InsertLanguagesForVoiceSetting(ctx, voiceSettingID, languageIDs)
if err != nil {
slog.Error("Failed to insert new languages", "error", err)
return err
}
err = donatService.donatRepo.UpdateVoiceSettings(ctx, streamerID, updateModel)
if err != nil {
slog.Error("Failed to update voice settings", "error", err)
return err
}
return nil
}
func (donatService *ServiceDonat) GetFiltersSettings(
ctx context.Context,
streamerID int,
) (model.FilterSettingResponse, error) {
filterSettingID, enableLinks, err := donatService.donatRepo.GetFilterSettingsByStreamerID(ctx, streamerID)
if err != nil {
slog.Error("Failed to get filter settings", "error", err)
return model.FilterSettingResponse{}, err
}
filteredWords, err := donatService.donatRepo.GetFilteredWords(ctx, filterSettingID)
if err != nil {
slog.Error("Failed to get filtered words", "error", err)
return model.FilterSettingResponse{}, err
}
if filteredWords == nil {
filteredWords = []string{}
}
response := model.FilterSettingResponse{
EnableLinks: enableLinks,
FilteredWords: filteredWords,
}
return response, nil
}
func (donatService *ServiceDonat) UpdateFiltersSettings(
ctx context.Context,
streamerID int,
updateModel model.UpdateFilterSettings,
) error {
filterID, err := donatService.donatRepo.GetFilterIDByStreamer(ctx, streamerID)
if err != nil {
slog.Error("Failed to get filter ID", "error", err)
return err
}
if updateModel.EnableLinks != nil {
err = donatService.donatRepo.UpdateFilterSettings(ctx, streamerID, updateModel.EnableLinks)
if err != nil {
slog.Error("Failed to update filter settings", "error", err)
return err
}
}
if len(updateModel.AddWords) > 0 {
err = donatService.donatRepo.AddFilteredWords(ctx, filterID, updateModel.AddWords)
if err != nil {
slog.Error("Failed to add filtered words", "error", err)
return err
}
}
if len(updateModel.RemoveWords) > 0 {
slog.Info("Removing filtered words", "filterID", filterID)
err = donatService.donatRepo.RemoveFilteredWords(ctx, streamerID, updateModel.RemoveWords)
if err != nil {
slog.Error("Failed to remove filtered words", "error", err)
return err
}
}
return nil
}
func (donatService *ServiceDonat) GetModerationSettings(
ctx context.Context,
streamerID int,
) (model.ModerationResponse, error) {
moderationModel, err := donatService.donatRepo.GetModeration(
ctx,
streamerID,
)
if err != nil {
slog.Error("Failed to get moderation settings", "error", err)
return model.ModerationResponse{}, err
}
return moderationModel, nil
}
func (donatService *ServiceDonat) UpdateModerationSettings(
ctx context.Context,
streamerID int,
updateModel model.UpdateModeration,
) error {
err := donatService.donatRepo.UpdateModeration(
ctx,
streamerID,
updateModel.Enable,
updateModel.Duration,
)
if err != nil {
slog.Error("Failed to update moderation settings", "error", err)
return err
}
return nil
}
func (donatService *ServiceDonat) GetDonationsStats(
ctx context.Context,
streamerID int,
period string,
) (model.DonationSummaryResponse, error) {
stats, err := donatService.donatRepo.GetDonationsStats(ctx, streamerID, period)
if err != nil {
slog.Error(err.Error())
return model.DonationSummaryResponse{}, err
}
var donationsStat []model.DonationStatResponse
var response model.DonationSummaryResponse
donationSummary, err := donatService.donatRepo.GetDonationsSummary(
ctx,
streamerID,
period,
)
if err != nil {
slog.Error(err.Error())
return model.DonationSummaryResponse{}, err
}
response.DonationSum = donationSummary
for _, stat := range stats {
donationsStat = append(donationsStat, model.DonationStatResponse{
Date: stat.Date,
AmountCollected: stat.AmountCollected,
DonationsCount: stat.DonationsCount,
})
}
response.Donations = donationsStat
return response, nil
}
func (donatService *ServiceDonat) GetDonatModeration(
ctx context.Context,
streamerID int,
) (model.DonationModeration, error) {
donation, err := donatService.donatRepo.GetDonatModeration(ctx, streamerID)
if err != nil {
slog.Error("Failed to get latest donation in moderation", "error", err)
return model.DonationModeration{}, err
}
return donation, nil
}
func (donatService *ServiceDonat) ModerateDonation(
ctx context.Context,
donatID int,
streamerID int,
updateModel model.ModerationDonat,
) error {
err := donatService.donatRepo.ModerateDonation(
ctx,
donatID,
streamerID,
updateModel,
)
if err != nil {
slog.Error("Failed to update donat", "error", err)
return err
}
return nil
}
func (donatService *ServiceDonat) InitNewStreamer(
ctx context.Context,
streamerID int,
login string,
) error {
err := donatService.widgetRepo.CreateStreamerWidgetPage(
ctx,
streamerID,
)
if err != nil {
slog.Error("Failed to create streamer widget", "error", err)
return err
}
return donatService.donatRepo.InitNewStreamer(
ctx,
streamerID,
login,
donatService.defaultAvatar,
donatService.defaultBackground,
donatService.defaultHead,
)
}
func (donatService *ServiceDonat) GetPlayingDonat(
ctx context.Context,
streamerID int,
) (model.PlayingDonat, error) {
playingDonat, err := donatService.donatRepo.GetPlayingDonat(ctx, streamerID)
if err != nil {
slog.Error("Failed to get playing donat", "error", err)
return model.PlayingDonat{}, err
}
if playingDonat.Image != nil {
imageUuid, err := uuid.Parse(*playingDonat.Image)
if err != nil {
return model.PlayingDonat{}, err
}
fileUrl := donatService.storage.DownloadLink(imageUuid)
playingDonat.Image = &fileUrl
}
if playingDonat.Audio != nil {
imageUuid, err := uuid.Parse(*playingDonat.Audio)
if err != nil {
return model.PlayingDonat{}, err
}
fileUrl := donatService.storage.DownloadLink(imageUuid)
playingDonat.Audio = &fileUrl
}
return playingDonat, nil
}