refactor fsm to pkg, copy more wizard logic to states
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Pavel 2024-05-13 19:08:46 +03:00
parent 77eaceb152
commit 68f2975201
13 changed files with 219 additions and 12 deletions

View File

@ -1,10 +1,17 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/db/model"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/util"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil"
"golang.org/x/text/language"
) )
const MaxChatMembers = 32
const AddChatMemberStateID fsm.StateID = "add_chat_member" const AddChatMemberStateID fsm.StateID = "add_chat_member"
type AddChatMemberState struct { type AddChatMemberState struct {
@ -23,7 +30,127 @@ func (s *AddChatMemberState) Enter(pl *Wizard, mc fsm.MachineControls[*Wizard])
} }
func (s *AddChatMemberState) Handle(pl *Wizard, mc fsm.MachineControls[*Wizard]) { func (s *AddChatMemberState) Handle(pl *Wizard, mc fsm.MachineControls[*Wizard]) {
// todo: copy implementation from func (h *ChatMemberUpdatedHandler) handleAddToChat(tgChat telego.Chat) error next := WaitingForMemberWebhookStateID
defer func() {
_ = mc.Move(next, pl)
}()
cr := s.App.DB().ForChat()
tgChat := pl.Data.MyChatMember.Chat
chat, err := cr.ByTelegramID(tgChat.ID)
if err != nil {
s.LogError(util.SendInternalError(s.App.TG(), tgChat.ID, nil))
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
user, err := s.getRegisteredAdmin(tgChat.ID)
if err != nil {
s.LogError(util.SendInternalError(s.App.TG(), tgChat.ID, nil))
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
if user == nil || user.ID == 0 {
_, err = s.App.TG().SendMessage(&telego.SendMessageParams{
ChatID: tu.ID(tgChat.ID),
Text: s.Localizer(language.English.String()).
Template("you_should_register_first", map[string]interface{}{"Name": s.App.TGProfile().Username}),
ParseMode: telego.ModeMarkdown,
})
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
loc := s.Localizer(user.Language)
totalMembers, err := s.App.TG().GetChatMemberCount(&telego.GetChatMemberCountParams{
ChatID: tu.ID(tgChat.ID),
})
if err != nil {
s.LogError(util.SendInternalError(s.App.TG(), tgChat.ID, nil))
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
if *totalMembers > MaxChatMembers {
_, err = s.App.TG().SendMessage(&telego.SendMessageParams{
ChatID: tu.ID(tgChat.ID),
Text: loc.Template("too_many_members_in_the_group", map[string]interface{}{"Limit": MaxChatMembers}),
ParseMode: telego.ModeMarkdown,
})
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
if chat == nil || chat.ID == 0 {
chat = &model.Chat{
TelegramID: tgChat.ID,
UserID: user.ID,
}
err := cr.Save(chat)
if err != nil {
_ = util.SendInternalError(s.App.TG(), tgChat.ID, loc)
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
} else {
chat.UserID = user.ID
err := s.App.DB().ForIntegration().DeleteForChat(chat.ID)
if err != nil {
_ = util.SendInternalError(s.App.TG(), tgChat.ID, loc)
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
err = cr.Save(chat)
if err != nil {
_ = util.SendInternalError(s.App.TG(), tgChat.ID, loc)
s.leaveChat(tgChat.ID)
s.LogError(err)
return
}
}
_, err = s.App.TG().SendMessage(&telego.SendMessageParams{
ChatID: tu.ID(user.ChatID),
Text: loc.Template("bot_was_added", map[string]interface{}{"Name": tgChat.Title}),
ParseMode: telego.ModeMarkdown,
})
s.LogError(err)
pl.User = user
pl.TGChat = tgChat
pl.Loc = loc
next = KeyboardChooserStateID
}
func (s *AddChatMemberState) getRegisteredAdmin(chatID int64) (*model.User, error) {
admins, err := s.App.TG().GetChatAdministrators(&telego.GetChatAdministratorsParams{
ChatID: tu.ID(chatID),
})
if err != nil {
return nil, err
}
adminIDs := make([]int64, len(admins))
for i, admin := range admins {
adminIDs[i] = admin.MemberUser().ID
}
dbAdmins, err := s.App.DB().ForUser().ByTelegramIDs(adminIDs)
if err != nil {
return nil, err
}
if len(dbAdmins) > 0 {
return &dbAdmins[0], nil
}
return nil, nil
}
func (s *AddChatMemberState) leaveChat(chatID int64) {
_ = s.App.TG().LeaveChat(&telego.LeaveChatParams{
ChatID: tu.ID(chatID),
})
} }
func (s *AddChatMemberState) ID() fsm.StateID { func (s *AddChatMemberState) ID() fsm.StateID {

View File

@ -1,16 +1,21 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/db/model"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/locale" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/locale"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/mymmrac/telego" "github.com/mymmrac/telego"
"golang.org/x/text/language"
"strings" "strings"
) )
type Wizard struct { type Wizard struct {
UserID int64 UserID int64
ChatID int64 ChatID int64
TGChat telego.Chat
User *model.User
Loc locale.Localizer
Data telego.Update Data telego.Update
} }
@ -23,7 +28,14 @@ func newBase(app iface.App) State {
return State{App: app} return State{App: app}
} }
func (s State) Localizer(lang string) locale.Localizer { func (s State) Localizer(langCode ...string) locale.Localizer {
lang := language.English.String()
if len(langCode) > 0 {
lang = langCode[0]
}
if s.Payload.Loc != nil && (len(langCode) == 0 || s.Payload.Loc.Tag().String() == lang) {
return s.Payload.Loc
}
lang = strings.ToLower(lang) lang = strings.ToLower(lang)
if len(lang) > 2 { if len(lang) > 2 {
lang = lang[:2] lang = lang[:2]

View File

@ -1,7 +1,7 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"go.uber.org/zap" "go.uber.org/zap"
) )

View File

@ -1,8 +1,8 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/mymmrac/telego" "github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil" tu "github.com/mymmrac/telego/telegoutil"
) )

View File

@ -1,8 +1,8 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/maypok86/otter" "github.com/maypok86/otter"
"time" "time"
) )
@ -44,6 +44,7 @@ func PopulateStates(app iface.App) {
NewRegisterState(app), NewRegisterState(app),
NewWaitingForMemberWebhookState(app), NewWaitingForMemberWebhookState(app),
NewAddChatMemberState(app), NewAddChatMemberState(app),
NewKeyboardChooserState(app),
NewRemoveChatMemberState(app), NewRemoveChatMemberState(app),
NewHelpState(app), NewHelpState(app),
} }

View File

@ -0,0 +1,56 @@
package wizard
import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/db/model"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/util"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil"
)
const KeyboardChooserStateID fsm.StateID = "keyboard_chooser"
type KeyboardChooserState struct {
State
}
func NewKeyboardChooserState(app iface.App) fsm.IState[Wizard] {
return &KeyboardChooserState{newBase(app)}
}
func (s *KeyboardChooserState) Enter(pl *Wizard, _ fsm.MachineControls[*Wizard]) error {
_, err := s.App.TG().SendMessage(&telego.SendMessageParams{
ChatID: tu.ID(pl.User.ChatID),
Text: s.Localizer().Template("choose_keyboard", map[string]interface{}{"Name": pl.TGChat.Title}),
ParseMode: telego.ModeMarkdown,
ReplyMarkup: &telego.InlineKeyboardMarkup{
InlineKeyboard: [][]telego.InlineKeyboardButton{
{
{
Text: s.Localizer().Message("standard_vote_keyboard"),
CallbackData: util.NewKeyboardChooserPayload(
pl.User.TelegramID, pl.TGChat.ID, uint8(model.StandardKeyboard)).String(),
},
},
{
{
Text: s.Localizer().Message("sp_vote_keyboard"),
CallbackData: util.NewKeyboardChooserPayload(
pl.User.TelegramID, pl.TGChat.ID, uint8(model.StoryPointsKeyboard)).String(),
},
},
},
},
})
s.LogError(err)
return err
}
func (s *KeyboardChooserState) Handle(pl *Wizard, _ fsm.MachineControls[*Wizard]) {
// todo: implement this using func (h *CallbackQueryHandler) handleChooseKeyboard(pl util.Payload, msgID int, user *model.User) error
}
func (s *KeyboardChooserState) ID() fsm.StateID {
return KeyboardChooserStateID
}

View File

@ -2,8 +2,8 @@ package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/db/model" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/db/model"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/mymmrac/telego" "github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil" tu "github.com/mymmrac/telego/telegoutil"
) )
@ -39,6 +39,7 @@ func (s *RegisterState) Handle(pl *Wizard, mc fsm.MachineControls[*Wizard]) {
if shouldUpdate { if shouldUpdate {
_ = userRepo.Save(user) _ = userRepo.Save(user)
} }
pl.User = user
_ = mc.Move(WaitingForMemberWebhookStateID, pl) _ = mc.Move(WaitingForMemberWebhookStateID, pl)
return return
} }
@ -57,6 +58,7 @@ func (s *RegisterState) Handle(pl *Wizard, mc fsm.MachineControls[*Wizard]) {
}) })
s.LogError(err) s.LogError(err)
} }
pl.User = user
_ = mc.Move(WaitingForMemberWebhookStateID, pl) _ = mc.Move(WaitingForMemberWebhookStateID, pl)
} }

