Skip to content

Commit 14892eb

Browse files
committed
feat: refactor tg_responder and enhance keyboard handling with new test cases
1 parent 82f2880 commit 14892eb

File tree

5 files changed

+513
-86
lines changed

5 files changed

+513
-86
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ go 1.24.3
99
//replace github.com/bots-go-framework/bots-fw-store => ../bots-fw-store
1010

1111
require (
12-
github.com/bots-go-framework/bots-api-telegram v0.14.0
12+
github.com/bots-go-framework/bots-api-telegram v0.14.2
1313
github.com/bots-go-framework/bots-fw v0.71.1
1414
github.com/bots-go-framework/bots-fw-store v0.10.0
1515
github.com/bots-go-framework/bots-fw-telegram-models v0.3.26

go.sum

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
github.com/alexsergivan/transliterator v1.0.1 h1:vON2ilWCHjq+S5Y4obhLGhHK4Y1VIhsHEtQlij5d9pI=
22
github.com/alexsergivan/transliterator v1.0.1/go.mod h1:0IrumukulURJ4PD0z6UcdJKP2job1DYDhnHAP5y+5pE=
3-
github.com/bots-go-framework/bots-api-telegram v0.14.0 h1:t4/Jvf+N+nU/LqG3GebIcSmQk8T0Vmdl+Nzi0QkdvhM=
4-
github.com/bots-go-framework/bots-api-telegram v0.14.0/go.mod h1:/HcUOCL75qOKP2l2mk+o0FSfp86r6Zto5L/voN8rvPo=
5-
github.com/bots-go-framework/bots-fw v0.70.2 h1:kwEVGN5Cichl77e+WK+4HBdvg3cRXRbJIaLx/zU2lwU=
6-
github.com/bots-go-framework/bots-fw v0.70.2/go.mod h1:T6EyFubSt3ZJbIosiL8b11YE4PGqTWGu47TPLSGTT2U=
7-
github.com/bots-go-framework/bots-fw v0.71.0 h1:/dZO4LQPB5o0kL2s3GtkJzxGxq/OgJx1qPuL2BtTAEI=
8-
github.com/bots-go-framework/bots-fw v0.71.0/go.mod h1:nomnLMcY//o6uWwKpNCkk7HldL3Xw5TStsPDrowT2Hg=
3+
github.com/bots-go-framework/bots-api-telegram v0.14.2 h1:HO267e5vRgyiV4XYC8Ix1MDd8cfVXJ70LRRrgTZF7ag=
4+
github.com/bots-go-framework/bots-api-telegram v0.14.2/go.mod h1:OjdV9b8kc9med/a+pfgWQzdBCzs6FKfHyAL45lvU17w=
95
github.com/bots-go-framework/bots-fw v0.71.1 h1:hEoKT69h1ugG+FScexVxpCwQxxW/2jiyWINRd9+knoI=
106
github.com/bots-go-framework/bots-fw v0.71.1/go.mod h1:gpoNv16aC42kNlCggvU9CCMzWX+ymJKtdVQm6p1jpHA=
117
github.com/bots-go-framework/bots-fw-store v0.10.0 h1:e6bD274mjrHVp+X05/7uqqT3s5xZOqV9divKTaM2W+w=
128
github.com/bots-go-framework/bots-fw-store v0.10.0/go.mod h1:7oU4B8j5HuJZM8AftosbyQD+AqckXsDv8eU1auGPzn8=
139
github.com/bots-go-framework/bots-fw-telegram-models v0.3.26 h1:J6mdMcrouCB0yjzDMFhVJxnB2epnnltC+iyTtISL27c=
1410
github.com/bots-go-framework/bots-fw-telegram-models v0.3.26/go.mod h1:Y4t7fKdZ2q+3pxhKKE7VEi7DXU2gn/CI2mQQp7zANcA=
15-
github.com/bots-go-framework/bots-go-core v0.2.1 h1:LN2575Fv+441LSQWae+R8nZzt1JbGRdVK1SP2Yt4Skk=
16-
github.com/bots-go-framework/bots-go-core v0.2.1/go.mod h1:XCn9z4TI8sbgwyus+VDzw7iMY2QCPWEAvl23GMDjeEU=
1711
github.com/bots-go-framework/bots-go-core v0.2.2 h1:9Wi8L4Y1sCpHiYAVejgXkwrezwk2r2yIF9I3IG3iJzc=
1812
github.com/bots-go-framework/bots-go-core v0.2.2/go.mod h1:XCn9z4TI8sbgwyus+VDzw7iMY2QCPWEAvl23GMDjeEU=
1913
github.com/dal-go/dalgo v0.24.0 h1:lwf2S7+zBhp5z1HQXSKpsLd5ZXkby0aDm3jcEQA2VQI=
@@ -27,8 +21,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
2721
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
2822
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
2923
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
30-
github.com/strongo/analytics v0.2.1 h1:PP/TMyE20QjfQjPY7S+bUbSgyd01f9ZUjeuniRsEvEE=
31-
github.com/strongo/analytics v0.2.1/go.mod h1:1OdiZI9/fPDN8ep1Pbz+F3UZPNbttUD7T1St15r760c=
3224
github.com/strongo/analytics v0.2.2 h1:D2xxTemgCK+4Qk0iBVvXXKsZnm5iS350TPAaZnXFeT8=
3325
github.com/strongo/analytics v0.2.2/go.mod h1:1OdiZI9/fPDN8ep1Pbz+F3UZPNbttUD7T1St15r760c=
3426
github.com/strongo/i18n v0.8.2 h1:tJxeajC6OLENFus2GQ/jZGDjFmd6lPQuhand9jD0Moc=

telegram/message_uid.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,11 @@ var _ botmsg.MessageUID = (*ChatMessageUID)(nil)
4949
func (m ChatMessageUID) UID() string {
5050
return fmt.Sprintf("%d:%d", m.ChatID, m.MessageID)
5151
}
52+
53+
func (m ChatMessageUID) GetChatID() int64 {
54+
return m.ChatID
55+
}
56+
57+
func (m ChatMessageUID) GetMessageID() int {
58+
return m.MessageID
59+
}

telegram/tg_responder.go

Lines changed: 111 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,16 @@ func newTgWebhookResponder(w http.ResponseWriter, whc *tgWebhookContext) tgWebho
7676

7777
func (r tgWebhookResponder) SendMessage(ctx context.Context, m botmsg.MessageFromBot, channel botmsg.BotAPISendMessageChannel) (resp botsfw.OnMessageSentResponse, err error) {
7878
logus.Debugf(ctx, "tgWebhookResponder.SendMessage(channel=%v, isEdit=%v)\nm: %+v", channel, m.IsEdit, m)
79-
channel = botsfw.BotAPISendMessageOverHTTPS
8079
switch channel {
8180
case botsfw.BotAPISendMessageOverHTTPS, botsfw.BotAPISendMessageOverResponse:
8281
// Known channels
8382
default:
8483
panic(fmt.Sprintf("Unknown channel: [%v]. Expected either 'https' or 'response'.", channel))
8584
}
85+
if channel != botsfw.BotAPISendMessageOverHTTPS {
86+
logus.Debugf(ctx, "Rewriting sending channel from %s to %s", channel, botsfw.BotAPISendMessageOverHTTPS)
87+
channel = botsfw.BotAPISendMessageOverHTTPS
88+
}
8689
//ctx := tc.Context()
8790

8891
var sendable tgbotapi.Sendable
@@ -188,38 +191,25 @@ func (r tgWebhookResponder) SendMessage(ctx context.Context, m botmsg.MessageFro
188191
inlineMessageID = ""
189192
}
190193
if m.EditMessageUID != nil {
191-
switch m.EditMessageUID.(type) { // TODO: How do we remove duplicates for value & pointer cases?
194+
switch messageUID := m.EditMessageUID.(type) { // TODO: How do we remove duplicates for value & pointer cases?
192195
case callbackCurrent:
193196
// do nothing
194-
case InlineMessageUID:
195-
inlineMessageID = m.EditMessageUID.(InlineMessageUID).InlineMessageID
196-
chatID = 0
197-
messageID = 0
198-
case *InlineMessageUID:
199-
inlineMessageID = m.EditMessageUID.(*InlineMessageUID).InlineMessageID
197+
case InlineMessageUID, *InlineMessageUID:
198+
inlineMessageID = messageUID.UID()
200199
chatID = 0
201200
messageID = 0
202-
case ChatMessageUID:
203-
chatMessageUID := m.EditMessageUID.(ChatMessageUID)
204-
inlineMessageID = ""
205-
if chatMessageUID.ChatID != 0 {
206-
chatID = chatMessageUID.ChatID
207-
}
208-
if chatMessageUID.MessageID != 0 {
209-
messageID = chatMessageUID.MessageID
210-
}
211-
case *ChatMessageUID:
212-
chatMessageUID := m.EditMessageUID.(*ChatMessageUID)
213-
inlineMessageID = ""
214-
if chatMessageUID.ChatID != 0 {
215-
chatID = chatMessageUID.ChatID
216-
}
217-
if chatMessageUID.MessageID != 0 {
218-
messageID = chatMessageUID.MessageID
219-
}
220201
default:
221202
err = fmt.Errorf("unknown EditMessageUID type %T(%v)", m.EditMessageUID, m.EditMessageUID)
222203
return
204+
case ChatMessageUID, *ChatMessageUID:
205+
inlineMessageID = ""
206+
if uid, ok := messageUID.(interface {
207+
GetChatID() int64
208+
GetMessageID() int
209+
}); ok {
210+
chatID = uid.GetChatID()
211+
messageID = uid.GetMessageID()
212+
}
223213
}
224214
}
225215
logus.Debugf(ctx, "Edit message => inlineMessageID: %v, chatID: %d, messageID: %d", inlineMessageID, chatID, messageID)
@@ -228,33 +218,46 @@ func (r tgWebhookResponder) SendMessage(ctx context.Context, m botmsg.MessageFro
228218
return
229219
}
230220
if m.Text == "" && m.Keyboard != nil {
231-
switch keyboard := m.Keyboard.(type) {
221+
keyboard := getTelegramKeyboard(m.Keyboard)
222+
switch kb := keyboard.(type) {
232223
case *tgbotapi.InlineKeyboardMarkup:
233-
sendable = tgbotapi.NewEditMessageReplyMarkup(chatID, messageID, inlineMessageID, keyboard)
234-
case *botkb.MessageKeyboard:
235-
switch keyboard.KeyboardType() {
236-
case botkb.KeyboardTypeInline:
237-
kb := getTelegramKeyboard(m.Keyboard)
238-
inlineKbMarkup := kb.(*tgbotapi.InlineKeyboardMarkup)
239-
sendable = tgbotapi.NewEditMessageReplyMarkup(chatID, messageID, inlineMessageID, tgbotapi.NewInlineKeyboardMarkup(inlineKbMarkup.InlineKeyboard...))
240-
case botkb.KeyboardTypeBottom:
241-
kb := getTelegramKeyboard(m.Keyboard)
242-
msg := tgbotapi.NewMessage(chatID, m.Text)
243-
msg.ReplyMarkup = kb.(*tgbotapi.InlineKeyboardMarkup)
244-
sendable = msg
224+
sendable = tgbotapi.NewEditMessageReplyMarkup(chatID, messageID, inlineMessageID, kb)
225+
case *tgbotapi.ReplyKeyboardMarkup, *tgbotapi.ReplyKeyboardHide:
226+
msg := tgbotapi.NewMessage(chatID, "")
227+
msg.ReplyMarkup = kb
228+
sendable = msg
229+
default:
230+
err = fmt.Errorf("unknown keyboard type %T(%v)", keyboard.KeyboardType(), keyboard)
231+
return
232+
}
233+
} else if m.Text != "" {
234+
kb := getTelegramKeyboard(m.Keyboard)
235+
236+
createEditMessage := func() *tgbotapi.EditMessageTextConfig {
237+
editMessageTextConfig := tgbotapi.NewEditMessageText(chatID, messageID, inlineMessageID, m.Text)
238+
editMessageTextConfig.ParseMode = parseMode()
239+
editMessageTextConfig.DisableWebPagePreview = m.DisableWebPagePreview
240+
sendable = editMessageTextConfig
241+
return editMessageTextConfig
242+
}
243+
244+
if kb == nil {
245+
createEditMessage()
246+
} else {
247+
switch kb := kb.(type) {
248+
case *tgbotapi.InlineKeyboardMarkup:
249+
editMessageTextConfig := createEditMessage()
250+
editMessageTextConfig.ReplyMarkup = kb
251+
sendable = editMessageTextConfig
252+
case *tgbotapi.ReplyKeyboardMarkup, *tgbotapi.ReplyKeyboardHide:
253+
messageConfig := tgbotapi.NewMessage(chatID, m.Text)
254+
messageConfig.ReplyMarkup = kb
255+
sendable = messageConfig
245256
default:
246-
err = fmt.Errorf("unknown keyboard type %T(%v)", keyboard.KeyboardType(), keyboard)
257+
err = fmt.Errorf("unknown keyboard type %T(%v)", kb.KeyboardType(), kb)
247258
return
248259
}
249260
}
250-
} else if m.Text != "" {
251-
editMessageTextConfig := tgbotapi.NewEditMessageText(chatID, messageID, inlineMessageID, m.Text)
252-
editMessageTextConfig.ParseMode = parseMode()
253-
editMessageTextConfig.DisableWebPagePreview = m.DisableWebPagePreview
254-
if m.Keyboard != nil {
255-
editMessageTextConfig.ReplyMarkup = getTelegramKeyboard(m.Keyboard).(*tgbotapi.InlineKeyboardMarkup)
256-
}
257-
sendable = editMessageTextConfig
258261
} else {
259262
err = fmt.Errorf("can't edit telegram message as got unknown output: %v", m)
260263
panic(err)
@@ -357,36 +360,69 @@ func getTelegramKeyboard(keyboard botkb.Keyboard) tgbotapi.Keyboard {
357360
}
358361
switch kb := keyboard.(type) {
359362
case *botkb.MessageKeyboard:
360-
tgButtons := make([][]tgbotapi.InlineKeyboardButton, len(kb.Buttons))
361-
for i, buttons := range kb.Buttons {
362-
tgButtons[i] = make([]tgbotapi.InlineKeyboardButton, len(buttons))
363-
for j, button := range buttons {
364-
switch btn := button.(type) {
365-
case botkb.DataButton:
366-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonData(btn.Text, btn.Data)
367-
case *botkb.DataButton:
368-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonData(btn.Text, btn.Data)
369-
case botkb.UrlButton:
370-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonURL(btn.Text, btn.URL)
371-
case *botkb.UrlButton:
372-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonURL(btn.Text, btn.URL)
373-
case botkb.SwitchInlineQueryButton:
374-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQuery(btn.Text, btn.Query)
375-
case *botkb.SwitchInlineQueryButton:
376-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQuery(btn.Text, btn.Query)
377-
case botkb.SwitchInlineQueryCurrentChatButton:
378-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQueryCurrentChat(btn.Text, btn.Query)
379-
case *botkb.SwitchInlineQueryCurrentChatButton:
380-
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQueryCurrentChat(btn.Text, btn.Query)
381-
default:
382-
panic(fmt.Sprintf("Unknown button type at [%d][%d]: %T", i, j, btn))
383-
}
384-
}
363+
switch keyboard.KeyboardType() {
364+
case botkb.KeyboardTypeInline:
365+
return getInlineKeyboard(kb)
366+
case botkb.KeyboardTypeBottom:
367+
return getReplyKeyboard(kb)
368+
case botkb.KeyboardTypeHide:
369+
return getHideKeyboard(kb)
370+
default:
371+
panic(fmt.Sprintf("keyboard.KeyboardType() returns unsupported type %v", kb.KeyboardType()))
385372
}
386-
return tgbotapi.NewInlineKeyboardMarkup(tgButtons...)
387373
default:
388-
panic(fmt.Sprintf("m.Keyboard has unsupported type %v", kb.KeyboardType()))
374+
panic(fmt.Sprintf("keyboard is of unsupported type %v", keyboard))
375+
}
376+
}
377+
378+
func getHideKeyboard(_ *botkb.MessageKeyboard) *tgbotapi.ReplyKeyboardHide {
379+
return &tgbotapi.ReplyKeyboardHide{HideKeyboard: true}
380+
}
381+
382+
func getReplyKeyboard(kb *botkb.MessageKeyboard) *tgbotapi.ReplyKeyboardMarkup {
383+
tgButtons := make([][]tgbotapi.KeyboardButton, len(kb.Buttons))
384+
for i, buttons := range kb.Buttons {
385+
tgButtons[i] = make([]tgbotapi.KeyboardButton, len(buttons))
386+
for j, button := range buttons {
387+
switch btn := button.(type) {
388+
case botkb.TextButton:
389+
tgButtons[i][j] = tgbotapi.KeyboardButton{Text: btn.Text}
390+
default:
391+
tgButtons[i][j] = tgbotapi.KeyboardButton{Text: btn.GetText()}
392+
}
393+
}
394+
}
395+
return tgbotapi.NewReplyKeyboard(tgButtons...)
396+
}
397+
398+
func getInlineKeyboard(kb *botkb.MessageKeyboard) *tgbotapi.InlineKeyboardMarkup {
399+
tgButtons := make([][]tgbotapi.InlineKeyboardButton, len(kb.Buttons))
400+
for i, buttons := range kb.Buttons {
401+
tgButtons[i] = make([]tgbotapi.InlineKeyboardButton, len(buttons))
402+
for j, button := range buttons {
403+
switch btn := button.(type) {
404+
case botkb.DataButton:
405+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonData(btn.Text, btn.Data)
406+
case *botkb.DataButton:
407+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonData(btn.Text, btn.Data)
408+
case botkb.UrlButton:
409+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonURL(btn.Text, btn.URL)
410+
case *botkb.UrlButton:
411+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonURL(btn.Text, btn.URL)
412+
case botkb.SwitchInlineQueryButton:
413+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQuery(btn.Text, btn.Query)
414+
case *botkb.SwitchInlineQueryButton:
415+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQuery(btn.Text, btn.Query)
416+
case botkb.SwitchInlineQueryCurrentChatButton:
417+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQueryCurrentChat(btn.Text, btn.Query)
418+
case *botkb.SwitchInlineQueryCurrentChatButton:
419+
tgButtons[i][j] = tgbotapi.NewInlineKeyboardButtonSwitchInlineQueryCurrentChat(btn.Text, btn.Query)
420+
default:
421+
panic(fmt.Sprintf("Unknown button type at [%d][%d]: %T", i, j, btn))
422+
}
423+
}
389424
}
425+
return tgbotapi.NewInlineKeyboardMarkup(tgButtons...)
390426
}
391427

392428
func GetTelegramBotAPIClient(ctx context.Context, botContext botsfw.BotContext) *tgbotapi.BotAPI {

0 commit comments

Comments
 (0)