feat: sync bot rich messages and inline menus
This commit is contained in:
parent
2965f5d47d
commit
1a2d03f529
24 changed files with 2073 additions and 38 deletions
|
|
@ -253,7 +253,7 @@ func apiMessageProjectable(msg domain.Message) bool {
|
|||
if msg.Out || msg.ID <= 0 {
|
||||
return false
|
||||
}
|
||||
return msg.Body != "" || len(apiMessageMedia(msg.Media, nil, nil)) > 0
|
||||
return msg.Body != "" || (msg.RichMessage != nil && len(msg.RichMessage.BotAPIProjection) > 0) || len(apiMessageMedia(msg.Media, nil, nil)) > 0
|
||||
}
|
||||
|
||||
func apiUser(u domain.User) map[string]any {
|
||||
|
|
@ -320,6 +320,12 @@ func apiMessage(msg domain.Message, users []domain.User, channelLists ...[]domai
|
|||
out["entities"] = entities
|
||||
}
|
||||
}
|
||||
if msg.RichMessage != nil && len(msg.RichMessage.BotAPIProjection) > 0 {
|
||||
var richMessage any
|
||||
if json.Unmarshal(msg.RichMessage.BotAPIProjection, &richMessage) == nil && richMessage != nil {
|
||||
out["rich_message"] = richMessage
|
||||
}
|
||||
}
|
||||
if msg.EditDate > 0 {
|
||||
out["edit_date"] = msg.EditDate
|
||||
}
|
||||
|
|
|
|||
99
internal/botapi/rich_message.go
Normal file
99
internal/botapi/rich_message.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
package botapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
const maxBotAPIRichSourceBytes = 256 << 10
|
||||
|
||||
func richMessageInputFromAPI(raw string) (domain.BotAPIRichMessageInput, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" || len(raw) > maxBotAPIRichSourceBytes {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
var fields map[string]json.RawMessage
|
||||
if err := json.Unmarshal([]byte(raw), &fields); err != nil {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
var out domain.BotAPIRichMessageInput
|
||||
sources := 0
|
||||
if value, ok := fields["html"]; ok && !bytes.Equal(bytes.TrimSpace(value), []byte("null")) {
|
||||
if err := json.Unmarshal(value, &out.HTML); err != nil || out.HTML == "" {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
sources++
|
||||
}
|
||||
if value, ok := fields["markdown"]; ok && !bytes.Equal(bytes.TrimSpace(value), []byte("null")) {
|
||||
if err := json.Unmarshal(value, &out.Markdown); err != nil || out.Markdown == "" {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
sources++
|
||||
}
|
||||
if value, ok := fields["blocks"]; ok && !bytes.Equal(bytes.TrimSpace(value), []byte("null")) {
|
||||
if len(bytes.TrimSpace(value)) == 0 {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
out.BlocksJSON = append([]byte(nil), value...)
|
||||
sources++
|
||||
}
|
||||
if sources != 1 {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
if len(out.BlocksJSON) != 0 {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_BLOCKS_UNSUPPORTED")
|
||||
}
|
||||
if value, ok := fields["media"]; ok && !bytes.Equal(bytes.TrimSpace(value), []byte("null")) && !bytes.Equal(bytes.TrimSpace(value), []byte("[]")) {
|
||||
out.MediaJSON = append([]byte(nil), value...)
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_MEDIA_UNSUPPORTED")
|
||||
}
|
||||
if value, ok := fields["is_rtl"]; ok {
|
||||
if err := json.Unmarshal(value, &out.RTL); err != nil {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
}
|
||||
if value, ok := fields["skip_entity_detection"]; ok {
|
||||
if err := json.Unmarshal(value, &out.SkipEntityDetection); err != nil {
|
||||
return domain.BotAPIRichMessageInput{}, errors.New("RICH_MESSAGE_INVALID")
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func richReplyMessageID(values map[string]string) (int, error) {
|
||||
legacy := apiInt(values["reply_to_message_id"], 0)
|
||||
raw := strings.TrimSpace(values["reply_parameters"])
|
||||
if raw == "" {
|
||||
if legacy < 0 {
|
||||
return 0, errors.New("REPLY_MESSAGE_ID_INVALID")
|
||||
}
|
||||
return legacy, nil
|
||||
}
|
||||
if legacy != 0 {
|
||||
return 0, errors.New("REPLY_PARAMETERS_INVALID")
|
||||
}
|
||||
var payload struct {
|
||||
MessageID int `json:"message_id"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(raw), &payload); err != nil || payload.MessageID <= 0 {
|
||||
return 0, errors.New("REPLY_PARAMETERS_INVALID")
|
||||
}
|
||||
return payload.MessageID, nil
|
||||
}
|
||||
|
||||
func apiInt64(raw string) (int64, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return 0, nil
|
||||
}
|
||||
value, err := strconv.ParseInt(raw, 10, 64)
|
||||
if err != nil || value < 0 {
|
||||
return 0, errors.New("VALUE_INVALID")
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
|
@ -43,9 +43,12 @@ type GatewayService interface {
|
|||
BotAPISelf(ctx context.Context, botID int64) (domain.User, error)
|
||||
BotAPIUpdates(ctx context.Context, botID int64, offset int64) ([]domain.UpdateEvent, error)
|
||||
BotAPISendMessage(ctx context.Context, botID, chatID int64, text string, entities []domain.MessageEntity, replyMarkup *domain.MessageReplyMarkup, disableWebPagePreview, silent bool, replyToMessageID int) (domain.Message, error)
|
||||
BotAPISendRichMessage(ctx context.Context, botID, chatID int64, rich domain.BotAPIRichMessageInput, replyMarkup *domain.MessageReplyMarkup, silent, noForwards bool, replyToMessageID int, effectID int64) (domain.Message, error)
|
||||
BotAPISendMedia(ctx context.Context, botID, chatID int64, kind, locationKey, remoteURL, fileName, mimeType string, fileBytes []byte, caption string, entities []domain.MessageEntity, replyMarkup *domain.MessageReplyMarkup, silent bool, replyToMessageID int) (domain.Message, error)
|
||||
BotAPIEditMessageText(ctx context.Context, botID, chatID int64, messageID int, text string, entities []domain.MessageEntity, setReplyMarkup bool, replyMarkup *domain.MessageReplyMarkup, disableWebPagePreview bool) (domain.Message, error)
|
||||
BotAPIEditRichMessage(ctx context.Context, botID, chatID int64, messageID int, rich domain.BotAPIRichMessageInput, setReplyMarkup bool, replyMarkup *domain.MessageReplyMarkup) (domain.Message, error)
|
||||
BotAPIEditInlineMessageText(ctx context.Context, botID int64, inlineMessageID domain.BotInlineMessageID, text string, entities []domain.MessageEntity, setReplyMarkup bool, replyMarkup *domain.MessageReplyMarkup, disableWebPagePreview bool) (bool, error)
|
||||
BotAPIEditInlineRichMessage(ctx context.Context, botID int64, inlineMessageID domain.BotInlineMessageID, rich domain.BotAPIRichMessageInput, setReplyMarkup bool, replyMarkup *domain.MessageReplyMarkup) (bool, error)
|
||||
BotAPIDeleteMessage(ctx context.Context, botID, chatID int64, messageID int) (bool, error)
|
||||
BotAPIAnswerCallbackQuery(ctx context.Context, botID int64, callbackQueryID, text, url string, showAlert bool, cacheTime int) (bool, error)
|
||||
BotAPIGetFile(ctx context.Context, botID int64, locationKey string, offset int64, limit int) (domain.FileChunk, bool, error)
|
||||
|
|
@ -204,6 +207,8 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) {
|
|||
h.getUpdates(w, r, botID)
|
||||
case "sendmessage":
|
||||
h.sendMessage(w, r, botID)
|
||||
case "sendrichmessage":
|
||||
h.sendRichMessage(w, r, botID)
|
||||
case "sendphoto":
|
||||
h.sendMedia(w, r, botID, "photo")
|
||||
case "sendanimation":
|
||||
|
|
@ -577,6 +582,71 @@ func (h *handler) sendMessage(w http.ResponseWriter, r *http.Request, botID int6
|
|||
writeAPIOK(w, apiMessage(msg, users))
|
||||
}
|
||||
|
||||
func (h *handler) sendRichMessage(w http.ResponseWriter, r *http.Request, botID int64) {
|
||||
if h.gateway == nil {
|
||||
writeAPIError(w, http.StatusNotImplemented, "METHOD_NOT_FOUND")
|
||||
return
|
||||
}
|
||||
values, err := requestValues(r)
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, "BAD_REQUEST")
|
||||
return
|
||||
}
|
||||
chatID, err := strconv.ParseInt(strings.TrimSpace(values["chat_id"]), 10, 64)
|
||||
if err != nil || chatID == 0 {
|
||||
writeAPIError(w, http.StatusBadRequest, "CHAT_ID_INVALID")
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(values["business_connection_id"]) != "" {
|
||||
writeAPIError(w, http.StatusBadRequest, "BUSINESS_CONNECTION_INVALID")
|
||||
return
|
||||
}
|
||||
if apiInt(values["message_thread_id"], 0) != 0 || apiInt(values["direct_messages_topic_id"], 0) != 0 {
|
||||
writeAPIError(w, http.StatusBadRequest, "MESSAGE_THREAD_INVALID")
|
||||
return
|
||||
}
|
||||
if apiBool(values["allow_paid_broadcast"]) || strings.TrimSpace(values["suggested_post_parameters"]) != "" {
|
||||
writeAPIError(w, http.StatusBadRequest, "RICH_MESSAGE_OPTION_UNSUPPORTED")
|
||||
return
|
||||
}
|
||||
rich, err := richMessageInputFromAPI(values["rich_message"])
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
var markup *domain.MessageReplyMarkup
|
||||
if raw := strings.TrimSpace(values["reply_markup"]); raw != "" {
|
||||
markup, err = inlineReplyMarkupFromAPI(json.RawMessage(raw))
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
replyTo, err := richReplyMessageID(values)
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
effectID, err := apiInt64(values["message_effect_id"])
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, "EFFECT_ID_INVALID")
|
||||
return
|
||||
}
|
||||
msg, err := h.gateway.BotAPISendRichMessage(
|
||||
r.Context(), botID, chatID, rich, markup,
|
||||
apiBool(values["disable_notification"]), apiBool(values["protect_content"]), replyTo, effectID,
|
||||
)
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, apiErrorDescription(err))
|
||||
return
|
||||
}
|
||||
users := []domain.User(nil)
|
||||
if self, err := h.gateway.BotAPISelf(r.Context(), botID); err == nil && self.ID != 0 {
|
||||
users = append(users, self)
|
||||
}
|
||||
writeAPIOK(w, apiMessage(msg, users))
|
||||
}
|
||||
|
||||
func (h *handler) sendMedia(w http.ResponseWriter, r *http.Request, botID int64, kind string) {
|
||||
if h.gateway == nil {
|
||||
writeAPIError(w, http.StatusNotImplemented, "METHOD_NOT_FOUND")
|
||||
|
|
@ -695,7 +765,26 @@ func (h *handler) editMessageText(w http.ResponseWriter, r *http.Request, botID
|
|||
writeAPIError(w, http.StatusBadRequest, "MESSAGE_IDENTIFIER_INVALID")
|
||||
return
|
||||
}
|
||||
text, entities, err := botAPIFormattedTextRaw(values["text"], values["parse_mode"], values["entities"], domain.MaxMessageTextLength, true)
|
||||
rawRich := strings.TrimSpace(values["rich_message"])
|
||||
_, textSpecified := values["text"]
|
||||
if rawRich != "" && textSpecified {
|
||||
writeAPIError(w, http.StatusBadRequest, "RICH_MESSAGE_INVALID")
|
||||
return
|
||||
}
|
||||
var (
|
||||
text string
|
||||
entities []domain.MessageEntity
|
||||
rich domain.BotAPIRichMessageInput
|
||||
)
|
||||
if rawRich != "" {
|
||||
rich, err = richMessageInputFromAPI(rawRich)
|
||||
} else {
|
||||
if !textSpecified {
|
||||
writeAPIError(w, http.StatusBadRequest, "MESSAGE_EMPTY")
|
||||
return
|
||||
}
|
||||
text, entities, err = botAPIFormattedTextRaw(values["text"], values["parse_mode"], values["entities"], domain.MaxMessageTextLength, true)
|
||||
}
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
|
|
@ -715,7 +804,12 @@ func (h *handler) editMessageText(w http.ResponseWriter, r *http.Request, botID
|
|||
writeAPIError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
ok, err := h.gateway.BotAPIEditInlineMessageText(r.Context(), botID, inlineID, text, entities, setReplyMarkup, markup, apiBool(values["disable_web_page_preview"]))
|
||||
var ok bool
|
||||
if rawRich != "" {
|
||||
ok, err = h.gateway.BotAPIEditInlineRichMessage(r.Context(), botID, inlineID, rich, setReplyMarkup, markup)
|
||||
} else {
|
||||
ok, err = h.gateway.BotAPIEditInlineMessageText(r.Context(), botID, inlineID, text, entities, setReplyMarkup, markup, apiBool(values["disable_web_page_preview"]))
|
||||
}
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, apiErrorDescription(err))
|
||||
return
|
||||
|
|
@ -723,7 +817,12 @@ func (h *handler) editMessageText(w http.ResponseWriter, r *http.Request, botID
|
|||
writeAPIOK(w, ok)
|
||||
return
|
||||
}
|
||||
msg, err := h.gateway.BotAPIEditMessageText(r.Context(), botID, chatID, messageID, text, entities, setReplyMarkup, markup, apiBool(values["disable_web_page_preview"]))
|
||||
var msg domain.Message
|
||||
if rawRich != "" {
|
||||
msg, err = h.gateway.BotAPIEditRichMessage(r.Context(), botID, chatID, messageID, rich, setReplyMarkup, markup)
|
||||
} else {
|
||||
msg, err = h.gateway.BotAPIEditMessageText(r.Context(), botID, chatID, messageID, text, entities, setReplyMarkup, markup, apiBool(values["disable_web_page_preview"]))
|
||||
}
|
||||
if err != nil {
|
||||
writeAPIError(w, http.StatusBadRequest, apiErrorDescription(err))
|
||||
return
|
||||
|
|
@ -1338,6 +1437,14 @@ func apiErrorDescription(err error) string {
|
|||
"RESULT_TYPE_INVALID",
|
||||
"MESSAGE_EMPTY",
|
||||
"MESSAGE_TOO_LONG",
|
||||
"RICH_MESSAGE_INVALID",
|
||||
"RICH_MESSAGE_TOO_LONG",
|
||||
"RICH_MESSAGE_DATE_INVALID",
|
||||
"RICH_MESSAGE_BLOCKS_UNSUPPORTED",
|
||||
"RICH_MESSAGE_MEDIA_UNSUPPORTED",
|
||||
"RICH_MESSAGE_OPTION_UNSUPPORTED",
|
||||
"WEBPAGE_MEDIA_EMPTY",
|
||||
"EFFECT_ID_INVALID",
|
||||
"BUTTON_INVALID",
|
||||
"BUTTON_DATA_INVALID",
|
||||
"BUTTON_URL_INVALID",
|
||||
|
|
|
|||
|
|
@ -600,6 +600,101 @@ func TestSendMessageParsesEntitiesMarkupAndCallsGateway(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSendRichMessageAndEditPreserveInlineKeyboardAndProjection(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
projection := json.RawMessage(`{"blocks":[{"type":"heading","size":4,"text":"Admin"}],"is_rtl":true}`)
|
||||
markup := &domain.MessageReplyMarkup{Type: domain.MessageReplyMarkupInline, Inline: [][]domain.MarkupButton{{{
|
||||
Type: domain.MarkupButtonCallback, Text: "Info", Data: []byte("menu:info"),
|
||||
}}}}
|
||||
message := domain.Message{
|
||||
ID: 21, OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: 1001},
|
||||
Date: 1700000021, Out: true, ReplyMarkup: markup,
|
||||
RichMessage: &domain.MessageRichMessage{Rtl: true, Blocks: []byte{1}, BotAPIProjection: projection},
|
||||
}
|
||||
gateway := &fakeBotAPIGateway{
|
||||
self: domain.User{ID: 1001, FirstName: "Bedolaga", Username: "bedolaga_bot", Bot: true},
|
||||
sendMessage: message,
|
||||
editMessage: message,
|
||||
}
|
||||
h := (&handler{bots: bots, gateway: gateway}).routes()
|
||||
|
||||
rec := performBotAPIRequest(t, h, bots.profile, "sendRichMessage", `{
|
||||
"chat_id":2001,
|
||||
"rich_message":{"html":"<h4>Admin</h4>","is_rtl":true,"skip_entity_detection":true},
|
||||
"reply_markup":{"inline_keyboard":[[{"text":"Info","callback_data":"menu:info"}]]},
|
||||
"disable_notification":true,
|
||||
"protect_content":true,
|
||||
"reply_parameters":{"message_id":7}
|
||||
}`)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("sendRichMessage status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !gateway.sendRichCalled || gateway.sendChatID != 2001 || gateway.sendRichInput.HTML != "<h4>Admin</h4>" ||
|
||||
!gateway.sendRichInput.RTL || !gateway.sendRichInput.SkipEntityDetection || !gateway.sendSilent || gateway.sendReplyTo != 7 {
|
||||
t.Fatalf("send rich call = %#v", gateway)
|
||||
}
|
||||
if gateway.sendRichMarkup == nil || len(gateway.sendRichMarkup.Inline) != 1 ||
|
||||
string(gateway.sendRichMarkup.Inline[0][0].Data) != "menu:info" {
|
||||
t.Fatalf("send rich markup = %#v", gateway.sendRichMarkup)
|
||||
}
|
||||
assertBotAPIRichMenuResponse(t, rec.Body.Bytes(), 21)
|
||||
|
||||
gateway.editMessage.RichMessage.BotAPIProjection = json.RawMessage(`{"blocks":[{"type":"paragraph","text":"Updated"}]}`)
|
||||
rec = performBotAPIRequest(t, h, bots.profile, "editMessageText", `{
|
||||
"chat_id":2001,
|
||||
"message_id":21,
|
||||
"rich_message":{"markdown":"**Updated**","skip_entity_detection":true},
|
||||
"reply_markup":{"inline_keyboard":[[{"text":"Info","callback_data":"menu:info"}]]}
|
||||
}`)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("editMessageText rich status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !gateway.editRichCalled || gateway.editRichInput.Markdown != "**Updated**" || !gateway.editRichInput.SkipEntityDetection || !gateway.editSetMarkup {
|
||||
t.Fatalf("edit rich call = %#v", gateway)
|
||||
}
|
||||
assertBotAPIRichMenuResponse(t, rec.Body.Bytes(), 21)
|
||||
}
|
||||
|
||||
func TestEditMessageTextRejectsTextAndRichMessageTogether(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
h := (&handler{bots: bots, gateway: &fakeBotAPIGateway{}}).routes()
|
||||
rec := performBotAPIRequest(t, h, bots.profile, "editMessageText", `{
|
||||
"chat_id":2001,"message_id":21,"text":"plain","rich_message":{"html":"<p>rich</p>"}
|
||||
}`)
|
||||
if rec.Code != http.StatusBadRequest || !strings.Contains(rec.Body.String(), "RICH_MESSAGE_INVALID") {
|
||||
t.Fatalf("edit text+rich status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func assertBotAPIRichMenuResponse(t *testing.T, raw []byte, messageID int) {
|
||||
t.Helper()
|
||||
var response struct {
|
||||
OK bool `json:"ok"`
|
||||
Result struct {
|
||||
MessageID int `json:"message_id"`
|
||||
RichMessage struct {
|
||||
Blocks []struct {
|
||||
Type string `json:"type"`
|
||||
} `json:"blocks"`
|
||||
} `json:"rich_message"`
|
||||
ReplyMarkup struct {
|
||||
InlineKeyboard [][]struct {
|
||||
CallbackData string `json:"callback_data"`
|
||||
} `json:"inline_keyboard"`
|
||||
} `json:"reply_markup"`
|
||||
} `json:"result"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &response); err != nil {
|
||||
t.Fatalf("decode rich response: %v", err)
|
||||
}
|
||||
if !response.OK || response.Result.MessageID != messageID || len(response.Result.RichMessage.Blocks) != 1 ||
|
||||
len(response.Result.ReplyMarkup.InlineKeyboard) != 1 || response.Result.ReplyMarkup.InlineKeyboard[0][0].CallbackData != "menu:info" {
|
||||
t.Fatalf("rich response = %s", raw)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendMessageParsesAndProjectsReplyKeyboard(t *testing.T) {
|
||||
bots := &fakeBotAPIBots{profile: domain.BotProfile{BotUserID: 1001, TokenSecret: "secret"}}
|
||||
markup := &domain.MessageReplyMarkup{
|
||||
|
|
@ -1329,6 +1424,9 @@ type fakeBotAPIGateway struct {
|
|||
sendSilent bool
|
||||
sendReplyTo int
|
||||
sendMessage domain.Message
|
||||
sendRichCalled bool
|
||||
sendRichInput domain.BotAPIRichMessageInput
|
||||
sendRichMarkup *domain.MessageReplyMarkup
|
||||
sendMediaCalled bool
|
||||
sendMediaKind string
|
||||
sendMediaChatID int64
|
||||
|
|
@ -1342,6 +1440,8 @@ type fakeBotAPIGateway struct {
|
|||
editEntities []domain.MessageEntity
|
||||
editSetMarkup bool
|
||||
editMessage domain.Message
|
||||
editRichCalled bool
|
||||
editRichInput domain.BotAPIRichMessageInput
|
||||
editInlineCalled bool
|
||||
editInlineID domain.BotInlineMessageID
|
||||
editInlineText string
|
||||
|
|
@ -1448,6 +1548,17 @@ func (f *fakeBotAPIGateway) BotAPISendMessage(_ context.Context, botID, chatID i
|
|||
return f.sendMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPISendRichMessage(_ context.Context, botID, chatID int64, rich domain.BotAPIRichMessageInput, replyMarkup *domain.MessageReplyMarkup, silent, noForwards bool, replyToMessageID int, effectID int64) (domain.Message, error) {
|
||||
f.sendRichCalled = true
|
||||
f.sendBotID = botID
|
||||
f.sendChatID = chatID
|
||||
f.sendRichInput = rich
|
||||
f.sendRichMarkup = replyMarkup
|
||||
f.sendSilent = silent
|
||||
f.sendReplyTo = replyToMessageID
|
||||
return f.sendMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPISendMedia(_ context.Context, botID, chatID int64, kind, locationKey, remoteURL, fileName, mimeType string, fileBytes []byte, caption string, entities []domain.MessageEntity, replyMarkup *domain.MessageReplyMarkup, silent bool, replyToMessageID int) (domain.Message, error) {
|
||||
f.sendMediaCalled = true
|
||||
f.sendMediaKind = kind
|
||||
|
|
@ -1467,6 +1578,13 @@ func (f *fakeBotAPIGateway) BotAPIEditMessageText(_ context.Context, botID, chat
|
|||
return f.editMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIEditRichMessage(_ context.Context, botID, chatID int64, messageID int, rich domain.BotAPIRichMessageInput, setReplyMarkup bool, replyMarkup *domain.MessageReplyMarkup) (domain.Message, error) {
|
||||
f.editRichCalled = true
|
||||
f.editRichInput = rich
|
||||
f.editSetMarkup = setReplyMarkup
|
||||
return f.editMessage, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIEditInlineMessageText(_ context.Context, _ int64, inlineMessageID domain.BotInlineMessageID, text string, entities []domain.MessageEntity, _ bool, _ *domain.MessageReplyMarkup, _ bool) (bool, error) {
|
||||
f.editInlineCalled, f.editInlineID = true, inlineMessageID
|
||||
f.editInlineText = text
|
||||
|
|
@ -1474,6 +1592,12 @@ func (f *fakeBotAPIGateway) BotAPIEditInlineMessageText(_ context.Context, _ int
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIEditInlineRichMessage(_ context.Context, _ int64, inlineMessageID domain.BotInlineMessageID, rich domain.BotAPIRichMessageInput, _ bool, _ *domain.MessageReplyMarkup) (bool, error) {
|
||||
f.editInlineCalled, f.editInlineID = true, inlineMessageID
|
||||
f.editRichInput = rich
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (f *fakeBotAPIGateway) BotAPIDeleteMessage(context.Context, int64, int64, int) (bool, error) {
|
||||
f.deleteCalled = true
|
||||
return true, nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue