diff --git a/internal/handler/callback_query_handler.go b/internal/handler/callback_query_handler.go index c53e772..a80baac 100644 --- a/internal/handler/callback_query_handler.go +++ b/internal/handler/callback_query_handler.go @@ -29,6 +29,7 @@ func (h *CallbackQueryHandler) Handle(wh telego.Update) error { if user != nil && user.ID > 0 { return h.handleSetupKey(cq, user) } + // @todo implement poker polls handling. return errors.New("not implemented yet") } diff --git a/internal/handler/chat/poll.go b/internal/handler/chat/poll.go new file mode 100644 index 0000000..008d123 --- /dev/null +++ b/internal/handler/chat/poll.go @@ -0,0 +1,28 @@ +package chat + +import ( + "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" + "github.com/mymmrac/telego" + tu "github.com/mymmrac/telego/telegoutil" +) + +type Poll struct { + iface.Base +} + +func NewPoll(app iface.App, userID, chatID int64) *Poll { + return &Poll{iface.NewBase(app, userID, chatID)} +} + +func (h *Poll) Handle(wh telego.Update) error { + if wh.Message.Chat.Type == telego.ChatTypePrivate { + _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(wh.Message.Chat.ID), + Text: h.Localizer(wh.Message.From.LanguageCode).Message("use_this_command_in_group"), + ParseMode: telego.ModeMarkdown, + }) + return err + } + // @todo implement poker polls. + return nil +} diff --git a/internal/handler/new_message_handler.go b/internal/handler/new_message_handler.go index 2db0e5e..8b2d18e 100644 --- a/internal/handler/new_message_handler.go +++ b/internal/handler/new_message_handler.go @@ -2,6 +2,7 @@ package handler import ( "encoding/json" + "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/chat" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/store" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/util" @@ -20,6 +21,9 @@ func NewMessageHandler(app iface.App) Handler { func (h *MessageHandler) Handle(wh telego.Update) error { if wh.Message.From != nil && wh.Message.Chat.Type == telego.ChatTypePrivate { + if util.MatchCommand("poll", wh.Message) { + return chat.NewPoll(h.app, wh.Message.From.ID, wh.Message.Chat.ID).Handle(wh) + } if util.MatchCommand("start", wh.Message) { return wizard.NewRegister(h.app, wh.Message.From.ID, wh.Message.Chat.ID).Handle(wh) } diff --git a/internal/handler/wizard/redmine_setup.go b/internal/handler/wizard/redmine_setup.go index 0544f39..ddd6877 100644 --- a/internal/handler/wizard/redmine_setup.go +++ b/internal/handler/wizard/redmine_setup.go @@ -5,6 +5,7 @@ import ( "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/store" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/handler/util" + "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/locale" "github.com/mymmrac/telego" tu "github.com/mymmrac/telego/telegoutil" "net/http" @@ -31,16 +32,42 @@ func (h *RedmineSetup) Handle(wh telego.Update) error { } loc := h.Localizer(wh.Message.From.LanguageCode) if h.Redmine.URL == "" { - h.Redmine.URL = h.processURL(wh.Message.Text) - if h.Redmine.URL == "" { - _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ - ChatID: tu.ID(h.ChatID), - Text: loc.Message("please_send_redmine_url"), - ParseMode: telego.ModeMarkdown, - }) - return err - } + return h.handleURLStep(wh.Message.Text, loc) + } + if h.Redmine.Key == "" { + return h.handleKeyStep(wh.Message.Text, loc) + } + + if h.Redmine.SPFieldName == "" && h.Redmine.WaitingForSPField { + return h.handleSPFieldStep(wh.Message.Text, loc) + } + + return nil +} + +func (h *RedmineSetup) handleURLStep(text string, loc locale.Localizer) error { + h.Redmine.URL = h.processURL(text) + if h.Redmine.URL == "" { + _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(h.ChatID), + Text: loc.Message("please_send_redmine_url"), + ParseMode: telego.ModeMarkdown, + }) + return err + } + + _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(h.ChatID), + Text: loc.Template("please_send_redmine_key", map[string]interface{}{"Origin": h.Redmine.URL}), + ParseMode: telego.ModeMarkdown, + }) + return err +} + +func (h *RedmineSetup) handleKeyStep(text string, loc locale.Localizer) error { + h.Redmine.Key = strings.TrimSpace(text) + if h.Redmine.Key == "" { _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ ChatID: tu.ID(h.ChatID), Text: loc.Template("please_send_redmine_key", map[string]interface{}{"Origin": h.Redmine.URL}), @@ -49,123 +76,109 @@ func (h *RedmineSetup) Handle(wh telego.Update) error { return err } - if h.Redmine.Key == "" { - h.Redmine.Key = strings.TrimSpace(wh.Message.Text) - if h.Redmine.Key == "" { - _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ - ChatID: tu.ID(h.ChatID), - Text: loc.Template("please_send_redmine_key", map[string]interface{}{"Origin": h.Redmine.URL}), - ParseMode: telego.ModeMarkdown, - }) - return err - } - - if !h.verifyRedmine() { - _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ - ChatID: tu.ID(h.ChatID), - Text: loc.Message("invalid_redmine_credentials"), - ParseMode: telego.ModeMarkdown, - ReplyMarkup: &telego.InlineKeyboardMarkup{InlineKeyboard: [][]telego.InlineKeyboardButton{ - { - { - Text: loc.Message("yes"), - CallbackData: util.NewRedmineQuestionPayload(h.UserID, h.Redmine.Chat, true).String(), - }, - { - Text: loc.Message("no"), - CallbackData: util.NewRedmineQuestionPayload(h.UserID, h.Redmine.Chat, false).String(), - }, - }, - }}, - }) - - return err - } - - chat, err := h.App.DB().ForChat().ByTelegramID(h.Redmine.Chat) - if err != nil { - _ = util.SendInternalError(h.App.TG(), h.ChatID, loc) - return err - } - if chat == nil || chat.ID == 0 { - _ = util.SendInternalError(h.App.TG(), h.ChatID, loc) - return nil - } - integration := &model.Integration{ - Type: model.RedmineIntegration, - ChatID: chat.ID, - } - integration.StoreRedmine(h.Redmine) - if err := h.App.DB().ForIntegration().Save(integration); err != nil { - _ = util.SendInternalError(h.App.TG(), h.ChatID, loc) - return err - } - - _, _ = h.App.TG().SendMessage(&telego.SendMessageParams{ + if !h.verifyRedmine() { + _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ ChatID: tu.ID(h.ChatID), - Text: loc.Message("redmine_was_connected"), - ParseMode: telego.ModeMarkdown, - }) - _, err = h.App.TG().SendMessage(&telego.SendMessageParams{ - ChatID: tu.ID(h.ChatID), - Text: loc.Message("should_send_estimated_hours_redmine"), + Text: loc.Message("invalid_redmine_credentials"), ParseMode: telego.ModeMarkdown, ReplyMarkup: &telego.InlineKeyboardMarkup{InlineKeyboard: [][]telego.InlineKeyboardButton{ { { Text: loc.Message("yes"), - CallbackData: util.NewRedmineHoursQuestionPayload(h.UserID, h.Redmine.Chat, true).String(), + CallbackData: util.NewRedmineQuestionPayload(h.UserID, h.Redmine.Chat, true).String(), }, { Text: loc.Message("no"), - CallbackData: util.NewRedmineHoursQuestionPayload(h.UserID, h.Redmine.Chat, false).String(), + CallbackData: util.NewRedmineQuestionPayload(h.UserID, h.Redmine.Chat, false).String(), }, }, }}, }) + return err } - if h.Redmine.SPFieldName == "" && h.Redmine.WaitingForSPField { - h.Redmine.SPFieldName = strings.TrimSpace(wh.Message.Text) - if h.Redmine.SPFieldName == "" { - _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ - ChatID: tu.ID(h.ChatID), - Text: loc.Message("specify_result_field"), - ParseMode: telego.ModeMarkdown, - }) - return err - } - - h.Redmine.WaitingForSPField = false - chat, err := h.App.DB().ForChat().ByTelegramIDWithIntegrations(h.Redmine.Chat) - if err != nil { - return err - } - - for _, integration := range chat.Integrations { - if integration.Type == model.RedmineIntegration { - rs := integration.LoadRedmine() - rs.SPFieldName = h.Redmine.SPFieldName - integration.StoreRedmine(rs) - if err := h.App.DB().ForIntegration().Save(&integration); err != nil { - return err - } - break - } - } - - _, _ = h.App.TG().SendMessage(&telego.SendMessageParams{ - ChatID: tu.ID(h.ChatID), - Text: loc.Template("redmine_poker_will_be_configured", - map[string]interface{}{"Name": h.Redmine.SPFieldName}), - ParseMode: telego.ModeMarkdown, - }) - store.RedmineSetups.Delete(h.ChatID) - return util.SendSetupDone(h.App.TG(), h.ChatID, loc) + chat, err := h.App.DB().ForChat().ByTelegramID(h.Redmine.Chat) + if err != nil { + _ = util.SendInternalError(h.App.TG(), h.ChatID, loc) + return err + } + if chat == nil || chat.ID == 0 { + _ = util.SendInternalError(h.App.TG(), h.ChatID, loc) + return nil + } + integration := &model.Integration{ + Type: model.RedmineIntegration, + ChatID: chat.ID, + } + integration.StoreRedmine(h.Redmine) + if err := h.App.DB().ForIntegration().Save(integration); err != nil { + _ = util.SendInternalError(h.App.TG(), h.ChatID, loc) + return err } - return nil + _, _ = h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(h.ChatID), + Text: loc.Message("redmine_was_connected"), + ParseMode: telego.ModeMarkdown, + }) + _, err = h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(h.ChatID), + Text: loc.Message("should_send_estimated_hours_redmine"), + ParseMode: telego.ModeMarkdown, + ReplyMarkup: &telego.InlineKeyboardMarkup{InlineKeyboard: [][]telego.InlineKeyboardButton{ + { + { + Text: loc.Message("yes"), + CallbackData: util.NewRedmineHoursQuestionPayload(h.UserID, h.Redmine.Chat, true).String(), + }, + { + Text: loc.Message("no"), + CallbackData: util.NewRedmineHoursQuestionPayload(h.UserID, h.Redmine.Chat, false).String(), + }, + }, + }}, + }) + return err +} + +func (h *RedmineSetup) handleSPFieldStep(text string, loc locale.Localizer) error { + h.Redmine.SPFieldName = strings.TrimSpace(text) + if h.Redmine.SPFieldName == "" { + _, err := h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(h.ChatID), + Text: loc.Message("specify_result_field"), + ParseMode: telego.ModeMarkdown, + }) + return err + } + + h.Redmine.WaitingForSPField = false + chat, err := h.App.DB().ForChat().ByTelegramIDWithIntegrations(h.Redmine.Chat) + if err != nil { + return err + } + + for _, integration := range chat.Integrations { + if integration.Type == model.RedmineIntegration { + rs := integration.LoadRedmine() + rs.SPFieldName = h.Redmine.SPFieldName + integration.StoreRedmine(rs) + if err := h.App.DB().ForIntegration().Save(&integration); err != nil { + return err + } + break + } + } + + _, _ = h.App.TG().SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(h.ChatID), + Text: loc.Template("redmine_poker_will_be_configured", + map[string]interface{}{"Name": h.Redmine.SPFieldName}), + ParseMode: telego.ModeMarkdown, + }) + store.RedmineSetups.Delete(h.ChatID) + return util.SendSetupDone(h.App.TG(), h.ChatID, loc) } func (h *RedmineSetup) processURL(input string) string { diff --git a/internal/locale/app.en.yaml b/internal/locale/app.en.yaml index d9ab50a..87fb56e 100644 --- a/internal/locale/app.en.yaml +++ b/internal/locale/app.en.yaml @@ -17,6 +17,7 @@ redmine_hours_will_be_configured: "👌 Vote results will be be sent to Redmine redmine_poker_will_not_be_configured: "👌 Vote results won't be sent to Redmine." redmine_poker_will_be_configured: "✔️ Done, vote results will be sent to Redmine in the field *{{.Name}}*." chosen_keyboard: "{{.Name}} has been selected." +use_this_command_in_group: "😒 This command should only be used in your group." please_send_redmine_url: "Please send the URL of your Redmine instance." please_send_redmine_key: "Please send your API key that will be used by the bot to interact with Redmine. The bot will perform the following actions:\n\n• retrieving task data;\n• writing the result of the poker in the task (if configured in subsequent steps).\n\nThe access key for the API can be found on the left part of the page by [this link]({{.Origin}}/my/account)." invalid_redmine_credentials: "⚠️ Failed to verify connection with Redmine. Will try setting up again?" diff --git a/internal/locale/app.ru.yaml b/internal/locale/app.ru.yaml index 53a2d84..d2d2e52 100644 --- a/internal/locale/app.ru.yaml +++ b/internal/locale/app.ru.yaml @@ -17,6 +17,7 @@ redmine_hours_will_be_configured: "👌 Оценка временных затр redmine_poker_will_not_be_configured: "👌 Результат голосования не будет передаваться в Redmine." redmine_poker_will_be_configured: "✔️ Готово, результат голосования будет передаваться в Redmine в поле *{{.Name}}*." chosen_keyboard: "Выбрана {{.Name}}." +use_this_command_in_group: "😒 Эта команда должна использоваться только в групповом чате." please_send_redmine_url: "Пожалуйста, отправьте ссылку на свой инстанс Redmine." please_send_redmine_key: "Отправьте свой API-ключ, который будет использоваться ботом для взаимодействия с Redmine. Бот будет выполнять следующие действия:\n\n• получение данных задачи;\n• запись результата покера в задачу (если будет настроено в следующих шагах).\n\nКлюч доступа к API можно найти в левой части страницы по [этой ссылке]({{.Origin}}/my/account)." invalid_redmine_credentials: "⚠️ Не удалось проверить связь с Redmine. Будете пробовать настроить заново?"