From 88e1a77b954d0018eb9b0dd673a5549f61d2c285 Mon Sep 17 00:00:00 2001 From: Mohammad Taha Date: Wed, 19 Jun 2019 08:44:38 +0430 Subject: [PATCH 01/28] Update helpers.go added a function with name `NewEditMessageTextAndMarkup` for edit text and replymarkup together --- helpers.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 3dabe11..7822152 100644 --- a/helpers.go +++ b/helpers.go @@ -615,6 +615,18 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex } } +// NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message. +func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig { + return EditMessageTextConfig{ + BaseEdit: BaseEdit{ + ChatID: chatID, + MessageID: messageID, + ReplyMarkup: &replyMarkup, + }, + Text: text, + } +} + // NewEditMessageCaption allows you to edit the caption of a message. func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig { return EditMessageCaptionConfig{ @@ -622,7 +634,7 @@ func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMess ChatID: chatID, MessageID: messageID, }, - Caption: caption, + Caption: caption, } } From 72a0e2d8087dc11548bb29edc2403b1323d881bd Mon Sep 17 00:00:00 2001 From: unstppbl Date: Wed, 3 Jul 2019 17:59:56 -0700 Subject: [PATCH 02/28] closes #246 --- bot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.go b/bot.go index a996790..7d8b9d1 100644 --- a/bot.go +++ b/bot.go @@ -438,7 +438,7 @@ func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { // RemoveWebhook unsets the webhook. func (bot *BotAPI) RemoveWebhook() (APIResponse, error) { - return bot.MakeRequest("setWebhook", url.Values{}) + return bot.MakeRequest("deleteWebhook", url.Values{}) } // SetWebhook sets a webhook. From b478ff9669daca239e94cf0659e7c941a5071a6c Mon Sep 17 00:00:00 2001 From: rozha Date: Sun, 11 Aug 2019 13:20:40 +0300 Subject: [PATCH 03/28] Introduce NewOneTimeReplyKeyboard() helper function --- helpers.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/helpers.go b/helpers.go index 3dabe11..fc19313 100644 --- a/helpers.go +++ b/helpers.go @@ -704,6 +704,13 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { } } +// NewOneTimeReplyKeyboard creates a new one time keyboard using NewReplyKeyboard() +func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { + markup := NewReplyKeyboard(rows...) + markup.OneTimeKeyboard = true + return markup +} + // NewInlineKeyboardButtonData creates an inline keyboard button with text // and data for a callback. func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton { From d4b2e3c2136aa63ffce72c297c97a9c3e0a06cc8 Mon Sep 17 00:00:00 2001 From: gropher Date: Wed, 18 Sep 2019 03:34:37 +0300 Subject: [PATCH 04/28] Added HandleUpdate method for serverless deploy --- bot.go | 19 ++++++++++++------- bot_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/bot.go b/bot.go index a996790..070e73d 100644 --- a/bot.go +++ b/bot.go @@ -533,18 +533,23 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel { ch := make(chan Update, bot.Buffer) http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { - bytes, _ := ioutil.ReadAll(r.Body) - r.Body.Close() - - var update Update - json.Unmarshal(bytes, &update) - - ch <- update + ch <- bot.HandleUpdate(w, r) }) return ch } +// HandleUpdate parses and returns update received via webhook +func (bot *BotAPI) HandleUpdate(res http.ResponseWriter, req *http.Request) Update { + bytes, _ := ioutil.ReadAll(req.Body) + req.Body.Close() + + var update Update + json.Unmarshal(bytes, &update) + + return update +} + // AnswerInlineQuery sends a response to an inline query. // // Note that you must respond to an inline query within 30 seconds. diff --git a/bot_test.go b/bot_test.go index 60f3e65..2e9d07a 100644 --- a/bot_test.go +++ b/bot_test.go @@ -593,6 +593,35 @@ func ExampleNewWebhook() { } } +func ExampleWebhookHandler() { + bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") + if err != nil { + log.Fatal(err) + } + + bot.Debug = true + + log.Printf("Authorized on account %s", bot.Self.UserName) + + _, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")) + if err != nil { + log.Fatal(err) + } + info, err := bot.GetWebhookInfo() + if err != nil { + log.Fatal(err) + } + if info.LastErrorDate != 0 { + log.Printf("[Telegram callback failed]%s", info.LastErrorMessage) + } + + http.HandleFunc("/" + bot.Token, func(w http.ResponseWriter, r *http.Request) { + log.Printf("%+v\n", bot.HandleUpdate(w, r)) + }) + + go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil) +} + func ExampleAnswerInlineQuery() { bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") // create new bot if err != nil { From 37eb2cb6bec0d833b3873f7fcd0b2fec9e15e6db Mon Sep 17 00:00:00 2001 From: NemoD503 <1historicus@gmail.com> Date: Tue, 8 Oct 2019 12:25:37 +0300 Subject: [PATCH 05/28] Go mod was added --- go.mod | 5 +++++ go.sum | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7df46f4 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/go-telegram-bot-api/telegram-bot-api + +go 1.12 + +require github.com/technoweenie/multipartstreamer v1.0.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8660600 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= From a6b4ce46a6e9a0270cbd9eb3a4d1c746886f4f05 Mon Sep 17 00:00:00 2001 From: NemoD503 <1historicus@gmail.com> Date: Sun, 20 Oct 2019 22:47:21 +0300 Subject: [PATCH 06/28] return pointer to error --- bot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.go b/bot.go index a996790..48f6816 100644 --- a/bot.go +++ b/bot.go @@ -92,7 +92,7 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, if apiResp.Parameters != nil { parameters = *apiResp.Parameters } - return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters} + return apiResp, &Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters} } return apiResp, nil From 1af25a19c77837105406e0a847c36a078bb408ac Mon Sep 17 00:00:00 2001 From: NemoD503 <1historicus@gmail.com> Date: Sun, 20 Oct 2019 23:01:22 +0300 Subject: [PATCH 07/28] add new versions of golang to travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5769aa1..51865c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,6 @@ language: go go: - '1.10' - '1.11' + - '1.12' + - '1.13' - tip From 935e204b042c70bd9ad117caaca97fb5622433dd Mon Sep 17 00:00:00 2001 From: Shao Yang Hong Date: Fri, 25 Oct 2019 11:47:24 +0800 Subject: [PATCH 08/28] README: link to godoc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf341d2..43b33ed 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) [![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api) -All methods are fairly self explanatory, and reading the godoc page should +All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should explain everything. If something isn't clear, open an issue or submit a pull request. From d944d68fe6ebbde4aaafa592d8d0a2b935548cf8 Mon Sep 17 00:00:00 2001 From: Xing GUO Date: Tue, 31 Dec 2019 14:38:21 +0800 Subject: [PATCH 09/28] Document `NewMessageToChannel` clearer --- helpers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 3dabe11..294f31b 100644 --- a/helpers.go +++ b/helpers.go @@ -29,7 +29,8 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { // NewMessageToChannel creates a new Message that is sent to a channel // by username. // -// username is the username of the channel, text is the message text. +// username is the username of the channel, text is the message text, +// and the username should be in the form of `@username`. func NewMessageToChannel(username string, text string) MessageConfig { return MessageConfig{ BaseChat: BaseChat{ From 87891c10fe27ef36715525c25ae3d9b35babc372 Mon Sep 17 00:00:00 2001 From: Daniel Leining Date: Sun, 5 Jan 2020 00:35:15 -0500 Subject: [PATCH 10/28] add ability to respond to inline queries with stickers --- helpers.go | 12 +++++++++++- types.go | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 3dabe11..04bf666 100644 --- a/helpers.go +++ b/helpers.go @@ -533,6 +533,16 @@ func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResul } } +// NewInlineQueryResultCachedSticker create a new inline query with cached sticker. +func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker { + return InlineQueryResultCachedSticker{ + Type: "sticker", + ID: id, + StickerID: stickerID, + Title: title, + } +} + // NewInlineQueryResultAudio creates a new inline query audio. func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio { return InlineQueryResultAudio{ @@ -622,7 +632,7 @@ func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMess ChatID: chatID, MessageID: messageID, }, - Caption: caption, + Caption: caption, } } diff --git a/types.go b/types.go index 52cb36c..9cd307a 100644 --- a/types.go +++ b/types.go @@ -736,6 +736,17 @@ type InlineQueryResultCachedVideo struct { InputMessageContent interface{} `json:"input_message_content,omitempty"` } +// InlineQueryResultCachedSticker is an inline query response with cached sticker. +type InlineQueryResultCachedSticker struct { + Type string `json:"type"` // required + ID string `json:"id"` // required + StickerID string `json:"sticker_file_id"` // required + Title string `json:"title"` // required + ParseMode string `json:"parse_mode"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + // InlineQueryResultAudio is an inline query response audio. type InlineQueryResultAudio struct { Type string `json:"type"` // required From 1f98cd2e470064aba333fce57528582065448889 Mon Sep 17 00:00:00 2001 From: mkishere <224617+mkishere@users.noreply.github.com> Date: Tue, 7 Jan 2020 00:28:13 +0800 Subject: [PATCH 11/28] Add inline venue type --- helpers.go | 14 +++++++++++++- types.go | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 3dabe11..c4d236f 100644 --- a/helpers.go +++ b/helpers.go @@ -604,6 +604,18 @@ func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) } } +// NewInlineQueryResultVenue creates a new inline query venue. +func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue { + return InlineQueryResultVenue{ + Type: "venue", + ID: id, + Title: title, + Address: address, + Latitude: latitude, + Longitude: longitude, + } +} + // NewEditMessageText allows you to edit the text of a message. func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig { return EditMessageTextConfig{ @@ -622,7 +634,7 @@ func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMess ChatID: chatID, MessageID: messageID, }, - Caption: caption, + Caption: caption, } } diff --git a/types.go b/types.go index 52cb36c..319f47f 100644 --- a/types.go +++ b/types.go @@ -827,6 +827,23 @@ type InlineQueryResultLocation struct { ThumbHeight int `json:"thumb_height"` } +// InlineQueryResultVenue is an inline query response venue. +type InlineQueryResultVenue struct { + Type string `json:"type"` // required + ID string `json:"id"` // required + Latitude float64 `json:"latitude"` // required + Longitude float64 `json:"longitude"` // required + Title string `json:"title"` // required + Address string `json:"address"` // required + FoursquareID string `json:"foursquare_id"` + FoursquareType string `json:"foursquare_type"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + InputMessageContent interface{} `json:"input_message_content,omitempty"` + ThumbURL string `json:"thumb_url"` + ThumbWidth int `json:"thumb_width"` + ThumbHeight int `json:"thumb_height"` +} + // InlineQueryResultGame is an inline query response game. type InlineQueryResultGame struct { Type string `json:"type"` From 613005ba7b6d21b9362271e69af5f0e584c80ecb Mon Sep 17 00:00:00 2001 From: Konstantin Chukhlomin Date: Sun, 12 Jan 2020 23:54:08 -0500 Subject: [PATCH 12/28] Update types.go Added IsAnimated to Sticker struct --- types.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/types.go b/types.go index 52cb36c..abfb3a9 100644 --- a/types.go +++ b/types.go @@ -338,13 +338,14 @@ type Document struct { // Sticker contains information about a sticker. type Sticker struct { - FileID string `json:"file_id"` - Width int `json:"width"` - Height int `json:"height"` - Thumbnail *PhotoSize `json:"thumb"` // optional - Emoji string `json:"emoji"` // optional - FileSize int `json:"file_size"` // optional - SetName string `json:"set_name"` // optional + FileID string `json:"file_id"` + Width int `json:"width"` + Height int `json:"height"` + Thumbnail *PhotoSize `json:"thumb"` // optional + Emoji string `json:"emoji"` // optional + FileSize int `json:"file_size"` // optional + SetName string `json:"set_name"` // optional + IsAnimated bool `json:"is_animated"` // optional } // ChatAnimation contains information about an animation. From 69bab9a28f2047c696d5c4d1c088fca6a2768bb8 Mon Sep 17 00:00:00 2001 From: Jiayu Yi Date: Mon, 13 Jan 2020 15:42:35 +0800 Subject: [PATCH 13/28] Add MaxConnections to WebhookInfo --- bot_test.go | 3 +++ types.go | 1 + 2 files changed, 4 insertions(+) diff --git a/bot_test.go b/bot_test.go index 60f3e65..b00ea41 100644 --- a/bot_test.go +++ b/bot_test.go @@ -497,6 +497,9 @@ func TestSetWebhookWithoutCert(t *testing.T) { if err != nil { t.Error(err) } + if info.MaxConnections == 0 { + t.Errorf("wanted max connections to be greater than 0") + } if info.LastErrorDate != 0 { t.Errorf("[Telegram callback failed]%s", info.LastErrorMessage) } diff --git a/types.go b/types.go index 70d66fa..b673dc6 100644 --- a/types.go +++ b/types.go @@ -571,6 +571,7 @@ type WebhookInfo struct { PendingUpdateCount int `json:"pending_update_count"` LastErrorDate int `json:"last_error_date"` // optional LastErrorMessage string `json:"last_error_message"` // optional + MaxConnections int `json:"max_connections"` } // IsSet returns true if a webhook is currently set. From e0d9306d8b80a6a5f9ac4d2aafa01bd790d6c10c Mon Sep 17 00:00:00 2001 From: Jiayu Yi Date: Mon, 13 Jan 2020 22:08:58 +0800 Subject: [PATCH 14/28] Include ResponseParameters in UploadFile error This makes UploadFile behave more similarly to MakeRequest when the response is not ok. --- bot.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bot.go b/bot.go index a996790..4a7e52e 100644 --- a/bot.go +++ b/bot.go @@ -226,7 +226,11 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna } if !apiResp.Ok { - return APIResponse{}, errors.New(apiResp.Description) + parameters := ResponseParameters{} + if apiResp.Parameters != nil { + parameters = *apiResp.Parameters + } + return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters} } return apiResp, nil @@ -740,9 +744,9 @@ func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) } // RestrictChatMember to restrict a user in a supergroup. The bot must be an -//administrator in the supergroup for this to work and must have the -//appropriate admin rights. Pass True for all boolean parameters to lift -//restrictions from a user. Returns True on success. +// administrator in the supergroup for this to work and must have the +// appropriate admin rights. Pass True for all boolean parameters to lift +// restrictions from a user. Returns True on success. func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) { v := url.Values{} From fd860fdd66745e140316aa97698ba458c330c58e Mon Sep 17 00:00:00 2001 From: Daniel Leining Date: Thu, 23 Jan 2020 23:41:44 -0500 Subject: [PATCH 15/28] add file_unique_id --- types.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/types.go b/types.go index 70d66fa..2dc3beb 100644 --- a/types.go +++ b/types.go @@ -338,14 +338,15 @@ type Document struct { // Sticker contains information about a sticker. type Sticker struct { - FileID string `json:"file_id"` - Width int `json:"width"` - Height int `json:"height"` - Thumbnail *PhotoSize `json:"thumb"` // optional - Emoji string `json:"emoji"` // optional - FileSize int `json:"file_size"` // optional - SetName string `json:"set_name"` // optional - IsAnimated bool `json:"is_animated"` // optional + FileUniqueID string `json:"file_unique_id"` + FileID string `json:"file_id"` + Width int `json:"width"` + Height int `json:"height"` + Thumbnail *PhotoSize `json:"thumb"` // optional + Emoji string `json:"emoji"` // optional + FileSize int `json:"file_size"` // optional + SetName string `json:"set_name"` // optional + IsAnimated bool `json:"is_animated"` // optional } // ChatAnimation contains information about an animation. From f44d515f71f957178c4b408d94f644a267d316d6 Mon Sep 17 00:00:00 2001 From: Daniel Leining Date: Wed, 29 Jan 2020 22:58:02 -0500 Subject: [PATCH 16/28] add getStickerSet call --- bot.go | 19 +++++++++++++++++++ configs.go | 15 +++++++++++++++ types.go | 8 ++++++++ 3 files changed, 42 insertions(+) diff --git a/bot.go b/bot.go index a996790..e91e4e0 100644 --- a/bot.go +++ b/bot.go @@ -974,3 +974,22 @@ func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, e return bot.MakeRequest(config.method(), v) } + +// GetStickerSet get a sticker set. +func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { + v, err := config.values() + if err != nil { + return StickerSet{}, err + } + bot.debugLog(config.method(), v, nil) + res, err := bot.MakeRequest(config.method(), v) + if err != nil { + return StickerSet{}, err + } + stickerSet := StickerSet{} + err = json.Unmarshal(res.Result, &stickerSet) + if err != nil { + return StickerSet{}, err + } + return stickerSet, nil +} diff --git a/configs.go b/configs.go index 181d4e4..a7052dd 100644 --- a/configs.go +++ b/configs.go @@ -1262,3 +1262,18 @@ func (config DeleteChatPhotoConfig) values() (url.Values, error) { return v, nil } + +// GetStickerSetConfig contains information for get sticker set. +type GetStickerSetConfig struct { + Name string +} + +func (config GetStickerSetConfig) method() string { + return "getStickerSet" +} + +func (config GetStickerSetConfig) values() (url.Values, error) { + v := url.Values{} + v.Add("name", config.Name) + return v, nil +} diff --git a/types.go b/types.go index 70d66fa..810dd9b 100644 --- a/types.go +++ b/types.go @@ -348,6 +348,14 @@ type Sticker struct { IsAnimated bool `json:"is_animated"` // optional } +type StickerSet struct { + Name string `json:"name"` + Title string `json:"title"` + IsAnimated bool `json:"is_animated"` + ContainsMasks bool `json:"contains_masks"` + Stickers []Sticker `json:"stickers"` +} + // ChatAnimation contains information about an animation. type ChatAnimation struct { FileID string `json:"file_id"` From 706e70933da04f25dbf2985bc5da4b3002319760 Mon Sep 17 00:00:00 2001 From: Tarcisio Gruppi Date: Sat, 22 Feb 2020 19:13:34 -0300 Subject: [PATCH 17/28] Close updates chan on stop --- bot.go | 1 + 1 file changed, 1 insertion(+) diff --git a/bot.go b/bot.go index a996790..019fe19 100644 --- a/bot.go +++ b/bot.go @@ -495,6 +495,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) { for { select { case <-bot.shutdownChannel: + close(ch) return default: } From b5d42143e7dd8968ad3794af63aeb8ccb15eacbb Mon Sep 17 00:00:00 2001 From: Adelya Date: Tue, 3 Mar 2020 17:00:42 +0300 Subject: [PATCH 18/28] Ability to create BotAPI instance directly with new API endpoint --- bot.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/bot.go b/bot.go index a996790..790f47f 100644 --- a/bot.go +++ b/bot.go @@ -36,21 +36,29 @@ type BotAPI struct { // // It requires a token, provided by @BotFather on Telegram. func NewBotAPI(token string) (*BotAPI, error) { - return NewBotAPIWithClient(token, &http.Client{}) + return NewBotAPIWithClient(token, APIEndpoint, &http.Client{}) +} + +// NewBotAPIWithAPIEndpoint creates a new BotAPI instance +// and allows you to pass API endpoint. +// +// It requires a token, provided by @BotFather on Telegram and API endpoint. +func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) { + return NewBotAPIWithClient(token, apiEndpoint, &http.Client{}) } // NewBotAPIWithClient creates a new BotAPI instance // and allows you to pass a http.Client. // -// It requires a token, provided by @BotFather on Telegram. -func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) { +// It requires a token, provided by @BotFather on Telegram and API endpoint. +func NewBotAPIWithClient(token, apiEndpoint string, client *http.Client) (*BotAPI, error) { bot := &BotAPI{ Token: token, Client: client, Buffer: 100, shutdownChannel: make(chan interface{}), - apiEndpoint: APIEndpoint, + apiEndpoint: apiEndpoint, } self, err := bot.GetMe() From 303a66f022f500bac7ae8d9bdf9d0a5dbfa1e0f6 Mon Sep 17 00:00:00 2001 From: Mendel E Date: Sun, 26 Apr 2020 00:30:21 -0400 Subject: [PATCH 19/28] Add ParseMode to InlineQueryResultPhoto --- types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/types.go b/types.go index 70d66fa..56a91d5 100644 --- a/types.go +++ b/types.go @@ -635,6 +635,7 @@ type InlineQueryResultPhoto struct { Title string `json:"title"` Description string `json:"description"` Caption string `json:"caption"` + ParseMode string `json:"parse_mode"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` InputMessageContent interface{} `json:"input_message_content,omitempty"` } From 74925cfcaf65580e42aa05296691424b181de85d Mon Sep 17 00:00:00 2001 From: "maria.bagdasarova" Date: Fri, 22 May 2020 11:42:19 +0300 Subject: [PATCH 20/28] Fix nil pointer on User String method --- types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types.go b/types.go index 5c1c55e..551b5c5 100644 --- a/types.go +++ b/types.go @@ -64,6 +64,9 @@ type User struct { // It is normally a user's username, but falls back to a first/last // name as available. func (u *User) String() string { + if u == nil { + return "" + } if u.UserName != "" { return u.UserName } From 6792fab6bb9bbeda26f6ef0573946e15fc4b33af Mon Sep 17 00:00:00 2001 From: Andrii Soluk Date: Sun, 24 May 2020 12:54:43 +0300 Subject: [PATCH 21/28] feat: Replaces *http.Client with an interface Signed-off-by: Andrii Soluk --- bot.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/bot.go b/bot.go index 5f25979..e6c2cc8 100644 --- a/bot.go +++ b/bot.go @@ -19,14 +19,18 @@ import ( "github.com/technoweenie/multipartstreamer" ) +type HttpClient interface { + Do(req *http.Request) (*http.Response, error) +} + // BotAPI allows you to interact with the Telegram Bot API. type BotAPI struct { Token string `json:"token"` Debug bool `json:"debug"` Buffer int `json:"buffer"` - Self User `json:"-"` - Client *http.Client `json:"-"` + Self User `json:"-"` + Client HttpClient `json:"-"` shutdownChannel chan interface{} apiEndpoint string @@ -51,7 +55,7 @@ func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) { // and allows you to pass a http.Client. // // It requires a token, provided by @BotFather on Telegram and API endpoint. -func NewBotAPIWithClient(token, apiEndpoint string, client *http.Client) (*BotAPI, error) { +func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, error) { bot := &BotAPI{ Token: token, Client: client, @@ -79,7 +83,13 @@ func (b *BotAPI) SetAPIEndpoint(apiEndpoint string) { func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) { method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) - resp, err := bot.Client.PostForm(method, params) + req, err := http.NewRequest("POST", method, strings.NewReader(params.Encode())) + if err != nil { + return APIResponse{}, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + resp, err := bot.Client.Do(req) if err != nil { return APIResponse{}, err } From e55e8bc55aa771d1a0bcc4d05a5f135020ceba10 Mon Sep 17 00:00:00 2001 From: Dmytro Kurest Date: Sun, 28 Jun 2020 22:13:32 +0300 Subject: [PATCH 22/28] Fixes error parameter name for AnswerPreCheckoutQuery --- bot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.go b/bot.go index e6c2cc8..0bac814 100644 --- a/bot.go +++ b/bot.go @@ -881,7 +881,7 @@ func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse v.Add("pre_checkout_query_id", config.PreCheckoutQueryID) v.Add("ok", strconv.FormatBool(config.OK)) if config.OK != true { - v.Add("error", config.ErrorMessage) + v.Add("error_message", config.ErrorMessage) } bot.debugLog("answerPreCheckoutQuery", v, nil) From dc71b50b19cb81acc603a6ef671714d017d6b333 Mon Sep 17 00:00:00 2001 From: "an.groshev" Date: Wed, 1 Jul 2020 20:03:05 +0300 Subject: [PATCH 23/28] add MarkdownV2 --- configs.go | 5 +++-- helpers.go | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/configs.go b/configs.go index a7052dd..1c5ca75 100644 --- a/configs.go +++ b/configs.go @@ -36,8 +36,9 @@ const ( // Constant values for ParseMode in MessageConfig const ( - ModeMarkdown = "Markdown" - ModeHTML = "HTML" + ModeMarkdown = "Markdown" + ModeMarkdownV2 = "MarkdownV2" + ModeHTML = "HTML" ) // Library errors diff --git a/helpers.go b/helpers.go index d2fb165..b9afb84 100644 --- a/helpers.go +++ b/helpers.go @@ -438,6 +438,19 @@ func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQu } } +// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing. +func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle { + return InlineQueryResultArticle{ + Type: "article", + ID: id, + Title: title, + InputMessageContent: InputTextMessageContent{ + Text: messageText, + ParseMode: "MarkdownV2", + }, + } +} + // NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing. func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle { return InlineQueryResultArticle{ From 86a3d94b4ba4e5318466cd56f738d18ca039fcdb Mon Sep 17 00:00:00 2001 From: ros-tel Date: Sun, 19 Jul 2020 10:11:27 +0500 Subject: [PATCH 24/28] Delete a message in a channel --- configs.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/configs.go b/configs.go index a7052dd..4bd2c33 100644 --- a/configs.go +++ b/configs.go @@ -1138,8 +1138,9 @@ type PreCheckoutConfig struct { // DeleteMessageConfig contains information of a message in a chat to delete. type DeleteMessageConfig struct { - ChatID int64 - MessageID int + ChannelUsername string + ChatID int64 + MessageID int } func (config DeleteMessageConfig) method() string { @@ -1149,7 +1150,12 @@ func (config DeleteMessageConfig) method() string { func (config DeleteMessageConfig) values() (url.Values, error) { v := url.Values{} - v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) + if config.ChannelUsername == "" { + v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) + } else { + v.Add("chat_id", config.ChannelUsername) + } + v.Add("message_id", strconv.Itoa(config.MessageID)) return v, nil From f11e1caecf8aca5a417dfdccb35cae275fc3507c Mon Sep 17 00:00:00 2001 From: mehanizm Date: Tue, 31 Mar 2020 09:02:18 +0300 Subject: [PATCH 25/28] feat: add sendDice configs Add sendDice config to use in Send method as a Chattable interface. Add NewDice and NewDiceWithEmoji helpers Add tests https://core.telegram.org/bots/api#senddice --- bot.go | 5 +++-- bot_test.go | 28 +++++++++++++++++++++++++++- configs.go | 27 +++++++++++++++++++++++++++ helpers.go | 26 +++++++++++++++++++++++++- helpers_test.go | 21 ++++++++++++++++++++- types.go | 1 + 6 files changed, 103 insertions(+), 5 deletions(-) diff --git a/bot.go b/bot.go index a7647d6..c112ab4 100644 --- a/bot.go +++ b/bot.go @@ -75,8 +75,9 @@ func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, return bot, nil } -func (b *BotAPI) SetAPIEndpoint(apiEndpoint string) { - b.apiEndpoint = apiEndpoint +// SetAPIEndpoint add telegram apiEndpont to Bot +func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) { + bot.apiEndpoint = apiEndpoint } // MakeRequest makes a request to a specific endpoint with our token. diff --git a/bot_test.go b/bot_test.go index 2e9d07a..0c98ee9 100644 --- a/bot_test.go +++ b/bot_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/go-telegram-bot-api/telegram-bot-api" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" ) const ( @@ -402,6 +402,32 @@ func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) { } } +func TestSendWithDice(t *testing.T) { + bot, _ := getBot(t) + + msg := tgbotapi.NewDice(ChatID) + _, err := bot.Send(msg) + + if err != nil { + t.Error(err) + t.Fail() + } + +} + +func TestSendWithDiceWithEmoji(t *testing.T) { + bot, _ := getBot(t) + + msg := tgbotapi.NewDiceWithEmoji(ChatID, "🏀") + _, err := bot.Send(msg) + + if err != nil { + t.Error(err) + t.Fail() + } + +} + func TestGetFile(t *testing.T) { bot, _ := getBot(t) diff --git a/configs.go b/configs.go index 0265ada..3989774 100644 --- a/configs.go +++ b/configs.go @@ -1284,3 +1284,30 @@ func (config GetStickerSetConfig) values() (url.Values, error) { v.Add("name", config.Name) return v, nil } + +// DiceConfig contains information about a sendDice request. +type DiceConfig struct { + BaseChat + // Emoji on which the dice throw animation is based. + // Currently, must be one of “🎲”, “🎯”, or “🏀”. + // Dice can have values 1-6 for “🎲” and “🎯”, and values 1-5 for “🏀”. + // Defaults to “🎲” + Emoji string +} + +// values returns a url.Values representation of DiceConfig. +func (config DiceConfig) values() (url.Values, error) { + v, err := config.BaseChat.values() + if err != nil { + return v, err + } + if config.Emoji != "" { + v.Add("emoji", config.Emoji) + } + return v, nil +} + +// method returns Telegram API method name for sending Dice. +func (config DiceConfig) method() string { + return "sendDice" +} diff --git a/helpers.go b/helpers.go index b9afb84..e8f8831 100644 --- a/helpers.go +++ b/helpers.go @@ -18,6 +18,30 @@ func NewMessage(chatID int64, text string) MessageConfig { } } +// NewDice creates a new DiceConfig. +// +// chatID is where to send it +func NewDice(chatID int64) DiceConfig { + return DiceConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + } +} + +// NewDiceWithEmoji creates a new DiceConfig. +// +// chatID is where to send it +// emoji is type of the Dice +func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig { + return DiceConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + Emoji: emoji, + } +} + // NewDeleteMessage creates a request to delete a message. func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { return DeleteMessageConfig{ @@ -491,7 +515,7 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF { } } -// NewInlineQueryResultCachedPhoto create a new inline query with cached photo. +// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF. func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif { return InlineQueryResultCachedMpeg4Gif{ Type: "mpeg4_gif", diff --git a/helpers_test.go b/helpers_test.go index 9542f02..ec15a4e 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -1,8 +1,9 @@ package tgbotapi_test import ( - "github.com/go-telegram-bot-api/telegram-bot-api" "testing" + + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" ) func TestNewInlineQueryResultArticle(t *testing.T) { @@ -175,3 +176,21 @@ func TestNewEditMessageReplyMarkup(t *testing.T) { } } + +func TestNewDice(t *testing.T) { + dice := tgbotapi.NewDice(42) + + if dice.ChatID != 42 || + dice.Emoji != "" { + t.Fail() + } +} + +func TestNewDiceWithEmoji(t *testing.T) { + dice := tgbotapi.NewDiceWithEmoji(42, "🏀") + + if dice.ChatID != 42 || + dice.Emoji != "🏀" { + t.Fail() + } +} diff --git a/types.go b/types.go index 6e295ca..f2ad140 100644 --- a/types.go +++ b/types.go @@ -352,6 +352,7 @@ type Sticker struct { IsAnimated bool `json:"is_animated"` // optional } +// StickerSet contains information about an sticker set. type StickerSet struct { Name string `json:"name"` Title string `json:"title"` From 64517d16e7c54529952c535c22764e8cbbfd939c Mon Sep 17 00:00:00 2001 From: Jiayu Yi Date: Tue, 21 Jul 2020 16:33:33 +0800 Subject: [PATCH 26/28] Mark WebhookInfo.MaxConnections as optional --- types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types.go b/types.go index b673dc6..4ca2fe9 100644 --- a/types.go +++ b/types.go @@ -571,7 +571,7 @@ type WebhookInfo struct { PendingUpdateCount int `json:"pending_update_count"` LastErrorDate int `json:"last_error_date"` // optional LastErrorMessage string `json:"last_error_message"` // optional - MaxConnections int `json:"max_connections"` + MaxConnections int `json:"max_connections"` // optional } // IsSet returns true if a webhook is currently set. From ce395c2286e5532256440120e145eb551e558555 Mon Sep 17 00:00:00 2001 From: Syfaro Date: Tue, 21 Jul 2020 03:35:48 -0500 Subject: [PATCH 27/28] Update comment on NewOneTimeReplyKeyboard. --- helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index fc19313..bf256b8 100644 --- a/helpers.go +++ b/helpers.go @@ -704,7 +704,7 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { } } -// NewOneTimeReplyKeyboard creates a new one time keyboard using NewReplyKeyboard() +// NewOneTimeReplyKeyboard creates a new one time keyboard. func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { markup := NewReplyKeyboard(rows...) markup.OneTimeKeyboard = true From 5c5e96de34ba4bcb0b1d1e9dd757559577c71e47 Mon Sep 17 00:00:00 2001 From: Jiayu Yi Date: Tue, 21 Jul 2020 16:37:08 +0800 Subject: [PATCH 28/28] Change assertion failure message --- bot_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot_test.go b/bot_test.go index b00ea41..8e5cf63 100644 --- a/bot_test.go +++ b/bot_test.go @@ -498,7 +498,7 @@ func TestSetWebhookWithoutCert(t *testing.T) { t.Error(err) } if info.MaxConnections == 0 { - t.Errorf("wanted max connections to be greater than 0") + t.Errorf("Expected maximum connections to be greater than 0") } if info.LastErrorDate != 0 { t.Errorf("[Telegram callback failed]%s", info.LastErrorMessage)