deps: bump github.com/iamxvbaba/td to v1.3.2

Matches upstream owpengram/owpengram-server's version. v1.3.2 collapses the
old per-kind KeyboardButtonClass sum type (KeyboardButton, KeyboardButtonURL,
KeyboardButtonCallback, KeyboardButtonRequestPeer, ...) into two unified
structs mirroring Telegram's actual current MTProto layer: KeyboardButton
(reply keyboards) and KeyboardInlineButton (inline keyboards), each carrying
a Text/Style pair plus a Type field (ButtonTypeClass / InlineButtonTypeClass)
that now holds what used to be the concrete Go type.

Migrated the two call sites (internal/rpc/convert_markup.go,
internal/rpc/bots_longtail.go) and their tests to the new shape. Behavior is
unchanged -- every button kind (callback, url, url_auth, web_view,
switch_inline, copy, request_phone, request_geo_location, request_poll,
request_peer, simple_web_view) still round-trips the same domain fields,
just read from/written to Type instead of the button's own concrete type.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Astra 2026-09-14 11:28:16 +01:00
parent ecdb14aaca
commit 7fef8438c5
9 changed files with 166 additions and 174 deletions

2
go.mod
View file

@ -9,7 +9,7 @@ require (
github.com/golang-migrate/migrate/v4 v4.19.1 github.com/golang-migrate/migrate/v4 v4.19.1
github.com/gotd/ige v0.3.0 github.com/gotd/ige v0.3.0
github.com/gotd/log/logzap v0.1.1 github.com/gotd/log/logzap v0.1.1
github.com/iamxvbaba/td v1.2.1 github.com/iamxvbaba/td v1.3.2
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
github.com/jackc/pgx/v5 v5.9.2 github.com/jackc/pgx/v5 v5.9.2
github.com/lestrrat-go/jwx/v3 v3.1.1 github.com/lestrrat-go/jwx/v3 v3.1.1

4
go.sum
View file

@ -83,8 +83,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/iamxvbaba/td v1.2.1 h1:5+Ji1F/tdrN8zUxeeEbTPHBQGSnTDE+UAH+8pQi7O1Y= github.com/iamxvbaba/td v1.3.2 h1:/EwvDU0oiArAof16WDDGfUXg/w02m2MqzDskCnXakZA=
github.com/iamxvbaba/td v1.2.1/go.mod h1:INkZJi18XbXtVOrldDnPtmQCJvIXhgDZdbo9MV/NY7M= github.com/iamxvbaba/td v1.3.2/go.mod h1:INkZJi18XbXtVOrldDnPtmQCJvIXhgDZdbo9MV/NY7M=
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw=
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=

View file

@ -230,9 +230,9 @@ func TestBotInlineKeyboardCallbackFlow(t *testing.T) {
return fmt.Errorf("bot getUsers(owner) = %d, want 1", len(got)) return fmt.Errorf("bot getUsers(owner) = %d, want 1", len(got))
} }
ownerSeen := got[0].(*tg.User) ownerSeen := got[0].(*tg.User)
markup := &tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButtonClass{ markup := &tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{Buttons: []tg.KeyboardInlineButton{
&tg.KeyboardButtonCallback{Text: "Press", Data: callbackData}, {Text: "Press", Type: &tg.InlineButtonTypeCallback{Data: callbackData}},
&tg.KeyboardButtonURL{Text: "Site", URL: "https://example.com/x"}, {Text: "Site", Type: &tg.InlineButtonTypeURL{URL: "https://example.com/x"}},
}}}} }}}}
req := &tg.MessagesSendMessageRequest{ req := &tg.MessagesSendMessageRequest{
Peer: &tg.InputPeerUser{UserID: ownerSeen.ID, AccessHash: ownerSeen.AccessHash}, Peer: &tg.InputPeerUser{UserID: ownerSeen.ID, AccessHash: ownerSeen.AccessHash},
@ -312,15 +312,15 @@ func TestBotInlineKeyboardCallbackFlow(t *testing.T) {
if !ok || len(inline.Rows) != 1 || len(inline.Rows[0].Buttons) != 2 { if !ok || len(inline.Rows) != 1 || len(inline.Rows[0].Buttons) != 2 {
t.Fatalf("unexpected markup shape: %#v", rm) t.Fatalf("unexpected markup shape: %#v", rm)
} }
cbBtn, ok := inline.Rows[0].Buttons[0].(*tg.KeyboardButtonCallback) cbBtn, ok := inline.Rows[0].Buttons[0].Type.(*tg.InlineButtonTypeCallback)
if !ok { if !ok {
t.Fatalf("first button not callback: %#v", inline.Rows[0].Buttons[0]) t.Fatalf("first button not callback: %#v", inline.Rows[0].Buttons[0].Type)
} }
if string(cbBtn.Data) != string(callbackData) { if string(cbBtn.Data) != string(callbackData) {
t.Fatalf("callback data round-trip mismatch: got %v want %v", cbBtn.Data, callbackData) t.Fatalf("callback data round-trip mismatch: got %v want %v", cbBtn.Data, callbackData)
} }
if _, ok := inline.Rows[0].Buttons[1].(*tg.KeyboardButtonURL); !ok { if _, ok := inline.Rows[0].Buttons[1].Type.(*tg.InlineButtonTypeURL); !ok {
t.Fatalf("second button not url: %#v", inline.Rows[0].Buttons[1]) t.Fatalf("second button not url: %#v", inline.Rows[0].Buttons[1].Type)
} }
msgID = msg.ID msgID = msg.ID
} }

View file

@ -844,8 +844,8 @@ func TestInlineBotArticleTextChannelRoundTrip(t *testing.T) {
} }
editReq := &tg.MessagesEditInlineBotMessageRequest{ID: msgID} editReq := &tg.MessagesEditInlineBotMessageRequest{ID: msgID}
editReq.SetMessage("inline group edited") editReq.SetMessage("inline group edited")
editReq.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{ editReq.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{
Buttons: []tg.KeyboardButtonClass{&tg.KeyboardButtonCallback{Text: "Done", Data: []byte("v2")}}, Buttons: []tg.KeyboardInlineButton{{Text: "Done", Type: &tg.InlineButtonTypeCallback{Data: []byte("v2")}}},
}}}) }}})
if ok, err := f.router.onMessagesEditInlineBotMessage(botCtx, editReq); err != nil || !ok { if ok, err := f.router.onMessagesEditInlineBotMessage(botCtx, editReq); err != nil || !ok {
t.Fatalf("channel inline edit = %v,%v, want true,nil", ok, err) t.Fatalf("channel inline edit = %v,%v, want true,nil", ok, err)
@ -2065,12 +2065,13 @@ func assertTGInlineReplyMarkup(t *testing.T, msg *tg.Message, wantText string, w
if len(markup.Rows) != 1 || len(markup.Rows[0].Buttons) != 1 { if len(markup.Rows) != 1 || len(markup.Rows[0].Buttons) != 1 {
t.Fatalf("reply_markup rows = %+v, want one callback button", markup.Rows) t.Fatalf("reply_markup rows = %+v, want one callback button", markup.Rows)
} }
button, ok := markup.Rows[0].Buttons[0].(*tg.KeyboardButtonCallback) button := markup.Rows[0].Buttons[0]
buttonType, ok := button.Type.(*tg.InlineButtonTypeCallback)
if !ok { if !ok {
t.Fatalf("reply_markup button = %T, want callback", markup.Rows[0].Buttons[0]) t.Fatalf("reply_markup button = %T, want callback", button.Type)
} }
if button.Text != wantText || !bytes.Equal(button.Data, wantData) { if button.Text != wantText || !bytes.Equal(buttonType.Data, wantData) {
t.Fatalf("reply_markup button = %q/%v, want %q/%v", button.Text, button.Data, wantText, wantData) t.Fatalf("reply_markup button = %q/%v, want %q/%v", button.Text, buttonType.Data, wantText, wantData)
} }
} }
@ -2119,8 +2120,8 @@ func inlineArticleResult(id, message string) tg.InputBotInlineResultClass {
func inlineArticleResultWithCallback(id, message, button string, data []byte) tg.InputBotInlineResultClass { func inlineArticleResultWithCallback(id, message, button string, data []byte) tg.InputBotInlineResultClass {
result := inlineArticleResult(id, message).(*tg.InputBotInlineResult) result := inlineArticleResult(id, message).(*tg.InputBotInlineResult)
msg := result.SendMessage.(*tg.InputBotInlineMessageText) msg := result.SendMessage.(*tg.InputBotInlineMessageText)
msg.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{ msg.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{
Buttons: []tg.KeyboardButtonClass{&tg.KeyboardButtonCallback{Text: button, Data: data}}, Buttons: []tg.KeyboardInlineButton{{Text: button, Type: &tg.InlineButtonTypeCallback{Data: data}}},
}}}) }}})
return result return result
} }
@ -2308,8 +2309,8 @@ func inlineContactResult(id, phone, first, last, vcard string) *tg.InputBotInlin
func inlineContactResultWithCallback(id, phone, first, last string, data []byte) tg.InputBotInlineResultClass { func inlineContactResultWithCallback(id, phone, first, last string, data []byte) tg.InputBotInlineResultClass {
result := inlineContactResult(id, phone, first, last, "BEGIN:VCARD\nFN:"+first+" "+last+"\nEND:VCARD") result := inlineContactResult(id, phone, first, last, "BEGIN:VCARD\nFN:"+first+" "+last+"\nEND:VCARD")
msg := result.SendMessage.(*tg.InputBotInlineMessageMediaContact) msg := result.SendMessage.(*tg.InputBotInlineMessageMediaContact)
msg.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{ msg.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{
Buttons: []tg.KeyboardButtonClass{&tg.KeyboardButtonCallback{Text: "Contact", Data: data}}, Buttons: []tg.KeyboardInlineButton{{Text: "Contact", Type: &tg.InlineButtonTypeCallback{Data: data}}},
}}}) }}})
return result return result
} }