View File

@ -1,8 +1,8 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
) )
const RemoveChatMemberStateID fsm.StateID = "remove_chat_member" const RemoveChatMemberStateID fsm.StateID = "remove_chat_member"

View File

@ -1,8 +1,8 @@
package wizard package wizard
import ( import (
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/fsm"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface"
"gitea.neur0tx.site/Neur0toxine/vegapokerbot/pkg/fsm"
"github.com/mymmrac/telego" "github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil" tu "github.com/mymmrac/telego/telegoutil"
) )

View File

@ -32,7 +32,7 @@ func init() {
} }
for _, tag := range tags { for _, tag := range tags {
localizers[tag.String()] = &localizer{loc: i18n.NewLocalizer(bundle, tag.String())} localizers[tag.String()] = &localizer{loc: i18n.NewLocalizer(bundle, tag.String()), tag: tag}
} }
} }

View File

@ -1,14 +1,19 @@
package locale package locale
import "github.com/nicksnyder/go-i18n/v2/i18n" import (
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
type Localizer interface { type Localizer interface {
Message(string) string Message(string) string
Template(string, interface{}) string Template(string, interface{}) string
Tag() language.Tag
} }
type localizer struct { type localizer struct {
loc *i18n.Localizer loc *i18n.Localizer
tag language.Tag
} }
func (l *localizer) Message(str string) string { func (l *localizer) Message(str string) string {
@ -21,3 +26,7 @@ func (l *localizer) Template(str string, tpl interface{}) string {
TemplateData: tpl, TemplateData: tpl,
}) })
} }
func (l *localizer) Tag() language.Tag {
return l.tag
}