1004 lines
25 KiB
Go
1004 lines
25 KiB
Go
package donat
|
|
|
|
import (
|
|
"context"
|
|
"donat-widget/internal/model"
|
|
"donat-widget/internal/model/api"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/google/uuid"
|
|
"github.com/labstack/echo/v4"
|
|
"log/slog"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type ServiceDonat struct {
|
|
donatRepo model.DonatRepo
|
|
widgetRepo model.WidgetRepo
|
|
authClient model.AuthClient
|
|
paymentClient model.PaymentClient
|
|
streamerClient model.StreamerClient
|
|
fileRepo model.FileRepo
|
|
fileService model.FileService
|
|
storage model.Storage
|
|
defaultAvatar string
|
|
defaultBackground string
|
|
defaultHead string
|
|
defaultWidgetID int
|
|
}
|
|
|
|
func New(
|
|
donatRepo model.DonatRepo,
|
|
widgetRepo model.WidgetRepo,
|
|
paymentClient model.PaymentClient,
|
|
authClient model.AuthClient,
|
|
streamerClient model.StreamerClient,
|
|
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"
|
|
|
|
var defaultWidgetID = 0
|
|
|
|
return &ServiceDonat{
|
|
donatRepo: donatRepo,
|
|
widgetRepo: widgetRepo,
|
|
paymentClient: paymentClient,
|
|
authClient: authClient,
|
|
streamerClient: streamerClient,
|
|
fileRepo: fileRepo,
|
|
fileService: fileService,
|
|
storage: storage,
|
|
defaultAvatar: defaultAvatar,
|
|
defaultBackground: defaultBackground,
|
|
defaultHead: defaultHead,
|
|
defaultWidgetID: defaultWidgetID,
|
|
}
|
|
}
|
|
|
|
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,
|
|
) (model.CreateDonatResponse, error) {
|
|
|
|
donatePage, err := donatService.donatRepo.GetDonatPageByLogin(ctx, streamerLogin)
|
|
if err != nil {
|
|
slog.Error("Failed to get donate page", "error", err.Error())
|
|
return model.CreateDonatResponse{}, err
|
|
}
|
|
|
|
widgets, err := donatService.widgetRepo.GetWidgetsByStreamerID(ctx, donatePage.StreamerID)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return model.CreateDonatResponse{}, err
|
|
}
|
|
|
|
orderID := uuid.New()
|
|
|
|
widgetID := donatService.defaultWidgetID
|
|
for _, widget := range widgets {
|
|
if amount >= widget.MinAmount && amount <= widget.MaxAmount {
|
|
widgetID = widget.ID
|
|
break
|
|
}
|
|
}
|
|
|
|
err = donatService.donatRepo.CreateDonat(
|
|
ctx,
|
|
donatePage.StreamerID,
|
|
targetID,
|
|
widgetID,
|
|
orderID,
|
|
amount,
|
|
text,
|
|
donatUser,
|
|
"pending",
|
|
)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return model.CreateDonatResponse{}, err
|
|
}
|
|
|
|
createPaymentResponse, err := donatService.paymentClient.CreatePayment(donatePage.StreamerID, amount, orderID)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return model.CreateDonatResponse{}, err
|
|
}
|
|
var createDonatResp model.CreateDonatResponse
|
|
createDonatResp.PaymentUrl = createPaymentResponse.PaymentUrl
|
|
createDonatResp.OrderID = orderID
|
|
|
|
return createDonatResp, err
|
|
}
|
|
|
|
func (donatService *ServiceDonat) CreateTestDonat(
|
|
ctx context.Context,
|
|
streamerID int,
|
|
text string,
|
|
donatUser string,
|
|
targetID *int,
|
|
amount int,
|
|
) error {
|
|
orderID := uuid.New()
|
|
|
|
widgets, err := donatService.widgetRepo.GetWidgetsByStreamerID(ctx, streamerID)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
|
|
widgetID := donatService.defaultWidgetID
|
|
for _, widget := range widgets {
|
|
if amount >= widget.MinAmount && amount <= widget.MaxAmount && widget.IsActive == true {
|
|
widgetID = widget.ID
|
|
break
|
|
}
|
|
}
|
|
|
|
err = donatService.donatRepo.CreateDonat(
|
|
ctx,
|
|
streamerID,
|
|
targetID,
|
|
widgetID,
|
|
orderID,
|
|
amount,
|
|
text,
|
|
donatUser,
|
|
"test_donat",
|
|
)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
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 {
|
|
donatModel, err := donatService.donatRepo.GetDonatByOrderID(ctx, orderID)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
|
|
moderationSettings, err := donatService.donatRepo.GetModeration(
|
|
ctx,
|
|
donatModel.StreamerID,
|
|
)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
|
|
err = donatService.donatRepo.MarkDonatPaid(ctx, orderID)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
|
|
if !moderationSettings.Enable {
|
|
moderated := true
|
|
updateModel := model.ModerationDonat{
|
|
Accepted: &moderated,
|
|
ShowText: &moderated,
|
|
ShowName: &moderated,
|
|
PlayContent: &moderated,
|
|
}
|
|
err = donatService.donatRepo.ModerateDonation(
|
|
ctx,
|
|
donatModel.ID,
|
|
donatModel.StreamerID,
|
|
updateModel,
|
|
)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
} else {
|
|
go func(streamerID, donatID int, duration int) {
|
|
select {
|
|
case <-time.After(time.Duration(duration) * time.Second):
|
|
slog.Info("Starting donate auto timeout:", duration)
|
|
moderated := true
|
|
updateModel := model.ModerationDonat{
|
|
Accepted: &moderated,
|
|
ShowText: &moderated,
|
|
ShowName: &moderated,
|
|
PlayContent: &moderated,
|
|
}
|
|
|
|
bgCtx := context.Background()
|
|
donateModel, err := donatService.donatRepo.GetDonatByOrderID(bgCtx, orderID)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return
|
|
}
|
|
if donateModel.AcceptedTime == nil {
|
|
slog.Info("Enable auto process.")
|
|
if err := donatService.donatRepo.ModerateDonation(
|
|
bgCtx,
|
|
donateModel.ID,
|
|
donatModel.StreamerID,
|
|
updateModel,
|
|
); err != nil {
|
|
slog.Error("failed to auto-moderate donation",
|
|
"error", err.Error(),
|
|
"donatID", donatID,
|
|
"streamerID", streamerID,
|
|
)
|
|
}
|
|
}
|
|
case <-ctx.Done():
|
|
slog.Warn("context canceled before auto-moderation",
|
|
"donatID", donatID,
|
|
"streamerID", streamerID,
|
|
)
|
|
}
|
|
}(donatModel.StreamerID, donatModel.ID, moderationSettings.Duration)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) MarkDonatView(
|
|
ctx context.Context,
|
|
orderID string,
|
|
) error {
|
|
err := donatService.donatRepo.MarkDonatView(
|
|
ctx,
|
|
orderID,
|
|
)
|
|
if err != nil {
|
|
slog.Error("donatService.donatRepo.MarkDonatView: " + err.Error())
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) GetInnerDonatPage(
|
|
ctx context.Context,
|
|
streamerID int,
|
|
token string,
|
|
) (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,
|
|
}
|
|
|
|
if donatePage.ProfileAvatar == true {
|
|
fileId, err := donatService.streamerClient.GetAvatarIdByToken(token)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
fileInfo, err := donatService.fileRepo.GetFileInfoById(ctx, fileId)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
if err == nil {
|
|
avatarFile = model.InnerFile{
|
|
FileID: fileInfo.ID,
|
|
FileName: fileInfo.FileName,
|
|
FileType: fileInfo.FileType,
|
|
FileLink: donatService.storage.DownloadLink(fileInfo.ID),
|
|
FileSize: int(fileInfo.Size),
|
|
}
|
|
}
|
|
}
|
|
|
|
backgroundImgFile := model.InnerFile{
|
|
FileID: donatePage.BackgroundImgFileId,
|
|
FileName: donatePage.BackgroundImgFileName,
|
|
FileType: donatePage.BackgroundImgType,
|
|
FileLink: donatService.storage.DownloadLink(donatePage.BackgroundImgFileId),
|
|
FileSize: donatePage.BackgroundImgSize,
|
|
}
|
|
|
|
innerDonatePageResponse := model.InnerDonatePageResponse{
|
|
Description: donatePage.Description,
|
|
TextAfterDonat: donatePage.TextAfterDonat,
|
|
ProfileAvatar: donatePage.ProfileAvatar,
|
|
PageBackground: donatePage.PageBackground,
|
|
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
|
|
}
|
|
|
|
avatarFileId := donatePage.AvatarFileId
|
|
|
|
if donatePage.ProfileAvatar == true {
|
|
donatModel, err := donatService.donatRepo.GetDonatPageByLogin(ctx, streamerLogin)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
streamerID := donatModel.StreamerID
|
|
if streamerID == 0 {
|
|
slog.Error("Account by login not found")
|
|
}
|
|
|
|
fileId, err := donatService.streamerClient.GetAvatarById(strconv.Itoa(streamerID))
|
|
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
avatarFileId = donatePage.AvatarFileId
|
|
}
|
|
avatarFileId, err = uuid.Parse(fileId)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
avatarFileId = donatePage.AvatarFileId
|
|
}
|
|
}
|
|
|
|
err = donatService.getLastStreamerOnline(ctx, donatePage.StreamerID)
|
|
var online string
|
|
if err != nil {
|
|
online = "offline"
|
|
} else {
|
|
online = "online"
|
|
}
|
|
|
|
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(avatarFileId),
|
|
}
|
|
return outerDonatePageResponse, nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) UpdateDonatePage(
|
|
ctx context.Context,
|
|
streamerID int,
|
|
updateModel model.UpdateDonatPage,
|
|
background multipart.FileHeader,
|
|
headImg multipart.FileHeader,
|
|
avatar multipart.FileHeader,
|
|
) error {
|
|
var backgroundFileID *string
|
|
var headImgFileID *string
|
|
var avatarFileID *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
|
|
}
|
|
|
|
if avatar.Size > 0 {
|
|
fileID, err := donatService.fileService.AddNewFile(
|
|
ctx,
|
|
avatar,
|
|
streamerID,
|
|
"donat_page",
|
|
)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return err
|
|
}
|
|
avatarFileID = &fileID
|
|
}
|
|
|
|
err := donatService.donatRepo.UpdateDonatePage(
|
|
ctx,
|
|
streamerID,
|
|
backgroundFileID,
|
|
headImgFileID,
|
|
avatarFileID,
|
|
updateModel.Description,
|
|
updateModel.TextAfterDonat,
|
|
updateModel.ProfileAvatar,
|
|
updateModel.PageBackground,
|
|
)
|
|
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 {
|
|
err = donatService.donatRepo.RemoveFilteredWords(ctx, filterID, 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 replaceFilteredWords(text string, words []string) string {
|
|
if len(words) == 0 {
|
|
return text
|
|
}
|
|
|
|
// Экранируем специальные символы в словах
|
|
escapedWords := make([]string, len(words))
|
|
for i, word := range words {
|
|
escapedWords[i] = regexp.QuoteMeta(word)
|
|
}
|
|
|
|
// Создаем регулярное выражение для поиска целых слов без учета регистра
|
|
pattern := `(?i)\b(` + strings.Join(escapedWords, "|") + `)\b`
|
|
re := regexp.MustCompile(pattern)
|
|
|
|
// Заменяем найденные слова на звёздочки
|
|
return re.ReplaceAllStringFunc(text, func(match string) string {
|
|
return strings.Repeat("*", len(match))
|
|
})
|
|
}
|
|
|
|
func (donatService *ServiceDonat) GetPlayingDonat(
|
|
ctx context.Context,
|
|
streamerID int,
|
|
) (model.PlayingDonatResponse, error) {
|
|
playingDonat, err := donatService.donatRepo.GetPlayingDonat(ctx, streamerID)
|
|
if err != nil {
|
|
slog.Error("Failed to get playing donat", "error", err)
|
|
return model.PlayingDonatResponse{}, err
|
|
}
|
|
|
|
response := model.PlayingDonatResponse{
|
|
Duration: playingDonat.Duration,
|
|
Image: playingDonat.Image,
|
|
Audio: playingDonat.Audio,
|
|
Text: playingDonat.Text,
|
|
Amount: playingDonat.Amount,
|
|
OrderID: playingDonat.OrderID,
|
|
DonatUser: playingDonat.DonatUser,
|
|
PlayContent: playingDonat.PlayContent,
|
|
ShowName: playingDonat.ShowName,
|
|
ShowText: playingDonat.ShowText,
|
|
VolumePercent: playingDonat.VolumePercent,
|
|
}
|
|
|
|
filteredSettings, err := donatService.GetFiltersSettings(ctx, streamerID)
|
|
if err != nil {
|
|
slog.Error("Failed to get filtered words", "error", err)
|
|
return model.PlayingDonatResponse{}, err
|
|
}
|
|
|
|
voiceSettings, err := donatService.donatRepo.GetVoiceSettingsByStreamerID(ctx, streamerID)
|
|
if err != nil {
|
|
slog.Error("Failed to get voice settings", "error", err)
|
|
return model.PlayingDonatResponse{}, err
|
|
}
|
|
|
|
if len(filteredSettings.FilteredWords) > 0 {
|
|
response.Text = donatService.replaceFilteredWords(response.Text, filteredSettings.FilteredWords)
|
|
}
|
|
|
|
if !filteredSettings.EnableLinks {
|
|
response.Text = donatService.replaceLinks(response.Text)
|
|
}
|
|
|
|
response.VoiceSpeed = voiceSettings.VoiceSpeed
|
|
response.Scenery = voiceSettings.Scenery
|
|
response.VoiceSoundPercent = voiceSettings.VoiceSoundPercent
|
|
response.MinPrice = voiceSettings.MinPrice
|
|
response.Languages = voiceSettings.Languages
|
|
response.VoiceEnabled = voiceSettings.Enable
|
|
|
|
if response.OrderID != "" {
|
|
if response.Image != nil {
|
|
imageUuid, err := uuid.Parse(*response.Image)
|
|
if err != nil {
|
|
return model.PlayingDonatResponse{}, err
|
|
}
|
|
fileUrl := donatService.storage.DownloadLink(imageUuid)
|
|
response.Image = &fileUrl
|
|
}
|
|
|
|
if response.Audio != nil {
|
|
audioUuid, err := uuid.Parse(*response.Audio)
|
|
if err != nil {
|
|
return model.PlayingDonatResponse{}, err
|
|
}
|
|
fileUrl := donatService.storage.DownloadLink(audioUuid)
|
|
response.Audio = &fileUrl
|
|
}
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) UpdateStreamerLogin(
|
|
ctx context.Context,
|
|
streamerLogin string,
|
|
streamerID int,
|
|
) error {
|
|
err := donatService.donatRepo.UpdateStreamerLogin(
|
|
ctx,
|
|
streamerLogin,
|
|
streamerID,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) UpdateAvatarStreamer(
|
|
token string,
|
|
avatarId string,
|
|
) error {
|
|
err := donatService.streamerClient.UpdateAvatarID(token, avatarId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) GetTextAfterDonatByOrder(
|
|
ctx context.Context,
|
|
orderID uuid.UUID,
|
|
) (string, error) {
|
|
donat, err := donatService.donatRepo.GetDonatByOrderID(ctx, orderID.String())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if donat.Paid == nil {
|
|
return "", errors.New("not found")
|
|
}
|
|
|
|
donatePage, err := donatService.donatRepo.GetDonatPage(ctx, donat.StreamerID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return donatePage.TextAfterDonat, nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) replaceFilteredWords(text string, words []string) string {
|
|
if len(words) == 0 {
|
|
return text
|
|
}
|
|
|
|
escapedWords := make([]string, len(words))
|
|
for i, word := range words {
|
|
escapedWords[i] = regexp.QuoteMeta(word)
|
|
}
|
|
|
|
// Создаем паттерны для каждого слова, чтобы находить их внутри любых последовательностей символов (кроме пробелов)
|
|
patterns := make([]string, len(escapedWords))
|
|
for i, word := range escapedWords {
|
|
patterns[i] = fmt.Sprintf(`\S*%s\S*`, word) // Ищем запрещённое слово в любом месте "слова"
|
|
}
|
|
|
|
// Комбинируем все паттерны в одно регулярное выражение
|
|
pattern := `(?i)(` + strings.Join(patterns, "|") + `)`
|
|
re := regexp.MustCompile(pattern)
|
|
|
|
// Заменяем все совпадения на звёздочки
|
|
return re.ReplaceAllStringFunc(text, func(match string) string {
|
|
return strings.Repeat("*", len(match))
|
|
})
|
|
}
|
|
|
|
func (donatService *ServiceDonat) UpdateStreamerOnline(
|
|
ctx context.Context,
|
|
streamerID int,
|
|
) error {
|
|
err := donatService.donatRepo.CreateStreamerOnline(
|
|
ctx,
|
|
streamerID,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) getLastStreamerOnline(
|
|
ctx context.Context,
|
|
streamerID int,
|
|
) error {
|
|
onlineTime, err := donatService.donatRepo.GetLastStreamerOnline(
|
|
ctx,
|
|
streamerID,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
currentTime := time.Now().UTC()
|
|
diff := currentTime.Sub(onlineTime)
|
|
|
|
if diff < 0 {
|
|
diff = -diff
|
|
}
|
|
|
|
if diff > time.Minute {
|
|
return fmt.Errorf("last online time is more than a minute old")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (donatService *ServiceDonat) replaceLinks(text string) string {
|
|
re := regexp.MustCompile(`(?i)\bhttps?://\S+\b`)
|
|
return re.ReplaceAllStringFunc(text, func(match string) string {
|
|
return strings.Repeat("*", len(match))
|
|
})
|
|
}
|