View file

@ -594,7 +594,7 @@ func (r *Router) onBotsRequestWebViewButton(ctx context.Context, req *tg.BotsReq
if err != nil { if err != nil {
return nil, internalErr() return nil, internalErr()
} }
if req.UserID == nil || req.Button == nil { if req.UserID == nil || req.Button.Type == nil {
return nil, buttonDataInvalidErr() return nil, buttonDataInvalidErr()
} }
if r.deps.Bots == nil { if r.deps.Bots == nil {
@ -622,21 +622,21 @@ func (r *Router) onBotsRequestWebViewButton(ctx context.Context, req *tg.BotsReq
return &tg.BotsRequestedButton{WebappReqID: saved.WebAppReqID}, nil return &tg.BotsRequestedButton{WebappReqID: saved.WebAppReqID}, nil
} }
func (r *Router) onBotsGetRequestedWebViewButton(ctx context.Context, req *tg.BotsGetRequestedWebViewButtonRequest) (tg.KeyboardButtonClass, error) { func (r *Router) onBotsGetRequestedWebViewButton(ctx context.Context, req *tg.BotsGetRequestedWebViewButtonRequest) (tg.KeyboardButton, error) {
userID, _, err := r.currentUserID(ctx) userID, _, err := r.currentUserID(ctx)
if err != nil { if err != nil {
return nil, internalErr() return tg.KeyboardButton{}, internalErr()
} }
bot, err := r.resolveBotUserForViewer(ctx, userID, req.Bot) bot, err := r.resolveBotUserForViewer(ctx, userID, req.Bot)
if err != nil { if err != nil {
return nil, err return tg.KeyboardButton{}, err
} }
button, found, err := r.deps.Bots.GetRequestedWebViewButton(ctx, bot.ID, userID, req.WebappReqID) button, found, err := r.deps.Bots.GetRequestedWebViewButton(ctx, bot.ID, userID, req.WebappReqID)
if err != nil { if err != nil {
return nil, internalErr() return tg.KeyboardButton{}, internalErr()
} }
if !found { if !found {
return nil, buttonDataInvalidErr() return tg.KeyboardButton{}, buttonDataInvalidErr()
} }
return tgKeyboardButtonRequestPeer(button), nil return tgKeyboardButtonRequestPeer(button), nil
} }
@ -761,21 +761,20 @@ func (r *Router) tgBotPreviewMedia(ctx context.Context, item domain.BotAppPrevie
return out return out
} }
func domainRequestedButtonFromTG(botUserID int64, _ tg.InputUserClass, button tg.KeyboardButtonClass) (domain.BotRequestedWebViewButton, error) { func domainRequestedButtonFromTG(botUserID int64, _ tg.InputUserClass, button tg.KeyboardButton) (domain.BotRequestedWebViewButton, error) {
var out domain.BotRequestedWebViewButton var out domain.BotRequestedWebViewButton
out.BotUserID = botUserID out.BotUserID = botUserID
switch b := button.(type) { out.Text = strings.TrimSpace(button.Text)
case *tg.InputKeyboardButtonRequestPeer: switch b := button.Type.(type) {
case *tg.InputButtonTypeRequestPeer:
out.ButtonID = b.ButtonID out.ButtonID = b.ButtonID
out.Text = strings.TrimSpace(b.Text)
out.PeerType, out.PeerFilter = domainRequestPeerFilter(b.PeerType) out.PeerType, out.PeerFilter = domainRequestPeerFilter(b.PeerType)
out.MaxQuantity = b.MaxQuantity out.MaxQuantity = b.MaxQuantity
out.NameRequested = b.NameRequested out.NameRequested = b.NameRequested
out.UsernameRequested = b.UsernameRequested out.UsernameRequested = b.UsernameRequested
out.PhotoRequested = b.PhotoRequested out.PhotoRequested = b.PhotoRequested
case *tg.KeyboardButtonRequestPeer: case *tg.ButtonTypeRequestPeer:
out.ButtonID = b.ButtonID out.ButtonID = b.ButtonID
out.Text = strings.TrimSpace(b.Text)
out.PeerType, out.PeerFilter = domainRequestPeerFilter(b.PeerType) out.PeerType, out.PeerFilter = domainRequestPeerFilter(b.PeerType)
out.MaxQuantity = b.MaxQuantity out.MaxQuantity = b.MaxQuantity
default: default:
@ -800,12 +799,14 @@ func requestPeerTypeName(peerType tg.RequestPeerTypeClass) string {
} }
} }
func tgKeyboardButtonRequestPeer(button domain.BotRequestedWebViewButton) tg.KeyboardButtonClass { func tgKeyboardButtonRequestPeer(button domain.BotRequestedWebViewButton) tg.KeyboardButton {
return &tg.KeyboardButtonRequestPeer{ return tg.KeyboardButton{
Text: button.Text, Text: button.Text,
Type: &tg.ButtonTypeRequestPeer{
ButtonID: button.ButtonID, ButtonID: button.ButtonID,
PeerType: tgRequestPeerTypeWithFilter(button.PeerType, button.PeerFilter), PeerType: tgRequestPeerTypeWithFilter(button.PeerType, button.PeerFilter),
MaxQuantity: button.MaxQuantity, MaxQuantity: button.MaxQuantity,
},
} }
} }

View file

@ -252,9 +252,9 @@ func TestBotsLongtailCommercialAndSettingsStubs(t *testing.T) {
} }
if _, err := f.router.onBotsRequestWebViewButton(botCtx, &tg.BotsRequestWebViewButtonRequest{ if _, err := f.router.onBotsRequestWebViewButton(botCtx, &tg.BotsRequestWebViewButtonRequest{
UserID: inputUser(f.owner), UserID: inputUser(f.owner),
Button: &tg.KeyboardButtonSimpleWebView{ Button: tg.KeyboardButton{
Text: "Open", Text: "Open",
URL: "https://example.com/app", Type: &tg.ButtonTypeSimpleWebView{URL: "https://example.com/app"},
}, },
}); !tgerr.Is(err, "BUTTON_DATA_INVALID") { }); !tgerr.Is(err, "BUTTON_DATA_INVALID") {
t.Fatalf("request webview button err = %v, want BUTTON_DATA_INVALID", err) t.Fatalf("request webview button err = %v, want BUTTON_DATA_INVALID", err)

View file

@ -229,34 +229,38 @@ func domainOutgoingReplyMarkupForSender(markup tg.ReplyMarkupClass, senderIsBot
} }
} }
func domainReplyKeyboardButton(button tg.KeyboardButtonClass) (domain.MarkupButton, error) { func domainReplyKeyboardButton(button tg.KeyboardButton) (domain.MarkupButton, error) {
style, icon, err := domainMarkupButtonStyle(button) style, icon, err := domainMarkupButtonStyle(button.GetStyle())
if err != nil { if err != nil {
return domain.MarkupButton{}, err return domain.MarkupButton{}, err
} }
base := domain.MarkupButton{Style: style, IconCustomEmojiID: icon} base := domain.MarkupButton{Style: style, IconCustomEmojiID: icon, Text: button.Text}
switch b := button.(type) { switch t := button.Type.(type) {
case *tg.KeyboardButton: case nil, *tg.ButtonTypeDefault:
base.Type, base.Text = domain.MarkupButtonText, b.Text base.Type = domain.MarkupButtonText
case *tg.KeyboardButtonRequestPhone: case *tg.ButtonTypeRequestPhone:
base.Type, base.Text = domain.MarkupButtonRequestPhone, b.Text base.Type = domain.MarkupButtonRequestPhone
case *tg.KeyboardButtonRequestGeoLocation: case *tg.ButtonTypeRequestGeoLocation:
base.Type, base.Text = domain.MarkupButtonRequestLocation, b.Text base.Type = domain.MarkupButtonRequestLocation
case *tg.KeyboardButtonRequestPoll: case *tg.ButtonTypeRequestPoll:
base.Type, base.Text = domain.MarkupButtonRequestPoll, b.Text base.Type = domain.MarkupButtonRequestPoll
if quiz, ok := b.GetQuiz(); ok { if quiz, ok := t.GetQuiz(); ok {
if quiz { if quiz {
base.PollType = "quiz" base.PollType = "quiz"
} else { } else {
base.PollType = "regular" base.PollType = "regular"
} }
} }
case *tg.KeyboardButtonRequestPeer: case *tg.ButtonTypeRequestPeer:
base.Type, base.Text = domain.MarkupButtonRequestPeer, b.Text base.Type = domain.MarkupButtonRequestPeer
base.ButtonID, base.MaxQuantity = b.ButtonID, b.MaxQuantity base.ButtonID, base.MaxQuantity = t.ButtonID, t.MaxQuantity
base.RequestPeerType, base.RequestPeerFilter = domainRequestPeerFilter(b.PeerType) base.RequestPeerType, base.RequestPeerFilter = domainRequestPeerFilter(t.PeerType)
case *tg.KeyboardButtonSimpleWebView: case *tg.InputButtonTypeRequestPeer:
base.Type, base.Text, base.URL = domain.MarkupButtonSimpleWebView, b.Text, b.URL base.Type = domain.MarkupButtonRequestPeer
base.ButtonID, base.MaxQuantity = t.ButtonID, t.MaxQuantity
base.RequestPeerType, base.RequestPeerFilter = domainRequestPeerFilter(t.PeerType)
case *tg.ButtonTypeSimpleWebView:
base.Type, base.URL = domain.MarkupButtonSimpleWebView, t.URL
default: default:
return domain.MarkupButton{}, domain.ErrButtonTypeInvalid return domain.MarkupButton{}, domain.ErrButtonTypeInvalid
} }
@ -281,29 +285,29 @@ func domainInlineMarkup(inline *tg.ReplyInlineMarkup) (*domain.MessageReplyMarku
return out, nil return out, nil
} }
func domainMarkupButton(btn tg.KeyboardButtonClass, buttonID int) (domain.MarkupButton, error) { func domainMarkupButton(btn tg.KeyboardInlineButton, buttonID int) (domain.MarkupButton, error) {
style, icon, err := domainMarkupButtonStyle(btn) style, icon, err := domainMarkupButtonStyle(btn.GetStyle())
if err != nil { if err != nil {
return domain.MarkupButton{}, err return domain.MarkupButton{}, err
} }
switch b := btn.(type) { switch t := btn.Type.(type) {
case *tg.KeyboardButtonCallback: case *tg.InlineButtonTypeCallback:
return domain.MarkupButton{ return domain.MarkupButton{
Type: domain.MarkupButtonCallback, Type: domain.MarkupButtonCallback,
Text: b.Text, Text: btn.Text,
Style: style, Style: style,
IconCustomEmojiID: icon, IconCustomEmojiID: icon,
Data: append([]byte(nil), b.Data...), Data: append([]byte(nil), t.Data...),
RequiresPassword: b.RequiresPassword, RequiresPassword: t.RequiresPassword,
}, nil }, nil
case *tg.KeyboardButtonURL: case *tg.InlineButtonTypeURL:
return domain.MarkupButton{ return domain.MarkupButton{
Type: domain.MarkupButtonURL, Text: b.Text, URL: b.URL, Type: domain.MarkupButtonURL, Text: btn.Text, URL: t.URL,
Style: style, IconCustomEmojiID: icon, Style: style, IconCustomEmojiID: icon,
}, nil }, nil
case *tg.InputKeyboardButtonURLAuth: case *tg.InputInlineButtonTypeURLAuth:
botUserID := int64(0) botUserID := int64(0)
switch bot := b.Bot.(type) { switch bot := t.Bot.(type) {
case nil, *tg.InputUserEmpty, *tg.InputUserSelf: case nil, *tg.InputUserEmpty, *tg.InputUserSelf:
case *tg.InputUser: case *tg.InputUser:
botUserID = bot.UserID botUserID = bot.UserID
@ -311,34 +315,33 @@ func domainMarkupButton(btn tg.KeyboardButtonClass, buttonID int) (domain.Markup
return domain.MarkupButton{}, domain.ErrButtonInvalid return domain.MarkupButton{}, domain.ErrButtonInvalid
} }
return domain.MarkupButton{ return domain.MarkupButton{
Type: domain.MarkupButtonLoginURL, Text: b.Text, URL: b.URL, Type: domain.MarkupButtonLoginURL, Text: btn.Text, URL: t.URL,
ForwardText: b.FwdText, ButtonID: buttonID, LoginBotUserID: botUserID, ForwardText: t.FwdText, ButtonID: buttonID, LoginBotUserID: botUserID,
RequestWriteAccess: b.RequestWriteAccess, Style: style, IconCustomEmojiID: icon, RequestWriteAccess: t.RequestWriteAccess, Style: style, IconCustomEmojiID: icon,
}, nil }, nil
case *tg.KeyboardButtonURLAuth: case *tg.InlineButtonTypeURLAuth:
return domain.MarkupButton{ return domain.MarkupButton{
Type: domain.MarkupButtonLoginURL, Text: b.Text, URL: b.URL, Type: domain.MarkupButtonLoginURL, Text: btn.Text, URL: t.URL,
ForwardText: b.FwdText, ButtonID: b.ButtonID, ForwardText: t.FwdText, ButtonID: t.ButtonID,
Style: style, IconCustomEmojiID: icon, Style: style, IconCustomEmojiID: icon,
}, nil }, nil
case *tg.KeyboardButtonWebView: case *tg.InlineButtonTypeWebView:
return domain.MarkupButton{Type: domain.MarkupButtonWebView, Text: b.Text, URL: b.URL, Style: style, IconCustomEmojiID: icon}, nil return domain.MarkupButton{Type: domain.MarkupButtonWebView, Text: btn.Text, URL: t.URL, Style: style, IconCustomEmojiID: icon}, nil
case *tg.KeyboardButtonSwitchInline: case *tg.InlineButtonTypeSwitchInline:
peerTypes, err := preparedInlinePeerTypesFromTG(b.PeerTypes) peerTypes, err := preparedInlinePeerTypesFromTG(t.PeerTypes)
if err != nil { if err != nil {
return domain.MarkupButton{}, domain.ErrButtonInvalid return domain.MarkupButton{}, domain.ErrButtonInvalid
} }
return domain.MarkupButton{Type: domain.MarkupButtonSwitchInline, Text: b.Text, Query: b.Query, SamePeer: b.SamePeer, PeerTypes: peerTypes, Style: style, IconCustomEmojiID: icon}, nil return domain.MarkupButton{Type: domain.MarkupButtonSwitchInline, Text: btn.Text, Query: t.Query, SamePeer: t.SamePeer, PeerTypes: peerTypes, Style: style, IconCustomEmojiID: icon}, nil
case *tg.KeyboardButtonCopy: case *tg.InlineButtonTypeCopy:
return domain.MarkupButton{Type: domain.MarkupButtonCopy, Text: b.Text, CopyText: b.CopyText, Style: style, IconCustomEmojiID: icon}, nil return domain.MarkupButton{Type: domain.MarkupButtonCopy, Text: btn.Text, CopyText: t.CopyText, Style: style, IconCustomEmojiID: icon}, nil
default: default:
// webview/game/url_auth/request_*/switch_inline/buy 等 P3 未实现按钮类型。 // webview/game/url_auth/request_*/switch_inline/buy 等 P3 未实现按钮类型。
return domain.MarkupButton{}, domain.ErrButtonTypeInvalid return domain.MarkupButton{}, domain.ErrButtonTypeInvalid
} }
} }
func domainMarkupButtonStyle(btn tg.KeyboardButtonClass) (domain.MarkupButtonStyle, int64, error) { func domainMarkupButtonStyle(style tg.KeyboardButtonStyle, ok bool) (domain.MarkupButtonStyle, int64, error) {
style, ok := btn.GetStyle()
if !ok { if !ok {
return "", 0, nil return "", 0, nil
} }
@ -388,7 +391,7 @@ func tgReplyMarkup(m *domain.MessageReplyMarkup) tg.ReplyMarkupClass {
case domain.MessageReplyMarkupKeyboard: case domain.MessageReplyMarkupKeyboard:
rows := make([]tg.KeyboardButtonRow, 0, len(m.Keyboard)) rows := make([]tg.KeyboardButtonRow, 0, len(m.Keyboard))
for _, row := range m.Keyboard { for _, row := range m.Keyboard {
buttons := make([]tg.KeyboardButtonClass, 0, len(row)) buttons := make([]tg.KeyboardButton, 0, len(row))
for _, btn := range row { for _, btn := range row {
buttons = append(buttons, tgReplyKeyboardButton(btn)) buttons = append(buttons, tgReplyKeyboardButton(btn))
} }
@ -415,93 +418,75 @@ func tgReplyMarkup(m *domain.MessageReplyMarkup) tg.ReplyMarkupClass {
default: default:
return nil return nil
} }
rows := make([]tg.KeyboardButtonRow, 0, len(m.Inline)) rows := make([]tg.KeyboardInlineButtonRow, 0, len(m.Inline))
for _, row := range m.Inline { for _, row := range m.Inline {
buttons := make([]tg.KeyboardButtonClass, 0, len(row)) buttons := make([]tg.KeyboardInlineButton, 0, len(row))
for _, btn := range row { for _, btn := range row {
buttons = append(buttons, tgMarkupButton(btn)) buttons = append(buttons, tgMarkupButton(btn))
} }
rows = append(rows, tg.KeyboardButtonRow{Buttons: buttons}) rows = append(rows, tg.KeyboardInlineButtonRow{Buttons: buttons})
} }
return &tg.ReplyInlineMarkup{Rows: rows} return &tg.ReplyInlineMarkup{Rows: rows}
} }
func tgMarkupButton(btn domain.MarkupButton) tg.KeyboardButtonClass { func tgMarkupButton(btn domain.MarkupButton) tg.KeyboardInlineButton {
out := tg.KeyboardInlineButton{Text: btn.Text}
if style, ok := tgMarkupButtonStyle(btn); ok {
out.SetStyle(style)
}
switch btn.Type { switch btn.Type {
case domain.MarkupButtonURL: case domain.MarkupButtonURL:
out := &tg.KeyboardButtonURL{Text: btn.Text, URL: btn.URL} out.Type = &tg.InlineButtonTypeURL{URL: btn.URL}
if style, ok := tgMarkupButtonStyle(btn); ok {
out.SetStyle(style)
}
return out
case domain.MarkupButtonLoginURL: case domain.MarkupButtonLoginURL:
out := &tg.KeyboardButtonURLAuth{Text: btn.Text, URL: btn.URL, ButtonID: btn.ButtonID} t := &tg.InlineButtonTypeURLAuth{URL: btn.URL, ButtonID: btn.ButtonID}
if btn.ForwardText != "" { if btn.ForwardText != "" {
out.SetFwdText(btn.ForwardText) t.SetFwdText(btn.ForwardText)
} }
if style, ok := tgMarkupButtonStyle(btn); ok { out.Type = t
out.SetStyle(style)
}
return out
case domain.MarkupButtonWebView: case domain.MarkupButtonWebView:
out := &tg.KeyboardButtonWebView{Text: btn.Text, URL: btn.URL} out.Type = &tg.InlineButtonTypeWebView{URL: btn.URL}
if style, ok := tgMarkupButtonStyle(btn); ok {
out.SetStyle(style)
}
return out
case domain.MarkupButtonSwitchInline: case domain.MarkupButtonSwitchInline:
out := &tg.KeyboardButtonSwitchInline{Text: btn.Text, Query: btn.Query, SamePeer: btn.SamePeer} t := &tg.InlineButtonTypeSwitchInline{Query: btn.Query, SamePeer: btn.SamePeer}
if len(btn.PeerTypes) > 0 { if len(btn.PeerTypes) > 0 {
out.SetPeerTypes(tgPreparedInlinePeerTypes(btn.PeerTypes)) t.SetPeerTypes(tgPreparedInlinePeerTypes(btn.PeerTypes))
} }
if style, ok := tgMarkupButtonStyle(btn); ok { out.Type = t
out.SetStyle(style)
}
return out
case domain.MarkupButtonCopy: case domain.MarkupButtonCopy:
out := &tg.KeyboardButtonCopy{Text: btn.Text, CopyText: btn.CopyText} out.Type = &tg.InlineButtonTypeCopy{CopyText: btn.CopyText}
if style, ok := tgMarkupButtonStyle(btn); ok {
out.SetStyle(style)
}
return out
default: // callback default: // callback
out := &tg.KeyboardButtonCallback{Text: btn.Text, Data: btn.Data} t := &tg.InlineButtonTypeCallback{Data: btn.Data}
if btn.RequiresPassword { if btn.RequiresPassword {
out.SetRequiresPassword(true) t.SetRequiresPassword(true)
} }
if style, ok := tgMarkupButtonStyle(btn); ok { out.Type = t
out.SetStyle(style)
} }
return out return out
} }
}
func tgReplyKeyboardButton(btn domain.MarkupButton) tg.KeyboardButtonClass { func tgReplyKeyboardButton(btn domain.MarkupButton) tg.KeyboardButton {
var out tg.KeyboardButtonClass out := tg.KeyboardButton{Text: btn.Text}
switch btn.Type { switch btn.Type {
case domain.MarkupButtonRequestPhone: case domain.MarkupButtonRequestPhone:
out = &tg.KeyboardButtonRequestPhone{Text: btn.Text} out.Type = &tg.ButtonTypeRequestPhone{}
case domain.MarkupButtonRequestLocation: case domain.MarkupButtonRequestLocation:
out = &tg.KeyboardButtonRequestGeoLocation{Text: btn.Text} out.Type = &tg.ButtonTypeRequestGeoLocation{}
case domain.MarkupButtonRequestPoll: case domain.MarkupButtonRequestPoll:
button := &tg.KeyboardButtonRequestPoll{Text: btn.Text} t := &tg.ButtonTypeRequestPoll{}
if btn.PollType == "quiz" { if btn.PollType == "quiz" {
button.SetQuiz(true) t.SetQuiz(true)
} else if btn.PollType == "regular" { } else if btn.PollType == "regular" {
button.SetQuiz(false) t.SetQuiz(false)
} }
out = button out.Type = t
case domain.MarkupButtonRequestPeer: case domain.MarkupButtonRequestPeer:
out = &tg.KeyboardButtonRequestPeer{Text: btn.Text, ButtonID: btn.ButtonID, PeerType: tgRequestPeerTypeWithFilter(btn.RequestPeerType, btn.RequestPeerFilter), MaxQuantity: btn.MaxQuantity} out.Type = &tg.ButtonTypeRequestPeer{ButtonID: btn.ButtonID, PeerType: tgRequestPeerTypeWithFilter(btn.RequestPeerType, btn.RequestPeerFilter), MaxQuantity: btn.MaxQuantity}
case domain.MarkupButtonSimpleWebView: case domain.MarkupButtonSimpleWebView:
out = &tg.KeyboardButtonSimpleWebView{Text: btn.Text, URL: btn.URL} out.Type = &tg.ButtonTypeSimpleWebView{URL: btn.URL}
default: default:
out = &tg.KeyboardButton{Text: btn.Text} out.Type = &tg.ButtonTypeDefault{}
} }
if style, ok := tgMarkupButtonStyle(btn); ok { if style, ok := tgMarkupButtonStyle(btn); ok {
if setter, ok := out.(interface{ SetStyle(tg.KeyboardButtonStyle) }); ok { out.SetStyle(style)
setter.SetStyle(style)
}
} }
return out return out
} }

View file

@ -9,22 +9,20 @@ import (
) )
func TestReplyKeyboardTLDomainRoundTrip(t *testing.T) { func TestReplyKeyboardTLDomainRoundTrip(t *testing.T) {
statusButton := tg.KeyboardButton{Text: "Status"}
style := tg.KeyboardButtonStyle{}
style.SetBgPrimary(true)
style.SetIcon(123456)
statusButton.SetStyle(style)
in := &tg.ReplyKeyboardMarkup{ in := &tg.ReplyKeyboardMarkup{
Resize: true, Resize: true,
SingleUse: true, SingleUse: true,
Selective: true, Selective: true,
Persistent: true, Persistent: true,
Placeholder: "Choose", Placeholder: "Choose",
Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButtonClass{ Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButton{
&tg.KeyboardButton{Text: "Help"}, {Text: "Help"},
func() *tg.KeyboardButton { statusButton,
button := &tg.KeyboardButton{Text: "Status"}
style := tg.KeyboardButtonStyle{}
style.SetBgPrimary(true)
style.SetIcon(123456)
button.SetStyle(style)
return button
}(),
}}}, }}},
} }
got, err := domainOutgoingReplyMarkupForSender(in, true) got, err := domainOutgoingReplyMarkupForSender(in, true)
@ -43,8 +41,9 @@ func TestReplyKeyboardTLDomainRoundTrip(t *testing.T) {
if !ok || len(wire.Rows) != 1 || len(wire.Rows[0].Buttons) != 2 { if !ok || len(wire.Rows) != 1 || len(wire.Rows[0].Buttons) != 2 {
t.Fatalf("wire markup = %#v", wire) t.Fatalf("wire markup = %#v", wire)
} }
if button, ok := wire.Rows[0].Buttons[1].(*tg.KeyboardButton); !ok || button.Text != "Status" { button := wire.Rows[0].Buttons[1]
t.Fatalf("second button = %#v", wire.Rows[0].Buttons[1]) if button.Text != "Status" {
t.Fatalf("second button = %#v", button)
} else if style, ok := button.GetStyle(); !ok || !style.GetBgPrimary() || style.Icon != 123456 { } else if style, ok := button.GetStyle(); !ok || !style.GetBgPrimary() || style.Icon != 123456 {
t.Fatalf("second button style = %#v ok=%v", style, ok) t.Fatalf("second button style = %#v ok=%v", style, ok)
} }
@ -54,30 +53,32 @@ func TestReplyKeyboardTLDomainRoundTrip(t *testing.T) {
} }
func TestInlineButtonStyleTLDomainRoundTrip(t *testing.T) { func TestInlineButtonStyleTLDomainRoundTrip(t *testing.T) {
button := &tg.KeyboardButtonCallback{Text: "Delete", Data: []byte("delete")} button := tg.KeyboardInlineButton{Text: "Delete", Type: &tg.InlineButtonTypeCallback{Data: []byte("delete")}}
style := tg.KeyboardButtonStyle{} style := tg.KeyboardButtonStyle{}
style.SetBgDanger(true) style.SetBgDanger(true)
button.SetStyle(style) button.SetStyle(style)
got, err := domainReplyMarkupForSender(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButtonClass{button}}}}, true) got, err := domainReplyMarkupForSender(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{Buttons: []tg.KeyboardInlineButton{button}}}}, true)
if err != nil { if err != nil {
t.Fatalf("domainReplyMarkupForSender: %v", err) t.Fatalf("domainReplyMarkupForSender: %v", err)
} }
if got.Inline[0][0].Style != domain.MarkupButtonStyleDanger { if got.Inline[0][0].Style != domain.MarkupButtonStyleDanger {
t.Fatalf("domain style = %#v", got.Inline[0][0]) t.Fatalf("domain style = %#v", got.Inline[0][0])
} }
wire := tgReplyMarkup(got).(*tg.ReplyInlineMarkup).Rows[0].Buttons[0].(*tg.KeyboardButtonCallback) wire := tgReplyMarkup(got).(*tg.ReplyInlineMarkup).Rows[0].Buttons[0]
if roundTrip, ok := wire.GetStyle(); !ok || !roundTrip.GetBgDanger() { if roundTrip, ok := wire.GetStyle(); !ok || !roundTrip.GetBgDanger() {
t.Fatalf("wire style = %#v ok=%v", roundTrip, ok) t.Fatalf("wire style = %#v ok=%v", roundTrip, ok)
} }
if _, ok := wire.Type.(*tg.InlineButtonTypeCallback); !ok {
t.Fatalf("wire type = %#v", wire.Type)
}
} }
func TestLoginURLButtonTLDomainProjection(t *testing.T) { func TestLoginURLButtonTLDomainProjection(t *testing.T) {
button := &tg.InputKeyboardButtonURLAuth{ buttonType := &tg.InputInlineButtonTypeURLAuth{URL: "https://example.com/login", Bot: &tg.InputUser{UserID: 9001, AccessHash: 77}}
Text: "Log in", URL: "https://example.com/login", Bot: &tg.InputUser{UserID: 9001, AccessHash: 77}, buttonType.SetRequestWriteAccess(true)
} buttonType.SetFwdText("Open login")
button.SetRequestWriteAccess(true) button := tg.KeyboardInlineButton{Text: "Log in", Type: buttonType}
button.SetFwdText("Open login") markup, err := domainReplyMarkupForSender(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{Buttons: []tg.KeyboardInlineButton{button}}}}, true)
markup, err := domainReplyMarkupForSender(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButtonClass{button}}}}, true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -85,8 +86,9 @@ func TestLoginURLButtonTLDomainProjection(t *testing.T) {
if got.Type != domain.MarkupButtonLoginURL || got.LoginBotUserID != 9001 || !got.RequestWriteAccess || got.ForwardText != "Open login" || got.ButtonID != 0 { if got.Type != domain.MarkupButtonLoginURL || got.LoginBotUserID != 9001 || !got.RequestWriteAccess || got.ForwardText != "Open login" || got.ButtonID != 0 {
t.Fatalf("domain login_url = %#v", got) t.Fatalf("domain login_url = %#v", got)
} }
wire, ok := tgReplyMarkup(markup).(*tg.ReplyInlineMarkup).Rows[0].Buttons[0].(*tg.KeyboardButtonURLAuth) wire := tgReplyMarkup(markup).(*tg.ReplyInlineMarkup).Rows[0].Buttons[0]
if !ok || wire.Text != "Log in" || wire.URL != "https://example.com/login" || wire.ButtonID != 0 || wire.FwdText != "Open login" { wireType, ok := wire.Type.(*tg.InlineButtonTypeURLAuth)
if !ok || wire.Text != "Log in" || wireType.URL != "https://example.com/login" || wireType.ButtonID != 0 || wireType.FwdText != "Open login" {
t.Fatalf("wire login_url = %#v", wire) t.Fatalf("wire login_url = %#v", wire)
} }
} }
@ -112,7 +114,7 @@ func TestReplyKeyboardHideAndForceReplyTLDomainRoundTrip(t *testing.T) {
func TestReplyKeyboardRequestPhoneTLDomainRoundTrip(t *testing.T) { func TestReplyKeyboardRequestPhoneTLDomainRoundTrip(t *testing.T) {
markup, err := domainOutgoingReplyMarkupForSender(&tg.ReplyKeyboardMarkup{Rows: []tg.KeyboardButtonRow{{ markup, err := domainOutgoingReplyMarkupForSender(&tg.ReplyKeyboardMarkup{Rows: []tg.KeyboardButtonRow{{
Buttons: []tg.KeyboardButtonClass{&tg.KeyboardButtonRequestPhone{Text: "Share phone"}}, Buttons: []tg.KeyboardButton{{Text: "Share phone", Type: &tg.ButtonTypeRequestPhone{}}},
}}}, true) }}}, true)
if err != nil || markup == nil || len(markup.Keyboard) != 1 || len(markup.Keyboard[0]) != 1 || if err != nil || markup == nil || len(markup.Keyboard) != 1 || len(markup.Keyboard[0]) != 1 ||
markup.Keyboard[0][0].Type != domain.MarkupButtonRequestPhone { markup.Keyboard[0][0].Type != domain.MarkupButtonRequestPhone {
@ -122,7 +124,7 @@ func TestReplyKeyboardRequestPhoneTLDomainRoundTrip(t *testing.T) {
if !ok || len(wire.Rows) != 1 || len(wire.Rows[0].Buttons) != 1 { if !ok || len(wire.Rows) != 1 || len(wire.Rows[0].Buttons) != 1 {
t.Fatalf("request_phone wire = %#v", wire) t.Fatalf("request_phone wire = %#v", wire)
} }
if _, ok := wire.Rows[0].Buttons[0].(*tg.KeyboardButtonRequestPhone); !ok { if _, ok := wire.Rows[0].Buttons[0].Type.(*tg.ButtonTypeRequestPhone); !ok {
t.Fatalf("request_phone button = %#v", wire.Rows[0].Buttons[0]) t.Fatalf("request_phone button = %#v", wire.Rows[0].Buttons[0])
} }
if _, err := domainReplyMarkupForSender(&tg.ReplyKeyboardHide{}, true); err == nil { if _, err := domainReplyMarkupForSender(&tg.ReplyKeyboardHide{}, true); err == nil {
@ -138,9 +140,9 @@ func TestReplyKeyboardRequestPeerFiltersTLDomainRoundTrip(t *testing.T) {
chatType.SetHasUsername(false) chatType.SetHasUsername(false)
chatType.SetForum(true) chatType.SetForum(true)
chatType.SetUserAdminRights(tg.ChatAdminRights{DeleteMessages: true, ManageTopics: true}) chatType.SetUserAdminRights(tg.ChatAdminRights{DeleteMessages: true, ManageTopics: true})
in := &tg.ReplyKeyboardMarkup{Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButtonClass{ in := &tg.ReplyKeyboardMarkup{Rows: []tg.KeyboardButtonRow{{Buttons: []tg.KeyboardButton{
&tg.KeyboardButtonRequestPeer{Text: "Premium person", ButtonID: 1, PeerType: userType, MaxQuantity: 2}, {Text: "Premium person", Type: &tg.ButtonTypeRequestPeer{ButtonID: 1, PeerType: userType, MaxQuantity: 2}},
&tg.KeyboardButtonRequestPeer{Text: "Forum", ButtonID: 2, PeerType: chatType, MaxQuantity: 1}, {Text: "Forum", Type: &tg.ButtonTypeRequestPeer{ButtonID: 2, PeerType: chatType, MaxQuantity: 1}},
}}}} }}}}
markup, err := domainOutgoingReplyMarkupForSender(in, true) markup, err := domainOutgoingReplyMarkupForSender(in, true)
if err != nil { if err != nil {
@ -157,14 +159,14 @@ func TestReplyKeyboardRequestPeerFiltersTLDomainRoundTrip(t *testing.T) {
t.Fatalf("chat filter = %#v", chatFilter) t.Fatalf("chat filter = %#v", chatFilter)
} }
wire := tgReplyMarkup(markup).(*tg.ReplyKeyboardMarkup) wire := tgReplyMarkup(markup).(*tg.ReplyKeyboardMarkup)
wireUser := wire.Rows[0].Buttons[0].(*tg.KeyboardButtonRequestPeer).PeerType.(*tg.RequestPeerTypeUser) wireUser := wire.Rows[0].Buttons[0].Type.(*tg.ButtonTypeRequestPeer).PeerType.(*tg.RequestPeerTypeUser)
if bot, ok := wireUser.GetBot(); !ok || bot { if bot, ok := wireUser.GetBot(); !ok || bot {
t.Fatalf("wire user bot=%v ok=%v", bot, ok) t.Fatalf("wire user bot=%v ok=%v", bot, ok)
} }
if premium, ok := wireUser.GetPremium(); !ok || !premium { if premium, ok := wireUser.GetPremium(); !ok || !premium {
t.Fatalf("wire user premium=%v ok=%v", premium, ok) t.Fatalf("wire user premium=%v ok=%v", premium, ok)
} }
wireChat := wire.Rows[0].Buttons[1].(*tg.KeyboardButtonRequestPeer).PeerType.(*tg.RequestPeerTypeChat) wireChat := wire.Rows[0].Buttons[1].Type.(*tg.ButtonTypeRequestPeer).PeerType.(*tg.RequestPeerTypeChat)
if !wireChat.Creator || !wireChat.BotParticipant { if !wireChat.Creator || !wireChat.BotParticipant {
t.Fatalf("wire chat = %#v", wireChat) t.Fatalf("wire chat = %#v", wireChat)
} }
@ -177,9 +179,12 @@ func TestReplyKeyboardRequestPeerFiltersTLDomainRoundTrip(t *testing.T) {
} }
func TestInputRequestPeerButtonPreservesRequestedMetadata(t *testing.T) { func TestInputRequestPeerButtonPreservesRequestedMetadata(t *testing.T) {
button := &tg.InputKeyboardButtonRequestPeer{ button := tg.KeyboardButton{
Text: "Share",
Type: &tg.InputButtonTypeRequestPeer{
NameRequested: true, UsernameRequested: true, PhotoRequested: true, NameRequested: true, UsernameRequested: true, PhotoRequested: true,
Text: "Share", ButtonID: 99, PeerType: &tg.RequestPeerTypeUser{}, MaxQuantity: 3, ButtonID: 99, PeerType: &tg.RequestPeerTypeUser{}, MaxQuantity: 3,
},
} }
got, err := domainRequestedButtonFromTG(1001, nil, button) got, err := domainRequestedButtonFromTG(1001, nil, button)
if err != nil { if err != nil {

View file

@ -99,8 +99,8 @@ func TestMessagesEditInlineBotMessageEditsPrivateInlineMessage(t *testing.T) {
editReq := &tg.MessagesEditInlineBotMessageRequest{ID: msgID} editReq := &tg.MessagesEditInlineBotMessageRequest{ID: msgID}
editReq.SetMessage("after edit") editReq.SetMessage("after edit")
editReq.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{ editReq.SetReplyMarkup(&tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{
Buttons: []tg.KeyboardButtonClass{&tg.KeyboardButtonCallback{Text: "done", Data: []byte("v2")}}, Buttons: []tg.KeyboardInlineButton{{Text: "done", Type: &tg.InlineButtonTypeCallback{Data: []byte("v2")}}},
}}}) }}})
if ok, err := f.router.onMessagesEditInlineBotMessage(botCtx, editReq); err != nil || !ok { if ok, err := f.router.onMessagesEditInlineBotMessage(botCtx, editReq); err != nil || !ok {
t.Fatalf("edit inline bot message = %v,%v, want true,nil", ok, err) t.Fatalf("edit inline bot message = %v,%v, want true,nil", ok, err)
@ -291,8 +291,8 @@ func inlineArticleResultWithCallbackMarkup(id, message, button string, data []by
Title: id, Title: id,
SendMessage: &tg.InputBotInlineMessageText{ SendMessage: &tg.InputBotInlineMessageText{
Message: message, Message: message,
ReplyMarkup: &tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{{ ReplyMarkup: &tg.ReplyInlineMarkup{Rows: []tg.KeyboardInlineButtonRow{{
Buttons: []tg.KeyboardButtonClass{&tg.KeyboardButtonCallback{Text: button, Data: data}}, Buttons: []tg.KeyboardInlineButton{{Text: button, Type: &tg.InlineButtonTypeCallback{Data: data}}},
}}}, }}},
}, },
} }