From 601f48a50ea31a9631011766c680ecef931ddafc Mon Sep 17 00:00:00 2001 From: Thom Dickson Date: Tue, 14 Mar 2023 18:03:04 -0400 Subject: Add support for Telegram topics (telegram) (#1942) Topics are surfaced by appending / to the channel setting for the gateway. An example for the topic with ID of 16 would be: ``` [[gateway.inout]] account="telegram.mytelegram" channel="-100xxxxxxxxxx/16" ``` --- bridge/telegram/handlers.go | 27 +- bridge/telegram/telegram.go | 59 +- go.mod | 2 +- go.sum | 4 +- .../telegram-bot-api/v5/.gitignore | 4 - .../telegram-bot-api/v5/LICENSE.txt | 21 - .../telegram-bot-api/v5/README.md | 121 - .../telegram-bot-api/v5/book.toml | 9 - .../go-telegram-bot-api/telegram-bot-api/v5/bot.go | 726 ---- .../telegram-bot-api/v5/configs.go | 2468 ------------- .../telegram-bot-api/v5/helpers.go | 927 ----- .../go-telegram-bot-api/telegram-bot-api/v5/log.go | 27 - .../telegram-bot-api/v5/params.go | 97 - .../telegram-bot-api/v5/passport.go | 317 -- .../telegram-bot-api/v5/types.go | 3225 ----------------- .../matterbridge/telegram-bot-api/v6/.gitignore | 5 + .../matterbridge/telegram-bot-api/v6/LICENSE.txt | 21 + .../matterbridge/telegram-bot-api/v6/README.md | 121 + .../matterbridge/telegram-bot-api/v6/book.toml | 9 + .../matterbridge/telegram-bot-api/v6/bot.go | 748 ++++ .../matterbridge/telegram-bot-api/v6/configs.go | 2934 +++++++++++++++ .../matterbridge/telegram-bot-api/v6/helpers.go | 989 +++++ .../matterbridge/telegram-bot-api/v6/log.go | 27 + .../matterbridge/telegram-bot-api/v6/params.go | 104 + .../matterbridge/telegram-bot-api/v6/passport.go | 317 ++ .../matterbridge/telegram-bot-api/v6/types.go | 3760 ++++++++++++++++++++ vendor/modules.txt | 6 +- 27 files changed, 9110 insertions(+), 7965 deletions(-) delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/.gitignore delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/LICENSE.txt delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/README.md delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/helpers.go delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/log.go delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/passport.go delete mode 100644 vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/.gitignore create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/LICENSE.txt create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/README.md create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/book.toml create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/bot.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/configs.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/helpers.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/log.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/params.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/passport.go create mode 100644 vendor/github.com/matterbridge/telegram-bot-api/v6/types.go diff --git a/bridge/telegram/handlers.go b/bridge/telegram/handlers.go index 5ffb1eca..985397ef 100644 --- a/bridge/telegram/handlers.go +++ b/bridge/telegram/handlers.go @@ -11,7 +11,7 @@ import ( "github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/helper" "github.com/davecgh/go-spew/spew" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + tgbotapi "github.com/matterbridge/telegram-bot-api/v6" ) func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message { @@ -20,6 +20,11 @@ func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited * if posted.Text == "/chatId" { chatID := strconv.FormatInt(posted.Chat.ID, 10) + // Handle chat topics + if posted.IsTopicMessage { + chatID = chatID + "/" + strconv.Itoa(posted.MessageThreadID) + } + _, err := b.Send(config.Message{ Channel: chatID, Text: fmt.Sprintf("ID of this chat: %s", chatID), @@ -91,7 +96,8 @@ func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Mess // handleQuoting handles quoting of previous messages func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Message) { - if message.ReplyToMessage != nil { + // Used to check if the message was a reply to the root topic + if message.ReplyToMessage != nil && !(message.ReplyToMessage.MessageID == message.MessageThreadID) { //nolint:nestif usernameReply := "" if message.ReplyToMessage.From != nil { if b.GetBool("UseFirstName") { @@ -211,9 +217,14 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { // set the ID's from the channel or group message rmsg.ID = strconv.Itoa(message.MessageID) rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10) + if message.MessageThreadID != 0 { + rmsg.Channel += "/" + strconv.Itoa(message.MessageThreadID) + } // preserve threading from telegram reply - if message.ReplyToMessage != nil { + if message.ReplyToMessage != nil && + // Used to check if the message was a reply to the root topic + !(message.ReplyToMessage.MessageID == message.MessageThreadID) { rmsg.ParentID = strconv.Itoa(message.ReplyToMessage.MessageID) } @@ -326,12 +337,12 @@ func (b *Btelegram) maybeConvertWebp(name *string, data *[]byte) { // handleDownloadFile handles file download func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Message) error { - size := 0 + size := int64(0) var url, name, text string switch { case message.Sticker != nil: text, name, url = b.getDownloadInfo(message.Sticker.FileID, ".webp", true) - size = message.Sticker.FileSize + size = int64(message.Sticker.FileSize) case message.Voice != nil: text, name, url = b.getDownloadInfo(message.Voice.FileID, ".ogg", true) size = message.Voice.FileSize @@ -348,7 +359,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa text = " " + message.Document.FileName + " : " + url case message.Photo != nil: photos := message.Photo - size = photos[len(photos)-1].FileSize + size = int64(photos[len(photos)-1].FileSize) text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true) } @@ -452,7 +463,7 @@ func (b *Btelegram) handleEdit(msg *config.Message, chatid int64) (string, error } // handleUploadFile handles native upload of files -func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, parentID int) (string, error) { +func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, threadid int, parentID int) (string, error) { var media []interface{} for _, f := range msg.Extra["file"] { fi := f.(config.FileInfo) @@ -502,7 +513,7 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, parentID } } - return b.sendMediaFiles(msg, chatid, parentID, media) + return b.sendMediaFiles(msg, chatid, threadid, parentID, media) } func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string { diff --git a/bridge/telegram/telegram.go b/bridge/telegram/telegram.go index 43cb818f..e7885ca3 100644 --- a/bridge/telegram/telegram.go +++ b/bridge/telegram/telegram.go @@ -10,7 +10,7 @@ import ( "github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/helper" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + tgbotapi "github.com/matterbridge/telegram-bot-api/v6" ) const ( @@ -86,11 +86,41 @@ func TGGetParseMode(b *Btelegram, username string, text string) (textout string, return textout, parsemode } +func (b *Btelegram) getIds(channel string) (int64, int, error) { + var chatid int64 + topicid := 0 + + // get the chatid + if strings.Contains(channel, "/") { //nolint:nestif + s := strings.Split(channel, "/") + if len(s) < 2 { + b.Log.Errorf("Invalid channel format: %#v\n", channel) + return 0, 0, nil + } + id, err := strconv.ParseInt(s[0], 10, 64) + if err != nil { + return 0, 0, err + } + chatid = id + tid, err := strconv.Atoi(s[1]) + if err != nil { + return 0, 0, err + } + topicid = tid + } else { + id, err := strconv.ParseInt(channel, 10, 64) + if err != nil { + return 0, 0, err + } + chatid = id + } + return chatid, topicid, nil +} + func (b *Btelegram) Send(msg config.Message) (string, error) { b.Log.Debugf("=> Receiving %#v", msg) - // get the chatid - chatid, err := strconv.ParseInt(msg.Channel, 10, 64) + chatid, topicid, err := b.getIds(msg.Channel) if err != nil { return "", err } @@ -123,13 +153,13 @@ func (b *Btelegram) Send(msg config.Message) (string, error) { // Upload a file if it exists if msg.Extra != nil { for _, rmsg := range helper.HandleExtra(&msg, b.General) { - if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text, parentID); msgErr != nil { + if _, msgErr := b.sendMessage(chatid, topicid, rmsg.Username, rmsg.Text, parentID); msgErr != nil { b.Log.Errorf("sendMessage failed: %s", msgErr) } } // check if we have files to upload (from slack, telegram or mattermost) if len(msg.Extra["file"]) > 0 { - return b.handleUploadFile(&msg, chatid, parentID) + return b.handleUploadFile(&msg, chatid, topicid, parentID) } } @@ -143,7 +173,7 @@ func (b *Btelegram) Send(msg config.Message) (string, error) { // Ignore empty text field needs for prevent double messages from whatsapp to telegram // when sending media with text caption if msg.Text != "" { - return b.sendMessage(chatid, msg.Username, msg.Text, parentID) + return b.sendMessage(chatid, topicid, msg.Username, msg.Text, parentID) } return "", nil @@ -157,9 +187,12 @@ func (b *Btelegram) getFileDirectURL(id string) string { return res } -func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID int) (string, error) { +func (b *Btelegram) sendMessage(chatid int64, topicid int, username, text string, parentID int) (string, error) { m := tgbotapi.NewMessage(chatid, "") m.Text, m.ParseMode = TGGetParseMode(b, username, text) + if topicid != 0 { + m.BaseChat.MessageThreadID = topicid + } m.ReplyToMessageID = parentID m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview") @@ -171,11 +204,19 @@ func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID in } // sendMediaFiles native upload media files via media group -func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, parentID int, media []interface{}) (string, error) { +func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, threadid int, parentID int, media []interface{}) (string, error) { if len(media) == 0 { return "", nil } - mg := tgbotapi.MediaGroupConfig{ChatID: chatid, ChannelUsername: msg.Username, Media: media, ReplyToMessageID: parentID} + mg := tgbotapi.MediaGroupConfig{ + BaseChat: tgbotapi.BaseChat{ + ChatID: chatid, + MessageThreadID: threadid, + ChannelUsername: msg.Username, + ReplyToMessageID: parentID, + }, + Media: media, + } messages, err := b.c.SendMediaGroup(mg) if err != nil { return "", err diff --git a/go.mod b/go.mod index 91adf773..c4c8c24a 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/d5/tengo/v2 v2.13.0 github.com/davecgh/go-spew v1.1.1 github.com/fsnotify/fsnotify v1.6.0 - github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/gomarkdown/markdown v0.0.0-20221013030248-663e2500819c github.com/google/gops v0.3.27 github.com/gorilla/schema v1.2.0 @@ -29,6 +28,7 @@ require ( github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75 github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba github.com/matterbridge/matterclient v0.0.0-20221106190440-8bcf49695e0d + github.com/matterbridge/telegram-bot-api/v6 v6.5.0 github.com/mattermost/mattermost-server/v5 v5.39.3 github.com/mattermost/mattermost-server/v6 v6.7.2 github.com/mattn/godown v0.0.1 diff --git a/go.sum b/go.sum index ac913120..f2087fe6 100644 --- a/go.sum +++ b/go.sum @@ -607,8 +607,6 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -1085,6 +1083,8 @@ github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d97130 github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU= github.com/matterbridge/matterclient v0.0.0-20221106190440-8bcf49695e0d h1:aI0ANEzy3dMv3vEAMQ80AItNie0fBR9ZxE2sAedORmM= github.com/matterbridge/matterclient v0.0.0-20221106190440-8bcf49695e0d/go.mod h1:Zg8PH1P/1CNUxozQ8blnjAV9PA4Qn2qWf33cX5yNKGM= +github.com/matterbridge/telegram-bot-api/v6 v6.5.0 h1:wCnHWvt4WGhfognQsuu2OnHyqENBdJRf2mReYTCXggQ= +github.com/matterbridge/telegram-bot-api/v6 v6.5.0/go.mod h1:/hSLrs8h/xNsQglQXjwXJ92iZU8XfTGkYUQ7KVDWEVo= github.com/mattermost/go-i18n v1.11.0/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34= diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/.gitignore b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/.gitignore deleted file mode 100644 index eb7a23b2..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.idea/ -coverage.out -tmp/ -book/ diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/LICENSE.txt b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/LICENSE.txt deleted file mode 100644 index b1fef93b..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Syfaro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/README.md b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/README.md deleted file mode 100644 index 45d3e1db..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Golang bindings for the Telegram Bot API - -[![Go Reference](https://pkg.go.dev/badge/github.com/go-telegram-bot-api/telegram-bot-api/v5.svg)](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) -[![Test](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml/badge.svg)](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml) - -All methods are fairly self-explanatory, and reading the [godoc](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) page should -explain everything. If something isn't clear, open an issue or submit -a pull request. - -There are more tutorials and high-level information on the website, [go-telegram-bot-api.dev](https://go-telegram-bot-api.dev). - -The scope of this project is just to provide a wrapper around the API -without any additional features. There are other projects for creating -something with plugins and command handlers without having to design -all that yourself. - -Join [the development group](https://telegram.me/go_telegram_bot_api) if -you want to ask questions or discuss development. - -## Example - -First, ensure the library is installed and up to date by running -`go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5`. - -This is a very simple bot that just displays any gotten updates, -then replies it to that chat. - -```go -package main - -import ( - "log" - - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" -) - -func main() { - bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") - if err != nil { - log.Panic(err) - } - - bot.Debug = true - - log.Printf("Authorized on account %s", bot.Self.UserName) - - u := tgbotapi.NewUpdate(0) - u.Timeout = 60 - - updates := bot.GetUpdatesChan(u) - - for update := range updates { - if update.Message != nil { // If we got a message - log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) - - msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) - msg.ReplyToMessageID = update.Message.MessageID - - bot.Send(msg) - } - } -} -``` - -If you need to use webhooks (if you wish to run on Google App Engine), -you may use a slightly different method. - -```go -package main - -import ( - "log" - "net/http" - - "github.com/go-telegram-bot-api/telegram-bot-api/v5" -) - -func main() { - bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") - if err != nil { - log.Fatal(err) - } - - bot.Debug = true - - log.Printf("Authorized on account %s", bot.Self.UserName) - - wh, _ := tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem") - - _, err = bot.SetWebhook(wh) - 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) - } - - updates := bot.ListenForWebhook("/" + bot.Token) - go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil) - - for update := range updates { - log.Printf("%+v\n", update) - } -} -``` - -If you need, you may generate a self-signed certificate, as this requires -HTTPS / TLS. The above example tells Telegram that this is your -certificate and that it should be trusted, even though it is not -properly signed. - - openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3560 -subj "//O=Org\CN=Test" -nodes - -Now that [Let's Encrypt](https://letsencrypt.org) is available, -you may wish to generate your free TLS certificate there. diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml deleted file mode 100644 index 841d5ba6..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml +++ /dev/null @@ -1,9 +0,0 @@ -[book] -authors = ["Syfaro"] -language = "en" -multilingual = false -src = "docs" -title = "Go Telegram Bot API" - -[output.html] -git-repository-url = "https://github.com/go-telegram-bot-api/telegram-bot-api" diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go deleted file mode 100644 index c58afec4..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go +++ /dev/null @@ -1,726 +0,0 @@ -// Package tgbotapi has functions and types used for interacting with -// the Telegram Bot API. -package tgbotapi - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "net/http" - "net/url" - "strings" - "time" -) - -// HTTPClient is the type needed for the bot to perform HTTP requests. -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 HTTPClient `json:"-"` - shutdownChannel chan interface{} - - apiEndpoint string -} - -// NewBotAPI creates a new BotAPI instance. -// -// It requires a token, provided by @BotFather on Telegram. -func NewBotAPI(token string) (*BotAPI, error) { - 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 and API endpoint. -func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) { - bot := &BotAPI{ - Token: token, - Client: client, - Buffer: 100, - shutdownChannel: make(chan interface{}), - - apiEndpoint: apiEndpoint, - } - - self, err := bot.GetMe() - if err != nil { - return nil, err - } - - bot.Self = self - - return bot, nil -} - -// SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance. -func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) { - bot.apiEndpoint = apiEndpoint -} - -func buildParams(in Params) url.Values { - if in == nil { - return url.Values{} - } - - out := url.Values{} - - for key, value := range in { - out.Set(key, value) - } - - return out -} - -// MakeRequest makes a request to a specific endpoint with our token. -func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) { - if bot.Debug { - log.Printf("Endpoint: %s, params: %v\n", endpoint, params) - } - - method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) - - values := buildParams(params) - - req, err := http.NewRequest("POST", method, strings.NewReader(values.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 nil, err - } - defer resp.Body.Close() - - var apiResp APIResponse - bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) - if err != nil { - return &apiResp, err - } - - if bot.Debug { - log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) - } - - if !apiResp.Ok { - var parameters ResponseParameters - - if apiResp.Parameters != nil { - parameters = *apiResp.Parameters - } - - return &apiResp, &Error{ - Code: apiResp.ErrorCode, - Message: apiResp.Description, - ResponseParameters: parameters, - } - } - - return &apiResp, nil -} - -// decodeAPIResponse decode response and return slice of bytes if debug enabled. -// If debug disabled, just decode http.Response.Body stream to APIResponse struct -// for efficient memory usage -func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) ([]byte, error) { - if !bot.Debug { - dec := json.NewDecoder(responseBody) - err := dec.Decode(resp) - return nil, err - } - - // if debug, read response body - data, err := ioutil.ReadAll(responseBody) - if err != nil { - return nil, err - } - - err = json.Unmarshal(data, resp) - if err != nil { - return nil, err - } - - return data, nil -} - -// UploadFiles makes a request to the API with files. -func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) { - r, w := io.Pipe() - m := multipart.NewWriter(w) - - // This code modified from the very helpful @HirbodBehnam - // https://github.com/go-telegram-bot-api/telegram-bot-api/issues/354#issuecomment-663856473 - go func() { - defer w.Close() - defer m.Close() - - for field, value := range params { - if err := m.WriteField(field, value); err != nil { - w.CloseWithError(err) - return - } - } - - for _, file := range files { - if file.Data.NeedsUpload() { - name, reader, err := file.Data.UploadData() - if err != nil { - w.CloseWithError(err) - return - } - - part, err := m.CreateFormFile(file.Name, name) - if err != nil { - w.CloseWithError(err) - return - } - - if _, err := io.Copy(part, reader); err != nil { - w.CloseWithError(err) - return - } - - if closer, ok := reader.(io.ReadCloser); ok { - if err = closer.Close(); err != nil { - w.CloseWithError(err) - return - } - } - } else { - value := file.Data.SendData() - - if err := m.WriteField(file.Name, value); err != nil { - w.CloseWithError(err) - return - } - } - } - }() - - if bot.Debug { - log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files)) - } - - method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) - - req, err := http.NewRequest("POST", method, r) - if err != nil { - return nil, err - } - - req.Header.Set("Content-Type", m.FormDataContentType()) - - resp, err := bot.Client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var apiResp APIResponse - bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) - if err != nil { - return &apiResp, err - } - - if bot.Debug { - log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) - } - - if !apiResp.Ok { - var parameters ResponseParameters - - if apiResp.Parameters != nil { - parameters = *apiResp.Parameters - } - - return &apiResp, &Error{ - Message: apiResp.Description, - ResponseParameters: parameters, - } - } - - return &apiResp, nil -} - -// GetFileDirectURL returns direct URL to file -// -// It requires the FileID. -func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) { - file, err := bot.GetFile(FileConfig{fileID}) - - if err != nil { - return "", err - } - - return file.Link(bot.Token), nil -} - -// GetMe fetches the currently authenticated bot. -// -// This method is called upon creation to validate the token, -// and so you may get this data from BotAPI.Self without the need for -// another request. -func (bot *BotAPI) GetMe() (User, error) { - resp, err := bot.MakeRequest("getMe", nil) - if err != nil { - return User{}, err - } - - var user User - err = json.Unmarshal(resp.Result, &user) - - return user, err -} - -// IsMessageToMe returns true if message directed to this bot. -// -// It requires the Message. -func (bot *BotAPI) IsMessageToMe(message Message) bool { - return strings.Contains(message.Text, "@"+bot.Self.UserName) -} - -func hasFilesNeedingUpload(files []RequestFile) bool { - for _, file := range files { - if file.Data.NeedsUpload() { - return true - } - } - - return false -} - -// Request sends a Chattable to Telegram, and returns the APIResponse. -func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) { - params, err := c.params() - if err != nil { - return nil, err - } - - if t, ok := c.(Fileable); ok { - files := t.files() - - // If we have files that need to be uploaded, we should delegate the - // request to UploadFile. - if hasFilesNeedingUpload(files) { - return bot.UploadFiles(t.method(), params, files) - } - - // However, if there are no files to be uploaded, there's likely things - // that need to be turned into params instead. - for _, file := range files { - params[file.Name] = file.Data.SendData() - } - } - - return bot.MakeRequest(c.method(), params) -} - -// Send will send a Chattable item to Telegram and provides the -// returned Message. -func (bot *BotAPI) Send(c Chattable) (Message, error) { - resp, err := bot.Request(c) - if err != nil { - return Message{}, err - } - - var message Message - err = json.Unmarshal(resp.Result, &message) - - return message, err -} - -// SendMediaGroup sends a media group and returns the resulting messages. -func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) { - resp, err := bot.Request(config) - if err != nil { - return nil, err - } - - var messages []Message - err = json.Unmarshal(resp.Result, &messages) - - return messages, err -} - -// GetUserProfilePhotos gets a user's profile photos. -// -// It requires UserID. -// Offset and Limit are optional. -func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { - resp, err := bot.Request(config) - if err != nil { - return UserProfilePhotos{}, err - } - - var profilePhotos UserProfilePhotos - err = json.Unmarshal(resp.Result, &profilePhotos) - - return profilePhotos, err -} - -// GetFile returns a File which can download a file from Telegram. -// -// Requires FileID. -func (bot *BotAPI) GetFile(config FileConfig) (File, error) { - resp, err := bot.Request(config) - if err != nil { - return File{}, err - } - - var file File - err = json.Unmarshal(resp.Result, &file) - - return file, err -} - -// GetUpdates fetches updates. -// If a WebHook is set, this will not return any data! -// -// Offset, Limit, Timeout, and AllowedUpdates are optional. -// To avoid stale items, set Offset to one higher than the previous item. -// Set Timeout to a large number to reduce requests, so you can get updates -// instantly instead of having to wait between requests. -func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { - resp, err := bot.Request(config) - if err != nil { - return []Update{}, err - } - - var updates []Update - err = json.Unmarshal(resp.Result, &updates) - - return updates, err -} - -// GetWebhookInfo allows you to fetch information about a webhook and if -// one currently is set, along with pending update count and error messages. -func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) { - resp, err := bot.MakeRequest("getWebhookInfo", nil) - if err != nil { - return WebhookInfo{}, err - } - - var info WebhookInfo - err = json.Unmarshal(resp.Result, &info) - - return info, err -} - -// GetUpdatesChan starts and returns a channel for getting updates. -func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel { - ch := make(chan Update, bot.Buffer) - - go func() { - for { - select { - case <-bot.shutdownChannel: - close(ch) - return - default: - } - - updates, err := bot.GetUpdates(config) - if err != nil { - log.Println(err) - log.Println("Failed to get updates, retrying in 3 seconds...") - time.Sleep(time.Second * 3) - - continue - } - - for _, update := range updates { - if update.UpdateID >= config.Offset { - config.Offset = update.UpdateID + 1 - ch <- update - } - } - } - }() - - return ch -} - -// StopReceivingUpdates stops the go routine which receives updates -func (bot *BotAPI) StopReceivingUpdates() { - if bot.Debug { - log.Println("Stopping the update receiver routine...") - } - close(bot.shutdownChannel) -} - -// ListenForWebhook registers a http handler for a webhook. -func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel { - ch := make(chan Update, bot.Buffer) - - http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { - update, err := bot.HandleUpdate(r) - if err != nil { - errMsg, _ := json.Marshal(map[string]string{"error": err.Error()}) - w.WriteHeader(http.StatusBadRequest) - w.Header().Set("Content-Type", "application/json") - _, _ = w.Write(errMsg) - return - } - - ch <- *update - }) - - return ch -} - -// ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook. -func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel { - ch := make(chan Update, bot.Buffer) - - func(w http.ResponseWriter, r *http.Request) { - update, err := bot.HandleUpdate(r) - if err != nil { - errMsg, _ := json.Marshal(map[string]string{"error": err.Error()}) - w.WriteHeader(http.StatusBadRequest) - w.Header().Set("Content-Type", "application/json") - _, _ = w.Write(errMsg) - return - } - - ch <- *update - close(ch) - }(w, r) - - return ch -} - -// HandleUpdate parses and returns update received via webhook -func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) { - if r.Method != http.MethodPost { - err := errors.New("wrong HTTP method required POST") - return nil, err - } - - var update Update - err := json.NewDecoder(r.Body).Decode(&update) - if err != nil { - return nil, err - } - - return &update, nil -} - -// WriteToHTTPResponse writes the request to the HTTP ResponseWriter. -// -// It doesn't support uploading files. -// -// See https://core.telegram.org/bots/api#making-requests-when-getting-updates -// for details. -func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error { - params, err := c.params() - if err != nil { - return err - } - - if t, ok := c.(Fileable); ok { - if hasFilesNeedingUpload(t.files()) { - return errors.New("unable to use http response to upload files") - } - } - - values := buildParams(params) - values.Set("method", c.method()) - - w.Header().Set("Content-Type", "application/x-www-form-urlencoded") - _, err = w.Write([]byte(values.Encode())) - return err -} - -// GetChat gets information about a chat. -func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) { - resp, err := bot.Request(config) - if err != nil { - return Chat{}, err - } - - var chat Chat - err = json.Unmarshal(resp.Result, &chat) - - return chat, err -} - -// GetChatAdministrators gets a list of administrators in the chat. -// -// If none have been appointed, only the creator will be returned. -// Bots are not shown, even if they are an administrator. -func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) { - resp, err := bot.Request(config) - if err != nil { - return []ChatMember{}, err - } - - var members []ChatMember - err = json.Unmarshal(resp.Result, &members) - - return members, err -} - -// GetChatMembersCount gets the number of users in a chat. -func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) { - resp, err := bot.Request(config) - if err != nil { - return -1, err - } - - var count int - err = json.Unmarshal(resp.Result, &count) - - return count, err -} - -// GetChatMember gets a specific chat member. -func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) { - resp, err := bot.Request(config) - if err != nil { - return ChatMember{}, err - } - - var member ChatMember - err = json.Unmarshal(resp.Result, &member) - - return member, err -} - -// GetGameHighScores allows you to get the high scores for a game. -func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) { - resp, err := bot.Request(config) - if err != nil { - return []GameHighScore{}, err - } - - var highScores []GameHighScore - err = json.Unmarshal(resp.Result, &highScores) - - return highScores, err -} - -// GetInviteLink get InviteLink for a chat -func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) { - resp, err := bot.Request(config) - if err != nil { - return "", err - } - - var inviteLink string - err = json.Unmarshal(resp.Result, &inviteLink) - - return inviteLink, err -} - -// GetStickerSet returns a StickerSet. -func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { - resp, err := bot.Request(config) - if err != nil { - return StickerSet{}, err - } - - var stickers StickerSet - err = json.Unmarshal(resp.Result, &stickers) - - return stickers, err -} - -// StopPoll stops a poll and returns the result. -func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) { - resp, err := bot.Request(config) - if err != nil { - return Poll{}, err - } - - var poll Poll - err = json.Unmarshal(resp.Result, &poll) - - return poll, err -} - -// GetMyCommands gets the currently registered commands. -func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) { - return bot.GetMyCommandsWithConfig(GetMyCommandsConfig{}) -} - -// GetMyCommandsWithConfig gets the currently registered commands with a config. -func (bot *BotAPI) GetMyCommandsWithConfig(config GetMyCommandsConfig) ([]BotCommand, error) { - resp, err := bot.Request(config) - if err != nil { - return nil, err - } - - var commands []BotCommand - err = json.Unmarshal(resp.Result, &commands) - - return commands, err -} - -// CopyMessage copy messages of any kind. The method is analogous to the method -// forwardMessage, but the copied message doesn't have a link to the original -// message. Returns the MessageID of the sent message on success. -func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) { - params, err := config.params() - if err != nil { - return MessageID{}, err - } - - resp, err := bot.MakeRequest(config.method(), params) - if err != nil { - return MessageID{}, err - } - - var messageID MessageID - err = json.Unmarshal(resp.Result, &messageID) - - return messageID, err -} - -// EscapeText takes an input text and escape Telegram markup symbols. -// In this way we can send a text without being afraid of having to escape the characters manually. -// Note that you don't have to include the formatting style in the input text, or it will be escaped too. -// If there is an error, an empty string will be returned. -// -// parseMode is the text formatting mode (ModeMarkdown, ModeMarkdownV2 or ModeHTML) -// text is the input string that will be escaped -func EscapeText(parseMode string, text string) string { - var replacer *strings.Replacer - - if parseMode == ModeHTML { - replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&") - } else if parseMode == ModeMarkdown { - replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[") - } else if parseMode == ModeMarkdownV2 { - replacer = strings.NewReplacer( - "_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(", - "\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>", - "#", "\\#", "+", "\\+", "-", "\\-", "=", "\\=", "|", - "\\|", "{", "\\{", "}", "\\}", ".", "\\.", "!", "\\!", - ) - } else { - return "" - } - - return replacer.Replace(text) -} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go deleted file mode 100644 index 5e43af49..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go +++ /dev/null @@ -1,2468 +0,0 @@ -package tgbotapi - -import ( - "bytes" - "fmt" - "io" - "net/url" - "os" - "strconv" -) - -// Telegram constants -const ( - // APIEndpoint is the endpoint for all API methods, - // with formatting for Sprintf. - APIEndpoint = "https://api.telegram.org/bot%s/%s" - // FileEndpoint is the endpoint for downloading a file from Telegram. - FileEndpoint = "https://api.telegram.org/file/bot%s/%s" -) - -// Constant values for ChatActions -const ( - ChatTyping = "typing" - ChatUploadPhoto = "upload_photo" - ChatRecordVideo = "record_video" - ChatUploadVideo = "upload_video" - ChatRecordVoice = "record_voice" - ChatUploadVoice = "upload_voice" - ChatUploadDocument = "upload_document" - ChatChooseSticker = "choose_sticker" - ChatFindLocation = "find_location" - ChatRecordVideoNote = "record_video_note" - ChatUploadVideoNote = "upload_video_note" -) - -// API errors -const ( - // ErrAPIForbidden happens when a token is bad - ErrAPIForbidden = "forbidden" -) - -// Constant values for ParseMode in MessageConfig -const ( - ModeMarkdown = "Markdown" - ModeMarkdownV2 = "MarkdownV2" - ModeHTML = "HTML" -) - -// Constant values for update types -const ( - // UpdateTypeMessage is new incoming message of any kind — text, photo, sticker, etc. - UpdateTypeMessage = "message" - - // UpdateTypeEditedMessage is new version of a message that is known to the bot and was edited - UpdateTypeEditedMessage = "edited_message" - - // UpdateTypeChannelPost is new incoming channel post of any kind — text, photo, sticker, etc. - UpdateTypeChannelPost = "channel_post" - - // UpdateTypeEditedChannelPost is new version of a channel post that is known to the bot and was edited - UpdateTypeEditedChannelPost = "edited_channel_post" - - // UpdateTypeInlineQuery is new incoming inline query - UpdateTypeInlineQuery = "inline_query" - - // UpdateTypeChosenInlineResult i the result of an inline query that was chosen by a user and sent to their - // chat partner. Please see the documentation on the feedback collecting for - // details on how to enable these updates for your bot. - UpdateTypeChosenInlineResult = "chosen_inline_result" - - // UpdateTypeCallbackQuery is new incoming callback query - UpdateTypeCallbackQuery = "callback_query" - - // UpdateTypeShippingQuery is new incoming shipping query. Only for invoices with flexible price - UpdateTypeShippingQuery = "shipping_query" - - // UpdateTypePreCheckoutQuery is new incoming pre-checkout query. Contains full information about checkout - UpdateTypePreCheckoutQuery = "pre_checkout_query" - - // UpdateTypePoll is new poll state. Bots receive only updates about stopped polls and polls - // which are sent by the bot - UpdateTypePoll = "poll" - - // UpdateTypePollAnswer is when user changed their answer in a non-anonymous poll. Bots receive new votes - // only in polls that were sent by the bot itself. - UpdateTypePollAnswer = "poll_answer" - - // UpdateTypeMyChatMember is when the bot's chat member status was updated in a chat. For private chats, this - // update is received only when the bot is blocked or unblocked by the user. - UpdateTypeMyChatMember = "my_chat_member" - - // UpdateTypeChatMember is when the bot must be an administrator in the chat and must explicitly specify - // this update in the list of allowed_updates to receive these updates. - UpdateTypeChatMember = "chat_member" -) - -// Library errors -const ( - ErrBadURL = "bad or empty url" -) - -// Chattable is any config type that can be sent. -type Chattable interface { - params() (Params, error) - method() string -} - -// Fileable is any config type that can be sent that includes a file. -type Fileable interface { - Chattable - files() []RequestFile -} - -// RequestFile represents a file associated with a field name. -type RequestFile struct { - // The file field name. - Name string - // The file data to include. - Data RequestFileData -} - -// RequestFileData represents the data to be used for a file. -type RequestFileData interface { - // NeedsUpload shows if the file needs to be uploaded. - NeedsUpload() bool - - // UploadData gets the file name and an `io.Reader` for the file to be uploaded. This - // must only be called when the file needs to be uploaded. - UploadData() (string, io.Reader, error) - // SendData gets the file data to send when a file does not need to be uploaded. This - // must only be called when the file does not need to be uploaded. - SendData() string -} - -// FileBytes contains information about a set of bytes to upload -// as a File. -type FileBytes struct { - Name string - Bytes []byte -} - -func (fb FileBytes) NeedsUpload() bool { - return true -} - -func (fb FileBytes) UploadData() (string, io.Reader, error) { - return fb.Name, bytes.NewReader(fb.Bytes), nil -} - -func (fb FileBytes) SendData() string { - panic("FileBytes must be uploaded") -} - -// FileReader contains information about a reader to upload as a File. -type FileReader struct { - Name string - Reader io.Reader -} - -func (fr FileReader) NeedsUpload() bool { - return true -} - -func (fr FileReader) UploadData() (string, io.Reader, error) { - return fr.Name, fr.Reader, nil -} - -func (fr FileReader) SendData() string { - panic("FileReader must be uploaded") -} - -// FilePath is a path to a local file. -type FilePath string - -func (fp FilePath) NeedsUpload() bool { - return true -} - -func (fp FilePath) UploadData() (string, io.Reader, error) { - fileHandle, err := os.Open(string(fp)) - if err != nil { - return "", nil, err - } - - name := fileHandle.Name() - return name, fileHandle, err -} - -func (fp FilePath) SendData() string { - panic("FilePath must be uploaded") -} - -// FileURL is a URL to use as a file for a request. -type FileURL string - -func (fu FileURL) NeedsUpload() bool { - return false -} - -func (fu FileURL) UploadData() (string, io.Reader, error) { - panic("FileURL cannot be uploaded") -} - -func (fu FileURL) SendData() string { - return string(fu) -} - -// FileID is an ID of a file already uploaded to Telegram. -type FileID string - -func (fi FileID) NeedsUpload() bool { - return false -} - -func (fi FileID) UploadData() (string, io.Reader, error) { - panic("FileID cannot be uploaded") -} - -func (fi FileID) SendData() string { - return string(fi) -} - -// fileAttach is an internal file type used for processed media groups. -type fileAttach string - -func (fa fileAttach) NeedsUpload() bool { - return false -} - -func (fa fileAttach) UploadData() (string, io.Reader, error) { - panic("fileAttach cannot be uploaded") -} - -func (fa fileAttach) SendData() string { - return string(fa) -} - -// LogOutConfig is a request to log out of the cloud Bot API server. -// -// Note that you may not log back in for at least 10 minutes. -type LogOutConfig struct{} - -func (LogOutConfig) method() string { - return "logOut" -} - -func (LogOutConfig) params() (Params, error) { - return nil, nil -} - -// CloseConfig is a request to close the bot instance on a local server. -// -// Note that you may not close an instance for the first 10 minutes after the -// bot has started. -type CloseConfig struct{} - -func (CloseConfig) method() string { - return "close" -} - -func (CloseConfig) params() (Params, error) { - return nil, nil -} - -// BaseChat is base type for all chat config types. -type BaseChat struct { - ChatID int64 // required - ChannelUsername string - ReplyToMessageID int - ReplyMarkup interface{} - DisableNotification bool - AllowSendingWithoutReply bool -} - -func (chat *BaseChat) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername) - params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID) - params.AddBool("disable_notification", chat.DisableNotification) - params.AddBool("allow_sending_without_reply", chat.AllowSendingWithoutReply) - - err := params.AddInterface("reply_markup", chat.ReplyMarkup) - - return params, err -} - -// BaseFile is a base type for all file config types. -type BaseFile struct { - BaseChat - File RequestFileData -} - -func (file BaseFile) params() (Params, error) { - return file.BaseChat.params() -} - -// BaseEdit is base type of all chat edits. -type BaseEdit struct { - ChatID int64 - ChannelUsername string - MessageID int - InlineMessageID string - ReplyMarkup *InlineKeyboardMarkup -} - -func (edit BaseEdit) params() (Params, error) { - params := make(Params) - - if edit.InlineMessageID != "" { - params["inline_message_id"] = edit.InlineMessageID - } else { - params.AddFirstValid("chat_id", edit.ChatID, edit.ChannelUsername) - params.AddNonZero("message_id", edit.MessageID) - } - - err := params.AddInterface("reply_markup", edit.ReplyMarkup) - - return params, err -} - -// MessageConfig contains information about a SendMessage request. -type MessageConfig struct { - BaseChat - Text string - ParseMode string - Entities []MessageEntity - DisableWebPagePreview bool -} - -func (config MessageConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonEmpty("text", config.Text) - params.AddBool("disable_web_page_preview", config.DisableWebPagePreview) - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("entities", config.Entities) - - return params, err -} - -func (config MessageConfig) method() string { - return "sendMessage" -} - -// ForwardConfig contains information about a ForwardMessage request. -type ForwardConfig struct { - BaseChat - FromChatID int64 // required - FromChannelUsername string - MessageID int // required -} - -func (config ForwardConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonZero64("from_chat_id", config.FromChatID) - params.AddNonZero("message_id", config.MessageID) - - return params, nil -} - -func (config ForwardConfig) method() string { - return "forwardMessage" -} - -// CopyMessageConfig contains information about a copyMessage request. -type CopyMessageConfig struct { - BaseChat - FromChatID int64 - FromChannelUsername string - MessageID int - Caption string - ParseMode string - CaptionEntities []MessageEntity -} - -func (config CopyMessageConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddFirstValid("from_chat_id", config.FromChatID, config.FromChannelUsername) - params.AddNonZero("message_id", config.MessageID) - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config CopyMessageConfig) method() string { - return "copyMessage" -} - -// PhotoConfig contains information about a SendPhoto request. -type PhotoConfig struct { - BaseFile - Thumb RequestFileData - Caption string - ParseMode string - CaptionEntities []MessageEntity -} - -func (config PhotoConfig) params() (Params, error) { - params, err := config.BaseFile.params() - if err != nil { - return params, err - } - - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config PhotoConfig) method() string { - return "sendPhoto" -} - -func (config PhotoConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "photo", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// AudioConfig contains information about a SendAudio request. -type AudioConfig struct { - BaseFile - Thumb RequestFileData - Caption string - ParseMode string - CaptionEntities []MessageEntity - Duration int - Performer string - Title string -} - -func (config AudioConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonZero("duration", config.Duration) - params.AddNonEmpty("performer", config.Performer) - params.AddNonEmpty("title", config.Title) - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config AudioConfig) method() string { - return "sendAudio" -} - -func (config AudioConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "audio", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// DocumentConfig contains information about a SendDocument request. -type DocumentConfig struct { - BaseFile - Thumb RequestFileData - Caption string - ParseMode string - CaptionEntities []MessageEntity - DisableContentTypeDetection bool -} - -func (config DocumentConfig) params() (Params, error) { - params, err := config.BaseFile.params() - - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - params.AddBool("disable_content_type_detection", config.DisableContentTypeDetection) - - return params, err -} - -func (config DocumentConfig) method() string { - return "sendDocument" -} - -func (config DocumentConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "document", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// StickerConfig contains information about a SendSticker request. -type StickerConfig struct { - BaseFile -} - -func (config StickerConfig) params() (Params, error) { - return config.BaseChat.params() -} - -func (config StickerConfig) method() string { - return "sendSticker" -} - -func (config StickerConfig) files() []RequestFile { - return []RequestFile{{ - Name: "sticker", - Data: config.File, - }} -} - -// VideoConfig contains information about a SendVideo request. -type VideoConfig struct { - BaseFile - Thumb RequestFileData - Duration int - Caption string - ParseMode string - CaptionEntities []MessageEntity - SupportsStreaming bool -} - -func (config VideoConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonZero("duration", config.Duration) - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - params.AddBool("supports_streaming", config.SupportsStreaming) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config VideoConfig) method() string { - return "sendVideo" -} - -func (config VideoConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "video", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// AnimationConfig contains information about a SendAnimation request. -type AnimationConfig struct { - BaseFile - Duration int - Thumb RequestFileData - Caption string - ParseMode string - CaptionEntities []MessageEntity -} - -func (config AnimationConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonZero("duration", config.Duration) - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config AnimationConfig) method() string { - return "sendAnimation" -} - -func (config AnimationConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "animation", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// VideoNoteConfig contains information about a SendVideoNote request. -type VideoNoteConfig struct { - BaseFile - Thumb RequestFileData - Duration int - Length int -} - -func (config VideoNoteConfig) params() (Params, error) { - params, err := config.BaseChat.params() - - params.AddNonZero("duration", config.Duration) - params.AddNonZero("length", config.Length) - - return params, err -} - -func (config VideoNoteConfig) method() string { - return "sendVideoNote" -} - -func (config VideoNoteConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "video_note", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// VoiceConfig contains information about a SendVoice request. -type VoiceConfig struct { - BaseFile - Thumb RequestFileData - Caption string - ParseMode string - CaptionEntities []MessageEntity - Duration int -} - -func (config VoiceConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonZero("duration", config.Duration) - params.AddNonEmpty("caption", config.Caption) - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config VoiceConfig) method() string { - return "sendVoice" -} - -func (config VoiceConfig) files() []RequestFile { - files := []RequestFile{{ - Name: "voice", - Data: config.File, - }} - - if config.Thumb != nil { - files = append(files, RequestFile{ - Name: "thumb", - Data: config.Thumb, - }) - } - - return files -} - -// LocationConfig contains information about a SendLocation request. -type LocationConfig struct { - BaseChat - Latitude float64 // required - Longitude float64 // required - HorizontalAccuracy float64 // optional - LivePeriod int // optional - Heading int // optional - ProximityAlertRadius int // optional -} - -func (config LocationConfig) params() (Params, error) { - params, err := config.BaseChat.params() - - params.AddNonZeroFloat("latitude", config.Latitude) - params.AddNonZeroFloat("longitude", config.Longitude) - params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy) - params.AddNonZero("live_period", config.LivePeriod) - params.AddNonZero("heading", config.Heading) - params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius) - - return params, err -} - -func (config LocationConfig) method() string { - return "sendLocation" -} - -// EditMessageLiveLocationConfig allows you to update a live location. -type EditMessageLiveLocationConfig struct { - BaseEdit - Latitude float64 // required - Longitude float64 // required - HorizontalAccuracy float64 // optional - Heading int // optional - ProximityAlertRadius int // optional -} - -func (config EditMessageLiveLocationConfig) params() (Params, error) { - params, err := config.BaseEdit.params() - - params.AddNonZeroFloat("latitude", config.Latitude) - params.AddNonZeroFloat("longitude", config.Longitude) - params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy) - params.AddNonZero("heading", config.Heading) - params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius) - - return params, err -} - -func (config EditMessageLiveLocationConfig) method() string { - return "editMessageLiveLocation" -} - -// StopMessageLiveLocationConfig stops updating a live location. -type StopMessageLiveLocationConfig struct { - BaseEdit -} - -func (config StopMessageLiveLocationConfig) params() (Params, error) { - return config.BaseEdit.params() -} - -func (config StopMessageLiveLocationConfig) method() string { - return "stopMessageLiveLocation" -} - -// VenueConfig contains information about a SendVenue request. -type VenueConfig struct { - BaseChat - Latitude float64 // required - Longitude float64 // required - Title string // required - Address string // required - FoursquareID string - FoursquareType string - GooglePlaceID string - GooglePlaceType string -} - -func (config VenueConfig) params() (Params, error) { - params, err := config.BaseChat.params() - - params.AddNonZeroFloat("latitude", config.Latitude) - params.AddNonZeroFloat("longitude", config.Longitude) - params["title"] = config.Title - params["address"] = config.Address - params.AddNonEmpty("foursquare_id", config.FoursquareID) - params.AddNonEmpty("foursquare_type", config.FoursquareType) - params.AddNonEmpty("google_place_id", config.GooglePlaceID) - params.AddNonEmpty("google_place_type", config.GooglePlaceType) - - return params, err -} - -func (config VenueConfig) method() string { - return "sendVenue" -} - -// ContactConfig allows you to send a contact. -type ContactConfig struct { - BaseChat - PhoneNumber string - FirstName string - LastName string - VCard string -} - -func (config ContactConfig) params() (Params, error) { - params, err := config.BaseChat.params() - - params["phone_number"] = config.PhoneNumber - params["first_name"] = config.FirstName - - params.AddNonEmpty("last_name", config.LastName) - params.AddNonEmpty("vcard", config.VCard) - - return params, err -} - -func (config ContactConfig) method() string { - return "sendContact" -} - -// SendPollConfig allows you to send a poll. -type SendPollConfig struct { - BaseChat - Question string - Options []string - IsAnonymous bool - Type string - AllowsMultipleAnswers bool - CorrectOptionID int64 - Explanation string - ExplanationParseMode string - ExplanationEntities []MessageEntity - OpenPeriod int - CloseDate int - IsClosed bool -} - -func (config SendPollConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params["question"] = config.Question - if err = params.AddInterface("options", config.Options); err != nil { - return params, err - } - params["is_anonymous"] = strconv.FormatBool(config.IsAnonymous) - params.AddNonEmpty("type", config.Type) - params["allows_multiple_answers"] = strconv.FormatBool(config.AllowsMultipleAnswers) - params["correct_option_id"] = strconv.FormatInt(config.CorrectOptionID, 10) - params.AddBool("is_closed", config.IsClosed) - params.AddNonEmpty("explanation", config.Explanation) - params.AddNonEmpty("explanation_parse_mode", config.ExplanationParseMode) - params.AddNonZero("open_period", config.OpenPeriod) - params.AddNonZero("close_date", config.CloseDate) - err = params.AddInterface("explanation_entities", config.ExplanationEntities) - - return params, err -} - -func (SendPollConfig) method() string { - return "sendPoll" -} - -// GameConfig allows you to send a game. -type GameConfig struct { - BaseChat - GameShortName string -} - -func (config GameConfig) params() (Params, error) { - params, err := config.BaseChat.params() - - params["game_short_name"] = config.GameShortName - - return params, err -} - -func (config GameConfig) method() string { - return "sendGame" -} - -// SetGameScoreConfig allows you to update the game score in a chat. -type SetGameScoreConfig struct { - UserID int64 - Score int - Force bool - DisableEditMessage bool - ChatID int64 - ChannelUsername string - MessageID int - InlineMessageID string -} - -func (config SetGameScoreConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero64("user_id", config.UserID) - params.AddNonZero("scrore", config.Score) - params.AddBool("disable_edit_message", config.DisableEditMessage) - - if config.InlineMessageID != "" { - params["inline_message_id"] = config.InlineMessageID - } else { - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) - } - - return params, nil -} - -func (config SetGameScoreConfig) method() string { - return "setGameScore" -} - -// GetGameHighScoresConfig allows you to fetch the high scores for a game. -type GetGameHighScoresConfig struct { - UserID int64 - ChatID int64 - ChannelUsername string - MessageID int - InlineMessageID string -} - -func (config GetGameHighScoresConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero64("user_id", config.UserID) - - if config.InlineMessageID != "" { - params["inline_message_id"] = config.InlineMessageID - } else { - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) - } - - return params, nil -} - -func (config GetGameHighScoresConfig) method() string { - return "getGameHighScores" -} - -// ChatActionConfig contains information about a SendChatAction request. -type ChatActionConfig struct { - BaseChat - Action string // required -} - -func (config ChatActionConfig) params() (Params, error) { - params, err := config.BaseChat.params() - - params["action"] = config.Action - - return params, err -} - -func (config ChatActionConfig) method() string { - return "sendChatAction" -} - -// EditMessageTextConfig allows you to modify the text in a message. -type EditMessageTextConfig struct { - BaseEdit - Text string - ParseMode string - Entities []MessageEntity - DisableWebPagePreview bool -} - -func (config EditMessageTextConfig) params() (Params, error) { - params, err := config.BaseEdit.params() - if err != nil { - return params, err - } - - params["text"] = config.Text - params.AddNonEmpty("parse_mode", config.ParseMode) - params.AddBool("disable_web_page_preview", config.DisableWebPagePreview) - err = params.AddInterface("entities", config.Entities) - - return params, err -} - -func (config EditMessageTextConfig) method() string { - return "editMessageText" -} - -// EditMessageCaptionConfig allows you to modify the caption of a message. -type EditMessageCaptionConfig struct { - BaseEdit - Caption string - ParseMode string - CaptionEntities []MessageEntity -} - -func (config EditMessageCaptionConfig) params() (Params, error) { - params, err := config.BaseEdit.params() - if err != nil { - return params, err - } - - params["caption"] = config.Caption - params.AddNonEmpty("parse_mode", config.ParseMode) - err = params.AddInterface("caption_entities", config.CaptionEntities) - - return params, err -} - -func (config EditMessageCaptionConfig) method() string { - return "editMessageCaption" -} - -// EditMessageMediaConfig allows you to make an editMessageMedia request. -type EditMessageMediaConfig struct { - BaseEdit - - Media interface{} -} - -func (EditMessageMediaConfig) method() string { - return "editMessageMedia" -} - -func (config EditMessageMediaConfig) params() (Params, error) { - params, err := config.BaseEdit.params() - if err != nil { - return params, err - } - - err = params.AddInterface("media", prepareInputMediaParam(config.Media, 0)) - - return params, err -} - -func (config EditMessageMediaConfig) files() []RequestFile { - return prepareInputMediaFile(config.Media, 0) -} - -// EditMessageReplyMarkupConfig allows you to modify the reply markup -// of a message. -type EditMessageReplyMarkupConfig struct { - BaseEdit -} - -func (config EditMessageReplyMarkupConfig) params() (Params, error) { - return config.BaseEdit.params() -} - -func (config EditMessageReplyMarkupConfig) method() string { - return "editMessageReplyMarkup" -} - -// StopPollConfig allows you to stop a poll sent by the bot. -type StopPollConfig struct { - BaseEdit -} - -func (config StopPollConfig) params() (Params, error) { - return config.BaseEdit.params() -} - -func (StopPollConfig) method() string { - return "stopPoll" -} - -// UserProfilePhotosConfig contains information about a -// GetUserProfilePhotos request. -type UserProfilePhotosConfig struct { - UserID int64 - Offset int - Limit int -} - -func (UserProfilePhotosConfig) method() string { - return "getUserProfilePhotos" -} - -func (config UserProfilePhotosConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero64("user_id", config.UserID) - params.AddNonZero("offset", config.Offset) - params.AddNonZero("limit", config.Limit) - - return params, nil -} - -// FileConfig has information about a file hosted on Telegram. -type FileConfig struct { - FileID string -} - -func (FileConfig) method() string { - return "getFile" -} - -func (config FileConfig) params() (Params, error) { - params := make(Params) - - params["file_id"] = config.FileID - - return params, nil -} - -// UpdateConfig contains information about a GetUpdates request. -type UpdateConfig struct { - Offset int - Limit int - Timeout int - AllowedUpdates []string -} - -func (UpdateConfig) method() string { - return "getUpdates" -} - -func (config UpdateConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero("offset", config.Offset) - params.AddNonZero("limit", config.Limit) - params.AddNonZero("timeout", config.Timeout) - params.AddInterface("allowed_updates", config.AllowedUpdates) - - return params, nil -} - -// WebhookConfig contains information about a SetWebhook request. -type WebhookConfig struct { - URL *url.URL - Certificate RequestFileData - IPAddress string - MaxConnections int - AllowedUpdates []string - DropPendingUpdates bool -} - -func (config WebhookConfig) method() string { - return "setWebhook" -} - -func (config WebhookConfig) params() (Params, error) { - params := make(Params) - - if config.URL != nil { - params["url"] = config.URL.String() - } - - params.AddNonEmpty("ip_address", config.IPAddress) - params.AddNonZero("max_connections", config.MaxConnections) - err := params.AddInterface("allowed_updates", config.AllowedUpdates) - params.AddBool("drop_pending_updates", config.DropPendingUpdates) - - return params, err -} - -func (config WebhookConfig) files() []RequestFile { - if config.Certificate != nil { - return []RequestFile{{ - Name: "certificate", - Data: config.Certificate, - }} - } - - return nil -} - -// DeleteWebhookConfig is a helper to delete a webhook. -type DeleteWebhookConfig struct { - DropPendingUpdates bool -} - -func (config DeleteWebhookConfig) method() string { - return "deleteWebhook" -} - -func (config DeleteWebhookConfig) params() (Params, error) { - params := make(Params) - - params.AddBool("drop_pending_updates", config.DropPendingUpdates) - - return params, nil -} - -// InlineConfig contains information on making an InlineQuery response. -type InlineConfig struct { - InlineQueryID string `json:"inline_query_id"` - Results []interface{} `json:"results"` - CacheTime int `json:"cache_time"` - IsPersonal bool `json:"is_personal"` - NextOffset string `json:"next_offset"` - SwitchPMText string `json:"switch_pm_text"` - SwitchPMParameter string `json:"switch_pm_parameter"` -} - -func (config InlineConfig) method() string { - return "answerInlineQuery" -} - -func (config InlineConfig) params() (Params, error) { - params := make(Params) - - params["inline_query_id"] = config.InlineQueryID - params.AddNonZero("cache_time", config.CacheTime) - params.AddBool("is_personal", config.IsPersonal) - params.AddNonEmpty("next_offset", config.NextOffset) - params.AddNonEmpty("switch_pm_text", config.SwitchPMText) - params.AddNonEmpty("switch_pm_parameter", config.SwitchPMParameter) - err := params.AddInterface("results", config.Results) - - return params, err -} - -// CallbackConfig contains information on making a CallbackQuery response. -type CallbackConfig struct { - CallbackQueryID string `json:"callback_query_id"` - Text string `json:"text"` - ShowAlert bool `json:"show_alert"` - URL string `json:"url"` - CacheTime int `json:"cache_time"` -} - -func (config CallbackConfig) method() string { - return "answerCallbackQuery" -} - -func (config CallbackConfig) params() (Params, error) { - params := make(Params) - - params["callback_query_id"] = config.CallbackQueryID - params.AddNonEmpty("text", config.Text) - params.AddBool("show_alert", config.ShowAlert) - params.AddNonEmpty("url", config.URL) - params.AddNonZero("cache_time", config.CacheTime) - - return params, nil -} - -// ChatMemberConfig contains information about a user in a chat for use -// with administrative functions such as kicking or unbanning a user. -type ChatMemberConfig struct { - ChatID int64 - SuperGroupUsername string - ChannelUsername string - UserID int64 -} - -// UnbanChatMemberConfig allows you to unban a user. -type UnbanChatMemberConfig struct { - ChatMemberConfig - OnlyIfBanned bool -} - -func (config UnbanChatMemberConfig) method() string { - return "unbanChatMember" -} - -func (config UnbanChatMemberConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) - params.AddBool("only_if_banned", config.OnlyIfBanned) - - return params, nil -} - -// BanChatMemberConfig contains extra fields to kick user. -type BanChatMemberConfig struct { - ChatMemberConfig - UntilDate int64 - RevokeMessages bool -} - -func (config BanChatMemberConfig) method() string { - return "banChatMember" -} - -func (config BanChatMemberConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero64("user_id", config.UserID) - params.AddNonZero64("until_date", config.UntilDate) - params.AddBool("revoke_messages", config.RevokeMessages) - - return params, nil -} - -// KickChatMemberConfig contains extra fields to ban user. -// -// This was renamed to BanChatMember in later versions of the Telegram Bot API. -type KickChatMemberConfig = BanChatMemberConfig - -// RestrictChatMemberConfig contains fields to restrict members of chat -type RestrictChatMemberConfig struct { - ChatMemberConfig - UntilDate int64 - Permissions *ChatPermissions -} - -func (config RestrictChatMemberConfig) method() string { - return "restrictChatMember" -} - -func (config RestrictChatMemberConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) - - err := params.AddInterface("permissions", config.Permissions) - params.AddNonZero64("until_date", config.UntilDate) - - return params, err -} - -// PromoteChatMemberConfig contains fields to promote members of chat -type PromoteChatMemberConfig struct { - ChatMemberConfig - IsAnonymous bool - CanManageChat bool - CanChangeInfo bool - CanPostMessages bool - CanEditMessages bool - CanDeleteMessages bool - CanManageVoiceChats bool - CanInviteUsers bool - CanRestrictMembers bool - CanPinMessages bool - CanPromoteMembers bool -} - -func (config PromoteChatMemberConfig) method() string { - return "promoteChatMember" -} - -func (config PromoteChatMemberConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) - - params.AddBool("is_anonymous", config.IsAnonymous) - params.AddBool("can_manage_chat", config.CanManageChat) - params.AddBool("can_change_info", config.CanChangeInfo) - params.AddBool("can_post_messages", config.CanPostMessages) - params.AddBool("can_edit_messages", config.CanEditMessages) - params.AddBool("can_delete_messages", config.CanDeleteMessages) - params.AddBool("can_manage_voice_chats", config.CanManageVoiceChats) - params.AddBool("can_invite_users", config.CanInviteUsers) - params.AddBool("can_restrict_members", config.CanRestrictMembers) - params.AddBool("can_pin_messages", config.CanPinMessages) - params.AddBool("can_promote_members", config.CanPromoteMembers) - - return params, nil -} - -// SetChatAdministratorCustomTitle sets the title of an administrative user -// promoted by the bot for a chat. -type SetChatAdministratorCustomTitle struct { - ChatMemberConfig - CustomTitle string -} - -func (SetChatAdministratorCustomTitle) method() string { - return "setChatAdministratorCustomTitle" -} - -func (config SetChatAdministratorCustomTitle) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) - params.AddNonEmpty("custom_title", config.CustomTitle) - - return params, nil -} - -// BanChatSenderChatConfig bans a channel chat in a supergroup or a channel. The -// owner of the chat will not be able to send messages and join live streams on -// behalf of the chat, unless it is unbanned first. The bot must be an -// administrator in the supergroup or channel for this to work and must have the -// appropriate administrator rights. -type BanChatSenderChatConfig struct { - ChatID int64 - ChannelUsername string - SenderChatID int64 - UntilDate int -} - -func (config BanChatSenderChatConfig) method() string { - return "banChatSenderChat" -} - -func (config BanChatSenderChatConfig) params() (Params, error) { - params := make(Params) - - _ = params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero64("sender_chat_id", config.SenderChatID) - params.AddNonZero("until_date", config.UntilDate) - - return params, nil -} - -// UnbanChatSenderChatConfig unbans a previously banned channel chat in a -// supergroup or channel. The bot must be an administrator for this to work and -// must have the appropriate administrator rights. -type UnbanChatSenderChatConfig struct { - ChatID int64 - ChannelUsername string - SenderChatID int64 -} - -func (config UnbanChatSenderChatConfig) method() string { - return "unbanChatSenderChat" -} - -func (config UnbanChatSenderChatConfig) params() (Params, error) { - params := make(Params) - - _ = params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero64("sender_chat_id", config.SenderChatID) - - return params, nil -} - -// ChatConfig contains information about getting information on a chat. -type ChatConfig struct { - ChatID int64 - SuperGroupUsername string -} - -func (config ChatConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil -} - -// ChatInfoConfig contains information about getting chat information. -type ChatInfoConfig struct { - ChatConfig -} - -func (ChatInfoConfig) method() string { - return "getChat" -} - -// ChatMemberCountConfig contains information about getting the number of users in a chat. -type ChatMemberCountConfig struct { - ChatConfig -} - -func (ChatMemberCountConfig) method() string { - return "getChatMembersCount" -} - -// ChatAdministratorsConfig contains information about getting chat administrators. -type ChatAdministratorsConfig struct { - ChatConfig -} - -func (ChatAdministratorsConfig) method() string { - return "getChatAdministrators" -} - -// SetChatPermissionsConfig allows you to set default permissions for the -// members in a group. The bot must be an administrator and have rights to -// restrict members. -type SetChatPermissionsConfig struct { - ChatConfig - Permissions *ChatPermissions -} - -func (SetChatPermissionsConfig) method() string { - return "setChatPermissions" -} - -func (config SetChatPermissionsConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - err := params.AddInterface("permissions", config.Permissions) - - return params, err -} - -// ChatInviteLinkConfig contains information about getting a chat link. -// -// Note that generating a new link will revoke any previous links. -type ChatInviteLinkConfig struct { - ChatConfig -} - -func (ChatInviteLinkConfig) method() string { - return "exportChatInviteLink" -} - -func (config ChatInviteLinkConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil -} - -// CreateChatInviteLinkConfig allows you to create an additional invite link for -// a chat. The bot must be an administrator in the chat for this to work and -// must have the appropriate admin rights. The link can be revoked using the -// RevokeChatInviteLinkConfig. -type CreateChatInviteLinkConfig struct { - ChatConfig - Name string - ExpireDate int - MemberLimit int - CreatesJoinRequest bool -} - -func (CreateChatInviteLinkConfig) method() string { - return "createChatInviteLink" -} - -func (config CreateChatInviteLinkConfig) params() (Params, error) { - params := make(Params) - - params.AddNonEmpty("name", config.Name) - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("expire_date", config.ExpireDate) - params.AddNonZero("member_limit", config.MemberLimit) - params.AddBool("creates_join_request", config.CreatesJoinRequest) - - return params, nil -} - -// EditChatInviteLinkConfig allows you to edit a non-primary invite link created -// by the bot. The bot must be an administrator in the chat for this to work and -// must have the appropriate admin rights. -type EditChatInviteLinkConfig struct { - ChatConfig - InviteLink string - Name string - ExpireDate int - MemberLimit int - CreatesJoinRequest bool -} - -func (EditChatInviteLinkConfig) method() string { - return "editChatInviteLink" -} - -func (config EditChatInviteLinkConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonEmpty("name", config.Name) - params["invite_link"] = config.InviteLink - params.AddNonZero("expire_date", config.ExpireDate) - params.AddNonZero("member_limit", config.MemberLimit) - params.AddBool("creates_join_request", config.CreatesJoinRequest) - - return params, nil -} - -// RevokeChatInviteLinkConfig allows you to revoke an invite link created by the -// bot. If the primary link is revoked, a new link is automatically generated. -// The bot must be an administrator in the chat for this to work and must have -// the appropriate admin rights. -type RevokeChatInviteLinkConfig struct { - ChatConfig - InviteLink string -} - -func (RevokeChatInviteLinkConfig) method() string { - return "revokeChatInviteLink" -} - -func (config RevokeChatInviteLinkConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params["invite_link"] = config.InviteLink - - return params, nil -} - -// ApproveChatJoinRequestConfig allows you to approve a chat join request. -type ApproveChatJoinRequestConfig struct { - ChatConfig - UserID int64 -} - -func (ApproveChatJoinRequestConfig) method() string { - return "approveChatJoinRequest" -} - -func (config ApproveChatJoinRequestConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("user_id", int(config.UserID)) - - return params, nil -} - -// DeclineChatJoinRequest allows you to decline a chat join request. -type DeclineChatJoinRequest struct { - ChatConfig - UserID int64 -} - -func (DeclineChatJoinRequest) method() string { - return "declineChatJoinRequest" -} - -func (config DeclineChatJoinRequest) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("user_id", int(config.UserID)) - - return params, nil -} - -// LeaveChatConfig allows you to leave a chat. -type LeaveChatConfig struct { - ChatID int64 - ChannelUsername string -} - -func (config LeaveChatConfig) method() string { - return "leaveChat" -} - -func (config LeaveChatConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, nil -} - -// ChatConfigWithUser contains information about a chat and a user. -type ChatConfigWithUser struct { - ChatID int64 - SuperGroupUsername string - UserID int64 -} - -func (config ChatConfigWithUser) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero64("user_id", config.UserID) - - return params, nil -} - -// GetChatMemberConfig is information about getting a specific member in a chat. -type GetChatMemberConfig struct { - ChatConfigWithUser -} - -func (GetChatMemberConfig) method() string { - return "getChatMember" -} - -// InvoiceConfig contains information for sendInvoice request. -type InvoiceConfig struct { - BaseChat - Title string // required - Description string // required - Payload string // required - ProviderToken string // required - Currency string // required - Prices []LabeledPrice // required - MaxTipAmount int - SuggestedTipAmounts []int - StartParameter string - ProviderData string - PhotoURL string - PhotoSize int - PhotoWidth int - PhotoHeight int - NeedName bool - NeedPhoneNumber bool - NeedEmail bool - NeedShippingAddress bool - SendPhoneNumberToProvider bool - SendEmailToProvider bool - IsFlexible bool -} - -func (config InvoiceConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params["title"] = config.Title - params["description"] = config.Description - params["payload"] = config.Payload - params["provider_token"] = config.ProviderToken - params["currency"] = config.Currency - if err = params.AddInterface("prices", config.Prices); err != nil { - return params, err - } - - params.AddNonZero("max_tip_amount", config.MaxTipAmount) - err = params.AddInterface("suggested_tip_amounts", config.SuggestedTipAmounts) - params.AddNonEmpty("start_parameter", config.StartParameter) - params.AddNonEmpty("provider_data", config.ProviderData) - params.AddNonEmpty("photo_url", config.PhotoURL) - params.AddNonZero("photo_size", config.PhotoSize) - params.AddNonZero("photo_width", config.PhotoWidth) - params.AddNonZero("photo_height", config.PhotoHeight) - params.AddBool("need_name", config.NeedName) - params.AddBool("need_phone_number", config.NeedPhoneNumber) - params.AddBool("need_email", config.NeedEmail) - params.AddBool("need_shipping_address", config.NeedShippingAddress) - params.AddBool("is_flexible", config.IsFlexible) - params.AddBool("send_phone_number_to_provider", config.SendPhoneNumberToProvider) - params.AddBool("send_email_to_provider", config.SendEmailToProvider) - - return params, err -} - -func (config InvoiceConfig) method() string { - return "sendInvoice" -} - -// ShippingConfig contains information for answerShippingQuery request. -type ShippingConfig struct { - ShippingQueryID string // required - OK bool // required - ShippingOptions []ShippingOption - ErrorMessage string -} - -func (config ShippingConfig) method() string { - return "answerShippingQuery" -} - -func (config ShippingConfig) params() (Params, error) { - params := make(Params) - - params["shipping_query_id"] = config.ShippingQueryID - params.AddBool("ok", config.OK) - err := params.AddInterface("shipping_options", config.ShippingOptions) - params.AddNonEmpty("error_message", config.ErrorMessage) - - return params, err -} - -// PreCheckoutConfig conatins information for answerPreCheckoutQuery request. -type PreCheckoutConfig struct { - PreCheckoutQueryID string // required - OK bool // required - ErrorMessage string -} - -func (config PreCheckoutConfig) method() string { - return "answerPreCheckoutQuery" -} - -func (config PreCheckoutConfig) params() (Params, error) { - params := make(Params) - - params["pre_checkout_query_id"] = config.PreCheckoutQueryID - params.AddBool("ok", config.OK) - params.AddNonEmpty("error_message", config.ErrorMessage) - - return params, nil -} - -// DeleteMessageConfig contains information of a message in a chat to delete. -type DeleteMessageConfig struct { - ChannelUsername string - ChatID int64 - MessageID int -} - -func (config DeleteMessageConfig) method() string { - return "deleteMessage" -} - -func (config DeleteMessageConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) - - return params, nil -} - -// PinChatMessageConfig contains information of a message in a chat to pin. -type PinChatMessageConfig struct { - ChatID int64 - ChannelUsername string - MessageID int - DisableNotification bool -} - -func (config PinChatMessageConfig) method() string { - return "pinChatMessage" -} - -func (config PinChatMessageConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) - params.AddBool("disable_notification", config.DisableNotification) - - return params, nil -} - -// UnpinChatMessageConfig contains information of a chat message to unpin. -// -// If MessageID is not specified, it will unpin the most recent pin. -type UnpinChatMessageConfig struct { - ChatID int64 - ChannelUsername string - MessageID int -} - -func (config UnpinChatMessageConfig) method() string { - return "unpinChatMessage" -} - -func (config UnpinChatMessageConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) - - return params, nil -} - -// UnpinAllChatMessagesConfig contains information of all messages to unpin in -// a chat. -type UnpinAllChatMessagesConfig struct { - ChatID int64 - ChannelUsername string -} - -func (config UnpinAllChatMessagesConfig) method() string { - return "unpinAllChatMessages" -} - -func (config UnpinAllChatMessagesConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, nil -} - -// SetChatPhotoConfig allows you to set a group, supergroup, or channel's photo. -type SetChatPhotoConfig struct { - BaseFile -} - -func (config SetChatPhotoConfig) method() string { - return "setChatPhoto" -} - -func (config SetChatPhotoConfig) files() []RequestFile { - return []RequestFile{{ - Name: "photo", - Data: config.File, - }} -} - -// DeleteChatPhotoConfig allows you to delete a group, supergroup, or channel's photo. -type DeleteChatPhotoConfig struct { - ChatID int64 - ChannelUsername string -} - -func (config DeleteChatPhotoConfig) method() string { - return "deleteChatPhoto" -} - -func (config DeleteChatPhotoConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, nil -} - -// SetChatTitleConfig allows you to set the title of something other than a private chat. -type SetChatTitleConfig struct { - ChatID int64 - ChannelUsername string - - Title string -} - -func (config SetChatTitleConfig) method() string { - return "setChatTitle" -} - -func (config SetChatTitleConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params["title"] = config.Title - - return params, nil -} - -// SetChatDescriptionConfig allows you to set the description of a supergroup or channel. -type SetChatDescriptionConfig struct { - ChatID int64 - ChannelUsername string - - Description string -} - -func (config SetChatDescriptionConfig) method() string { - return "setChatDescription" -} - -func (config SetChatDescriptionConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params["description"] = config.Description - - return params, nil -} - -// GetStickerSetConfig allows you to get the stickers in a set. -type GetStickerSetConfig struct { - Name string -} - -func (config GetStickerSetConfig) method() string { - return "getStickerSet" -} - -func (config GetStickerSetConfig) params() (Params, error) { - params := make(Params) - - params["name"] = config.Name - - return params, nil -} - -// UploadStickerConfig allows you to upload a sticker for use in a set later. -type UploadStickerConfig struct { - UserID int64 - PNGSticker RequestFileData -} - -func (config UploadStickerConfig) method() string { - return "uploadStickerFile" -} - -func (config UploadStickerConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero64("user_id", config.UserID) - - return params, nil -} - -func (config UploadStickerConfig) files() []RequestFile { - return []RequestFile{{ - Name: "png_sticker", - Data: config.PNGSticker, - }} -} - -// NewStickerSetConfig allows creating a new sticker set. -// -// You must set either PNGSticker or TGSSticker. -type NewStickerSetConfig struct { - UserID int64 - Name string - Title string - PNGSticker RequestFileData - TGSSticker RequestFileData - Emojis string - ContainsMasks bool - MaskPosition *MaskPosition -} - -func (config NewStickerSetConfig) method() string { - return "createNewStickerSet" -} - -func (config NewStickerSetConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero64("user_id", config.UserID) - params["name"] = config.Name - params["title"] = config.Title - - params["emojis"] = config.Emojis - - params.AddBool("contains_masks", config.ContainsMasks) - - err := params.AddInterface("mask_position", config.MaskPosition) - - return params, err -} - -func (config NewStickerSetConfig) files() []RequestFile { - if config.PNGSticker != nil { - return []RequestFile{{ - Name: "png_sticker", - Data: config.PNGSticker, - }} - } - - return []RequestFile{{ - Name: "tgs_sticker", - Data: config.TGSSticker, - }} -} - -// AddStickerConfig allows you to add a sticker to a set. -type AddStickerConfig struct { - UserID int64 - Name string - PNGSticker RequestFileData - TGSSticker RequestFileData - Emojis string - MaskPosition *MaskPosition -} - -func (config AddStickerConfig) method() string { - return "addStickerToSet" -} - -func (config AddStickerConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero64("user_id", config.UserID) - params["name"] = config.Name - params["emojis"] = config.Emojis - - err := params.AddInterface("mask_position", config.MaskPosition) - - return params, err -} - -func (config AddStickerConfig) files() []RequestFile { - if config.PNGSticker != nil { - return []RequestFile{{ - Name: "png_sticker", - Data: config.PNGSticker, - }} - } - - return []RequestFile{{ - Name: "tgs_sticker", - Data: config.TGSSticker, - }} - -} - -// SetStickerPositionConfig allows you to change the position of a sticker in a set. -type SetStickerPositionConfig struct { - Sticker string - Position int -} - -func (config SetStickerPositionConfig) method() string { - return "setStickerPositionInSet" -} - -func (config SetStickerPositionConfig) params() (Params, error) { - params := make(Params) - - params["sticker"] = config.Sticker - params.AddNonZero("position", config.Position) - - return params, nil -} - -// DeleteStickerConfig allows you to delete a sticker from a set. -type DeleteStickerConfig struct { - Sticker string -} - -func (config DeleteStickerConfig) method() string { - return "deleteStickerFromSet" -} - -func (config DeleteStickerConfig) params() (Params, error) { - params := make(Params) - - params["sticker"] = config.Sticker - - return params, nil -} - -// SetStickerSetThumbConfig allows you to set the thumbnail for a sticker set. -type SetStickerSetThumbConfig struct { - Name string - UserID int64 - Thumb RequestFileData -} - -func (config SetStickerSetThumbConfig) method() string { - return "setStickerSetThumb" -} - -func (config SetStickerSetThumbConfig) params() (Params, error) { - params := make(Params) - - params["name"] = config.Name - params.AddNonZero64("user_id", config.UserID) - - return params, nil -} - -func (config SetStickerSetThumbConfig) files() []RequestFile { - return []RequestFile{{ - Name: "thumb", - Data: config.Thumb, - }} -} - -// SetChatStickerSetConfig allows you to set the sticker set for a supergroup. -type SetChatStickerSetConfig struct { - ChatID int64 - SuperGroupUsername string - - StickerSetName string -} - -func (config SetChatStickerSetConfig) method() string { - return "setChatStickerSet" -} - -func (config SetChatStickerSetConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params["sticker_set_name"] = config.StickerSetName - - return params, nil -} - -// DeleteChatStickerSetConfig allows you to remove a supergroup's sticker set. -type DeleteChatStickerSetConfig struct { - ChatID int64 - SuperGroupUsername string -} - -func (config DeleteChatStickerSetConfig) method() string { - return "deleteChatStickerSet" -} - -func (config DeleteChatStickerSetConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil -} - -// MediaGroupConfig allows you to send a group of media. -// -// Media consist of InputMedia items (InputMediaPhoto, InputMediaVideo). -type MediaGroupConfig struct { - ChatID int64 - ChannelUsername string - - Media []interface{} - DisableNotification bool - ReplyToMessageID int -} - -func (config MediaGroupConfig) method() string { - return "sendMediaGroup" -} - -func (config MediaGroupConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddBool("disable_notification", config.DisableNotification) - params.AddNonZero("reply_to_message_id", config.ReplyToMessageID) - - err := params.AddInterface("media", prepareInputMediaForParams(config.Media)) - - return params, err -} - -func (config MediaGroupConfig) files() []RequestFile { - return prepareInputMediaForFiles(config.Media) -} - -// 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 🎳, values 1-5 for 🏀 and ⚽, - // and values 1-64 for 🎰. - // Defaults to “🎲” - Emoji string -} - -func (config DiceConfig) method() string { - return "sendDice" -} - -func (config DiceConfig) params() (Params, error) { - params, err := config.BaseChat.params() - if err != nil { - return params, err - } - - params.AddNonEmpty("emoji", config.Emoji) - - return params, err -} - -// GetMyCommandsConfig gets a list of the currently registered commands. -type GetMyCommandsConfig struct { - Scope *BotCommandScope - LanguageCode string -} - -func (config GetMyCommandsConfig) method() string { - return "getMyCommands" -} - -func (config GetMyCommandsConfig) params() (Params, error) { - params := make(Params) - - err := params.AddInterface("scope", config.Scope) - params.AddNonEmpty("language_code", config.LanguageCode) - - return params, err -} - -// SetMyCommandsConfig sets a list of commands the bot understands. -type SetMyCommandsConfig struct { - Commands []BotCommand - Scope *BotCommandScope - LanguageCode string -} - -func (config SetMyCommandsConfig) method() string { - return "setMyCommands" -} - -func (config SetMyCommandsConfig) params() (Params, error) { - params := make(Params) - - if err := params.AddInterface("commands", config.Commands); err != nil { - return params, err - } - err := params.AddInterface("scope", config.Scope) - params.AddNonEmpty("language_code", config.LanguageCode) - - return params, err -} - -type DeleteMyCommandsConfig struct { - Scope *BotCommandScope - LanguageCode string -} - -func (config DeleteMyCommandsConfig) method() string { - return "deleteMyCommands" -} - -func (config DeleteMyCommandsConfig) params() (Params, error) { - params := make(Params) - - err := params.AddInterface("scope", config.Scope) - params.AddNonEmpty("language_code", config.LanguageCode) - - return params, err -} - -// prepareInputMediaParam evaluates a single InputMedia and determines if it -// needs to be modified for a successful upload. If it returns nil, then the -// value does not need to be included in the params. Otherwise, it will return -// the same type as was originally provided. -// -// The idx is used to calculate the file field name. If you only have a single -// file, 0 may be used. It is formatted into "attach://file-%d" for the primary -// media and "attach://file-%d-thumb" for thumbnails. -// -// It is expected to be used in conjunction with prepareInputMediaFile. -func prepareInputMediaParam(inputMedia interface{}, idx int) interface{} { - switch m := inputMedia.(type) { - case InputMediaPhoto: - if m.Media.NeedsUpload() { - m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) - } - - return m - case InputMediaVideo: - if m.Media.NeedsUpload() { - m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) - } - - if m.Thumb != nil && m.Thumb.NeedsUpload() { - m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx)) - } - - return m - case InputMediaAudio: - if m.Media.NeedsUpload() { - m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) - } - - if m.Thumb != nil && m.Thumb.NeedsUpload() { - m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx)) - } - - return m - case InputMediaDocument: - if m.Media.NeedsUpload() { - m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) - } - - if m.Thumb != nil && m.Thumb.NeedsUpload() { - m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx)) - } - - return m - } - - return nil -} - -// prepareInputMediaFile generates an array of RequestFile to provide for -// Fileable's files method. It returns an array as a single InputMedia may have -// multiple files, for the primary media and a thumbnail. -// -// The idx parameter is used to generate file field names. It uses the names -// "file-%d" for the main file and "file-%d-thumb" for the thumbnail. -// -// It is expected to be used in conjunction with prepareInputMediaParam. -func prepareInputMediaFile(inputMedia interface{}, idx int) []RequestFile { - files := []RequestFile{} - - switch m := inputMedia.(type) { - case InputMediaPhoto: - if m.Media.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Media, - }) - } - case InputMediaVideo: - if m.Media.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Media, - }) - } - - if m.Thumb != nil && m.Thumb.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Thumb, - }) - } - case InputMediaDocument: - if m.Media.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Media, - }) - } - - if m.Thumb != nil && m.Thumb.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Thumb, - }) - } - case InputMediaAudio: - if m.Media.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Media, - }) - } - - if m.Thumb != nil && m.Thumb.NeedsUpload() { - files = append(files, RequestFile{ - Name: fmt.Sprintf("file-%d", idx), - Data: m.Thumb, - }) - } - } - - return files -} - -// prepareInputMediaForParams calls prepareInputMediaParam for each item -// provided and returns a new array with the correct params for a request. -// -// It is expected that files will get data from the associated function, -// prepareInputMediaForFiles. -func prepareInputMediaForParams(inputMedia []interface{}) []interface{} { - newMedia := make([]interface{}, len(inputMedia)) - copy(newMedia, inputMedia) - - for idx, media := range inputMedia { - if param := prepareInputMediaParam(media, idx); param != nil { - newMedia[idx] = param - } - } - - return newMedia -} - -// prepareInputMediaForFiles calls prepareInputMediaFile for each item -// provided and returns a new array with the correct files for a request. -// -// It is expected that params will get data from the associated function, -// prepareInputMediaForParams. -func prepareInputMediaForFiles(inputMedia []interface{}) []RequestFile { - files := []RequestFile{} - - for idx, media := range inputMedia { - if file := prepareInputMediaFile(media, idx); file != nil { - files = append(files, file...) - } - } - - return files -} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/helpers.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/helpers.go deleted file mode 100644 index 8220e74e..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/helpers.go +++ /dev/null @@ -1,927 +0,0 @@ -package tgbotapi - -import ( - "net/url" -) - -// NewMessage creates a new Message. -// -// chatID is where to send it, text is the message text. -func NewMessage(chatID int64, text string) MessageConfig { - return MessageConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - ReplyToMessageID: 0, - }, - Text: text, - DisableWebPagePreview: false, - } -} - -// NewDeleteMessage creates a request to delete a message. -func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { - return DeleteMessageConfig{ - ChatID: chatID, - MessageID: messageID, - } -} - -// 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, -// and the username should be in the form of `@username`. -func NewMessageToChannel(username string, text string) MessageConfig { - return MessageConfig{ - BaseChat: BaseChat{ - ChannelUsername: username, - }, - Text: text, - } -} - -// NewForward creates a new forward. -// -// chatID is where to send it, fromChatID is the source chat, -// and messageID is the ID of the original message. -func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { - return ForwardConfig{ - BaseChat: BaseChat{ChatID: chatID}, - FromChatID: fromChatID, - MessageID: messageID, - } -} - -// NewCopyMessage creates a new copy message. -// -// chatID is where to send it, fromChatID is the source chat, -// and messageID is the ID of the original message. -func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig { - return CopyMessageConfig{ - BaseChat: BaseChat{ChatID: chatID}, - FromChatID: fromChatID, - MessageID: messageID, - } -} - -// NewPhoto creates a new sendPhoto request. -// -// chatID is where to send it, file is a string path to the file, -// FileReader, or FileBytes. -// -// Note that you must send animated GIFs as a document. -func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { - return PhotoConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewPhotoToChannel creates a new photo uploader to send a photo to a channel. -// -// Note that you must send animated GIFs as a document. -func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { - return PhotoConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ - ChannelUsername: username, - }, - File: file, - }, - } -} - -// NewAudio creates a new sendAudio request. -func NewAudio(chatID int64, file RequestFileData) AudioConfig { - return AudioConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewDocument creates a new sendDocument request. -func NewDocument(chatID int64, file RequestFileData) DocumentConfig { - return DocumentConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewSticker creates a new sendSticker request. -func NewSticker(chatID int64, file RequestFileData) StickerConfig { - return StickerConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewVideo creates a new sendVideo request. -func NewVideo(chatID int64, file RequestFileData) VideoConfig { - return VideoConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewAnimation creates a new sendAnimation request. -func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { - return AnimationConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewVideoNote creates a new sendVideoNote request. -// -// chatID is where to send it, file is a string path to the file, -// FileReader, or FileBytes. -func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig { - return VideoNoteConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - Length: length, - } -} - -// NewVoice creates a new sendVoice request. -func NewVoice(chatID int64, file RequestFileData) VoiceConfig { - return VoiceConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, - File: file, - }, - } -} - -// NewMediaGroup creates a new media group. Files should be an array of -// two to ten InputMediaPhoto or InputMediaVideo. -func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig { - return MediaGroupConfig{ - ChatID: chatID, - Media: files, - } -} - -// NewInputMediaPhoto creates a new InputMediaPhoto. -func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto { - return InputMediaPhoto{ - BaseInputMedia{ - Type: "photo", - Media: media, - }, - } -} - -// NewInputMediaVideo creates a new InputMediaVideo. -func NewInputMediaVideo(media RequestFileData) InputMediaVideo { - return InputMediaVideo{ - BaseInputMedia: BaseInputMedia{ - Type: "video", - Media: media, - }, - } -} - -// NewInputMediaAnimation creates a new InputMediaAnimation. -func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation { - return InputMediaAnimation{ - BaseInputMedia: BaseInputMedia{ - Type: "animation", - Media: media, - }, - } -} - -// NewInputMediaAudio creates a new InputMediaAudio. -func NewInputMediaAudio(media RequestFileData) InputMediaAudio { - return InputMediaAudio{ - BaseInputMedia: BaseInputMedia{ - Type: "audio", - Media: media, - }, - } -} - -// NewInputMediaDocument creates a new InputMediaDocument. -func NewInputMediaDocument(media RequestFileData) InputMediaDocument { - return InputMediaDocument{ - BaseInputMedia: BaseInputMedia{ - Type: "document", - Media: media, - }, - } -} - -// NewContact allows you to send a shared contact. -func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig { - return ContactConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - PhoneNumber: phoneNumber, - FirstName: firstName, - } -} - -// NewLocation shares your location. -// -// chatID is where to send it, latitude and longitude are coordinates. -func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig { - return LocationConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - Latitude: latitude, - Longitude: longitude, - } -} - -// NewVenue allows you to send a venue and its location. -func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig { - return VenueConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - Title: title, - Address: address, - Latitude: latitude, - Longitude: longitude, - } -} - -// NewChatAction sets a chat action. -// Actions last for 5 seconds, or until your next action. -// -// chatID is where to send it, action should be set via Chat constants. -func NewChatAction(chatID int64, action string) ChatActionConfig { - return ChatActionConfig{ - BaseChat: BaseChat{ChatID: chatID}, - Action: action, - } -} - -// NewUserProfilePhotos gets user profile photos. -// -// userID is the ID of the user you wish to get profile photos from. -func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig { - return UserProfilePhotosConfig{ - UserID: userID, - Offset: 0, - Limit: 0, - } -} - -// NewUpdate gets updates since the last Offset. -// -// offset is the last Update ID to include. -// You likely want to set this to the last Update ID plus 1. -func NewUpdate(offset int) UpdateConfig { - return UpdateConfig{ - Offset: offset, - Limit: 0, - Timeout: 0, - } -} - -// NewWebhook creates a new webhook. -// -// link is the url parsable link you wish to get the updates. -func NewWebhook(link string) (WebhookConfig, error) { - u, err := url.Parse(link) - - if err != nil { - return WebhookConfig{}, err - } - - return WebhookConfig{ - URL: u, - }, nil -} - -// NewWebhookWithCert creates a new webhook with a certificate. -// -// link is the url you wish to get webhooks, -// file contains a string to a file, FileReader, or FileBytes. -func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) { - u, err := url.Parse(link) - - if err != nil { - return WebhookConfig{}, err - } - - return WebhookConfig{ - URL: u, - Certificate: file, - }, nil -} - -// NewInlineQueryResultArticle creates a new inline query article. -func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle { - return InlineQueryResultArticle{ - Type: "article", - ID: id, - Title: title, - InputMessageContent: InputTextMessageContent{ - Text: messageText, - }, - } -} - -// NewInlineQueryResultArticleMarkdown creates a new inline query article with Markdown parsing. -func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQueryResultArticle { - return InlineQueryResultArticle{ - Type: "article", - ID: id, - Title: title, - InputMessageContent: InputTextMessageContent{ - Text: messageText, - ParseMode: "Markdown", - }, - } -} - -// 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{ - Type: "article", - ID: id, - Title: title, - InputMessageContent: InputTextMessageContent{ - Text: messageText, - ParseMode: "HTML", - }, - } -} - -// NewInlineQueryResultGIF creates a new inline query GIF. -func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF { - return InlineQueryResultGIF{ - Type: "gif", - ID: id, - URL: url, - } -} - -// NewInlineQueryResultCachedGIF create a new inline query with cached photo. -func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF { - return InlineQueryResultCachedGIF{ - Type: "gif", - ID: id, - GIFID: gifID, - } -} - -// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF. -func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF { - return InlineQueryResultMPEG4GIF{ - Type: "mpeg4_gif", - ID: id, - URL: url, - } -} - -// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF. -func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF { - return InlineQueryResultCachedMPEG4GIF{ - Type: "mpeg4_gif", - ID: id, - MPEG4FileID: MPEG4GIFID, - } -} - -// NewInlineQueryResultPhoto creates a new inline query photo. -func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto { - return InlineQueryResultPhoto{ - Type: "photo", - ID: id, - URL: url, - } -} - -// NewInlineQueryResultPhotoWithThumb creates a new inline query photo. -func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResultPhoto { - return InlineQueryResultPhoto{ - Type: "photo", - ID: id, - URL: url, - ThumbURL: thumb, - } -} - -// NewInlineQueryResultCachedPhoto create a new inline query with cached photo. -func NewInlineQueryResultCachedPhoto(id, photoID string) InlineQueryResultCachedPhoto { - return InlineQueryResultCachedPhoto{ - Type: "photo", - ID: id, - PhotoID: photoID, - } -} - -// NewInlineQueryResultVideo creates a new inline query video. -func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo { - return InlineQueryResultVideo{ - Type: "video", - ID: id, - URL: url, - } -} - -// NewInlineQueryResultCachedVideo create a new inline query with cached video. -func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResultCachedVideo { - return InlineQueryResultCachedVideo{ - Type: "video", - ID: id, - VideoID: videoID, - Title: title, - } -} - -// 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{ - Type: "audio", - ID: id, - URL: url, - Title: title, - } -} - -// NewInlineQueryResultCachedAudio create a new inline query with cached photo. -func NewInlineQueryResultCachedAudio(id, audioID string) InlineQueryResultCachedAudio { - return InlineQueryResultCachedAudio{ - Type: "audio", - ID: id, - AudioID: audioID, - } -} - -// NewInlineQueryResultVoice creates a new inline query voice. -func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice { - return InlineQueryResultVoice{ - Type: "voice", - ID: id, - URL: url, - Title: title, - } -} - -// NewInlineQueryResultCachedVoice create a new inline query with cached photo. -func NewInlineQueryResultCachedVoice(id, voiceID, title string) InlineQueryResultCachedVoice { - return InlineQueryResultCachedVoice{ - Type: "voice", - ID: id, - VoiceID: voiceID, - Title: title, - } -} - -// NewInlineQueryResultDocument creates a new inline query document. -func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument { - return InlineQueryResultDocument{ - Type: "document", - ID: id, - URL: url, - Title: title, - MimeType: mimeType, - } -} - -// NewInlineQueryResultCachedDocument create a new inline query with cached photo. -func NewInlineQueryResultCachedDocument(id, documentID, title string) InlineQueryResultCachedDocument { - return InlineQueryResultCachedDocument{ - Type: "document", - ID: id, - DocumentID: documentID, - Title: title, - } -} - -// NewInlineQueryResultLocation creates a new inline query location. -func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation { - return InlineQueryResultLocation{ - Type: "location", - ID: id, - Title: title, - Latitude: latitude, - Longitude: longitude, - } -} - -// 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{ - BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, - }, - Text: text, - } -} - -// 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{ - BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, - }, - Caption: caption, - } -} - -// NewEditMessageReplyMarkup allows you to edit the inline -// keyboard markup. -func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig { - return EditMessageReplyMarkupConfig{ - BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, - ReplyMarkup: &replyMarkup, - }, - } -} - -// NewRemoveKeyboard hides the keyboard, with the option for being selective -// or hiding for everyone. -func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove { - return ReplyKeyboardRemove{ - RemoveKeyboard: true, - Selective: selective, - } -} - -// NewKeyboardButton creates a regular keyboard button. -func NewKeyboardButton(text string) KeyboardButton { - return KeyboardButton{ - Text: text, - } -} - -// NewKeyboardButtonContact creates a keyboard button that requests -// user contact information upon click. -func NewKeyboardButtonContact(text string) KeyboardButton { - return KeyboardButton{ - Text: text, - RequestContact: true, - } -} - -// NewKeyboardButtonLocation creates a keyboard button that requests -// user location information upon click. -func NewKeyboardButtonLocation(text string) KeyboardButton { - return KeyboardButton{ - Text: text, - RequestLocation: true, - } -} - -// NewKeyboardButtonRow creates a row of keyboard buttons. -func NewKeyboardButtonRow(buttons ...KeyboardButton) []KeyboardButton { - var row []KeyboardButton - - row = append(row, buttons...) - - return row -} - -// NewReplyKeyboard creates a new regular keyboard with sane defaults. -func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { - var keyboard [][]KeyboardButton - - keyboard = append(keyboard, rows...) - - return ReplyKeyboardMarkup{ - ResizeKeyboard: true, - Keyboard: keyboard, - } -} - -// NewOneTimeReplyKeyboard creates a new one time keyboard. -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 { - return InlineKeyboardButton{ - Text: text, - CallbackData: &data, - } -} - -// NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text -// which goes to a LoginURL. -func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - LoginURL: &loginURL, - } -} - -// NewInlineKeyboardButtonURL creates an inline keyboard button with text -// which goes to a URL. -func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - URL: &url, - } -} - -// NewInlineKeyboardButtonSwitch creates an inline keyboard button with -// text which allows the user to switch to a chat or return to a chat. -func NewInlineKeyboardButtonSwitch(text, sw string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - SwitchInlineQuery: &sw, - } -} - -// NewInlineKeyboardRow creates an inline keyboard row with buttons. -func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { - var row []InlineKeyboardButton - - row = append(row, buttons...) - - return row -} - -// NewInlineKeyboardMarkup creates a new inline keyboard. -func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup { - var keyboard [][]InlineKeyboardButton - - keyboard = append(keyboard, rows...) - - return InlineKeyboardMarkup{ - InlineKeyboard: keyboard, - } -} - -// NewCallback creates a new callback message. -func NewCallback(id, text string) CallbackConfig { - return CallbackConfig{ - CallbackQueryID: id, - Text: text, - ShowAlert: false, - } -} - -// NewCallbackWithAlert creates a new callback message that alerts -// the user. -func NewCallbackWithAlert(id, text string) CallbackConfig { - return CallbackConfig{ - CallbackQueryID: id, - Text: text, - ShowAlert: true, - } -} - -// NewInvoice creates a new Invoice request to the user. -func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig { - return InvoiceConfig{ - BaseChat: BaseChat{ChatID: chatID}, - Title: title, - Description: description, - Payload: payload, - ProviderToken: providerToken, - StartParameter: startParameter, - Currency: currency, - Prices: prices} -} - -// NewChatTitle allows you to update the title of a chat. -func NewChatTitle(chatID int64, title string) SetChatTitleConfig { - return SetChatTitleConfig{ - ChatID: chatID, - Title: title, - } -} - -// NewChatDescription allows you to update the description of a chat. -func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig { - return SetChatDescriptionConfig{ - ChatID: chatID, - Description: description, - } -} - -// NewChatPhoto allows you to update the photo for a chat. -func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { - return SetChatPhotoConfig{ - BaseFile: BaseFile{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - File: photo, - }, - } -} - -// NewDeleteChatPhoto allows you to delete the photo for a chat. -func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { - return DeleteChatPhotoConfig{ - ChatID: chatID, - } -} - -// NewPoll allows you to create a new poll. -func NewPoll(chatID int64, question string, options ...string) SendPollConfig { - return SendPollConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - Question: question, - Options: options, - IsAnonymous: true, // This is Telegram's default. - } -} - -// NewStopPoll allows you to stop a poll. -func NewStopPoll(chatID int64, messageID int) StopPollConfig { - return StopPollConfig{ - BaseEdit{ - ChatID: chatID, - MessageID: messageID, - }, - } -} - -// NewDice allows you to send a random dice roll. -func NewDice(chatID int64) DiceConfig { - return DiceConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - } -} - -// NewDiceWithEmoji allows you to send a random roll of one of many types. -// -// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5). -func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig { - return DiceConfig{ - BaseChat: BaseChat{ - ChatID: chatID, - }, - Emoji: emoji, - } -} - -// NewBotCommandScopeDefault represents the default scope of bot commands. -func NewBotCommandScopeDefault() BotCommandScope { - return BotCommandScope{Type: "default"} -} - -// NewBotCommandScopeAllPrivateChats represents the scope of bot commands, -// covering all private chats. -func NewBotCommandScopeAllPrivateChats() BotCommandScope { - return BotCommandScope{Type: "all_private_chats"} -} - -// NewBotCommandScopeAllGroupChats represents the scope of bot commands, -// covering all group and supergroup chats. -func NewBotCommandScopeAllGroupChats() BotCommandScope { - return BotCommandScope{Type: "all_group_chats"} -} - -// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands, -// covering all group and supergroup chat administrators. -func NewBotCommandScopeAllChatAdministrators() BotCommandScope { - return BotCommandScope{Type: "all_chat_administrators"} -} - -// NewBotCommandScopeChat represents the scope of bot commands, covering a -// specific chat. -func NewBotCommandScopeChat(chatID int64) BotCommandScope { - return BotCommandScope{ - Type: "chat", - ChatID: chatID, - } -} - -// NewBotCommandScopeChatAdministrators represents the scope of bot commands, -// covering all administrators of a specific group or supergroup chat. -func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope { - return BotCommandScope{ - Type: "chat_administrators", - ChatID: chatID, - } -} - -// NewBotCommandScopeChatMember represents the scope of bot commands, covering a -// specific member of a group or supergroup chat. -func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope { - return BotCommandScope{ - Type: "chat_member", - ChatID: chatID, - UserID: userID, - } -} - -// NewGetMyCommandsWithScope allows you to set the registered commands for a -// given scope. -func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig { - return GetMyCommandsConfig{Scope: &scope} -} - -// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered -// commands for a given scope and language code. -func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig { - return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} -} - -// NewSetMyCommands allows you to set the registered commands. -func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig { - return SetMyCommandsConfig{Commands: commands} -} - -// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope. -func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig { - return SetMyCommandsConfig{Commands: commands, Scope: &scope} -} - -// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope -// and language code. -func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig { - return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode} -} - -// NewDeleteMyCommands allows you to delete the registered commands. -func NewDeleteMyCommands() DeleteMyCommandsConfig { - return DeleteMyCommandsConfig{} -} - -// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given -// scope. -func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig { - return DeleteMyCommandsConfig{Scope: &scope} -} - -// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given -// scope and language code. -func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig { - return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} -} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/log.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/log.go deleted file mode 100644 index 18725514..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/log.go +++ /dev/null @@ -1,27 +0,0 @@ -package tgbotapi - -import ( - "errors" - stdlog "log" - "os" -) - -// BotLogger is an interface that represents the required methods to log data. -// -// Instead of requiring the standard logger, we can just specify the methods we -// use and allow users to pass anything that implements these. -type BotLogger interface { - Println(v ...interface{}) - Printf(format string, v ...interface{}) -} - -var log BotLogger = stdlog.New(os.Stderr, "", stdlog.LstdFlags) - -// SetLogger specifies the logger that the package should use. -func SetLogger(logger BotLogger) error { - if logger == nil { - return errors.New("logger is nil") - } - log = logger - return nil -} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go deleted file mode 100644 index 134f85e4..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go +++ /dev/null @@ -1,97 +0,0 @@ -package tgbotapi - -import ( - "encoding/json" - "reflect" - "strconv" -) - -// Params represents a set of parameters that gets passed to a request. -type Params map[string]string - -// AddNonEmpty adds a value if it not an empty string. -func (p Params) AddNonEmpty(key, value string) { - if value != "" { - p[key] = value - } -} - -// AddNonZero adds a value if it is not zero. -func (p Params) AddNonZero(key string, value int) { - if value != 0 { - p[key] = strconv.Itoa(value) - } -} - -// AddNonZero64 is the same as AddNonZero except uses an int64. -func (p Params) AddNonZero64(key string, value int64) { - if value != 0 { - p[key] = strconv.FormatInt(value, 10) - } -} - -// AddBool adds a value of a bool if it is true. -func (p Params) AddBool(key string, value bool) { - if value { - p[key] = strconv.FormatBool(value) - } -} - -// AddNonZeroFloat adds a floating point value that is not zero. -func (p Params) AddNonZeroFloat(key string, value float64) { - if value != 0 { - p[key] = strconv.FormatFloat(value, 'f', 6, 64) - } -} - -// AddInterface adds an interface if it is not nil and can be JSON marshalled. -func (p Params) AddInterface(key string, value interface{}) error { - if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { - return nil - } - - b, err := json.Marshal(value) - if err != nil { - return err - } - - p[key] = string(b) - - return nil -} - -// AddFirstValid attempts to add the first item that is not a default value. -// -// For example, AddFirstValid(0, "", "test") would add "test". -func (p Params) AddFirstValid(key string, args ...interface{}) error { - for _, arg := range args { - switch v := arg.(type) { - case int: - if v != 0 { - p[key] = strconv.Itoa(v) - return nil - } - case int64: - if v != 0 { - p[key] = strconv.FormatInt(v, 10) - return nil - } - case string: - if v != "" { - p[key] = v - return nil - } - case nil: - default: - b, err := json.Marshal(arg) - if err != nil { - return err - } - - p[key] = string(b) - return nil - } - } - - return nil -} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/passport.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/passport.go deleted file mode 100644 index 4fedb965..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/passport.go +++ /dev/null @@ -1,317 +0,0 @@ -package tgbotapi - -// PassportRequestInfoConfig allows you to request passport info -type PassportRequestInfoConfig struct { - BotID int `json:"bot_id"` - Scope *PassportScope `json:"scope"` - Nonce string `json:"nonce"` - PublicKey string `json:"public_key"` -} - -// PassportScopeElement supports using one or one of several elements. -type PassportScopeElement interface { - ScopeType() string -} - -// PassportScope is the requested scopes of data. -type PassportScope struct { - V int `json:"v"` - Data []PassportScopeElement `json:"data"` -} - -// PassportScopeElementOneOfSeveral allows you to request any one of the -// requested documents. -type PassportScopeElementOneOfSeveral struct { -} - -// ScopeType is the scope type. -func (eo *PassportScopeElementOneOfSeveral) ScopeType() string { - return "one_of" -} - -// PassportScopeElementOne requires the specified element be provided. -type PassportScopeElementOne struct { - Type string `json:"type"` // One of “personal_details”, “passport”, “driver_license”, “identity_card”, “internal_passport”, “address”, “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration”, “temporary_registration”, “phone_number”, “email” - Selfie bool `json:"selfie"` - Translation bool `json:"translation"` - NativeNames bool `json:"native_name"` -} - -// ScopeType is the scope type. -func (eo *PassportScopeElementOne) ScopeType() string { - return "one" -} - -type ( - // PassportData contains information about Telegram Passport data shared with - // the bot by the user. - PassportData struct { - // Array with information about documents and other Telegram Passport - // elements that was shared with the bot - Data []EncryptedPassportElement `json:"data"` - - // Encrypted credentials required to decrypt the data - Credentials *EncryptedCredentials `json:"credentials"` - } - - // PassportFile represents a file uploaded to Telegram Passport. Currently, all - // Telegram Passport files are in JPEG format when decrypted and don't exceed - // 10MB. - PassportFile struct { - // Unique identifier for this file - FileID string `json:"file_id"` - - FileUniqueID string `json:"file_unique_id"` - - // File size - FileSize int `json:"file_size"` - - // Unix time when the file was uploaded - FileDate int64 `json:"file_date"` - } - - // EncryptedPassportElement contains information about documents or other - // Telegram Passport elements shared with the bot by the user. - EncryptedPassportElement struct { - // Element type. - Type string `json:"type"` - - // Base64-encoded encrypted Telegram Passport element data provided by - // the user, available for "personal_details", "passport", - // "driver_license", "identity_card", "identity_passport" and "address" - // types. Can be decrypted and verified using the accompanying - // EncryptedCredentials. - Data string `json:"data,omitempty"` - - // User's verified phone number, available only for "phone_number" type - PhoneNumber string `json:"phone_number,omitempty"` - - // User's verified email address, available only for "email" type - Email string `json:"email,omitempty"` - - // Array of encrypted files with documents provided by the user, - // available for "utility_bill", "bank_statement", "rental_agreement", - // "passport_registration" and "temporary_registration" types. Files can - // be decrypted and verified using the accompanying EncryptedCredentials. - Files []PassportFile `json:"files,omitempty"` - - // Encrypted file with the front side of the document, provided by the - // user. Available for "passport", "driver_license", "identity_card" and - // "internal_passport". The file can be decrypted and verified using the - // accompanying EncryptedCredentials. - FrontSide *PassportFile `json:"front_side,omitempty"` - - // Encrypted file with the reverse side of the document, provided by the - // user. Available for "driver_license" and "identity_card". The file can - // be decrypted and verified using the accompanying EncryptedCredentials. - ReverseSide *PassportFile `json:"reverse_side,omitempty"` - - // Encrypted file with the selfie of the user holding a document, - // provided by the user; available for "passport", "driver_license", - // "identity_card" and "internal_passport". The file can be decrypted - // and verified using the accompanying EncryptedCredentials. - Selfie *PassportFile `json:"selfie,omitempty"` - } - - // EncryptedCredentials contains data required for decrypting and - // authenticating EncryptedPassportElement. See the Telegram Passport - // Documentation for a complete description of the data decryption and - // authentication processes. - EncryptedCredentials struct { - // Base64-encoded encrypted JSON-serialized data with unique user's - // payload, data hashes and secrets required for EncryptedPassportElement - // decryption and authentication - Data string `json:"data"` - - // Base64-encoded data hash for data authentication - Hash string `json:"hash"` - - // Base64-encoded secret, encrypted with the bot's public RSA key, - // required for data decryption - Secret string `json:"secret"` - } - - // PassportElementError represents an error in the Telegram Passport element - // which was submitted that should be resolved by the user. - PassportElementError interface{} - - // PassportElementErrorDataField represents an issue in one of the data - // fields that was provided by the user. The error is considered resolved - // when the field's value changes. - PassportElementErrorDataField struct { - // Error source, must be data - Source string `json:"source"` - - // The section of the user's Telegram Passport which has the error, one - // of "personal_details", "passport", "driver_license", "identity_card", - // "internal_passport", "address" - Type string `json:"type"` - - // Name of the data field which has the error - FieldName string `json:"field_name"` - - // Base64-encoded data hash - DataHash string `json:"data_hash"` - - // Error message - Message string `json:"message"` - } - - // PassportElementErrorFrontSide represents an issue with the front side of - // a document. The error is considered resolved when the file with the front - // side of the document changes. - PassportElementErrorFrontSide struct { - // Error source, must be front_side - Source string `json:"source"` - - // The section of the user's Telegram Passport which has the issue, one - // of "passport", "driver_license", "identity_card", "internal_passport" - Type string `json:"type"` - - // Base64-encoded hash of the file with the front side of the document - FileHash string `json:"file_hash"` - - // Error message - Message string `json:"message"` - } - - // PassportElementErrorReverseSide represents an issue with the reverse side - // of a document. The error is considered resolved when the file with reverse - // side of the document changes. - PassportElementErrorReverseSide struct { - // Error source, must be reverse_side - Source string `json:"source"` - - // The section of the user's Telegram Passport which has the issue, one - // of "driver_license", "identity_card" - Type string `json:"type"` - - // Base64-encoded hash of the file with the reverse side of the document - FileHash string `json:"file_hash"` - - // Error message - Message string `json:"message"` - } - - // PassportElementErrorSelfie represents an issue with the selfie with a - // document. The error is considered resolved when the file with the selfie - // changes. - PassportElementErrorSelfie struct { - // Error source, must be selfie - Source string `json:"source"` - - // The section of the user's Telegram Passport which has the issue, one - // of "passport", "driver_license", "identity_card", "internal_passport" - Type string `json:"type"` - - // Base64-encoded hash of the file with the selfie - FileHash string `json:"file_hash"` - - // Error message - Message string `json:"message"` - } - - // PassportElementErrorFile represents an issue with a document scan. The - // error is considered resolved when the file with the document scan changes. - PassportElementErrorFile struct { - // Error source, must be a file - Source string `json:"source"` - - // The section of the user's Telegram Passport which has the issue, one - // of "utility_bill", "bank_statement", "rental_agreement", - // "passport_registration", "temporary_registration" - Type string `json:"type"` - - // Base64-encoded file hash - FileHash string `json:"file_hash"` - - // Error message - Message string `json:"message"` - } - - // PassportElementErrorFiles represents an issue with a list of scans. The - // error is considered resolved when the list of files containing the scans - // changes. - PassportElementErrorFiles struct { - // Error source, must be files - Source string `json:"source"` - - // The section of the user's Telegram Passport which has the issue, one - // of "utility_bill", "bank_statement", "rental_agreement", - // "passport_registration", "temporary_registration" - Type string `json:"type"` - - // List of base64-encoded file hashes - FileHashes []string `json:"file_hashes"` - - // Error message - Message string `json:"message"` - } - - // Credentials contains encrypted data. - Credentials struct { - Data SecureData `json:"secure_data"` - // Nonce the same nonce given in the request - Nonce string `json:"nonce"` - } - - // SecureData is a map of the fields and their encrypted values. - SecureData map[string]*SecureValue - // PersonalDetails *SecureValue `json:"personal_details"` - // Passport *SecureValue `json:"passport"` - // InternalPassport *SecureValue `json:"internal_passport"` - // DriverLicense *SecureValue `json:"driver_license"` - // IdentityCard *SecureValue `json:"identity_card"` - // Address *SecureValue `json:"address"` - // UtilityBill *SecureValue `json:"utility_bill"` - // BankStatement *SecureValue `json:"bank_statement"` - // RentalAgreement *SecureValue `json:"rental_agreement"` - // PassportRegistration *SecureValue `json:"passport_registration"` - // TemporaryRegistration *SecureValue `json:"temporary_registration"` - - // SecureValue contains encrypted values for a SecureData item. - SecureValue struct { - Data *DataCredentials `json:"data"` - FrontSide *FileCredentials `json:"front_side"` - ReverseSide *FileCredentials `json:"reverse_side"` - Selfie *FileCredentials `json:"selfie"` - Translation []*FileCredentials `json:"translation"` - Files []*FileCredentials `json:"files"` - } - - // DataCredentials contains information required to decrypt data. - DataCredentials struct { - // DataHash checksum of encrypted data - DataHash string `json:"data_hash"` - // Secret of encrypted data - Secret string `json:"secret"` - } - - // FileCredentials contains information required to decrypt files. - FileCredentials struct { - // FileHash checksum of encrypted data - FileHash string `json:"file_hash"` - // Secret of encrypted data - Secret string `json:"secret"` - } - - // PersonalDetails https://core.telegram.org/passport#personaldetails - PersonalDetails struct { - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - MiddleName string `json:"middle_name"` - BirthDate string `json:"birth_date"` - Gender string `json:"gender"` - CountryCode string `json:"country_code"` - ResidenceCountryCode string `json:"residence_country_code"` - FirstNameNative string `json:"first_name_native"` - LastNameNative string `json:"last_name_native"` - MiddleNameNative string `json:"middle_name_native"` - } - - // IDDocumentData https://core.telegram.org/passport#iddocumentdata - IDDocumentData struct { - DocumentNumber string `json:"document_no"` - ExpiryDate string `json:"expiry_date"` - } -) diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go deleted file mode 100644 index 847f1b14..00000000 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go +++ /dev/null @@ -1,3225 +0,0 @@ -package tgbotapi - -import ( - "encoding/json" - "errors" - "fmt" - "net/url" - "strings" - "time" -) - -// APIResponse is a response from the Telegram API with the result -// stored raw. -type APIResponse struct { - Ok bool `json:"ok"` - Result json.RawMessage `json:"result,omitempty"` - ErrorCode int `json:"error_code,omitempty"` - Description string `json:"description,omitempty"` - Parameters *ResponseParameters `json:"parameters,omitempty"` -} - -// Error is an error containing extra information returned by the Telegram API. -type Error struct { - Code int - Message string - ResponseParameters -} - -// Error message string. -func (e Error) Error() string { - return e.Message -} - -// Update is an update response, from GetUpdates. -type Update struct { - // UpdateID is the update's unique identifier. - // Update identifiers start from a certain positive number and increase - // sequentially. - // This ID becomes especially handy if you're using Webhooks, - // since it allows you to ignore repeated updates or to restore - // the correct update sequence, should they get out of order. - // If there are no new updates for at least a week, then identifier - // of the next update will be chosen randomly instead of sequentially. - UpdateID int `json:"update_id"` - // Message new incoming message of any kind — text, photo, sticker, etc. - // - // optional - Message *Message `json:"message,omitempty"` - // EditedMessage new version of a message that is known to the bot and was - // edited - // - // optional - EditedMessage *Message `json:"edited_message,omitempty"` - // ChannelPost new version of a message that is known to the bot and was - // edited - // - // optional - ChannelPost *Message `json:"channel_post,omitempty"` - // EditedChannelPost new incoming channel post of any kind — text, photo, - // sticker, etc. - // - // optional - EditedChannelPost *Message `json:"edited_channel_post,omitempty"` - // InlineQuery new incoming inline query - // - // optional - InlineQuery *InlineQuery `json:"inline_query,omitempty"` - // ChosenInlineResult is the result of an inline query - // that was chosen by a user and sent to their chat partner. - // Please see our documentation on the feedback collecting - // for details on how to enable these updates for your bot. - // - // optional - ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result,omitempty"` - // CallbackQuery new incoming callback query - // - // optional - CallbackQuery *CallbackQuery `json:"callback_query,omitempty"` - // ShippingQuery new incoming shipping query. Only for invoices with - // flexible price - // - // optional - ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"` - // PreCheckoutQuery new incoming pre-checkout query. Contains full - // information about checkout - // - // optional - PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"` - // Pool new poll state. Bots receive only updates about stopped polls and - // polls, which are sent by the bot - // - // optional - Poll *Poll `json:"poll,omitempty"` - // PollAnswer user changed their answer in a non-anonymous poll. Bots - // receive new votes only in polls that were sent by the bot itself. - // - // optional - PollAnswer *PollAnswer `json:"poll_answer,omitempty"` - // MyChatMember is the bot's chat member status was updated in a chat. For - // private chats, this update is received only when the bot is blocked or - // unblocked by the user. - // - // optional - MyChatMember *ChatMemberUpdated `json:"my_chat_member"` - // ChatMember is a chat member's status was updated in a chat. The bot must - // be an administrator in the chat and must explicitly specify "chat_member" - // in the list of allowed_updates to receive these updates. - // - // optional - ChatMember *ChatMemberUpdated `json:"chat_member"` - // ChatJoinRequest is a request to join the chat has been sent. The bot must - // have the can_invite_users administrator right in the chat to receive - // these updates. - // - // optional - ChatJoinRequest *ChatJoinRequest `json:"chat_join_request"` -} - -// SentFrom returns the user who sent an update. Can be nil, if Telegram did not provide information -// about the user in the update object. -func (u *Update) SentFrom() *User { - switch { - case u.Message != nil: - return u.Message.From - case u.EditedMessage != nil: - return u.EditedMessage.From - case u.InlineQuery != nil: - return u.InlineQuery.From - case u.ChosenInlineResult != nil: - return u.ChosenInlineResult.From - case u.CallbackQuery != nil: - return u.CallbackQuery.From - case u.ShippingQuery != nil: - return u.ShippingQuery.From - case u.PreCheckoutQuery != nil: - return u.PreCheckoutQuery.From - default: - return nil - } -} - -// CallbackData returns the callback query data, if it exists. -func (u *Update) CallbackData() string { - if u.CallbackQuery != nil { - return u.CallbackQuery.Data - } - return "" -} - -// FromChat returns the chat where an update occurred. -func (u *Update) FromChat() *Chat { - switch { - case u.Message != nil: - return u.Message.Chat - case u.EditedMessage != nil: - return u.EditedMessage.Chat - case u.ChannelPost != nil: - return u.ChannelPost.Chat - case u.EditedChannelPost != nil: - return u.EditedChannelPost.Chat - case u.CallbackQuery != nil: - return u.CallbackQuery.Message.Chat - default: - return nil - } -} - -// UpdatesChannel is the channel for getting updates. -type UpdatesChannel <-chan Update - -// Clear discards all unprocessed incoming updates. -func (ch UpdatesChannel) Clear() { - for len(ch) != 0 { - <-ch - } -} - -// User represents a Telegram user or bot. -type User struct { - // ID is a unique identifier for this user or bot - ID int64 `json:"id"` - // IsBot true, if this user is a bot - // - // optional - IsBot bool `json:"is_bot,omitempty"` - // FirstName user's or bot's first name - FirstName string `json:"first_name"` - // LastName user's or bot's last name - // - // optional - LastName string `json:"last_name,omitempty"` - // UserName user's or bot's username - // - // optional - UserName string `json:"username,omitempty"` - // LanguageCode IETF language tag of the user's language - // more info: https://en.wikipedia.org/wiki/IETF_language_tag - // - // optional - LanguageCode string `json:"language_code,omitempty"` - // CanJoinGroups is true, if the bot can be invited to groups. - // Returned only in getMe. - // - // optional - CanJoinGroups bool `json:"can_join_groups,omitempty"` - // CanReadAllGroupMessages is true, if privacy mode is disabled for the bot. - // Returned only in getMe. - // - // optional - CanReadAllGroupMessages bool `json:"can_read_all_group_messages,omitempty"` - // SupportsInlineQueries is true, if the bot supports inline queries. - // Returned only in getMe. - // - // optional - SupportsInlineQueries bool `json:"supports_inline_queries,omitempty"` -} - -// String displays a simple text version of a user. -// -// 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 - } - - name := u.FirstName - if u.LastName != "" { - name += " " + u.LastName - } - - return name -} - -// Chat represents a chat. -type Chat struct { - // ID is a unique identifier for this chat - ID int64 `json:"id"` - // Type of chat, can be either “private”, “group”, “supergroup” or “channel” - Type string `json:"type"` - // Title for supergroups, channels and group chats - // - // optional - Title string `json:"title,omitempty"` - // UserName for private chats, supergroups and channels if available - // - // optional - UserName string `json:"username,omitempty"` - // FirstName of the other party in a private chat - // - // optional - FirstName string `json:"first_name,omitempty"` - // LastName of the other party in a private chat - // - // optional - LastName string `json:"last_name,omitempty"` - // Photo is a chat photo - Photo *ChatPhoto `json:"photo"` - // Bio is the bio of the other party in a private chat. Returned only in - // getChat - // - // optional - Bio string `json:"bio,omitempty"` - // HasPrivateForwards is true if privacy settings of the other party in the - // private chat allows to use tg://user?id= links only in chats - // with the user. Returned only in getChat. - // - // optional - HasPrivateForwards bool `json:"has_private_forwards,omitempty"` - // Description for groups, supergroups and channel chats - // - // optional - Description string `json:"description,omitempty"` - // InviteLink is a chat invite link, for groups, supergroups and channel chats. - // Each administrator in a chat generates their own invite links, - // so the bot must first generate the link using exportChatInviteLink - // - // optional - InviteLink string `json:"invite_link,omitempty"` - // PinnedMessage is the pinned message, for groups, supergroups and channels - // - // optional - PinnedMessage *Message `json:"pinned_message,omitempty"` - // Permissions are default chat member permissions, for groups and - // supergroups. Returned only in getChat. - // - // optional - Permissions *ChatPermissions `json:"permissions,omitempty"` - // SlowModeDelay is for supergroups, the minimum allowed delay between - // consecutive messages sent by each unpriviledged user. Returned only in - // getChat. - // - // optional - SlowModeDelay int `json:"slow_mode_delay,omitempty"` - // MessageAutoDeleteTime is the time after which all messages sent to the - // chat will be automatically deleted; in seconds. Returned only in getChat. - // - // optional - MessageAutoDeleteTime int `json:"message_auto_delete_time,omitempty"` - // HasProtectedContent is true if messages from the chat can't be forwarded - // to other chats. Returned only in getChat. - // - // optional - HasProtectedContent bool `json:"has_protected_content,omitempty"` - // StickerSetName is for supergroups, name of group sticker set.Returned - // only in getChat. - // - // optional - StickerSetName string `json:"sticker_set_name,omitempty"` - // CanSetStickerSet is true, if the bot can change the group sticker set. - // Returned only in getChat. - // - // optional - CanSetStickerSet bool `json:"can_set_sticker_set,omitempty"` - // LinkedChatID is a unique identifier for the linked chat, i.e. the - // discussion group identifier for a channel and vice versa; for supergroups - // and channel chats. - // - // optional - LinkedChatID int64 `json:"linked_chat_id,omitempty"` - // Location is for supergroups, the location to which the supergroup is - // connected. Returned only in getChat. - // - // optional - Location *ChatLocation `json:"location"` -} - -// IsPrivate returns if the Chat is a private conversation. -func (c Chat) IsPrivate() bool { - return c.Type == "private" -} - -// IsGroup returns if the Chat is a group. -func (c Chat) IsGroup() bool { - return c.Type == "group" -} - -// IsSuperGroup returns if the Chat is a supergroup. -func (c Chat) IsSuperGroup() bool { - return c.Type == "supergroup" -} - -// IsChannel returns if the Chat is a channel. -func (c Chat) IsChannel() bool { - return c.Type == "channel" -} - -// ChatConfig returns a ChatConfig struct for chat related methods. -func (c Chat) ChatConfig() ChatConfig { - return ChatConfig{ChatID: c.ID} -} - -// Message represents a message. -type Message struct { - // MessageID is a unique message identifier inside this chat - MessageID int `json:"message_id"` - // From is a sender, empty for messages sent to channels; - // - // optional - From *User `json:"from,omitempty"` - // SenderChat is the sender of the message, sent on behalf of a chat. The - // channel itself for channel messages. The supergroup itself for messages - // from anonymous group administrators. The linked channel for messages - // automatically forwarded to the discussion group - // - // optional - SenderChat *Chat `json:"sender_chat,omitempty"` - // Date of the message was sent in Unix time - Date int `json:"date"` - // Chat is the conversation the message belongs to - Chat *Chat `json:"chat"` - // ForwardFrom for forwarded messages, sender of the original message; - // - // optional - ForwardFrom *User `json:"forward_from,omitempty"` - // ForwardFromChat for messages forwarded from channels, - // information about the original channel; - // - // optional - ForwardFromChat *Chat `json:"forward_from_chat,omitempty"` - // ForwardFromMessageID for messages forwarded from channels, - // identifier of the original message in the channel; - // - // optional - ForwardFromMessageID int `json:"forward_from_message_id,omitempty"` - // ForwardSignature for messages forwarded from channels, signature of the - // post author if present - // - // optional - ForwardSignature string `json:"forward_signature,omitempty"` - // ForwardSenderName is the sender's name for messages forwarded from users - // who disallow adding a link to their account in forwarded messages - // - // optional - ForwardSenderName string `json:"forward_sender_name,omitempty"` - // ForwardDate for forwarded messages, date the original message was sent in Unix time; - // - // optional - ForwardDate int `json:"forward_date,omitempty"` - // IsAutomaticForward is true if the message is a channel post that was - // automatically forwarded to the connected discussion group. - // - // optional - IsAutomaticForward bool `json:"is_automatic_forward,omitempty"` - // ReplyToMessage for replies, the original message. - // Note that the Message object in this field will not contain further ReplyToMessage fields - // even if it itself is a reply; - // - // optional - ReplyToMessage *Message `json:"reply_to_message,omitempty"` - // ViaBot through which the message was sent; - // - // optional - ViaBot *User `json:"via_bot,omitempty"` - // EditDate of the message was last edited in Unix time; - // - // optional - EditDate int `json:"edit_date,omitempty"` - // HasProtectedContent is true if the message can't be forwarded. - // - // optional - HasProtectedContent bool `json:"has_protected_content,omitempty"` - // MediaGroupID is the unique identifier of a media message group this message belongs to; - // - // optional - MediaGroupID string `json:"media_group_id,omitempty"` - // AuthorSignature is the signature of the post author for messages in channels; - // - // optional - AuthorSignature string `json:"author_signature,omitempty"` - // Text is for text messages, the actual UTF-8 text of the message, 0-4096 characters; - // - // optional - Text string `json:"text,omitempty"` - // Entities are for text messages, special entities like usernames, - // URLs, bot commands, etc. that appear in the text; - // - // optional - Entities []MessageEntity `json:"entities,omitempty"` - // Animation message is an animation, information about the animation. - // For backward compatibility, when this field is set, the document field will also be set; - // - // optional - Animation *Animation `json:"animation,omitempty"` - // Audio message is an audio file, information about the file; - // - // optional - Audio *Audio `json:"audio,omitempty"` - // Document message is a general file, information about the file; - // - // optional - Document *Document `json:"document,omitempty"` - // Photo message is a photo, available sizes of the photo; - // - // optional - Photo []PhotoSize `json:"photo,omitempty"` - // Sticker message is a sticker, information about the sticker; - // - // optional - Sticker *Sticker `json:"sticker,omitempty"` - // Video message is a video, information about the video; - // - // optional - Video *Video `json:"video,omitempty"` - // VideoNote message is a video note, information about the video message; - // - // optional - VideoNote *VideoNote `json:"video_note,omitempty"` - // Voice message is a voice message, information about the file; - // - // optional - Voice *Voice `json:"voice,omitempty"` - // Caption for the animation, audio, document, photo, video or voice, 0-1024 characters; - // - // optional - Caption string `json:"caption,omitempty"` - // CaptionEntities; - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Contact message is a shared contact, information about the contact; - // - // optional - Contact *Contact `json:"contact,omitempty"` - // Dice is a dice with random value; - // - // optional - Dice *Dice `json:"dice,omitempty"` - // Game message is a game, information about the game; - // - // optional - Game *Game `json:"game,omitempty"` - // Poll is a native poll, information about the poll; - // - // optional - Poll *Poll `json:"poll,omitempty"` - // Venue message is a venue, information about the venue. - // For backward compatibility, when this field is set, the location field - // will also be set; - // - // optional - Venue *Venue `json:"venue,omitempty"` - // Location message is a shared location, information about the location; - // - // optional - Location *Location `json:"location,omitempty"` - // NewChatMembers that were added to the group or supergroup - // and information about them (the bot itself may be one of these members); - // - // optional - NewChatMembers []User `json:"new_chat_members,omitempty"` - // LeftChatMember is a member was removed from the group, - // information about them (this member may be the bot itself); - // - // optional - LeftChatMember *User `json:"left_chat_member,omitempty"` - // NewChatTitle is a chat title was changed to this value; - // - // optional - NewChatTitle string `json:"new_chat_title,omitempty"` - // NewChatPhoto is a chat photo was change to this value; - // - // optional - NewChatPhoto []PhotoSize `json:"new_chat_photo,omitempty"` - // DeleteChatPhoto is a service message: the chat photo was deleted; - // - // optional - DeleteChatPhoto bool `json:"delete_chat_photo,omitempty"` - // GroupChatCreated is a service message: the group has been created; - // - // optional - GroupChatCreated bool `json:"group_chat_created,omitempty"` - // SuperGroupChatCreated is a service message: the supergroup has been created. - // This field can't be received in a message coming through updates, - // because bot can't be a member of a supergroup when it is created. - // It can only be found in ReplyToMessage if someone replies to a very first message - // in a directly created supergroup; - // - // optional - SuperGroupChatCreated bool `json:"supergroup_chat_created,omitempty"` - // ChannelChatCreated is a service message: the channel has been created. - // This field can't be received in a message coming through updates, - // because bot can't be a member of a channel when it is created. - // It can only be found in ReplyToMessage - // if someone replies to a very first message in a channel; - // - // optional - ChannelChatCreated bool `json:"channel_chat_created,omitempty"` - // MessageAutoDeleteTimerChanged is a service message: auto-delete timer - // settings changed in the chat. - // - // optional - MessageAutoDeleteTimerChanged *MessageAutoDeleteTimerChanged `json:"message_auto_delete_timer_changed"` - // MigrateToChatID is the group has been migrated to a supergroup with the specified identifier. - // This number may be greater than 32 bits and some programming languages - // may have difficulty/silent defects in interpreting it. - // But it is smaller than 52 bits, so a signed 64-bit integer - // or double-precision float type are safe for storing this identifier; - // - // optional - MigrateToChatID int64 `json:"migrate_to_chat_id,omitempty"` - // MigrateFromChatID is the supergroup has been migrated from a group with the specified identifier. - // This number may be greater than 32 bits and some programming languages - // may have difficulty/silent defects in interpreting it. - // But it is smaller than 52 bits, so a signed 64-bit integer - // or double-precision float type are safe for storing this identifier; - // - // optional - MigrateFromChatID int64 `json:"migrate_from_chat_id,omitempty"` - // PinnedMessage is a specified message was pinned. - // Note that the Message object in this field will not contain further ReplyToMessage - // fields even if it is itself a reply; - // - // optional - PinnedMessage *Message `json:"pinned_message,omitempty"` - // Invoice message is an invoice for a payment; - // - // optional - Invoice *Invoice `json:"invoice,omitempty"` - // SuccessfulPayment message is a service message about a successful payment, - // information about the payment; - // - // optional - SuccessfulPayment *SuccessfulPayment `json:"successful_payment,omitempty"` - // ConnectedWebsite is the domain name of the website on which the user has - // logged in; - // - // optional - ConnectedWebsite string `json:"connected_website,omitempty"` - // PassportData is a Telegram Passport data; - // - // optional - PassportData *PassportData `json:"passport_data,omitempty"` - // ProximityAlertTriggered is a service message. A user in the chat - // triggered another user's proximity alert while sharing Live Location - // - // optional - ProximityAlertTriggered *ProximityAlertTriggered `json:"proximity_alert_triggered"` - // VoiceChatScheduled is a service message: voice chat scheduled. - // - // optional - VoiceChatScheduled *VoiceChatScheduled `json:"voice_chat_scheduled"` - // VoiceChatStarted is a service message: voice chat started. - // - // optional - VoiceChatStarted *VoiceChatStarted `json:"voice_chat_started"` - // VoiceChatEnded is a service message: voice chat ended. - // - // optional - VoiceChatEnded *VoiceChatEnded `json:"voice_chat_ended"` - // VoiceChatParticipantsInvited is a service message: new participants - // invited to a voice chat. - // - // optional - VoiceChatParticipantsInvited *VoiceChatParticipantsInvited `json:"voice_chat_participants_invited"` - // ReplyMarkup is the Inline keyboard attached to the message. - // login_url buttons are represented as ordinary url buttons. - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -// Time converts the message timestamp into a Time. -func (m *Message) Time() time.Time { - return time.Unix(int64(m.Date), 0) -} - -// IsCommand returns true if message starts with a "bot_command" entity. -func (m *Message) IsCommand() bool { - if m.Entities == nil || len(m.Entities) == 0 { - return false - } - - entity := m.Entities[0] - return entity.Offset == 0 && entity.IsCommand() -} - -// Command checks if the message was a command and if it was, returns the -// command. If the Message was not a command, it returns an empty string. -// -// If the command contains the at name syntax, it is removed. Use -// CommandWithAt() if you do not want that. -func (m *Message) Command() string { - command := m.CommandWithAt() - - if i := strings.Index(command, "@"); i != -1 { - command = command[:i] - } - - return command -} - -// CommandWithAt checks if the message was a command and if it was, returns the -// command. If the Message was not a command, it returns an empty string. -// -// If the command contains the at name syntax, it is not removed. Use Command() -// if you want that. -func (m *Message) CommandWithAt() string { - if !m.IsCommand() { - return "" - } - - // IsCommand() checks that the message begins with a bot_command entity - entity := m.Entities[0] - return m.Text[1:entity.Length] -} - -// CommandArguments checks if the message was a command and if it was, -// returns all text after the command name. If the Message was not a -// command, it returns an empty string. -// -// Note: The first character after the command name is omitted: -// - "/foo bar baz" yields "bar baz", not " bar baz" -// - "/foo-bar baz" yields "bar baz", too -// Even though the latter is not a command conforming to the spec, the API -// marks "/foo" as command entity. -func (m *Message) CommandArguments() string { - if !m.IsCommand() { - return "" - } - - // IsCommand() checks that the message begins with a bot_command entity - entity := m.Entities[0] - - if len(m.Text) == entity.Length { - return "" // The command makes up the whole message - } - - return m.Text[entity.Length+1:] -} - -// MessageID represents a unique message identifier. -type MessageID struct { - MessageID int `json:"message_id"` -} - -// MessageEntity represents one special entity in a text message. -type MessageEntity struct { - // Type of the entity. - // Can be: - // “mention” (@username), - // “hashtag” (#hashtag), - // “cashtag” ($USD), - // “bot_command” (/start@jobs_bot), - // “url” (https://telegram.org), - // “email” (do-not-reply@telegram.org), - // “phone_number” (+1-212-555-0123), - // “bold” (bold text), - // “italic” (italic text), - // “underline” (underlined text), - // “strikethrough” (strikethrough text), - // “code” (monowidth string), - // “pre” (monowidth block), - // “text_link” (for clickable text URLs), - // “text_mention” (for users without usernames) - Type string `json:"type"` - // Offset in UTF-16 code units to the start of the entity - Offset int `json:"offset"` - // Length - Length int `json:"length"` - // URL for “text_link” only, url that will be opened after user taps on the text - // - // optional - URL string `json:"url,omitempty"` - // User for “text_mention” only, the mentioned user - // - // optional - User *User `json:"user,omitempty"` - // Language for “pre” only, the programming language of the entity text - // - // optional - Language string `json:"language,omitempty"` -} - -// ParseURL attempts to parse a URL contained within a MessageEntity. -func (e MessageEntity) ParseURL() (*url.URL, error) { - if e.URL == "" { - return nil, errors.New(ErrBadURL) - } - - return url.Parse(e.URL) -} - -// IsMention returns true if the type of the message entity is "mention" (@username). -func (e MessageEntity) IsMention() bool { - return e.Type == "mention" -} - -// IsHashtag returns true if the type of the message entity is "hashtag". -func (e MessageEntity) IsHashtag() bool { - return e.Type == "hashtag" -} - -// IsCommand returns true if the type of the message entity is "bot_command". -func (e MessageEntity) IsCommand() bool { - return e.Type == "bot_command" -} - -// IsURL returns true if the type of the message entity is "url". -func (e MessageEntity) IsURL() bool { - return e.Type == "url" -} - -// IsEmail returns true if the type of the message entity is "email". -func (e MessageEntity) IsEmail() bool { - return e.Type == "email" -} - -// IsBold returns true if the type of the message entity is "bold" (bold text). -func (e MessageEntity) IsBold() bool { - return e.Type == "bold" -} - -// IsItalic returns true if the type of the message entity is "italic" (italic text). -func (e MessageEntity) IsItalic() bool { - return e.Type == "italic" -} - -// IsCode returns true if the type of the message entity is "code" (monowidth string). -func (e MessageEntity) IsCode() bool { - return e.Type == "code" -} - -// IsPre returns true if the type of the message entity is "pre" (monowidth block). -func (e MessageEntity) IsPre() bool { - return e.Type == "pre" -} - -// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL). -func (e MessageEntity) IsTextLink() bool { - return e.Type == "text_link" -} - -// PhotoSize represents one size of a photo or a file / sticker thumbnail. -type PhotoSize struct { - // FileID identifier for this file, which can be used to download or reuse - // the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Width photo width - Width int `json:"width"` - // Height photo height - Height int `json:"height"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// Animation represents an animation file. -type Animation struct { - // FileID is the identifier for this file, which can be used to download or reuse - // the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Width video width as defined by sender - Width int `json:"width"` - // Height video height as defined by sender - Height int `json:"height"` - // Duration of the video in seconds as defined by sender - Duration int `json:"duration"` - // Thumbnail animation thumbnail as defined by sender - // - // optional - Thumbnail *PhotoSize `json:"thumb,omitempty"` - // FileName original animation filename as defined by sender - // - // optional - FileName string `json:"file_name,omitempty"` - // MimeType of the file as defined by sender - // - // optional - MimeType string `json:"mime_type,omitempty"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// Audio represents an audio file to be treated as music by the Telegram clients. -type Audio struct { - // FileID is an identifier for this file, which can be used to download or - // reuse the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Duration of the audio in seconds as defined by sender - Duration int `json:"duration"` - // Performer of the audio as defined by sender or by audio tags - // - // optional - Performer string `json:"performer,omitempty"` - // Title of the audio as defined by sender or by audio tags - // - // optional - Title string `json:"title,omitempty"` - // FileName is the original filename as defined by sender - // - // optional - FileName string `json:"file_name,omitempty"` - // MimeType of the file as defined by sender - // - // optional - MimeType string `json:"mime_type,omitempty"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` - // Thumbnail is the album cover to which the music file belongs - // - // optional - Thumbnail *PhotoSize `json:"thumb,omitempty"` -} - -// Document represents a general file. -type Document struct { - // FileID is an identifier for this file, which can be used to download or - // reuse the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Thumbnail document thumbnail as defined by sender - // - // optional - Thumbnail *PhotoSize `json:"thumb,omitempty"` - // FileName original filename as defined by sender - // - // optional - FileName string `json:"file_name,omitempty"` - // MimeType of the file as defined by sender - // - // optional - MimeType string `json:"mime_type,omitempty"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// Video represents a video file. -type Video struct { - // FileID identifier for this file, which can be used to download or reuse - // the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Width video width as defined by sender - Width int `json:"width"` - // Height video height as defined by sender - Height int `json:"height"` - // Duration of the video in seconds as defined by sender - Duration int `json:"duration"` - // Thumbnail video thumbnail - // - // optional - Thumbnail *PhotoSize `json:"thumb,omitempty"` - // FileName is the original filename as defined by sender - // - // optional - FileName string `json:"file_name,omitempty"` - // MimeType of a file as defined by sender - // - // optional - MimeType string `json:"mime_type,omitempty"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// VideoNote object represents a video message. -type VideoNote struct { - // FileID identifier for this file, which can be used to download or reuse the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Length video width and height (diameter of the video message) as defined by sender - Length int `json:"length"` - // Duration of the video in seconds as defined by sender - Duration int `json:"duration"` - // Thumbnail video thumbnail - // - // optional - Thumbnail *PhotoSize `json:"thumb,omitempty"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// Voice represents a voice note. -type Voice struct { - // FileID identifier for this file, which can be used to download or reuse the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Duration of the audio in seconds as defined by sender - Duration int `json:"duration"` - // MimeType of the file as defined by sender - // - // optional - MimeType string `json:"mime_type,omitempty"` - // FileSize file size - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// Contact represents a phone contact. -// -// Note that LastName and UserID may be empty. -type Contact struct { - // PhoneNumber contact's phone number - PhoneNumber string `json:"phone_number"` - // FirstName contact's first name - FirstName string `json:"first_name"` - // LastName contact's last name - // - // optional - LastName string `json:"last_name,omitempty"` - // UserID contact's user identifier in Telegram - // - // optional - UserID int64 `json:"user_id,omitempty"` - // VCard is additional data about the contact in the form of a vCard. - // - // optional - VCard string `json:"vcard,omitempty"` -} - -// Dice represents an animated emoji that displays a random value. -type Dice struct { - // Emoji on which the dice throw animation is based - Emoji string `json:"emoji"` - // Value of the dice - Value int `json:"value"` -} - -// PollOption contains information about one answer option in a poll. -type PollOption struct { - // Text is the option text, 1-100 characters - Text string `json:"text"` - // VoterCount is the number of users that voted for this option - VoterCount int `json:"voter_count"` -} - -// PollAnswer represents an answer of a user in a non-anonymous poll. -type PollAnswer struct { - // PollID is the unique poll identifier - PollID string `json:"poll_id"` - // User who changed the answer to the poll - User User `json:"user"` - // OptionIDs is the 0-based identifiers of poll options chosen by the user. - // May be empty if user retracted vote. - OptionIDs []int `json:"option_ids"` -} - -// Poll contains information about a poll. -type Poll struct { - // ID is the unique poll identifier - ID string `json:"id"` - // Question is the poll question, 1-255 characters - Question string `json:"question"` - // Options is the list of poll options - Options []PollOption `json:"options"` - // TotalVoterCount is the total numbers of users who voted in the poll - TotalVoterCount int `json:"total_voter_count"` - // IsClosed is if the poll is closed - IsClosed bool `json:"is_closed"` - // IsAnonymous is if the poll is anonymous - IsAnonymous bool `json:"is_anonymous"` - // Type is the poll type, currently can be "regular" or "quiz" - Type string `json:"type"` - // AllowsMultipleAnswers is true, if the poll allows multiple answers - AllowsMultipleAnswers bool `json:"allows_multiple_answers"` - // CorrectOptionID is the 0-based identifier of the correct answer option. - // Available only for polls in quiz mode, which are closed, or was sent (not - // forwarded) by the bot or to the private chat with the bot. - // - // optional - CorrectOptionID int `json:"correct_option_id,omitempty"` - // Explanation is text that is shown when a user chooses an incorrect answer - // or taps on the lamp icon in a quiz-style poll, 0-200 characters - // - // optional - Explanation string `json:"explanation,omitempty"` - // ExplanationEntities are special entities like usernames, URLs, bot - // commands, etc. that appear in the explanation - // - // optional - ExplanationEntities []MessageEntity `json:"explanation_entities,omitempty"` - // OpenPeriod is the amount of time in seconds the poll will be active - // after creation - // - // optional - OpenPeriod int `json:"open_period,omitempty"` - // CloseDate is the point in time (unix timestamp) when the poll will be - // automatically closed - // - // optional - CloseDate int `json:"close_date,omitempty"` -} - -// Location represents a point on the map. -type Location struct { - // Longitude as defined by sender - Longitude float64 `json:"longitude"` - // Latitude as defined by sender - Latitude float64 `json:"latitude"` - // HorizontalAccuracy is the radius of uncertainty for the location, - // measured in meters; 0-1500 - // - // optional - HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` - // LivePeriod is time relative to the message sending date, during which the - // location can be updated, in seconds. For active live locations only. - // - // optional - LivePeriod int `json:"live_period,omitempty"` - // Heading is the direction in which user is moving, in degrees; 1-360. For - // active live locations only. - // - // optional - Heading int `json:"heading,omitempty"` - // ProximityAlertRadius is the maximum distance for proximity alerts about - // approaching another chat member, in meters. For sent live locations only. - // - // optional - ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` -} - -// Venue represents a venue. -type Venue struct { - // Location is the venue location - Location Location `json:"location"` - // Title is the name of the venue - Title string `json:"title"` - // Address of the venue - Address string `json:"address"` - // FoursquareID is the foursquare identifier of the venue - // - // optional - FoursquareID string `json:"foursquare_id,omitempty"` - // FoursquareType is the foursquare type of the venue - // - // optional - FoursquareType string `json:"foursquare_type,omitempty"` - // GooglePlaceID is the Google Places identifier of the venue - // - // optional - GooglePlaceID string `json:"google_place_id,omitempty"` - // GooglePlaceType is the Google Places type of the venue - // - // optional - GooglePlaceType string `json:"google_place_type,omitempty"` -} - -// ProximityAlertTriggered represents a service message sent when a user in the -// chat triggers a proximity alert sent by another user. -type ProximityAlertTriggered struct { - // Traveler is the user that triggered the alert - Traveler User `json:"traveler"` - // Watcher is the user that set the alert - Watcher User `json:"watcher"` - // Distance is the distance between the users - Distance int `json:"distance"` -} - -// MessageAutoDeleteTimerChanged represents a service message about a change in -// auto-delete timer settings. -type MessageAutoDeleteTimerChanged struct { - // New auto-delete time for messages in the chat. - MessageAutoDeleteTime int `json:"message_auto_delete_time"` -} - -// VoiceChatScheduled represents a service message about a voice chat scheduled -// in the chat. -type VoiceChatScheduled struct { - // Point in time (Unix timestamp) when the voice chat is supposed to be - // started by a chat administrator - StartDate int `json:"start_date"` -} - -// Time converts the scheduled start date into a Time. -func (m *VoiceChatScheduled) Time() time.Time { - return time.Unix(int64(m.StartDate), 0) -} - -// VoiceChatStarted represents a service message about a voice chat started in -// the chat. -type VoiceChatStarted struct{} - -// VoiceChatEnded represents a service message about a voice chat ended in the -// chat. -type VoiceChatEnded struct { - // Voice chat duration; in seconds. - Duration int `json:"duration"` -} - -// VoiceChatParticipantsInvited represents a service message about new members -// invited to a voice chat. -type VoiceChatParticipantsInvited struct { - // New members that were invited to the voice chat. - // - // optional - Users []User `json:"users"` -} - -// UserProfilePhotos contains a set of user profile photos. -type UserProfilePhotos struct { - // TotalCount total number of profile pictures the target user has - TotalCount int `json:"total_count"` - // Photos requested profile pictures (in up to 4 sizes each) - Photos [][]PhotoSize `json:"photos"` -} - -// File contains information about a file to download from Telegram. -type File struct { - // FileID identifier for this file, which can be used to download or reuse - // the file - FileID string `json:"file_id"` - // FileUniqueID is the unique identifier for this file, which is supposed to - // be the same over time and for different bots. Can't be used to download - // or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // FileSize file size, if known - // - // optional - FileSize int `json:"file_size,omitempty"` - // FilePath file path - // - // optional - FilePath string `json:"file_path,omitempty"` -} - -// Link returns a full path to the download URL for a File. -// -// It requires the Bot token to create the link. -func (f *File) Link(token string) string { - return fmt.Sprintf(FileEndpoint, token, f.FilePath) -} - -// ReplyKeyboardMarkup represents a custom keyboard with reply options. -type ReplyKeyboardMarkup struct { - // Keyboard is an array of button rows, each represented by an Array of KeyboardButton objects - Keyboard [][]KeyboardButton `json:"keyboard"` - // ResizeKeyboard requests clients to resize the keyboard vertically for optimal fit - // (e.g., make the keyboard smaller if there are just two rows of buttons). - // Defaults to false, in which case the custom keyboard - // is always of the same height as the app's standard keyboard. - // - // optional - ResizeKeyboard bool `json:"resize_keyboard,omitempty"` - // OneTimeKeyboard requests clients to hide the keyboard as soon as it's been used. - // The keyboard will still be available, but clients will automatically display - // the usual letter-keyboard in the chat – the user can press a special button - // in the input field to see the custom keyboard again. - // Defaults to false. - // - // optional - OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"` - // InputFieldPlaceholder is the placeholder to be shown in the input field when - // the keyboard is active; 1-64 characters. - // - // optional - InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` - // Selective use this parameter if you want to show the keyboard to specific users only. - // Targets: - // 1) users that are @mentioned in the text of the Message object; - // 2) if the bot's message is a reply (has Message.ReplyToMessage not nil), sender of the original message. - // - // Example: A user requests to change the bot's language, - // bot replies to the request with a keyboard to select the new language. - // Other users in the group don't see the keyboard. - // - // optional - Selective bool `json:"selective,omitempty"` -} - -// KeyboardButton represents one button of the reply keyboard. For simple text -// buttons String can be used instead of this object to specify text of the -// button. Optional fields request_contact, request_location, and request_poll -// are mutually exclusive. -type KeyboardButton struct { - // Text of the button. If none of the optional fields are used, - // it will be sent as a message when the button is pressed. - Text string `json:"text"` - // RequestContact if True, the user's phone number will be sent - // as a contact when the button is pressed. - // Available in private chats only. - // - // optional - RequestContact bool `json:"request_contact,omitempty"` - // RequestLocation if True, the user's current location will be sent when - // the button is pressed. - // Available in private chats only. - // - // optional - RequestLocation bool `json:"request_location,omitempty"` - // RequestPoll if True, the user will be asked to create a poll and send it - // to the bot when the button is pressed. Available in private chats only - // - // optional - RequestPoll *KeyboardButtonPollType `json:"request_poll,omitempty"` -} - -// KeyboardButtonPollType represents type of poll, which is allowed to -// be created and sent when the corresponding button is pressed. -type KeyboardButtonPollType struct { - // Type is if quiz is passed, the user will be allowed to create only polls - // in the quiz mode. If regular is passed, only regular polls will be - // allowed. Otherwise, the user will be allowed to create a poll of any type. - Type string `json:"type"` -} - -// ReplyKeyboardRemove Upon receiving a message with this object, Telegram -// clients will remove the current custom keyboard and display the default -// letter-keyboard. By default, custom keyboards are displayed until a new -// keyboard is sent by a bot. An exception is made for one-time keyboards -// that are hidden immediately after the user presses a button. -type ReplyKeyboardRemove struct { - // RemoveKeyboard requests clients to remove the custom keyboard - // (user will not be able to summon this keyboard; - // if you want to hide the keyboard from sight but keep it accessible, - // use one_time_keyboard in ReplyKeyboardMarkup). - RemoveKeyboard bool `json:"remove_keyboard"` - // Selective use this parameter if you want to remove the keyboard for specific users only. - // Targets: - // 1) users that are @mentioned in the text of the Message object; - // 2) if the bot's message is a reply (has Message.ReplyToMessage not nil), sender of the original message. - // - // Example: A user votes in a poll, bot returns confirmation message - // in reply to the vote and removes the keyboard for that user, - // while still showing the keyboard with poll options to users who haven't voted yet. - // - // optional - Selective bool `json:"selective,omitempty"` -} - -// InlineKeyboardMarkup represents an inline keyboard that appears right next to -// the message it belongs to. -type InlineKeyboardMarkup struct { - // InlineKeyboard array of button rows, each represented by an Array of - // InlineKeyboardButton objects - InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"` -} - -// InlineKeyboardButton represents one button of an inline keyboard. You must -// use exactly one of the optional fields. -// -// Note that some values are references as even an empty string -// will change behavior. -// -// CallbackGame, if set, MUST be first button in first row. -type InlineKeyboardButton struct { - // Text label text on the button - Text string `json:"text"` - // URL HTTP or tg:// url to be opened when button is pressed. - // - // optional - URL *string `json:"url,omitempty"` - // LoginURL is an HTTP URL used to automatically authorize the user. Can be - // used as a replacement for the Telegram Login Widget - // - // optional - LoginURL *LoginURL `json:"login_url,omitempty"` - // CallbackData data to be sent in a callback query to the bot when button is pressed, 1-64 bytes. - // - // optional - CallbackData *string `json:"callback_data,omitempty"` - // SwitchInlineQuery if set, pressing the button will prompt the user to select one of their chats, - // open that chat and insert the bot's username and the specified inline query in the input field. - // Can be empty, in which case just the bot's username will be inserted. - // - // This offers an easy way for users to start using your bot - // in inline mode when they are currently in a private chat with it. - // Especially useful when combined with switch_pm… actions – in this case - // the user will be automatically returned to the chat they switched from, - // skipping the chat selection screen. - // - // optional - SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` - // SwitchInlineQueryCurrentChat if set, pressing the button will insert the bot's username - // and the specified inline query in the current chat's input field. - // Can be empty, in which case only the bot's username will be inserted. - // - // This offers a quick way for the user to open your bot in inline mode - // in the same chat – good for selecting something from multiple options. - // - // optional - SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` - // CallbackGame description of the game that will be launched when the user presses the button. - // - // optional - CallbackGame *CallbackGame `json:"callback_game,omitempty"` - // Pay specify True, to send a Pay button. - // - // NOTE: This type of button must always be the first button in the first row. - // - // optional - Pay bool `json:"pay,omitempty"` -} - -// LoginURL represents a parameter of the inline keyboard button used to -// automatically authorize a user. Serves as a great replacement for the -// Telegram Login Widget when the user is coming from Telegram. All the user -// needs to do is tap/click a button and confirm that they want to log in. -type LoginURL struct { - // URL is an HTTP URL to be opened with user authorization data added to the - // query string when the button is pressed. If the user refuses to provide - // authorization data, the original URL without information about the user - // will be opened. The data added is the same as described in Receiving - // authorization data. - // - // NOTE: You must always check the hash of the received data to verify the - // authentication and the integrity of the data as described in Checking - // authorization. - URL string `json:"url"` - // ForwardText is the new text of the button in forwarded messages - // - // optional - ForwardText string `json:"forward_text,omitempty"` - // BotUsername is the username of a bot, which will be used for user - // authorization. See Setting up a bot for more details. If not specified, - // the current bot's username will be assumed. The url's domain must be the - // same as the domain linked with the bot. See Linking your domain to the - // bot for more details. - // - // optional - BotUsername string `json:"bot_username,omitempty"` - // RequestWriteAccess if true requests permission for your bot to send - // messages to the user - // - // optional - RequestWriteAccess bool `json:"request_write_access,omitempty"` -} - -// CallbackQuery represents an incoming callback query from a callback button in -// an inline keyboard. If the button that originated the query was attached to a -// message sent by the bot, the field message will be present. If the button was -// attached to a message sent via the bot (in inline mode), the field -// inline_message_id will be present. Exactly one of the fields data or -// game_short_name will be present. -type CallbackQuery struct { - // ID unique identifier for this query - ID string `json:"id"` - // From sender - From *User `json:"from"` - // Message with the callback button that originated the query. - // Note that message content and message date will not be available if the - // message is too old. - // - // optional - Message *Message `json:"message,omitempty"` - // InlineMessageID identifier of the message sent via the bot in inline - // mode, that originated the query. - // - // optional - InlineMessageID string `json:"inline_message_id,omitempty"` - // ChatInstance global identifier, uniquely corresponding to the chat to - // which the message with the callback button was sent. Useful for high - // scores in games. - ChatInstance string `json:"chat_instance"` - // Data associated with the callback button. Be aware that - // a bad client can send arbitrary data in this field. - // - // optional - Data string `json:"data,omitempty"` - // GameShortName short name of a Game to be returned, serves as the unique identifier for the game. - // - // optional - GameShortName string `json:"game_short_name,omitempty"` -} - -// ForceReply when receiving a message with this object, Telegram clients will -// display a reply interface to the user (act as if the user has selected the -// bot's message and tapped 'Reply'). This can be extremely useful if you want -// to create user-friendly step-by-step interfaces without having to sacrifice -// privacy mode. -type ForceReply struct { - // ForceReply shows reply interface to the user, - // as if they manually selected the bot's message and tapped 'Reply'. - ForceReply bool `json:"force_reply"` - // InputFieldPlaceholder is the placeholder to be shown in the input field when - // the reply is active; 1-64 characters. - // - // optional - InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` - // Selective use this parameter if you want to force reply from specific users only. - // Targets: - // 1) users that are @mentioned in the text of the Message object; - // 2) if the bot's message is a reply (has Message.ReplyToMessage not nil), sender of the original message. - // - // optional - Selective bool `json:"selective,omitempty"` -} - -// ChatPhoto represents a chat photo. -type ChatPhoto struct { - // SmallFileID is a file identifier of small (160x160) chat photo. - // This file_id can be used only for photo download and - // only for as long as the photo is not changed. - SmallFileID string `json:"small_file_id"` - // SmallFileUniqueID is a unique file identifier of small (160x160) chat - // photo, which is supposed to be the same over time and for different bots. - // Can't be used to download or reuse the file. - SmallFileUniqueID string `json:"small_file_unique_id"` - // BigFileID is a file identifier of big (640x640) chat photo. - // This file_id can be used only for photo download and - // only for as long as the photo is not changed. - BigFileID string `json:"big_file_id"` - // BigFileUniqueID is a file identifier of big (640x640) chat photo, which - // is supposed to be the same over time and for different bots. Can't be - // used to download or reuse the file. - BigFileUniqueID string `json:"big_file_unique_id"` -} - -// ChatInviteLink represents an invite link for a chat. -type ChatInviteLink struct { - // InviteLink is the invite link. If the link was created by another chat - // administrator, then the second part of the link will be replaced with “…”. - InviteLink string `json:"invite_link"` - // Creator of the link. - Creator User `json:"creator"` - // CreatesJoinRequest is true if users joining the chat via the link need to - // be approved by chat administrators. - // - // optional - CreatesJoinRequest bool `json:"creates_join_request"` - // IsPrimary is true, if the link is primary. - IsPrimary bool `json:"is_primary"` - // IsRevoked is true, if the link is revoked. - IsRevoked bool `json:"is_revoked"` - // Name is the name of the invite link. - // - // optional - Name string `json:"name"` - // ExpireDate is the point in time (Unix timestamp) when the link will - // expire or has been expired. - // - // optional - ExpireDate int `json:"expire_date"` - // MemberLimit is the maximum number of users that can be members of the - // chat simultaneously after joining the chat via this invite link; 1-99999. - // - // optional - MemberLimit int `json:"member_limit"` - // PendingJoinRequestCount is the number of pending join requests created - // using this link. - // - // optional - PendingJoinRequestCount int `json:"pending_join_request_count"` -} - -// ChatMember contains information about one member of a chat. -type ChatMember struct { - // User information about the user - User *User `json:"user"` - // Status the member's status in the chat. - // Can be - // “creator”, - // “administrator”, - // “member”, - // “restricted”, - // “left” or - // “kicked” - Status string `json:"status"` - // CustomTitle owner and administrators only. Custom title for this user - // - // optional - CustomTitle string `json:"custom_title,omitempty"` - // IsAnonymous owner and administrators only. True, if the user's presence - // in the chat is hidden - // - // optional - IsAnonymous bool `json:"is_anonymous"` - // UntilDate restricted and kicked only. - // Date when restrictions will be lifted for this user; - // unix time. - // - // optional - UntilDate int64 `json:"until_date,omitempty"` - // CanBeEdited administrators only. - // True, if the bot is allowed to edit administrator privileges of that user. - // - // optional - CanBeEdited bool `json:"can_be_edited,omitempty"` - // CanManageChat administrators only. - // True, if the administrator can access the chat event log, chat - // statistics, message statistics in channels, see channel members, see - // anonymous administrators in supergroups and ignore slow mode. Implied by - // any other administrator privilege. - // - // optional - CanManageChat bool `json:"can_manage_chat"` - // CanPostMessages administrators only. - // True, if the administrator can post in the channel; - // channels only. - // - // optional - CanPostMessages bool `json:"can_post_messages,omitempty"` - // CanEditMessages administrators only. - // True, if the administrator can edit messages of other users and can pin messages; - // channels only. - // - // optional - CanEditMessages bool `json:"can_edit_messages,omitempty"` - // CanDeleteMessages administrators only. - // True, if the administrator can delete messages of other users. - // - // optional - CanDeleteMessages bool `json:"can_delete_messages,omitempty"` - // CanManageVoiceChats administrators only. - // True, if the administrator can manage voice chats. - // - // optional - CanManageVoiceChats bool `json:"can_manage_voice_chats"` - // CanRestrictMembers administrators only. - // True, if the administrator can restrict, ban or unban chat members. - // - // optional - CanRestrictMembers bool `json:"can_restrict_members,omitempty"` - // CanPromoteMembers administrators only. - // True, if the administrator can add new administrators - // with a subset of their own privileges or demote administrators that he has promoted, - // directly or indirectly (promoted by administrators that were appointed by the user). - // - // optional - CanPromoteMembers bool `json:"can_promote_members,omitempty"` - // CanChangeInfo administrators and restricted only. - // True, if the user is allowed to change the chat title, photo and other settings. - // - // optional - CanChangeInfo bool `json:"can_change_info,omitempty"` - // CanInviteUsers administrators and restricted only. - // True, if the user is allowed to invite new users to the chat. - // - // optional - CanInviteUsers bool `json:"can_invite_users,omitempty"` - // CanPinMessages administrators and restricted only. - // True, if the user is allowed to pin messages; groups and supergroups only - // - // optional - CanPinMessages bool `json:"can_pin_messages,omitempty"` - // IsMember is true, if the user is a member of the chat at the moment of - // the request - IsMember bool `json:"is_member"` - // CanSendMessages - // - // optional - CanSendMessages bool `json:"can_send_messages,omitempty"` - // CanSendMediaMessages restricted only. - // True, if the user is allowed to send text messages, contacts, locations and venues - // - // optional - CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` - // CanSendPolls restricted only. - // True, if the user is allowed to send polls - // - // optional - CanSendPolls bool `json:"can_send_polls,omitempty"` - // CanSendOtherMessages restricted only. - // True, if the user is allowed to send audios, documents, - // photos, videos, video notes and voice notes. - // - // optional - CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` - // CanAddWebPagePreviews restricted only. - // True, if the user is allowed to add web page previews to their messages. - // - // optional - CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` -} - -// IsCreator returns if the ChatMember was the creator of the chat. -func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" } - -// IsAdministrator returns if the ChatMember is a chat administrator. -func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" } - -// HasLeft returns if the ChatMember left the chat. -func (chat ChatMember) HasLeft() bool { return chat.Status == "left" } - -// WasKicked returns if the ChatMember was kicked from the chat. -func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" } - -// ChatMemberUpdated represents changes in the status of a chat member. -type ChatMemberUpdated struct { - // Chat the user belongs to. - Chat Chat `json:"chat"` - // From is the performer of the action, which resulted in the change. - From User `json:"from"` - // Date the change was done in Unix time. - Date int `json:"date"` - // Previous information about the chat member. - OldChatMember ChatMember `json:"old_chat_member"` - // New information about the chat member. - NewChatMember ChatMember `json:"new_chat_member"` - // InviteLink is the link which was used by the user to join the chat; - // for joining by invite link events only. - // - // optional - InviteLink *ChatInviteLink `json:"invite_link"` -} - -// ChatJoinRequest represents a join request sent to a chat. -type ChatJoinRequest struct { - // Chat to which the request was sent. - Chat Chat `json:"chat"` - // User that sent the join request. - From User `json:"from"` - // Date the request was sent in Unix time. - Date int `json:"date"` - // Bio of the user. - // - // optional - Bio string `json:"bio"` - // InviteLink is the link that was used by the user to send the join request. - // - // optional - InviteLink *ChatInviteLink `json:"invite_link"` -} - -// ChatPermissions describes actions that a non-administrator user is -// allowed to take in a chat. All fields are optional. -type ChatPermissions struct { - // CanSendMessages is true, if the user is allowed to send text messages, - // contacts, locations and venues - // - // optional - CanSendMessages bool `json:"can_send_messages,omitempty"` - // CanSendMediaMessages is true, if the user is allowed to send audios, - // documents, photos, videos, video notes and voice notes, implies - // can_send_messages - // - // optional - CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` - // CanSendPolls is true, if the user is allowed to send polls, implies - // can_send_messages - // - // optional - CanSendPolls bool `json:"can_send_polls,omitempty"` - // CanSendOtherMessages is true, if the user is allowed to send animations, - // games, stickers and use inline bots, implies can_send_media_messages - // - // optional - CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` - // CanAddWebPagePreviews is true, if the user is allowed to add web page - // previews to their messages, implies can_send_media_messages - // - // optional - CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` - // CanChangeInfo is true, if the user is allowed to change the chat title, - // photo and other settings. Ignored in public supergroups - // - // optional - CanChangeInfo bool `json:"can_change_info,omitempty"` - // CanInviteUsers is true, if the user is allowed to invite new users to the - // chat - // - // optional - CanInviteUsers bool `json:"can_invite_users,omitempty"` - // CanPinMessages is true, if the user is allowed to pin messages. Ignored - // in public supergroups - // - // optional - CanPinMessages bool `json:"can_pin_messages,omitempty"` -} - -// ChatLocation represents a location to which a chat is connected. -type ChatLocation struct { - // Location is the location to which the supergroup is connected. Can't be a - // live location. - Location Location `json:"location"` - // Address is the location address; 1-64 characters, as defined by the chat - // owner - Address string `json:"address"` -} - -// BotCommand represents a bot command. -type BotCommand struct { - // Command text of the command, 1-32 characters. - // Can contain only lowercase English letters, digits and underscores. - Command string `json:"command"` - // Description of the command, 3-256 characters. - Description string `json:"description"` -} - -// BotCommandScope represents the scope to which bot commands are applied. -// -// It contains the fields for all types of scopes, different types only support -// specific (or no) fields. -type BotCommandScope struct { - Type string `json:"type"` - ChatID int64 `json:"chat_id,omitempty"` - UserID int64 `json:"user_id,omitempty"` -} - -// ResponseParameters are various errors that can be returned in APIResponse. -type ResponseParameters struct { - // The group has been migrated to a supergroup with the specified identifier. - // - // optional - MigrateToChatID int64 `json:"migrate_to_chat_id,omitempty"` - // In case of exceeding flood control, the number of seconds left to wait - // before the request can be repeated. - // - // optional - RetryAfter int `json:"retry_after,omitempty"` -} - -// BaseInputMedia is a base type for the InputMedia types. -type BaseInputMedia struct { - // Type of the result. - Type string `json:"type"` - // Media file to send. Pass a file_id to send a file - // that exists on the Telegram servers (recommended), - // pass an HTTP URL for Telegram to get a file from the Internet, - // or pass “attach://” to upload a new one - // using multipart/form-data under name. - Media RequestFileData `json:"media"` - // thumb intentionally missing as it is not currently compatible - - // Caption of the video to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities"` -} - -// InputMediaPhoto is a photo to send as part of a media group. -type InputMediaPhoto struct { - BaseInputMedia -} - -// InputMediaVideo is a video to send as part of a media group. -type InputMediaVideo struct { - BaseInputMedia - // Thumbnail of the file sent; can be ignored if thumbnail generation for - // the file is supported server-side. - // - // optional - Thumb RequestFileData `json:"thumb,omitempty"` - // Width video width - // - // optional - Width int `json:"width,omitempty"` - // Height video height - // - // optional - Height int `json:"height,omitempty"` - // Duration video duration - // - // optional - Duration int `json:"duration,omitempty"` - // SupportsStreaming pass True, if the uploaded video is suitable for streaming. - // - // optional - SupportsStreaming bool `json:"supports_streaming,omitempty"` -} - -// InputMediaAnimation is an animation to send as part of a media group. -type InputMediaAnimation struct { - BaseInputMedia - // Thumbnail of the file sent; can be ignored if thumbnail generation for - // the file is supported server-side. - // - // optional - Thumb RequestFileData `json:"thumb,omitempty"` - // Width video width - // - // optional - Width int `json:"width,omitempty"` - // Height video height - // - // optional - Height int `json:"height,omitempty"` - // Duration video duration - // - // optional - Duration int `json:"duration,omitempty"` -} - -// InputMediaAudio is an audio to send as part of a media group. -type InputMediaAudio struct { - BaseInputMedia - // Thumbnail of the file sent; can be ignored if thumbnail generation for - // the file is supported server-side. - // - // optional - Thumb RequestFileData `json:"thumb,omitempty"` - // Duration of the audio in seconds - // - // optional - Duration int `json:"duration,omitempty"` - // Performer of the audio - // - // optional - Performer string `json:"performer,omitempty"` - // Title of the audio - // - // optional - Title string `json:"title,omitempty"` -} - -// InputMediaDocument is a general file to send as part of a media group. -type InputMediaDocument struct { - BaseInputMedia - // Thumbnail of the file sent; can be ignored if thumbnail generation for - // the file is supported server-side. - // - // optional - Thumb RequestFileData `json:"thumb,omitempty"` - // DisableContentTypeDetection disables automatic server-side content type - // detection for files uploaded using multipart/form-data. Always true, if - // the document is sent as part of an album - // - // optional - DisableContentTypeDetection bool `json:"disable_content_type_detection,omitempty"` -} - -// Sticker represents a sticker. -type Sticker struct { - // FileID is an identifier for this file, which can be used to download or - // reuse the file - FileID string `json:"file_id"` - // FileUniqueID is a unique identifier for this file, - // which is supposed to be the same over time and for different bots. - // Can't be used to download or reuse the file. - FileUniqueID string `json:"file_unique_id"` - // Width sticker width - Width int `json:"width"` - // Height sticker height - Height int `json:"height"` - // IsAnimated true, if the sticker is animated - // - // optional - IsAnimated bool `json:"is_animated,omitempty"` - // Thumbnail sticker thumbnail in the .WEBP or .JPG format - // - // optional - Thumbnail *PhotoSize `json:"thumb,omitempty"` - // Emoji associated with the sticker - // - // optional - Emoji string `json:"emoji,omitempty"` - // SetName of the sticker set to which the sticker belongs - // - // optional - SetName string `json:"set_name,omitempty"` - // MaskPosition is for mask stickers, the position where the mask should be - // placed - // - // optional - MaskPosition *MaskPosition `json:"mask_position,omitempty"` - // FileSize - // - // optional - FileSize int `json:"file_size,omitempty"` -} - -// StickerSet represents a sticker set. -type StickerSet struct { - // Name sticker set name - Name string `json:"name"` - // Title sticker set title - Title string `json:"title"` - // IsAnimated true, if the sticker set contains animated stickers - IsAnimated bool `json:"is_animated"` - // ContainsMasks true, if the sticker set contains masks - ContainsMasks bool `json:"contains_masks"` - // Stickers list of all set stickers - Stickers []Sticker `json:"stickers"` - // Thumb is the sticker set thumbnail in the .WEBP or .TGS format - Thumbnail *PhotoSize `json:"thumb"` -} - -// MaskPosition describes the position on faces where a mask should be placed -// by default. -type MaskPosition struct { - // The part of the face relative to which the mask should be placed. - // One of “forehead”, “eyes”, “mouth”, or “chin”. - Point string `json:"point"` - // Shift by X-axis measured in widths of the mask scaled to the face size, - // from left to right. For example, choosing -1.0 will place mask just to - // the left of the default mask position. - XShift float64 `json:"x_shift"` - // Shift by Y-axis measured in heights of the mask scaled to the face size, - // from top to bottom. For example, 1.0 will place the mask just below the - // default mask position. - YShift float64 `json:"y_shift"` - // Mask scaling coefficient. For example, 2.0 means double size. - Scale float64 `json:"scale"` -} - -// Game represents a game. Use BotFather to create and edit games, their short -// names will act as unique identifiers. -type Game struct { - // Title of the game - Title string `json:"title"` - // Description of the game - Description string `json:"description"` - // Photo that will be displayed in the game message in chats. - Photo []PhotoSize `json:"photo"` - // Text a brief description of the game or high scores included in the game message. - // Can be automatically edited to include current high scores for the game - // when the bot calls setGameScore, or manually edited using editMessageText. 0-4096 characters. - // - // optional - Text string `json:"text,omitempty"` - // TextEntities special entities that appear in text, such as usernames, URLs, bot commands, etc. - // - // optional - TextEntities []MessageEntity `json:"text_entities,omitempty"` - // Animation is an animation that will be displayed in the game message in chats. - // Upload via BotFather (https://t.me/botfather). - // - // optional - Animation Animation `json:"animation,omitempty"` -} - -// GameHighScore is a user's score and position on the leaderboard. -type GameHighScore struct { - // Position in high score table for the game - Position int `json:"position"` - // User user - User User `json:"user"` - // Score score - Score int `json:"score"` -} - -// CallbackGame is for starting a game in an inline keyboard button. -type CallbackGame struct{} - -// WebhookInfo is information about a currently set webhook. -type WebhookInfo struct { - // URL webhook URL, may be empty if webhook is not set up. - URL string `json:"url"` - // HasCustomCertificate true, if a custom certificate was provided for webhook certificate checks. - HasCustomCertificate bool `json:"has_custom_certificate"` - // PendingUpdateCount number of updates awaiting delivery. - PendingUpdateCount int `json:"pending_update_count"` - // IPAddress is the currently used webhook IP address - // - // optional - IPAddress string `json:"ip_address,omitempty"` - // LastErrorDate unix time for the most recent error - // that happened when trying to deliver an update via webhook. - // - // optional - LastErrorDate int `json:"last_error_date,omitempty"` - // LastErrorMessage error message in human-readable format for the most recent error - // that happened when trying to deliver an update via webhook. - // - // optional - LastErrorMessage string `json:"last_error_message,omitempty"` - // MaxConnections maximum allowed number of simultaneous - // HTTPS connections to the webhook for update delivery. - // - // optional - MaxConnections int `json:"max_connections,omitempty"` - // AllowedUpdates is a list of update types the bot is subscribed to. - // Defaults to all update types - // - // optional - AllowedUpdates []string `json:"allowed_updates,omitempty"` -} - -// IsSet returns true if a webhook is currently set. -func (info WebhookInfo) IsSet() bool { - return info.URL != "" -} - -// InlineQuery is a Query from Telegram for an inline request. -type InlineQuery struct { - // ID unique identifier for this query - ID string `json:"id"` - // From sender - From *User `json:"from"` - // Query text of the query (up to 256 characters). - Query string `json:"query"` - // Offset of the results to be returned, can be controlled by the bot. - Offset string `json:"offset"` - // Type of the chat, from which the inline query was sent. Can be either - // “sender” for a private chat with the inline query sender, “private”, - // “group”, “supergroup”, or “channel”. The chat type should be always known - // for requests sent from official clients and most third-party clients, - // unless the request was sent from a secret chat - // - // optional - ChatType string `json:"chat_type"` - // Location sender location, only for bots that request user location. - // - // optional - Location *Location `json:"location,omitempty"` -} - -// InlineQueryResultCachedAudio is an inline query response with cached audio. -type InlineQueryResultCachedAudio struct { - // Type of the result, must be audio - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // AudioID a valid file identifier for the audio file - AudioID string `json:"audio_file_id"` - // Caption 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the audio - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedDocument is an inline query response with cached document. -type InlineQueryResultCachedDocument struct { - // Type of the result, must be a document - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // DocumentID a valid file identifier for the file - DocumentID string `json:"document_file_id"` - // Title for the result - // - // optional - Title string `json:"title,omitempty"` - // Caption of the document to be sent, 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // Description short description of the result - // - // optional - Description string `json:"description,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // // See formatting options for more details - // // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the file - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedGIF is an inline query response with cached gif. -type InlineQueryResultCachedGIF struct { - // Type of the result, must be gif. - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes. - ID string `json:"id"` - // GifID a valid file identifier for the GIF file. - GIFID string `json:"gif_file_id"` - // Title for the result - // - // optional - Title string `json:"title,omitempty"` - // Caption of the GIF file to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message. - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the GIF animation. - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedMPEG4GIF is an inline query response with cached -// H.264/MPEG-4 AVC video without sound gif. -type InlineQueryResultCachedMPEG4GIF struct { - // Type of the result, must be mpeg4_gif - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // MPEG4FileID a valid file identifier for the MP4 file - MPEG4FileID string `json:"mpeg4_file_id"` - // Title for the result - // - // optional - Title string `json:"title,omitempty"` - // Caption of the MPEG-4 file to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message. - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the video animation. - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedPhoto is an inline query response with cached photo. -type InlineQueryResultCachedPhoto struct { - // Type of the result, must be a photo. - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes. - ID string `json:"id"` - // PhotoID a valid file identifier of the photo. - PhotoID string `json:"photo_file_id"` - // Title for the result. - // - // optional - Title string `json:"title,omitempty"` - // Description short description of the result. - // - // optional - Description string `json:"description,omitempty"` - // Caption of the photo to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the photo caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message. - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the photo. - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedSticker is an inline query response with cached sticker. -type InlineQueryResultCachedSticker struct { - // Type of the result, must be a sticker - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // StickerID a valid file identifier of the sticker - StickerID string `json:"sticker_file_id"` - // Title is a title - Title string `json:"title"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the sticker - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedVideo is an inline query response with cached video. -type InlineQueryResultCachedVideo struct { - // Type of the result, must be video - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // VideoID a valid file identifier for the video file - VideoID string `json:"video_file_id"` - // Title for the result - Title string `json:"title"` - // Description short description of the result - // - // optional - Description string `json:"description,omitempty"` - // Caption of the video to be sent, 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the video - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultCachedVoice is an inline query response with cached voice. -type InlineQueryResultCachedVoice struct { - // Type of the result, must be voice - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // VoiceID a valid file identifier for the voice message - VoiceID string `json:"voice_file_id"` - // Title voice message title - Title string `json:"title"` - // Caption 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the voice message - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultArticle represents a link to an article or web page. -type InlineQueryResultArticle struct { - // Type of the result, must be article. - Type string `json:"type"` - // ID unique identifier for this result, 1-64 Bytes. - ID string `json:"id"` - // Title of the result - Title string `json:"title"` - // InputMessageContent content of the message to be sent. - InputMessageContent interface{} `json:"input_message_content,omitempty"` - // ReplyMarkup Inline keyboard attached to the message. - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // URL of the result. - // - // optional - URL string `json:"url,omitempty"` - // HideURL pass True, if you don't want the URL to be shown in the message. - // - // optional - HideURL bool `json:"hide_url,omitempty"` - // Description short description of the result. - // - // optional - Description string `json:"description,omitempty"` - // ThumbURL url of the thumbnail for the result - // - // optional - ThumbURL string `json:"thumb_url,omitempty"` - // ThumbWidth thumbnail width - // - // optional - ThumbWidth int `json:"thumb_width,omitempty"` - // ThumbHeight thumbnail height - // - // optional - ThumbHeight int `json:"thumb_height,omitempty"` -} - -// InlineQueryResultAudio is an inline query response audio. -type InlineQueryResultAudio struct { - // Type of the result, must be audio - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // URL a valid url for the audio file - URL string `json:"audio_url"` - // Title is a title - Title string `json:"title"` - // Caption 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Performer is a performer - // - // optional - Performer string `json:"performer,omitempty"` - // Duration audio duration in seconds - // - // optional - Duration int `json:"audio_duration,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the audio - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultContact is an inline query response contact. -type InlineQueryResultContact struct { - Type string `json:"type"` // required - ID string `json:"id"` // required - PhoneNumber string `json:"phone_number"` // required - FirstName string `json:"first_name"` // required - LastName string `json:"last_name"` - VCard string `json:"vcard"` - 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 of the result, must be game - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // GameShortName short name of the game - GameShortName string `json:"game_short_name"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` -} - -// InlineQueryResultDocument is an inline query response document. -type InlineQueryResultDocument struct { - // Type of the result, must be a document - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // Title for the result - Title string `json:"title"` - // Caption of the document to be sent, 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // URL a valid url for the file - URL string `json:"document_url"` - // MimeType of the content of the file, either “application/pdf” or “application/zip” - MimeType string `json:"mime_type"` - // Description short description of the result - // - // optional - Description string `json:"description,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the file - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` - // ThumbURL url of the thumbnail (jpeg only) for the file - // - // optional - ThumbURL string `json:"thumb_url,omitempty"` - // ThumbWidth thumbnail width - // - // optional - ThumbWidth int `json:"thumb_width,omitempty"` - // ThumbHeight thumbnail height - // - // optional - ThumbHeight int `json:"thumb_height,omitempty"` -} - -// InlineQueryResultGIF is an inline query response GIF. -type InlineQueryResultGIF struct { - // Type of the result, must be gif. - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes. - ID string `json:"id"` - // URL a valid URL for the GIF file. File size must not exceed 1MB. - URL string `json:"gif_url"` - // ThumbURL url of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result. - ThumbURL string `json:"thumb_url"` - // Width of the GIF - // - // optional - Width int `json:"gif_width,omitempty"` - // Height of the GIF - // - // optional - Height int `json:"gif_height,omitempty"` - // Duration of the GIF - // - // optional - Duration int `json:"gif_duration,omitempty"` - // Title for the result - // - // optional - Title string `json:"title,omitempty"` - // Caption of the GIF file to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the GIF animation. - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultLocation is an inline query response location. -type InlineQueryResultLocation struct { - // Type of the result, must be location - Type string `json:"type"` - // ID unique identifier for this result, 1-64 Bytes - ID string `json:"id"` - // Latitude of the location in degrees - Latitude float64 `json:"latitude"` - // Longitude of the location in degrees - Longitude float64 `json:"longitude"` - // Title of the location - Title string `json:"title"` - // HorizontalAccuracy is the radius of uncertainty for the location, - // measured in meters; 0-1500 - // - // optional - HorizontalAccuracy float64 `json:"horizontal_accuracy"` - // LivePeriod is the period in seconds for which the location can be - // updated, should be between 60 and 86400. - // - // optional - LivePeriod int `json:"live_period"` - // Heading is for live locations, a direction in which the user is moving, - // in degrees. Must be between 1 and 360 if specified. - // - // optional - Heading int `json:"heading"` - // ProximityAlertRadius is for live locations, a maximum distance for - // proximity alerts about approaching another chat member, in meters. Must - // be between 1 and 100000 if specified. - // - // optional - ProximityAlertRadius int `json:"proximity_alert_radius"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the location - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` - // ThumbURL url of the thumbnail for the result - // - // optional - ThumbURL string `json:"thumb_url,omitempty"` - // ThumbWidth thumbnail width - // - // optional - ThumbWidth int `json:"thumb_width,omitempty"` - // ThumbHeight thumbnail height - // - // optional - ThumbHeight int `json:"thumb_height,omitempty"` -} - -// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF. -type InlineQueryResultMPEG4GIF struct { - // Type of the result, must be mpeg4_gif - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // URL a valid URL for the MP4 file. File size must not exceed 1MB - URL string `json:"mpeg4_url"` - // Width video width - // - // optional - Width int `json:"mpeg4_width"` - // Height vVideo height - // - // optional - Height int `json:"mpeg4_height"` - // Duration video duration - // - // optional - Duration int `json:"mpeg4_duration"` - // ThumbURL url of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result. - ThumbURL string `json:"thumb_url"` - // Title for the result - // - // optional - Title string `json:"title,omitempty"` - // Caption of the MPEG-4 file to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the video animation - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultPhoto is an inline query response photo. -type InlineQueryResultPhoto struct { - // Type of the result, must be article. - Type string `json:"type"` - // ID unique identifier for this result, 1-64 Bytes. - ID string `json:"id"` - // URL a valid URL of the photo. Photo must be in jpeg format. - // Photo size must not exceed 5MB. - URL string `json:"photo_url"` - // MimeType - MimeType string `json:"mime_type"` - // Width of the photo - // - // optional - Width int `json:"photo_width,omitempty"` - // Height of the photo - // - // optional - Height int `json:"photo_height,omitempty"` - // ThumbURL url of the thumbnail for the photo. - // - // optional - ThumbURL string `json:"thumb_url,omitempty"` - // Title for the result - // - // optional - Title string `json:"title,omitempty"` - // Description short description of the result - // - // optional - Description string `json:"description,omitempty"` - // Caption of the photo to be sent, 0-1024 characters after entities parsing. - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the photo caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // ReplyMarkup inline keyboard attached to the message. - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // InputMessageContent content of the message to be sent instead of the photo. - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultVenue is an inline query response venue. -type InlineQueryResultVenue struct { - // Type of the result, must be venue - Type string `json:"type"` - // ID unique identifier for this result, 1-64 Bytes - ID string `json:"id"` - // Latitude of the venue location in degrees - Latitude float64 `json:"latitude"` - // Longitude of the venue location in degrees - Longitude float64 `json:"longitude"` - // Title of the venue - Title string `json:"title"` - // Address of the venue - Address string `json:"address"` - // FoursquareID foursquare identifier of the venue if known - // - // optional - FoursquareID string `json:"foursquare_id,omitempty"` - // FoursquareType foursquare type of the venue, if known. - // (For example, “arts_entertainment/default”, “arts_entertainment/aquarium” or “food/icecream”.) - // - // optional - FoursquareType string `json:"foursquare_type,omitempty"` - // GooglePlaceID is the Google Places identifier of the venue - // - // optional - GooglePlaceID string `json:"google_place_id,omitempty"` - // GooglePlaceType is the Google Places type of the venue - // - // optional - GooglePlaceType string `json:"google_place_type,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the venue - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` - // ThumbURL url of the thumbnail for the result - // - // optional - ThumbURL string `json:"thumb_url,omitempty"` - // ThumbWidth thumbnail width - // - // optional - ThumbWidth int `json:"thumb_width,omitempty"` - // ThumbHeight thumbnail height - // - // optional - ThumbHeight int `json:"thumb_height,omitempty"` -} - -// InlineQueryResultVideo is an inline query response video. -type InlineQueryResultVideo struct { - // Type of the result, must be video - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // URL a valid url for the embedded video player or video file - URL string `json:"video_url"` - // MimeType of the content of video url, “text/html” or “video/mp4” - MimeType string `json:"mime_type"` - // - // ThumbURL url of the thumbnail (jpeg only) for the video - // optional - ThumbURL string `json:"thumb_url,omitempty"` - // Title for the result - Title string `json:"title"` - // Caption of the video to be sent, 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // Width video width - // - // optional - Width int `json:"video_width,omitempty"` - // Height video height - // - // optional - Height int `json:"video_height,omitempty"` - // Duration video duration in seconds - // - // optional - Duration int `json:"video_duration,omitempty"` - // Description short description of the result - // - // optional - Description string `json:"description,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the video. - // This field is required if InlineQueryResultVideo is used to send - // an HTML-page as a result (e.g., a YouTube video). - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// InlineQueryResultVoice is an inline query response voice. -type InlineQueryResultVoice struct { - // Type of the result, must be voice - Type string `json:"type"` - // ID unique identifier for this result, 1-64 bytes - ID string `json:"id"` - // URL a valid URL for the voice recording - URL string `json:"voice_url"` - // Title recording title - Title string `json:"title"` - // Caption 0-1024 characters after entities parsing - // - // optional - Caption string `json:"caption,omitempty"` - // ParseMode mode for parsing entities in the video caption. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // CaptionEntities is a list of special entities that appear in the caption, - // which can be specified instead of parse_mode - // - // optional - CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Duration recording duration in seconds - // - // optional - Duration int `json:"voice_duration,omitempty"` - // ReplyMarkup inline keyboard attached to the message - // - // optional - ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` - // InputMessageContent content of the message to be sent instead of the voice recording - // - // optional - InputMessageContent interface{} `json:"input_message_content,omitempty"` -} - -// ChosenInlineResult is an inline query result chosen by a User -type ChosenInlineResult struct { - // ResultID the unique identifier for the result that was chosen - ResultID string `json:"result_id"` - // From the user that chose the result - From *User `json:"from"` - // Location sender location, only for bots that require user location - // - // optional - Location *Location `json:"location,omitempty"` - // InlineMessageID identifier of the sent inline message. - // Available only if there is an inline keyboard attached to the message. - // Will be also received in callback queries and can be used to edit the message. - // - // optional - InlineMessageID string `json:"inline_message_id,omitempty"` - // Query the query that was used to obtain the result - Query string `json:"query"` -} - -// InputTextMessageContent contains text for displaying -// as an inline query result. -type InputTextMessageContent struct { - // Text of the message to be sent, 1-4096 characters - Text string `json:"message_text"` - // ParseMode mode for parsing entities in the message text. - // See formatting options for more details - // (https://core.telegram.org/bots/api#formatting-options). - // - // optional - ParseMode string `json:"parse_mode,omitempty"` - // Entities is a list of special entities that appear in message text, which - // can be specified instead of parse_mode - // - // optional - Entities []MessageEntity `json:"entities,omitempty"` - // DisableWebPagePreview disables link previews for links in the sent message - // - // optional - DisableWebPagePreview bool `json:"disable_web_page_preview,omitempty"` -} - -// InputLocationMessageContent contains a location for displaying -// as an inline query result. -type InputLocationMessageContent struct { - // Latitude of the location in degrees - Latitude float64 `json:"latitude"` - // Longitude of the location in degrees - Longitude float64 `json:"longitude"` - // HorizontalAccuracy is the radius of uncertainty for the location, - // measured in meters; 0-1500 - // - // optional - HorizontalAccuracy float64 `json:"horizontal_accuracy"` - // LivePeriod is the period in seconds for which the location can be - // updated, should be between 60 and 86400 - // - // optional - LivePeriod int `json:"live_period,omitempty"` - // Heading is for live locations, a direction in which the user is moving, - // in degrees. Must be between 1 and 360 if specified. - // - // optional - Heading int `json:"heading"` - // ProximityAlertRadius is for live locations, a maximum distance for - // proximity alerts about approaching another chat member, in meters. Must - // be between 1 and 100000 if specified. - // - // optional - ProximityAlertRadius int `json:"proximity_alert_radius"` -} - -// InputVenueMessageContent contains a venue for displaying -// as an inline query result. -type InputVenueMessageContent struct { - // Latitude of the venue in degrees - Latitude float64 `json:"latitude"` - // Longitude of the venue in degrees - Longitude float64 `json:"longitude"` - // Title name of the venue - Title string `json:"title"` - // Address of the venue - Address string `json:"address"` - // FoursquareID foursquare identifier of the venue, if known - // - // optional - FoursquareID string `json:"foursquare_id,omitempty"` - // FoursquareType Foursquare type of the venue, if known - // - // optional - FoursquareType string `json:"foursquare_type,omitempty"` - // GooglePlaceID is the Google Places identifier of the venue - // - // optional - GooglePlaceID string `json:"google_place_id"` - // GooglePlaceType is the Google Places type of the venue - // - // optional - GooglePlaceType string `json:"google_place_type"` -} - -// InputContactMessageContent contains a contact for displaying -// as an inline query result. -type InputContactMessageContent struct { - // PhoneNumber contact's phone number - PhoneNumber string `json:"phone_number"` - // FirstName contact's first name - FirstName string `json:"first_name"` - // LastName contact's last name - // - // optional - LastName string `json:"last_name,omitempty"` - // Additional data about the contact in the form of a vCard - // - // optional - VCard string `json:"vcard,omitempty"` -} - -// InputInvoiceMessageContent represents the content of an invoice message to be -// sent as the result of an inline query. -type InputInvoiceMessageContent struct { - // Product name, 1-32 characters - Title string `json:"title"` - // Product description, 1-255 characters - Description string `json:"description"` - // Bot-defined invoice payload, 1-128 bytes. This will not be displayed to - // the user, use for your internal processes. - Payload string `json:"payload"` - // Payment provider token, obtained via Botfather - ProviderToken string `json:"provider_token"` - // Three-letter ISO 4217 currency code - Currency string `json:"currency"` - // Price breakdown, a JSON-serialized list of components (e.g. product - // price, tax, discount, delivery cost, delivery tax, bonus, etc.) - Prices []LabeledPrice `json:"prices"` - // The maximum accepted amount for tips in the smallest units of the - // currency (integer, not float/double). - // - // optional - MaxTipAmount int `json:"max_tip_amount,omitempty"` - // An array of suggested amounts of tip in the smallest units of the - // currency (integer, not float/double). At most 4 suggested tip amounts can - // be specified. The suggested tip amounts must be positive, passed in a - // strictly increased order and must not exceed max_tip_amount. - // - // optional - SuggestedTipAmounts []int `json:"suggested_tip_amounts,omitempty"` - // A JSON-serialized object for data about the invoice, which will be shared - // with the payment provider. A detailed description of the required fields - // should be provided by the payment provider. - // - // optional - ProviderData string `json:"provider_data,omitempty"` - // URL of the product photo for the invoice. Can be a photo of the goods or - // a marketing image for a service. People like it better when they see what - // they are paying for. - // - // optional - PhotoURL string `json:"photo_url,omitempty"` - // Photo size - // - // optional - PhotoSize int `json:"photo_size,omitempty"` - // Photo width - // - // optional - PhotoWidth int `json:"photo_width,omitempty"` - // Photo height - // - // optional - PhotoHeight int `json:"photo_height,omitempty"` - // Pass True, if you require the user's full name to complete the order - // - // optional - NeedName bool `json:"need_name,omitempty"` - // Pass True, if you require the user's phone number to complete the order - // - // optional - NeedPhoneNumber bool `json:"need_phone_number,omitempty"` - // Pass True, if you require the user's email address to complete the order - // - // optional - NeedEmail bool `json:"need_email,omitempty"` - // Pass True, if you require the user's shipping address to complete the order - // - // optional - NeedShippingAddress bool `json:"need_shipping_address,omitempty"` - // Pass True, if user's phone number should be sent to provider - // - // optional - SendPhoneNumberToProvider bool `json:"send_phone_number_to_provider,omitempty"` - // Pass True, if user's email address should be sent to provider - // - // optional - SendEmailToProvider bool `json:"send_email_to_provider,omitempty"` - // Pass True, if the final price depends on the shipping method - // - // optional - IsFlexible bool `json:"is_flexible,omitempty"` -} - -// LabeledPrice represents a portion of the price for goods or services. -type LabeledPrice struct { - // Label portion label - Label string `json:"label"` - // Amount price of the product in the smallest units of the currency (integer, not float/double). - // For example, for a price of US$ 1.45 pass amount = 145. - // See the exp parameter in currencies.json - // (https://core.telegram.org/bots/payments/currencies.json), - // it shows the number of digits past the decimal point - // for each currency (2 for the majority of currencies). - Amount int `json:"amount"` -} - -// Invoice contains basic information about an invoice. -type Invoice struct { - // Title product name - Title string `json:"title"` - // Description product description - Description string `json:"description"` - // StartParameter unique bot deep-linking parameter that can be used to generate this invoice - StartParameter string `json:"start_parameter"` - // Currency three-letter ISO 4217 currency code - // (see https://core.telegram.org/bots/payments#supported-currencies) - Currency string `json:"currency"` - // TotalAmount total price in the smallest units of the currency (integer, not float/double). - // For example, for a price of US$ 1.45 pass amount = 145. - // See the exp parameter in currencies.json - // (https://core.telegram.org/bots/payments/currencies.json), - // it shows the number of digits past the decimal point - // for each currency (2 for the majority of currencies). - TotalAmount int `json:"total_amount"` -} - -// ShippingAddress represents a shipping address. -type ShippingAddress struct { - // CountryCode ISO 3166-1 alpha-2 country code - CountryCode string `json:"country_code"` - // State if applicable - State string `json:"state"` - // City city - City string `json:"city"` - // StreetLine1 first line for the address - StreetLine1 string `json:"street_line1"` - // StreetLine2 second line for the address - StreetLine2 string `json:"street_line2"` - // PostCode address post code - PostCode string `json:"post_code"` -} - -// OrderInfo represents information about an order. -type OrderInfo struct { - // Name user name - // - // optional - Name string `json:"name,omitempty"` - // PhoneNumber user's phone number - // - // optional - PhoneNumber string `json:"phone_number,omitempty"` - // Email user email - // - // optional - Email string `json:"email,omitempty"` - // ShippingAddress user shipping address - // - // optional - ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` -} - -// ShippingOption represents one shipping option. -type ShippingOption struct { - // ID shipping option identifier - ID string `json:"id"` - // Title option title - Title string `json:"title"` - // Prices list of price portions - Prices []LabeledPrice `json:"prices"` -} - -// SuccessfulPayment contains basic information about a successful payment. -type SuccessfulPayment struct { - // Currency three-letter ISO 4217 currency code - // (see https://core.telegram.org/bots/payments#supported-currencies) - Currency string `json:"currency"` - // TotalAmount total price in the smallest units of the currency (integer, not float/double). - // For example, for a price of US$ 1.45 pass amount = 145. - // See the exp parameter in currencies.json, - // (https://core.telegram.org/bots/payments/currencies.json) - // it shows the number of digits past the decimal point - // for each currency (2 for the majority of currencies). - TotalAmount int `json:"total_amount"` - // InvoicePayload bot specified invoice payload - InvoicePayload string `json:"invoice_payload"` - // ShippingOptionID identifier of the shipping option chosen by the user - // - // optional - ShippingOptionID string `json:"shipping_option_id,omitempty"` - // OrderInfo order info provided by the user - // - // optional - OrderInfo *OrderInfo `json:"order_info,omitempty"` - // TelegramPaymentChargeID telegram payment identifier - TelegramPaymentChargeID string `json:"telegram_payment_charge_id"` - // ProviderPaymentChargeID provider payment identifier - ProviderPaymentChargeID string `json:"provider_payment_charge_id"` -} - -// ShippingQuery contains information about an incoming shipping query. -type ShippingQuery struct { - // ID unique query identifier - ID string `json:"id"` - // From user who sent the query - From *User `json:"from"` - // InvoicePayload bot specified invoice payload - InvoicePayload string `json:"invoice_payload"` - // ShippingAddress user specified shipping address - ShippingAddress *ShippingAddress `json:"shipping_address"` -} - -// PreCheckoutQuery contains information about an incoming pre-checkout query. -type PreCheckoutQuery struct { - // ID unique query identifier - ID string `json:"id"` - // From user who sent the query - From *User `json:"from"` - // Currency three-letter ISO 4217 currency code - // // (see https://core.telegram.org/bots/payments#supported-currencies) - Currency string `json:"currency"` - // TotalAmount total price in the smallest units of the currency (integer, not float/double). - // // For example, for a price of US$ 1.45 pass amount = 145. - // // See the exp parameter in currencies.json, - // // (https://core.telegram.org/bots/payments/currencies.json) - // // it shows the number of digits past the decimal point - // // for each currency (2 for the majority of currencies). - TotalAmount int `json:"total_amount"` - // InvoicePayload bot specified invoice payload - InvoicePayload string `json:"invoice_payload"` - // ShippingOptionID identifier of the shipping option chosen by the user - // - // optional - ShippingOptionID string `json:"shipping_option_id,omitempty"` - // OrderInfo order info provided by the user - // - // optional - OrderInfo *OrderInfo `json:"order_info,omitempty"` -} diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/.gitignore b/vendor/github.com/matterbridge/telegram-bot-api/v6/.gitignore new file mode 100644 index 00000000..d3083e5f --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/.gitignore @@ -0,0 +1,5 @@ +.idea/ +coverage.out +tmp/ +book/ +.vscode/ diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/LICENSE.txt b/vendor/github.com/matterbridge/telegram-bot-api/v6/LICENSE.txt new file mode 100644 index 00000000..b1fef93b --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Syfaro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/README.md b/vendor/github.com/matterbridge/telegram-bot-api/v6/README.md new file mode 100644 index 00000000..b18d15dd --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/README.md @@ -0,0 +1,121 @@ +# Golang bindings for the Telegram Bot API + +[![Go Reference](https://pkg.go.dev/badge/github.com/go-telegram-bot-api/telegram-bot-api/v5.svg)](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) +[![Test](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml/badge.svg)](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml) + +All methods are fairly self-explanatory, and reading the [godoc](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) page should +explain everything. If something isn't clear, open an issue or submit +a pull request. + +There are more tutorials and high-level information on the website, [go-telegram-bot-api.dev](https://go-telegram-bot-api.dev). + +The scope of this project is just to provide a wrapper around the API +without any additional features. There are other projects for creating +something with plugins and command handlers without having to design +all that yourself. + +Join [the development group](https://telegram.me/go_telegram_bot_api) if +you want to ask questions or discuss development. + +## Example + +First, ensure the library is installed and up to date by running +`go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5`. + +This is a very simple bot that just displays any gotten updates, +then replies it to that chat. + +```go +package main + +import ( + "log" + + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +func main() { + bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") + if err != nil { + log.Panic(err) + } + + bot.Debug = true + + log.Printf("Authorized on account %s", bot.Self.UserName) + + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 + + updates := bot.GetUpdatesChan(u) + + for update := range updates { + if update.Message != nil { // If we got a message + log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) + msg.ReplyToMessageID = update.Message.MessageID + + bot.Send(msg) + } + } +} +``` + +If you need to use webhooks (if you wish to run on Google App Engine), +you may use a slightly different method. + +```go +package main + +import ( + "log" + "net/http" + + "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +func main() { + bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") + if err != nil { + log.Fatal(err) + } + + bot.Debug = true + + log.Printf("Authorized on account %s", bot.Self.UserName) + + wh, _ := tgbotapi.NewWebhookWithCert("https://www.example.com:8443/"+bot.Token, "cert.pem") + + _, err = bot.Request(wh) + 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) + } + + updates := bot.ListenForWebhook("/" + bot.Token) + go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil) + + for update := range updates { + log.Printf("%+v\n", update) + } +} +``` + +If you need, you may generate a self-signed certificate, as this requires +HTTPS / TLS. The above example tells Telegram that this is your +certificate and that it should be trusted, even though it is not +properly signed. + + openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3560 -subj "//O=Org\CN=Test" -nodes + +Now that [Let's Encrypt](https://letsencrypt.org) is available, +you may wish to generate your free TLS certificate there. diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/book.toml b/vendor/github.com/matterbridge/telegram-bot-api/v6/book.toml new file mode 100644 index 00000000..841d5ba6 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/book.toml @@ -0,0 +1,9 @@ +[book] +authors = ["Syfaro"] +language = "en" +multilingual = false +src = "docs" +title = "Go Telegram Bot API" + +[output.html] +git-repository-url = "https://github.com/go-telegram-bot-api/telegram-bot-api" diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/bot.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/bot.go new file mode 100644 index 00000000..39037b8d --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/bot.go @@ -0,0 +1,748 @@ +// Package tgbotapi has functions and types used for interacting with +// the Telegram Bot API. +package tgbotapi + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "strings" + "time" +) + +// HTTPClient is the type needed for the bot to perform HTTP requests. +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 HTTPClient `json:"-"` + shutdownChannel chan interface{} + + apiEndpoint string +} + +// NewBotAPI creates a new BotAPI instance. +// +// It requires a token, provided by @BotFather on Telegram. +func NewBotAPI(token string) (*BotAPI, error) { + 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 and API endpoint. +func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) { + bot := &BotAPI{ + Token: token, + Client: client, + Buffer: 100, + shutdownChannel: make(chan interface{}), + + apiEndpoint: apiEndpoint, + } + + self, err := bot.GetMe() + if err != nil { + return nil, err + } + + bot.Self = self + + return bot, nil +} + +// SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance. +func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) { + bot.apiEndpoint = apiEndpoint +} + +func buildParams(in Params) url.Values { + if in == nil { + return url.Values{} + } + + out := url.Values{} + + for key, value := range in { + out.Set(key, value) + } + + return out +} + +// MakeRequest makes a request to a specific endpoint with our token. +func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) { + if bot.Debug { + log.Printf("Endpoint: %s, params: %v\n", endpoint, params) + } + + method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) + + values := buildParams(params) + + req, err := http.NewRequest("POST", method, strings.NewReader(values.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 nil, err + } + defer resp.Body.Close() + + var apiResp APIResponse + bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) + if err != nil { + return &apiResp, err + } + + if bot.Debug { + log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) + } + + if !apiResp.Ok { + var parameters ResponseParameters + + if apiResp.Parameters != nil { + parameters = *apiResp.Parameters + } + + return &apiResp, &Error{ + Code: apiResp.ErrorCode, + Message: apiResp.Description, + ResponseParameters: parameters, + } + } + + return &apiResp, nil +} + +// decodeAPIResponse decode response and return slice of bytes if debug enabled. +// If debug disabled, just decode http.Response.Body stream to APIResponse struct +// for efficient memory usage +func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) ([]byte, error) { + if !bot.Debug { + dec := json.NewDecoder(responseBody) + err := dec.Decode(resp) + return nil, err + } + + // if debug, read response body + data, err := io.ReadAll(responseBody) + if err != nil { + return nil, err + } + + err = json.Unmarshal(data, resp) + if err != nil { + return nil, err + } + + return data, nil +} + +// UploadFiles makes a request to the API with files. +func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) { + r, w := io.Pipe() + m := multipart.NewWriter(w) + + // This code modified from the very helpful @HirbodBehnam + // https://github.com/go-telegram-bot-api/telegram-bot-api/issues/354#issuecomment-663856473 + go func() { + defer w.Close() + defer m.Close() + + for field, value := range params { + if err := m.WriteField(field, value); err != nil { + w.CloseWithError(err) + return + } + } + + for _, file := range files { + if file.Data.NeedsUpload() { + name, reader, err := file.Data.UploadData() + if err != nil { + w.CloseWithError(err) + return + } + + part, err := m.CreateFormFile(file.Name, name) + if err != nil { + w.CloseWithError(err) + return + } + + if _, err := io.Copy(part, reader); err != nil { + w.CloseWithError(err) + return + } + + if closer, ok := reader.(io.ReadCloser); ok { + if err = closer.Close(); err != nil { + w.CloseWithError(err) + return + } + } + } else { + value := file.Data.SendData() + + if err := m.WriteField(file.Name, value); err != nil { + w.CloseWithError(err) + return + } + } + } + }() + + if bot.Debug { + log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files)) + } + + method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) + + req, err := http.NewRequest("POST", method, r) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", m.FormDataContentType()) + + resp, err := bot.Client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var apiResp APIResponse + bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) + if err != nil { + return &apiResp, err + } + + if bot.Debug { + log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) + } + + if !apiResp.Ok { + var parameters ResponseParameters + + if apiResp.Parameters != nil { + parameters = *apiResp.Parameters + } + + return &apiResp, &Error{ + Message: apiResp.Description, + ResponseParameters: parameters, + } + } + + return &apiResp, nil +} + +// GetFileDirectURL returns direct URL to file +// +// It requires the FileID. +func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) { + file, err := bot.GetFile(FileConfig{fileID}) + + if err != nil { + return "", err + } + + return file.Link(bot.Token), nil +} + +// GetMe fetches the currently authenticated bot. +// +// This method is called upon creation to validate the token, +// and so you may get this data from BotAPI.Self without the need for +// another request. +func (bot *BotAPI) GetMe() (User, error) { + resp, err := bot.MakeRequest("getMe", nil) + if err != nil { + return User{}, err + } + + var user User + err = json.Unmarshal(resp.Result, &user) + + return user, err +} + +// IsMessageToMe returns true if message directed to this bot. +// +// It requires the Message. +func (bot *BotAPI) IsMessageToMe(message Message) bool { + return strings.Contains(message.Text, "@"+bot.Self.UserName) +} + +func hasFilesNeedingUpload(files []RequestFile) bool { + for _, file := range files { + if file.Data.NeedsUpload() { + return true + } + } + + return false +} + +// Request sends a Chattable to Telegram, and returns the APIResponse. +func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) { + params, err := c.params() + if err != nil { + return nil, err + } + + if t, ok := c.(Fileable); ok { + files := t.files() + + // If we have files that need to be uploaded, we should delegate the + // request to UploadFile. + if hasFilesNeedingUpload(files) { + return bot.UploadFiles(t.method(), params, files) + } + + // However, if there are no files to be uploaded, there's likely things + // that need to be turned into params instead. + for _, file := range files { + params[file.Name] = file.Data.SendData() + } + } + + return bot.MakeRequest(c.method(), params) +} + +// Send will send a Chattable item to Telegram and provides the +// returned Message. +func (bot *BotAPI) Send(c Chattable) (Message, error) { + resp, err := bot.Request(c) + if err != nil { + return Message{}, err + } + + var message Message + err = json.Unmarshal(resp.Result, &message) + + return message, err +} + +// SendMediaGroup sends a media group and returns the resulting messages. +func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) { + resp, err := bot.Request(config) + if err != nil { + return nil, err + } + + var messages []Message + err = json.Unmarshal(resp.Result, &messages) + + return messages, err +} + +// GetUserProfilePhotos gets a user's profile photos. +// +// It requires UserID. +// Offset and Limit are optional. +func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { + resp, err := bot.Request(config) + if err != nil { + return UserProfilePhotos{}, err + } + + var profilePhotos UserProfilePhotos + err = json.Unmarshal(resp.Result, &profilePhotos) + + return profilePhotos, err +} + +// GetFile returns a File which can download a file from Telegram. +// +// Requires FileID. +func (bot *BotAPI) GetFile(config FileConfig) (File, error) { + resp, err := bot.Request(config) + if err != nil { + return File{}, err + } + + var file File + err = json.Unmarshal(resp.Result, &file) + + return file, err +} + +// GetUpdates fetches updates. +// If a WebHook is set, this will not return any data! +// +// Offset, Limit, Timeout, and AllowedUpdates are optional. +// To avoid stale items, set Offset to one higher than the previous item. +// Set Timeout to a large number to reduce requests, so you can get updates +// instantly instead of having to wait between requests. +func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { + resp, err := bot.Request(config) + if err != nil { + return []Update{}, err + } + + var updates []Update + err = json.Unmarshal(resp.Result, &updates) + + return updates, err +} + +// GetWebhookInfo allows you to fetch information about a webhook and if +// one currently is set, along with pending update count and error messages. +func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) { + resp, err := bot.MakeRequest("getWebhookInfo", nil) + if err != nil { + return WebhookInfo{}, err + } + + var info WebhookInfo + err = json.Unmarshal(resp.Result, &info) + + return info, err +} + +// GetUpdatesChan starts and returns a channel for getting updates. +func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel { + ch := make(chan Update, bot.Buffer) + + go func() { + for { + select { + case <-bot.shutdownChannel: + close(ch) + return + default: + } + + updates, err := bot.GetUpdates(config) + if err != nil { + log.Println(err) + log.Println("Failed to get updates, retrying in 3 seconds...") + time.Sleep(time.Second * 3) + + continue + } + + for _, update := range updates { + if update.UpdateID >= config.Offset { + config.Offset = update.UpdateID + 1 + ch <- update + } + } + } + }() + + return ch +} + +// StopReceivingUpdates stops the go routine which receives updates +func (bot *BotAPI) StopReceivingUpdates() { + if bot.Debug { + log.Println("Stopping the update receiver routine...") + } + close(bot.shutdownChannel) +} + +// ListenForWebhook registers a http handler for a webhook. +func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel { + ch := make(chan Update, bot.Buffer) + + http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { + update, err := bot.HandleUpdate(r) + if err != nil { + errMsg, _ := json.Marshal(map[string]string{"error": err.Error()}) + w.WriteHeader(http.StatusBadRequest) + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write(errMsg) + return + } + + ch <- *update + }) + + return ch +} + +// ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook. +func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel { + ch := make(chan Update, bot.Buffer) + + func(w http.ResponseWriter, r *http.Request) { + defer close(ch) + + update, err := bot.HandleUpdate(r) + if err != nil { + errMsg, _ := json.Marshal(map[string]string{"error": err.Error()}) + w.WriteHeader(http.StatusBadRequest) + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write(errMsg) + return + } + + ch <- *update + }(w, r) + + return ch +} + +// HandleUpdate parses and returns update received via webhook +func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) { + if r.Method != http.MethodPost { + err := errors.New("wrong HTTP method required POST") + return nil, err + } + + var update Update + err := json.NewDecoder(r.Body).Decode(&update) + if err != nil { + return nil, err + } + + return &update, nil +} + +// WriteToHTTPResponse writes the request to the HTTP ResponseWriter. +// +// It doesn't support uploading files. +// +// See https://core.telegram.org/bots/api#making-requests-when-getting-updates +// for details. +func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error { + params, err := c.params() + if err != nil { + return err + } + + if t, ok := c.(Fileable); ok { + if hasFilesNeedingUpload(t.files()) { + return errors.New("unable to use http response to upload files") + } + } + + values := buildParams(params) + values.Set("method", c.method()) + + w.Header().Set("Content-Type", "application/x-www-form-urlencoded") + _, err = w.Write([]byte(values.Encode())) + return err +} + +// GetChat gets information about a chat. +func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) { + resp, err := bot.Request(config) + if err != nil { + return Chat{}, err + } + + var chat Chat + err = json.Unmarshal(resp.Result, &chat) + + return chat, err +} + +// GetChatAdministrators gets a list of administrators in the chat. +// +// If none have been appointed, only the creator will be returned. +// Bots are not shown, even if they are an administrator. +func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) { + resp, err := bot.Request(config) + if err != nil { + return []ChatMember{}, err + } + + var members []ChatMember + err = json.Unmarshal(resp.Result, &members) + + return members, err +} + +// GetChatMembersCount gets the number of users in a chat. +func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) { + resp, err := bot.Request(config) + if err != nil { + return -1, err + } + + var count int + err = json.Unmarshal(resp.Result, &count) + + return count, err +} + +// GetChatMember gets a specific chat member. +func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) { + resp, err := bot.Request(config) + if err != nil { + return ChatMember{}, err + } + + var member ChatMember + err = json.Unmarshal(resp.Result, &member) + + return member, err +} + +// GetGameHighScores allows you to get the high scores for a game. +func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) { + resp, err := bot.Request(config) + if err != nil { + return []GameHighScore{}, err + } + + var highScores []GameHighScore + err = json.Unmarshal(resp.Result, &highScores) + + return highScores, err +} + +// GetInviteLink get InviteLink for a chat +func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) { + resp, err := bot.Request(config) + if err != nil { + return "", err + } + + var inviteLink string + err = json.Unmarshal(resp.Result, &inviteLink) + + return inviteLink, err +} + +// GetStickerSet returns a StickerSet. +func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { + resp, err := bot.Request(config) + if err != nil { + return StickerSet{}, err + } + + var stickers StickerSet + err = json.Unmarshal(resp.Result, &stickers) + + return stickers, err +} + +// StopPoll stops a poll and returns the result. +func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) { + resp, err := bot.Request(config) + if err != nil { + return Poll{}, err + } + + var poll Poll + err = json.Unmarshal(resp.Result, &poll) + + return poll, err +} + +// GetMyCommands gets the currently registered commands. +func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) { + return bot.GetMyCommandsWithConfig(GetMyCommandsConfig{}) +} + +// GetMyCommandsWithConfig gets the currently registered commands with a config. +func (bot *BotAPI) GetMyCommandsWithConfig(config GetMyCommandsConfig) ([]BotCommand, error) { + resp, err := bot.Request(config) + if err != nil { + return nil, err + } + + var commands []BotCommand + err = json.Unmarshal(resp.Result, &commands) + + return commands, err +} + +// CopyMessage copy messages of any kind. The method is analogous to the method +// forwardMessage, but the copied message doesn't have a link to the original +// message. Returns the MessageID of the sent message on success. +func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) { + resp, err := bot.Request(config) + if err != nil { + return MessageID{}, err + } + + var messageID MessageID + err = json.Unmarshal(resp.Result, &messageID) + + return messageID, err +} + +// AnswerWebAppQuery sets the result of an interaction with a Web App and send a +// corresponding message on behalf of the user to the chat from which the query originated. +func (bot *BotAPI) AnswerWebAppQuery(config AnswerWebAppQueryConfig) (SentWebAppMessage, error) { + var sentWebAppMessage SentWebAppMessage + + resp, err := bot.Request(config) + if err != nil { + return sentWebAppMessage, err + } + + err = json.Unmarshal(resp.Result, &sentWebAppMessage) + return sentWebAppMessage, err +} + +// GetMyDefaultAdministratorRights gets the current default administrator rights of the bot. +func (bot *BotAPI) GetMyDefaultAdministratorRights(config GetMyDefaultAdministratorRightsConfig) (ChatAdministratorRights, error) { + var rights ChatAdministratorRights + + resp, err := bot.Request(config) + if err != nil { + return rights, err + } + + err = json.Unmarshal(resp.Result, &rights) + return rights, err +} + +// EscapeText takes an input text and escape Telegram markup symbols. +// In this way we can send a text without being afraid of having to escape the characters manually. +// Note that you don't have to include the formatting style in the input text, or it will be escaped too. +// If there is an error, an empty string will be returned. +// +// parseMode is the text formatting mode (ModeMarkdown, ModeMarkdownV2 or ModeHTML) +// text is the input string that will be escaped +func EscapeText(parseMode string, text string) string { + var replacer *strings.Replacer + + if parseMode == ModeHTML { + replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&") + } else if parseMode == ModeMarkdown { + replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[") + } else if parseMode == ModeMarkdownV2 { + replacer = strings.NewReplacer( + "_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(", + "\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>", + "#", "\\#", "+", "\\+", "-", "\\-", "=", "\\=", "|", + "\\|", "{", "\\{", "}", "\\}", ".", "\\.", "!", "\\!", + ) + } else { + return "" + } + + return replacer.Replace(text) +} diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/configs.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/configs.go new file mode 100644 index 00000000..09c9c468 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/configs.go @@ -0,0 +1,2934 @@ +package tgbotapi + +import ( + "bytes" + "fmt" + "io" + "net/url" + "os" + "strconv" +) + +// Telegram constants +const ( + // APIEndpoint is the endpoint for all API methods, + // with formatting for Sprintf. + APIEndpoint = "https://api.telegram.org/bot%s/%s" + // FileEndpoint is the endpoint for downloading a file from Telegram. + FileEndpoint = "https://api.telegram.org/file/bot%s/%s" +) + +// Constant values for ChatActions +const ( + ChatTyping = "typing" + ChatUploadPhoto = "upload_photo" + ChatRecordVideo = "record_video" + ChatUploadVideo = "upload_video" + ChatRecordVoice = "record_voice" + ChatUploadVoice = "upload_voice" + ChatUploadDocument = "upload_document" + ChatChooseSticker = "choose_sticker" + ChatFindLocation = "find_location" + ChatRecordVideoNote = "record_video_note" + ChatUploadVideoNote = "upload_video_note" +) + +// API errors +const ( + // ErrAPIForbidden happens when a token is bad + ErrAPIForbidden = "forbidden" +) + +// Constant values for ParseMode in MessageConfig +const ( + ModeMarkdown = "Markdown" + ModeMarkdownV2 = "MarkdownV2" + ModeHTML = "HTML" +) + +// Constant values for update types +const ( + // UpdateTypeMessage is new incoming message of any kind — text, photo, sticker, etc. + UpdateTypeMessage = "message" + + // UpdateTypeEditedMessage is new version of a message that is known to the bot and was edited + UpdateTypeEditedMessage = "edited_message" + + // UpdateTypeChannelPost is new incoming channel post of any kind — text, photo, sticker, etc. + UpdateTypeChannelPost = "channel_post" + + // UpdateTypeEditedChannelPost is new version of a channel post that is known to the bot and was edited + UpdateTypeEditedChannelPost = "edited_channel_post" + + // UpdateTypeInlineQuery is new incoming inline query + UpdateTypeInlineQuery = "inline_query" + + // UpdateTypeChosenInlineResult i the result of an inline query that was chosen by a user and sent to their + // chat partner. Please see the documentation on the feedback collecting for + // details on how to enable these updates for your bot. + UpdateTypeChosenInlineResult = "chosen_inline_result" + + // UpdateTypeCallbackQuery is new incoming callback query + UpdateTypeCallbackQuery = "callback_query" + + // UpdateTypeShippingQuery is new incoming shipping query. Only for invoices with flexible price + UpdateTypeShippingQuery = "shipping_query" + + // UpdateTypePreCheckoutQuery is new incoming pre-checkout query. Contains full information about checkout + UpdateTypePreCheckoutQuery = "pre_checkout_query" + + // UpdateTypePoll is new poll state. Bots receive only updates about stopped polls and polls + // which are sent by the bot + UpdateTypePoll = "poll" + + // UpdateTypePollAnswer is when user changed their answer in a non-anonymous poll. Bots receive new votes + // only in polls that were sent by the bot itself. + UpdateTypePollAnswer = "poll_answer" + + // UpdateTypeMyChatMember is when the bot's chat member status was updated in a chat. For private chats, this + // update is received only when the bot is blocked or unblocked by the user. + UpdateTypeMyChatMember = "my_chat_member" + + // UpdateTypeChatMember is when the bot must be an administrator in the chat and must explicitly specify + // this update in the list of allowed_updates to receive these updates. + UpdateTypeChatMember = "chat_member" +) + +// Library errors +const ( + ErrBadURL = "bad or empty url" +) + +// Chattable is any config type that can be sent. +type Chattable interface { + params() (Params, error) + method() string +} + +// Fileable is any config type that can be sent that includes a file. +type Fileable interface { + Chattable + files() []RequestFile +} + +// RequestFile represents a file associated with a field name. +type RequestFile struct { + // The file field name. + Name string + // The file data to include. + Data RequestFileData +} + +// RequestFileData represents the data to be used for a file. +type RequestFileData interface { + // NeedsUpload shows if the file needs to be uploaded. + NeedsUpload() bool + + // UploadData gets the file name and an `io.Reader` for the file to be uploaded. This + // must only be called when the file needs to be uploaded. + UploadData() (string, io.Reader, error) + // SendData gets the file data to send when a file does not need to be uploaded. This + // must only be called when the file does not need to be uploaded. + SendData() string +} + +// FileBytes contains information about a set of bytes to upload +// as a File. +type FileBytes struct { + Name string + Bytes []byte +} + +func (fb FileBytes) NeedsUpload() bool { + return true +} + +func (fb FileBytes) UploadData() (string, io.Reader, error) { + return fb.Name, bytes.NewReader(fb.Bytes), nil +} + +func (fb FileBytes) SendData() string { + panic("FileBytes must be uploaded") +} + +// FileReader contains information about a reader to upload as a File. +type FileReader struct { + Name string + Reader io.Reader +} + +func (fr FileReader) NeedsUpload() bool { + return true +} + +func (fr FileReader) UploadData() (string, io.Reader, error) { + return fr.Name, fr.Reader, nil +} + +func (fr FileReader) SendData() string { + panic("FileReader must be uploaded") +} + +// FilePath is a path to a local file. +type FilePath string + +func (fp FilePath) NeedsUpload() bool { + return true +} + +func (fp FilePath) UploadData() (string, io.Reader, error) { + fileHandle, err := os.Open(string(fp)) + if err != nil { + return "", nil, err + } + + name := fileHandle.Name() + return name, fileHandle, err +} + +func (fp FilePath) SendData() string { + panic("FilePath must be uploaded") +} + +// FileURL is a URL to use as a file for a request. +type FileURL string + +func (fu FileURL) NeedsUpload() bool { + return false +} + +func (fu FileURL) UploadData() (string, io.Reader, error) { + panic("FileURL cannot be uploaded") +} + +func (fu FileURL) SendData() string { + return string(fu) +} + +// FileID is an ID of a file already uploaded to Telegram. +type FileID string + +func (fi FileID) NeedsUpload() bool { + return false +} + +func (fi FileID) UploadData() (string, io.Reader, error) { + panic("FileID cannot be uploaded") +} + +func (fi FileID) SendData() string { + return string(fi) +} + +// fileAttach is an internal file type used for processed media groups. +type fileAttach string + +func (fa fileAttach) NeedsUpload() bool { + return false +} + +func (fa fileAttach) UploadData() (string, io.Reader, error) { + panic("fileAttach cannot be uploaded") +} + +func (fa fileAttach) SendData() string { + return string(fa) +} + +// LogOutConfig is a request to log out of the cloud Bot API server. +// +// Note that you may not log back in for at least 10 minutes. +type LogOutConfig struct{} + +func (LogOutConfig) method() string { + return "logOut" +} + +func (LogOutConfig) params() (Params, error) { + return nil, nil +} + +// CloseConfig is a request to close the bot instance on a local server. +// +// Note that you may not close an instance for the first 10 minutes after the +// bot has started. +type CloseConfig struct{} + +func (CloseConfig) method() string { + return "close" +} + +func (CloseConfig) params() (Params, error) { + return nil, nil +} + +// BaseChat is base type for all chat config types. +type BaseChat struct { + ChatID int64 // required + MessageThreadID int + ChannelUsername string + ProtectContent bool + ReplyToMessageID int + ReplyMarkup interface{} + DisableNotification bool + AllowSendingWithoutReply bool +} + +func (chat *BaseChat) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername) + params.AddNonZero("message_thread_id", chat.MessageThreadID) + params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID) + params.AddBool("disable_notification", chat.DisableNotification) + params.AddBool("allow_sending_without_reply", chat.AllowSendingWithoutReply) + params.AddBool("protect_content", chat.ProtectContent) + + err := params.AddInterface("reply_markup", chat.ReplyMarkup) + + return params, err +} + +// BaseFile is a base type for all file config types. +type BaseFile struct { + BaseChat + File RequestFileData +} + +func (file BaseFile) params() (Params, error) { + return file.BaseChat.params() +} + +// BaseEdit is base type of all chat edits. +type BaseEdit struct { + ChatID int64 + ChannelUsername string + MessageID int + InlineMessageID string + ReplyMarkup *InlineKeyboardMarkup +} + +func (edit BaseEdit) params() (Params, error) { + params := make(Params) + + if edit.InlineMessageID != "" { + params["inline_message_id"] = edit.InlineMessageID + } else { + params.AddFirstValid("chat_id", edit.ChatID, edit.ChannelUsername) + params.AddNonZero("message_id", edit.MessageID) + } + + err := params.AddInterface("reply_markup", edit.ReplyMarkup) + + return params, err +} + +// BaseSpoiler is base type of structures with spoilers. +type BaseSpoiler struct { + HasSpoiler bool +} + +func (spoiler BaseSpoiler) params() (Params, error) { + params := make(Params) + + if spoiler.HasSpoiler { + params.AddBool("has_spoiler", true) + } + + return params, nil +} + +// MessageConfig contains information about a SendMessage request. +type MessageConfig struct { + BaseChat + Text string + ParseMode string + Entities []MessageEntity + DisableWebPagePreview bool +} + +func (config MessageConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonEmpty("text", config.Text) + params.AddBool("disable_web_page_preview", config.DisableWebPagePreview) + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("entities", config.Entities) + + return params, err +} + +func (config MessageConfig) method() string { + return "sendMessage" +} + +// ForwardConfig contains information about a ForwardMessage request. +type ForwardConfig struct { + BaseChat + FromChatID int64 // required + FromChannelUsername string + MessageID int // required +} + +func (config ForwardConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonZero64("from_chat_id", config.FromChatID) + params.AddNonZero("message_id", config.MessageID) + + return params, nil +} + +func (config ForwardConfig) method() string { + return "forwardMessage" +} + +// CopyMessageConfig contains information about a copyMessage request. +type CopyMessageConfig struct { + BaseChat + FromChatID int64 + FromChannelUsername string + MessageID int + Caption string + ParseMode string + CaptionEntities []MessageEntity +} + +func (config CopyMessageConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddFirstValid("from_chat_id", config.FromChatID, config.FromChannelUsername) + params.AddNonZero("message_id", config.MessageID) + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("caption_entities", config.CaptionEntities) + + return params, err +} + +func (config CopyMessageConfig) method() string { + return "copyMessage" +} + +// PhotoConfig contains information about a SendPhoto request. +type PhotoConfig struct { + BaseFile + BaseSpoiler + Thumb RequestFileData + Caption string + ParseMode string + CaptionEntities []MessageEntity +} + +func (config PhotoConfig) params() (Params, error) { + params, err := config.BaseFile.params() + if err != nil { + return params, err + } + + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("caption_entities", config.CaptionEntities) + if err != nil { + return params, err + } + + p1, err := config.BaseSpoiler.params() + if err != nil { + return params, err + } + params.Merge(p1) + + return params, err +} + +func (config PhotoConfig) method() string { + return "sendPhoto" +} + +func (config PhotoConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "photo", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// AudioConfig contains information about a SendAudio request. +type AudioConfig struct { + BaseFile + Thumb RequestFileData + Caption string + ParseMode string + CaptionEntities []MessageEntity + Duration int + Performer string + Title string +} + +func (config AudioConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonZero("duration", config.Duration) + params.AddNonEmpty("performer", config.Performer) + params.AddNonEmpty("title", config.Title) + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("caption_entities", config.CaptionEntities) + + return params, err +} + +func (config AudioConfig) method() string { + return "sendAudio" +} + +func (config AudioConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "audio", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// DocumentConfig contains information about a SendDocument request. +type DocumentConfig struct { + BaseFile + Thumb RequestFileData + Caption string + ParseMode string + CaptionEntities []MessageEntity + DisableContentTypeDetection bool +} + +func (config DocumentConfig) params() (Params, error) { + params, err := config.BaseFile.params() + + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + params.AddBool("disable_content_type_detection", config.DisableContentTypeDetection) + + return params, err +} + +func (config DocumentConfig) method() string { + return "sendDocument" +} + +func (config DocumentConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "document", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// StickerConfig contains information about a SendSticker request. +type StickerConfig struct { + BaseFile +} + +func (config StickerConfig) params() (Params, error) { + return config.BaseChat.params() +} + +func (config StickerConfig) method() string { + return "sendSticker" +} + +func (config StickerConfig) files() []RequestFile { + return []RequestFile{{ + Name: "sticker", + Data: config.File, + }} +} + +// VideoConfig contains information about a SendVideo request. +type VideoConfig struct { + BaseFile + BaseSpoiler + Thumb RequestFileData + Duration int + Caption string + ParseMode string + CaptionEntities []MessageEntity + SupportsStreaming bool +} + +func (config VideoConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonZero("duration", config.Duration) + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + params.AddBool("supports_streaming", config.SupportsStreaming) + err = params.AddInterface("caption_entities", config.CaptionEntities) + if err != nil { + return params, err + } + + p1, err := config.BaseSpoiler.params() + if err != nil { + return params, err + } + params.Merge(p1) + + return params, err +} + +func (config VideoConfig) method() string { + return "sendVideo" +} + +func (config VideoConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "video", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// AnimationConfig contains information about a SendAnimation request. +type AnimationConfig struct { + BaseFile + BaseSpoiler + Duration int + Thumb RequestFileData + Caption string + ParseMode string + CaptionEntities []MessageEntity +} + +func (config AnimationConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonZero("duration", config.Duration) + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("caption_entities", config.CaptionEntities) + if err != nil { + return params, err + } + + p1, err := config.BaseSpoiler.params() + if err != nil { + return params, err + } + params.Merge(p1) + + return params, err +} + +func (config AnimationConfig) method() string { + return "sendAnimation" +} + +func (config AnimationConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "animation", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// VideoNoteConfig contains information about a SendVideoNote request. +type VideoNoteConfig struct { + BaseFile + Thumb RequestFileData + Duration int + Length int +} + +func (config VideoNoteConfig) params() (Params, error) { + params, err := config.BaseChat.params() + + params.AddNonZero("duration", config.Duration) + params.AddNonZero("length", config.Length) + + return params, err +} + +func (config VideoNoteConfig) method() string { + return "sendVideoNote" +} + +func (config VideoNoteConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "video_note", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// VoiceConfig contains information about a SendVoice request. +type VoiceConfig struct { + BaseFile + Thumb RequestFileData + Caption string + ParseMode string + CaptionEntities []MessageEntity + Duration int +} + +func (config VoiceConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonZero("duration", config.Duration) + params.AddNonEmpty("caption", config.Caption) + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("caption_entities", config.CaptionEntities) + + return params, err +} + +func (config VoiceConfig) method() string { + return "sendVoice" +} + +func (config VoiceConfig) files() []RequestFile { + files := []RequestFile{{ + Name: "voice", + Data: config.File, + }} + + if config.Thumb != nil { + files = append(files, RequestFile{ + Name: "thumb", + Data: config.Thumb, + }) + } + + return files +} + +// LocationConfig contains information about a SendLocation request. +type LocationConfig struct { + BaseChat + Latitude float64 // required + Longitude float64 // required + HorizontalAccuracy float64 // optional + LivePeriod int // optional + Heading int // optional + ProximityAlertRadius int // optional +} + +func (config LocationConfig) params() (Params, error) { + params, err := config.BaseChat.params() + + params.AddNonZeroFloat("latitude", config.Latitude) + params.AddNonZeroFloat("longitude", config.Longitude) + params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy) + params.AddNonZero("live_period", config.LivePeriod) + params.AddNonZero("heading", config.Heading) + params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius) + + return params, err +} + +func (config LocationConfig) method() string { + return "sendLocation" +} + +// EditMessageLiveLocationConfig allows you to update a live location. +type EditMessageLiveLocationConfig struct { + BaseEdit + Latitude float64 // required + Longitude float64 // required + HorizontalAccuracy float64 // optional + Heading int // optional + ProximityAlertRadius int // optional +} + +func (config EditMessageLiveLocationConfig) params() (Params, error) { + params, err := config.BaseEdit.params() + + params.AddNonZeroFloat("latitude", config.Latitude) + params.AddNonZeroFloat("longitude", config.Longitude) + params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy) + params.AddNonZero("heading", config.Heading) + params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius) + + return params, err +} + +func (config EditMessageLiveLocationConfig) method() string { + return "editMessageLiveLocation" +} + +// StopMessageLiveLocationConfig stops updating a live location. +type StopMessageLiveLocationConfig struct { + BaseEdit +} + +func (config StopMessageLiveLocationConfig) params() (Params, error) { + return config.BaseEdit.params() +} + +func (config StopMessageLiveLocationConfig) method() string { + return "stopMessageLiveLocation" +} + +// VenueConfig contains information about a SendVenue request. +type VenueConfig struct { + BaseChat + Latitude float64 // required + Longitude float64 // required + Title string // required + Address string // required + FoursquareID string + FoursquareType string + GooglePlaceID string + GooglePlaceType string +} + +func (config VenueConfig) params() (Params, error) { + params, err := config.BaseChat.params() + + params.AddNonZeroFloat("latitude", config.Latitude) + params.AddNonZeroFloat("longitude", config.Longitude) + params["title"] = config.Title + params["address"] = config.Address + params.AddNonEmpty("foursquare_id", config.FoursquareID) + params.AddNonEmpty("foursquare_type", config.FoursquareType) + params.AddNonEmpty("google_place_id", config.GooglePlaceID) + params.AddNonEmpty("google_place_type", config.GooglePlaceType) + + return params, err +} + +func (config VenueConfig) method() string { + return "sendVenue" +} + +// ContactConfig allows you to send a contact. +type ContactConfig struct { + BaseChat + PhoneNumber string + FirstName string + LastName string + VCard string +} + +func (config ContactConfig) params() (Params, error) { + params, err := config.BaseChat.params() + + params["phone_number"] = config.PhoneNumber + params["first_name"] = config.FirstName + + params.AddNonEmpty("last_name", config.LastName) + params.AddNonEmpty("vcard", config.VCard) + + return params, err +} + +func (config ContactConfig) method() string { + return "sendContact" +} + +// SendPollConfig allows you to send a poll. +type SendPollConfig struct { + BaseChat + Question string + Options []string + IsAnonymous bool + Type string + AllowsMultipleAnswers bool + CorrectOptionID int64 + Explanation string + ExplanationParseMode string + ExplanationEntities []MessageEntity + OpenPeriod int + CloseDate int + IsClosed bool +} + +func (config SendPollConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params["question"] = config.Question + if err = params.AddInterface("options", config.Options); err != nil { + return params, err + } + params["is_anonymous"] = strconv.FormatBool(config.IsAnonymous) + params.AddNonEmpty("type", config.Type) + params["allows_multiple_answers"] = strconv.FormatBool(config.AllowsMultipleAnswers) + params["correct_option_id"] = strconv.FormatInt(config.CorrectOptionID, 10) + params.AddBool("is_closed", config.IsClosed) + params.AddNonEmpty("explanation", config.Explanation) + params.AddNonEmpty("explanation_parse_mode", config.ExplanationParseMode) + params.AddNonZero("open_period", config.OpenPeriod) + params.AddNonZero("close_date", config.CloseDate) + err = params.AddInterface("explanation_entities", config.ExplanationEntities) + + return params, err +} + +func (SendPollConfig) method() string { + return "sendPoll" +} + +// GameConfig allows you to send a game. +type GameConfig struct { + BaseChat + GameShortName string +} + +func (config GameConfig) params() (Params, error) { + params, err := config.BaseChat.params() + + params["game_short_name"] = config.GameShortName + + return params, err +} + +func (config GameConfig) method() string { + return "sendGame" +} + +// SetGameScoreConfig allows you to update the game score in a chat. +type SetGameScoreConfig struct { + UserID int64 + Score int + Force bool + DisableEditMessage bool + ChatID int64 + ChannelUsername string + MessageID int + InlineMessageID string +} + +func (config SetGameScoreConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero64("user_id", config.UserID) + params.AddNonZero("scrore", config.Score) + params.AddBool("disable_edit_message", config.DisableEditMessage) + + if config.InlineMessageID != "" { + params["inline_message_id"] = config.InlineMessageID + } else { + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero("message_id", config.MessageID) + } + + return params, nil +} + +func (config SetGameScoreConfig) method() string { + return "setGameScore" +} + +// GetGameHighScoresConfig allows you to fetch the high scores for a game. +type GetGameHighScoresConfig struct { + UserID int64 + ChatID int64 + ChannelUsername string + MessageID int + InlineMessageID string +} + +func (config GetGameHighScoresConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero64("user_id", config.UserID) + + if config.InlineMessageID != "" { + params["inline_message_id"] = config.InlineMessageID + } else { + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero("message_id", config.MessageID) + } + + return params, nil +} + +func (config GetGameHighScoresConfig) method() string { + return "getGameHighScores" +} + +// ChatActionConfig contains information about a SendChatAction request. +type ChatActionConfig struct { + BaseChat + MessageThreadID int + Action string // required +} + +func (config ChatActionConfig) params() (Params, error) { + params, err := config.BaseChat.params() + + params["action"] = config.Action + params.AddNonZero("message_thread_id", config.MessageThreadID) + + return params, err +} + +func (config ChatActionConfig) method() string { + return "sendChatAction" +} + +// EditMessageTextConfig allows you to modify the text in a message. +type EditMessageTextConfig struct { + BaseEdit + Text string + ParseMode string + Entities []MessageEntity + DisableWebPagePreview bool +} + +func (config EditMessageTextConfig) params() (Params, error) { + params, err := config.BaseEdit.params() + if err != nil { + return params, err + } + + params["text"] = config.Text + params.AddNonEmpty("parse_mode", config.ParseMode) + params.AddBool("disable_web_page_preview", config.DisableWebPagePreview) + err = params.AddInterface("entities", config.Entities) + + return params, err +} + +func (config EditMessageTextConfig) method() string { + return "editMessageText" +} + +// EditMessageCaptionConfig allows you to modify the caption of a message. +type EditMessageCaptionConfig struct { + BaseEdit + Caption string + ParseMode string + CaptionEntities []MessageEntity +} + +func (config EditMessageCaptionConfig) params() (Params, error) { + params, err := config.BaseEdit.params() + if err != nil { + return params, err + } + + params["caption"] = config.Caption + params.AddNonEmpty("parse_mode", config.ParseMode) + err = params.AddInterface("caption_entities", config.CaptionEntities) + + return params, err +} + +func (config EditMessageCaptionConfig) method() string { + return "editMessageCaption" +} + +// EditMessageMediaConfig allows you to make an editMessageMedia request. +type EditMessageMediaConfig struct { + BaseEdit + + Media interface{} +} + +func (EditMessageMediaConfig) method() string { + return "editMessageMedia" +} + +func (config EditMessageMediaConfig) params() (Params, error) { + params, err := config.BaseEdit.params() + if err != nil { + return params, err + } + + err = params.AddInterface("media", prepareInputMediaParam(config.Media, 0)) + + return params, err +} + +func (config EditMessageMediaConfig) files() []RequestFile { + return prepareInputMediaFile(config.Media, 0) +} + +// EditMessageReplyMarkupConfig allows you to modify the reply markup +// of a message. +type EditMessageReplyMarkupConfig struct { + BaseEdit +} + +func (config EditMessageReplyMarkupConfig) params() (Params, error) { + return config.BaseEdit.params() +} + +func (config EditMessageReplyMarkupConfig) method() string { + return "editMessageReplyMarkup" +} + +// StopPollConfig allows you to stop a poll sent by the bot. +type StopPollConfig struct { + BaseEdit +} + +func (config StopPollConfig) params() (Params, error) { + return config.BaseEdit.params() +} + +func (StopPollConfig) method() string { + return "stopPoll" +} + +// UserProfilePhotosConfig contains information about a +// GetUserProfilePhotos request. +type UserProfilePhotosConfig struct { + UserID int64 + Offset int + Limit int +} + +func (UserProfilePhotosConfig) method() string { + return "getUserProfilePhotos" +} + +func (config UserProfilePhotosConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero64("user_id", config.UserID) + params.AddNonZero("offset", config.Offset) + params.AddNonZero("limit", config.Limit) + + return params, nil +} + +// FileConfig has information about a file hosted on Telegram. +type FileConfig struct { + FileID string +} + +func (FileConfig) method() string { + return "getFile" +} + +func (config FileConfig) params() (Params, error) { + params := make(Params) + + params["file_id"] = config.FileID + + return params, nil +} + +// UpdateConfig contains information about a GetUpdates request. +type UpdateConfig struct { + Offset int + Limit int + Timeout int + AllowedUpdates []string +} + +func (UpdateConfig) method() string { + return "getUpdates" +} + +func (config UpdateConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero("offset", config.Offset) + params.AddNonZero("limit", config.Limit) + params.AddNonZero("timeout", config.Timeout) + params.AddInterface("allowed_updates", config.AllowedUpdates) + + return params, nil +} + +// WebhookConfig contains information about a SetWebhook request. +type WebhookConfig struct { + URL *url.URL + Certificate RequestFileData + IPAddress string + MaxConnections int + AllowedUpdates []string + DropPendingUpdates bool + SecretToken string +} + +func (config WebhookConfig) method() string { + return "setWebhook" +} + +func (config WebhookConfig) params() (Params, error) { + params := make(Params) + + if config.URL != nil { + params["url"] = config.URL.String() + } + + params.AddNonEmpty("ip_address", config.IPAddress) + params.AddNonZero("max_connections", config.MaxConnections) + err := params.AddInterface("allowed_updates", config.AllowedUpdates) + params.AddBool("drop_pending_updates", config.DropPendingUpdates) + params.AddNonEmpty("secret_token", config.SecretToken) + + return params, err +} + +func (config WebhookConfig) files() []RequestFile { + if config.Certificate != nil { + return []RequestFile{{ + Name: "certificate", + Data: config.Certificate, + }} + } + + return nil +} + +// DeleteWebhookConfig is a helper to delete a webhook. +type DeleteWebhookConfig struct { + DropPendingUpdates bool +} + +func (config DeleteWebhookConfig) method() string { + return "deleteWebhook" +} + +func (config DeleteWebhookConfig) params() (Params, error) { + params := make(Params) + + params.AddBool("drop_pending_updates", config.DropPendingUpdates) + + return params, nil +} + +// InlineConfig contains information on making an InlineQuery response. +type InlineConfig struct { + InlineQueryID string `json:"inline_query_id"` + Results []interface{} `json:"results"` + CacheTime int `json:"cache_time"` + IsPersonal bool `json:"is_personal"` + NextOffset string `json:"next_offset"` + SwitchPMText string `json:"switch_pm_text"` + SwitchPMParameter string `json:"switch_pm_parameter"` +} + +func (config InlineConfig) method() string { + return "answerInlineQuery" +} + +func (config InlineConfig) params() (Params, error) { + params := make(Params) + + params["inline_query_id"] = config.InlineQueryID + params.AddNonZero("cache_time", config.CacheTime) + params.AddBool("is_personal", config.IsPersonal) + params.AddNonEmpty("next_offset", config.NextOffset) + params.AddNonEmpty("switch_pm_text", config.SwitchPMText) + params.AddNonEmpty("switch_pm_parameter", config.SwitchPMParameter) + err := params.AddInterface("results", config.Results) + + return params, err +} + +// AnswerWebAppQueryConfig is used to set the result of an interaction with a +// Web App and send a corresponding message on behalf of the user to the chat +// from which the query originated. +type AnswerWebAppQueryConfig struct { + // WebAppQueryID is the unique identifier for the query to be answered. + WebAppQueryID string `json:"web_app_query_id"` + // Result is an InlineQueryResult object describing the message to be sent. + Result interface{} `json:"result"` +} + +func (config AnswerWebAppQueryConfig) method() string { + return "answerWebAppQuery" +} + +func (config AnswerWebAppQueryConfig) params() (Params, error) { + params := make(Params) + + params["web_app_query_id"] = config.WebAppQueryID + err := params.AddInterface("result", config.Result) + + return params, err +} + +// CallbackConfig contains information on making a CallbackQuery response. +type CallbackConfig struct { + CallbackQueryID string `json:"callback_query_id"` + Text string `json:"text"` + ShowAlert bool `json:"show_alert"` + URL string `json:"url"` + CacheTime int `json:"cache_time"` +} + +func (config CallbackConfig) method() string { + return "answerCallbackQuery" +} + +func (config CallbackConfig) params() (Params, error) { + params := make(Params) + + params["callback_query_id"] = config.CallbackQueryID + params.AddNonEmpty("text", config.Text) + params.AddBool("show_alert", config.ShowAlert) + params.AddNonEmpty("url", config.URL) + params.AddNonZero("cache_time", config.CacheTime) + + return params, nil +} + +// ChatMemberConfig contains information about a user in a chat for use +// with administrative functions such as kicking or unbanning a user. +type ChatMemberConfig struct { + ChatID int64 + SuperGroupUsername string + ChannelUsername string + UserID int64 +} + +// UnbanChatMemberConfig allows you to unban a user. +type UnbanChatMemberConfig struct { + ChatMemberConfig + OnlyIfBanned bool +} + +func (config UnbanChatMemberConfig) method() string { + return "unbanChatMember" +} + +func (config UnbanChatMemberConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) + params.AddNonZero64("user_id", config.UserID) + params.AddBool("only_if_banned", config.OnlyIfBanned) + + return params, nil +} + +// BanChatMemberConfig contains extra fields to kick user. +type BanChatMemberConfig struct { + ChatMemberConfig + UntilDate int64 + RevokeMessages bool +} + +func (config BanChatMemberConfig) method() string { + return "banChatMember" +} + +func (config BanChatMemberConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero64("user_id", config.UserID) + params.AddNonZero64("until_date", config.UntilDate) + params.AddBool("revoke_messages", config.RevokeMessages) + + return params, nil +} + +// KickChatMemberConfig contains extra fields to ban user. +// +// This was renamed to BanChatMember in later versions of the Telegram Bot API. +type KickChatMemberConfig = BanChatMemberConfig + +// RestrictChatMemberConfig contains fields to restrict members of chat +type RestrictChatMemberConfig struct { + ChatMemberConfig + UntilDate int64 + UseIndependentChatPermissions bool + Permissions *ChatPermissions +} + +func (config RestrictChatMemberConfig) method() string { + return "restrictChatMember" +} + +func (config RestrictChatMemberConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) + params.AddNonZero64("user_id", config.UserID) + params.AddBool("use_independent_chat_permissions", config.UseIndependentChatPermissions) + + err := params.AddInterface("permissions", config.Permissions) + params.AddNonZero64("until_date", config.UntilDate) + + return params, err +} + +// PromoteChatMemberConfig contains fields to promote members of chat +type PromoteChatMemberConfig struct { + ChatMemberConfig + IsAnonymous bool + CanManageChat bool + CanChangeInfo bool + CanPostMessages bool + CanEditMessages bool + CanDeleteMessages bool + CanManageVideoChats bool + CanInviteUsers bool + CanRestrictMembers bool + CanPinMessages bool + CanPromoteMembers bool + CanManageTopics bool +} + +func (config PromoteChatMemberConfig) method() string { + return "promoteChatMember" +} + +func (config PromoteChatMemberConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) + params.AddNonZero64("user_id", config.UserID) + + params.AddBool("is_anonymous", config.IsAnonymous) + params.AddBool("can_manage_chat", config.CanManageChat) + params.AddBool("can_change_info", config.CanChangeInfo) + params.AddBool("can_post_messages", config.CanPostMessages) + params.AddBool("can_edit_messages", config.CanEditMessages) + params.AddBool("can_delete_messages", config.CanDeleteMessages) + params.AddBool("can_manage_video_chats", config.CanManageVideoChats) + params.AddBool("can_invite_users", config.CanInviteUsers) + params.AddBool("can_restrict_members", config.CanRestrictMembers) + params.AddBool("can_pin_messages", config.CanPinMessages) + params.AddBool("can_promote_members", config.CanPromoteMembers) + params.AddBool("can_manage_topics", config.CanManageTopics) + + return params, nil +} + +// SetChatAdministratorCustomTitle sets the title of an administrative user +// promoted by the bot for a chat. +type SetChatAdministratorCustomTitle struct { + ChatMemberConfig + CustomTitle string +} + +func (SetChatAdministratorCustomTitle) method() string { + return "setChatAdministratorCustomTitle" +} + +func (config SetChatAdministratorCustomTitle) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) + params.AddNonZero64("user_id", config.UserID) + params.AddNonEmpty("custom_title", config.CustomTitle) + + return params, nil +} + +// BanChatSenderChatConfig bans a channel chat in a supergroup or a channel. The +// owner of the chat will not be able to send messages and join live streams on +// behalf of the chat, unless it is unbanned first. The bot must be an +// administrator in the supergroup or channel for this to work and must have the +// appropriate administrator rights. +type BanChatSenderChatConfig struct { + ChatID int64 + ChannelUsername string + SenderChatID int64 + UntilDate int +} + +func (config BanChatSenderChatConfig) method() string { + return "banChatSenderChat" +} + +func (config BanChatSenderChatConfig) params() (Params, error) { + params := make(Params) + + _ = params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero64("sender_chat_id", config.SenderChatID) + params.AddNonZero("until_date", config.UntilDate) + + return params, nil +} + +// UnbanChatSenderChatConfig unbans a previously banned channel chat in a +// supergroup or channel. The bot must be an administrator for this to work and +// must have the appropriate administrator rights. +type UnbanChatSenderChatConfig struct { + ChatID int64 + ChannelUsername string + SenderChatID int64 +} + +func (config UnbanChatSenderChatConfig) method() string { + return "unbanChatSenderChat" +} + +func (config UnbanChatSenderChatConfig) params() (Params, error) { + params := make(Params) + + _ = params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero64("sender_chat_id", config.SenderChatID) + + return params, nil +} + +// ChatConfig contains information about getting information on a chat. +type ChatConfig struct { + ChatID int64 + SuperGroupUsername string +} + +func (config ChatConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + + return params, nil +} + +// ChatInfoConfig contains information about getting chat information. +type ChatInfoConfig struct { + ChatConfig +} + +func (ChatInfoConfig) method() string { + return "getChat" +} + +// ChatMemberCountConfig contains information about getting the number of users in a chat. +type ChatMemberCountConfig struct { + ChatConfig +} + +func (ChatMemberCountConfig) method() string { + return "getChatMembersCount" +} + +// ChatAdministratorsConfig contains information about getting chat administrators. +type ChatAdministratorsConfig struct { + ChatConfig +} + +func (ChatAdministratorsConfig) method() string { + return "getChatAdministrators" +} + +// SetChatPermissionsConfig allows you to set default permissions for the +// members in a group. The bot must be an administrator and have rights to +// restrict members. +type SetChatPermissionsConfig struct { + ChatConfig + UseIndependentChatPermissions bool + Permissions *ChatPermissions +} + +func (SetChatPermissionsConfig) method() string { + return "setChatPermissions" +} + +func (config SetChatPermissionsConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddBool("use_independent_chat_permissions", config.UseIndependentChatPermissions) + err := params.AddInterface("permissions", config.Permissions) + + return params, err +} + +// ChatInviteLinkConfig contains information about getting a chat link. +// +// Note that generating a new link will revoke any previous links. +type ChatInviteLinkConfig struct { + ChatConfig +} + +func (ChatInviteLinkConfig) method() string { + return "exportChatInviteLink" +} + +func (config ChatInviteLinkConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + + return params, nil +} + +// CreateChatInviteLinkConfig allows you to create an additional invite link for +// a chat. The bot must be an administrator in the chat for this to work and +// must have the appropriate admin rights. The link can be revoked using the +// RevokeChatInviteLinkConfig. +type CreateChatInviteLinkConfig struct { + ChatConfig + Name string + ExpireDate int + MemberLimit int + CreatesJoinRequest bool +} + +func (CreateChatInviteLinkConfig) method() string { + return "createChatInviteLink" +} + +func (config CreateChatInviteLinkConfig) params() (Params, error) { + params := make(Params) + + params.AddNonEmpty("name", config.Name) + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero("expire_date", config.ExpireDate) + params.AddNonZero("member_limit", config.MemberLimit) + params.AddBool("creates_join_request", config.CreatesJoinRequest) + + return params, nil +} + +// EditChatInviteLinkConfig allows you to edit a non-primary invite link created +// by the bot. The bot must be an administrator in the chat for this to work and +// must have the appropriate admin rights. +type EditChatInviteLinkConfig struct { + ChatConfig + InviteLink string + Name string + ExpireDate int + MemberLimit int + CreatesJoinRequest bool +} + +func (EditChatInviteLinkConfig) method() string { + return "editChatInviteLink" +} + +func (config EditChatInviteLinkConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonEmpty("name", config.Name) + params["invite_link"] = config.InviteLink + params.AddNonZero("expire_date", config.ExpireDate) + params.AddNonZero("member_limit", config.MemberLimit) + params.AddBool("creates_join_request", config.CreatesJoinRequest) + + return params, nil +} + +// RevokeChatInviteLinkConfig allows you to revoke an invite link created by the +// bot. If the primary link is revoked, a new link is automatically generated. +// The bot must be an administrator in the chat for this to work and must have +// the appropriate admin rights. +type RevokeChatInviteLinkConfig struct { + ChatConfig + InviteLink string +} + +func (RevokeChatInviteLinkConfig) method() string { + return "revokeChatInviteLink" +} + +func (config RevokeChatInviteLinkConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params["invite_link"] = config.InviteLink + + return params, nil +} + +// ApproveChatJoinRequestConfig allows you to approve a chat join request. +type ApproveChatJoinRequestConfig struct { + ChatConfig + UserID int64 +} + +func (ApproveChatJoinRequestConfig) method() string { + return "approveChatJoinRequest" +} + +func (config ApproveChatJoinRequestConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero("user_id", int(config.UserID)) + + return params, nil +} + +// DeclineChatJoinRequest allows you to decline a chat join request. +type DeclineChatJoinRequest struct { + ChatConfig + UserID int64 +} + +func (DeclineChatJoinRequest) method() string { + return "declineChatJoinRequest" +} + +func (config DeclineChatJoinRequest) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero("user_id", int(config.UserID)) + + return params, nil +} + +// LeaveChatConfig allows you to leave a chat. +type LeaveChatConfig struct { + ChatID int64 + ChannelUsername string +} + +func (config LeaveChatConfig) method() string { + return "leaveChat" +} + +func (config LeaveChatConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + + return params, nil +} + +// ChatConfigWithUser contains information about a chat and a user. +type ChatConfigWithUser struct { + ChatID int64 + SuperGroupUsername string + UserID int64 +} + +func (config ChatConfigWithUser) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero64("user_id", config.UserID) + + return params, nil +} + +// GetChatMemberConfig is information about getting a specific member in a chat. +type GetChatMemberConfig struct { + ChatConfigWithUser +} + +func (GetChatMemberConfig) method() string { + return "getChatMember" +} + +// InvoiceConfig contains information for sendInvoice request. +type InvoiceConfig struct { + BaseChat + Title string // required + Description string // required + Payload string // required + ProviderToken string // required + Currency string // required + Prices []LabeledPrice // required + MaxTipAmount int + SuggestedTipAmounts []int + StartParameter string + ProviderData string + PhotoURL string + PhotoSize int + PhotoWidth int + PhotoHeight int + NeedName bool + NeedPhoneNumber bool + NeedEmail bool + NeedShippingAddress bool + SendPhoneNumberToProvider bool + SendEmailToProvider bool + IsFlexible bool +} + +func (config InvoiceConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params["title"] = config.Title + params["description"] = config.Description + params["payload"] = config.Payload + params["provider_token"] = config.ProviderToken + params["currency"] = config.Currency + if err = params.AddInterface("prices", config.Prices); err != nil { + return params, err + } + + params.AddNonZero("max_tip_amount", config.MaxTipAmount) + err = params.AddInterface("suggested_tip_amounts", config.SuggestedTipAmounts) + params.AddNonEmpty("start_parameter", config.StartParameter) + params.AddNonEmpty("provider_data", config.ProviderData) + params.AddNonEmpty("photo_url", config.PhotoURL) + params.AddNonZero("photo_size", config.PhotoSize) + params.AddNonZero("photo_width", config.PhotoWidth) + params.AddNonZero("photo_height", config.PhotoHeight) + params.AddBool("need_name", config.NeedName) + params.AddBool("need_phone_number", config.NeedPhoneNumber) + params.AddBool("need_email", config.NeedEmail) + params.AddBool("need_shipping_address", config.NeedShippingAddress) + params.AddBool("is_flexible", config.IsFlexible) + params.AddBool("send_phone_number_to_provider", config.SendPhoneNumberToProvider) + params.AddBool("send_email_to_provider", config.SendEmailToProvider) + + return params, err +} + +func (config InvoiceConfig) method() string { + return "sendInvoice" +} + +// InvoiceLinkConfig contains information for createInvoiceLink method +type InvoiceLinkConfig struct { + Title string //Required + Description string //Required + Payload string //Required + ProviderToken string //Required + Currency string //Required + Prices []LabeledPrice //Required + MaxTipAmount int + SuggestedTipAmounts []int + ProviderData string + PhotoURL string + PhotoSize int + PhotoWidth int + PhotoHeight int + NeedName bool + NeedPhoneNumber bool + NeedEmail bool + NeedShippingAddress bool + SendPhoneNumberToProvider bool + SendEmailToProvider bool + IsFlexible bool +} + +func (config InvoiceLinkConfig) params() (Params, error) { + params := make(Params) + + params["title"] = config.Title + params["description"] = config.Description + params["payload"] = config.Payload + params["provider_token"] = config.ProviderToken + params["currency"] = config.Currency + if err := params.AddInterface("prices", config.Prices); err != nil { + return params, err + } + + params.AddNonZero("max_tip_amount", config.MaxTipAmount) + err := params.AddInterface("suggested_tip_amounts", config.SuggestedTipAmounts) + params.AddNonEmpty("provider_data", config.ProviderData) + params.AddNonEmpty("photo_url", config.PhotoURL) + params.AddNonZero("photo_size", config.PhotoSize) + params.AddNonZero("photo_width", config.PhotoWidth) + params.AddNonZero("photo_height", config.PhotoHeight) + params.AddBool("need_name", config.NeedName) + params.AddBool("need_phone_number", config.NeedPhoneNumber) + params.AddBool("need_email", config.NeedEmail) + params.AddBool("need_shipping_address", config.NeedShippingAddress) + params.AddBool("send_phone_number_to_provider", config.SendPhoneNumberToProvider) + params.AddBool("send_email_to_provider", config.SendEmailToProvider) + params.AddBool("is_flexible", config.IsFlexible) + + return params, err +} + +func (config InvoiceLinkConfig) method() string { + return "createInvoiceLink" +} + +// ShippingConfig contains information for answerShippingQuery request. +type ShippingConfig struct { + ShippingQueryID string // required + OK bool // required + ShippingOptions []ShippingOption + ErrorMessage string +} + +func (config ShippingConfig) method() string { + return "answerShippingQuery" +} + +func (config ShippingConfig) params() (Params, error) { + params := make(Params) + + params["shipping_query_id"] = config.ShippingQueryID + params.AddBool("ok", config.OK) + err := params.AddInterface("shipping_options", config.ShippingOptions) + params.AddNonEmpty("error_message", config.ErrorMessage) + + return params, err +} + +// PreCheckoutConfig contains information for answerPreCheckoutQuery request. +type PreCheckoutConfig struct { + PreCheckoutQueryID string // required + OK bool // required + ErrorMessage string +} + +func (config PreCheckoutConfig) method() string { + return "answerPreCheckoutQuery" +} + +func (config PreCheckoutConfig) params() (Params, error) { + params := make(Params) + + params["pre_checkout_query_id"] = config.PreCheckoutQueryID + params.AddBool("ok", config.OK) + params.AddNonEmpty("error_message", config.ErrorMessage) + + return params, nil +} + +// DeleteMessageConfig contains information of a message in a chat to delete. +type DeleteMessageConfig struct { + ChannelUsername string + ChatID int64 + MessageID int +} + +func (config DeleteMessageConfig) method() string { + return "deleteMessage" +} + +func (config DeleteMessageConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero("message_id", config.MessageID) + + return params, nil +} + +// PinChatMessageConfig contains information of a message in a chat to pin. +type PinChatMessageConfig struct { + ChatID int64 + ChannelUsername string + MessageID int + DisableNotification bool +} + +func (config PinChatMessageConfig) method() string { + return "pinChatMessage" +} + +func (config PinChatMessageConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero("message_id", config.MessageID) + params.AddBool("disable_notification", config.DisableNotification) + + return params, nil +} + +// UnpinChatMessageConfig contains information of a chat message to unpin. +// +// If MessageID is not specified, it will unpin the most recent pin. +type UnpinChatMessageConfig struct { + ChatID int64 + ChannelUsername string + MessageID int +} + +func (config UnpinChatMessageConfig) method() string { + return "unpinChatMessage" +} + +func (config UnpinChatMessageConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddNonZero("message_id", config.MessageID) + + return params, nil +} + +// UnpinAllChatMessagesConfig contains information of all messages to unpin in +// a chat. +type UnpinAllChatMessagesConfig struct { + ChatID int64 + ChannelUsername string +} + +func (config UnpinAllChatMessagesConfig) method() string { + return "unpinAllChatMessages" +} + +func (config UnpinAllChatMessagesConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + + return params, nil +} + +// SetChatPhotoConfig allows you to set a group, supergroup, or channel's photo. +type SetChatPhotoConfig struct { + BaseFile +} + +func (config SetChatPhotoConfig) method() string { + return "setChatPhoto" +} + +func (config SetChatPhotoConfig) files() []RequestFile { + return []RequestFile{{ + Name: "photo", + Data: config.File, + }} +} + +// DeleteChatPhotoConfig allows you to delete a group, supergroup, or channel's photo. +type DeleteChatPhotoConfig struct { + ChatID int64 + ChannelUsername string +} + +func (config DeleteChatPhotoConfig) method() string { + return "deleteChatPhoto" +} + +func (config DeleteChatPhotoConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + + return params, nil +} + +// SetChatTitleConfig allows you to set the title of something other than a private chat. +type SetChatTitleConfig struct { + ChatID int64 + ChannelUsername string + + Title string +} + +func (config SetChatTitleConfig) method() string { + return "setChatTitle" +} + +func (config SetChatTitleConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params["title"] = config.Title + + return params, nil +} + +// SetChatDescriptionConfig allows you to set the description of a supergroup or channel. +type SetChatDescriptionConfig struct { + ChatID int64 + ChannelUsername string + + Description string +} + +func (config SetChatDescriptionConfig) method() string { + return "setChatDescription" +} + +func (config SetChatDescriptionConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params["description"] = config.Description + + return params, nil +} + +// GetStickerSetConfig allows you to get the stickers in a set. +type GetStickerSetConfig struct { + Name string +} + +func (config GetStickerSetConfig) method() string { + return "getStickerSet" +} + +func (config GetStickerSetConfig) params() (Params, error) { + params := make(Params) + + params["name"] = config.Name + + return params, nil +} + +// GetCustomEmojiStickersConfig get information about +// custom emoji stickers by their identifiers. +type GetCustomEmojiStickersConfig struct { + CustomEmojiIDs []string +} + +func (config GetCustomEmojiStickersConfig) params() (Params, error) { + params := make(Params) + + params.AddInterface("custom_emoji_ids", config.CustomEmojiIDs) + + return params, nil +} + +func (config GetCustomEmojiStickersConfig) method() string { + return "getCustomEmojiStickers" +} + +// UploadStickerConfig allows you to upload a sticker for use in a set later. +type UploadStickerConfig struct { + UserID int64 + PNGSticker RequestFileData +} + +func (config UploadStickerConfig) method() string { + return "uploadStickerFile" +} + +func (config UploadStickerConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero64("user_id", config.UserID) + + return params, nil +} + +func (config UploadStickerConfig) files() []RequestFile { + return []RequestFile{{ + Name: "png_sticker", + Data: config.PNGSticker, + }} +} + +// NewStickerSetConfig allows creating a new sticker set. +// +// You must set either PNGSticker or TGSSticker. +type NewStickerSetConfig struct { + UserID int64 + Name string + Title string + PNGSticker RequestFileData + TGSSticker RequestFileData + StickerType string + Emojis string + ContainsMasks bool // deprecated + MaskPosition *MaskPosition +} + +func (config NewStickerSetConfig) method() string { + return "createNewStickerSet" +} + +func (config NewStickerSetConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero64("user_id", config.UserID) + params["name"] = config.Name + params["title"] = config.Title + params["emojis"] = config.Emojis + + params.AddBool("contains_masks", config.ContainsMasks) + params.AddNonEmpty("sticker_type", string(config.StickerType)) + err := params.AddInterface("mask_position", config.MaskPosition) + + return params, err +} + +func (config NewStickerSetConfig) files() []RequestFile { + if config.PNGSticker != nil { + return []RequestFile{{ + Name: "png_sticker", + Data: config.PNGSticker, + }} + } + + return []RequestFile{{ + Name: "tgs_sticker", + Data: config.TGSSticker, + }} +} + +// AddStickerConfig allows you to add a sticker to a set. +type AddStickerConfig struct { + UserID int64 + Name string + PNGSticker RequestFileData + TGSSticker RequestFileData + Emojis string + MaskPosition *MaskPosition +} + +func (config AddStickerConfig) method() string { + return "addStickerToSet" +} + +func (config AddStickerConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero64("user_id", config.UserID) + params["name"] = config.Name + params["emojis"] = config.Emojis + + err := params.AddInterface("mask_position", config.MaskPosition) + + return params, err +} + +func (config AddStickerConfig) files() []RequestFile { + if config.PNGSticker != nil { + return []RequestFile{{ + Name: "png_sticker", + Data: config.PNGSticker, + }} + } + + return []RequestFile{{ + Name: "tgs_sticker", + Data: config.TGSSticker, + }} + +} + +// SetStickerPositionConfig allows you to change the position of a sticker in a set. +type SetStickerPositionConfig struct { + Sticker string + Position int +} + +func (config SetStickerPositionConfig) method() string { + return "setStickerPositionInSet" +} + +func (config SetStickerPositionConfig) params() (Params, error) { + params := make(Params) + + params["sticker"] = config.Sticker + params.AddNonZero("position", config.Position) + + return params, nil +} + +// DeleteStickerConfig allows you to delete a sticker from a set. +type DeleteStickerConfig struct { + Sticker string +} + +func (config DeleteStickerConfig) method() string { + return "deleteStickerFromSet" +} + +func (config DeleteStickerConfig) params() (Params, error) { + params := make(Params) + + params["sticker"] = config.Sticker + + return params, nil +} + +// SetStickerSetThumbConfig allows you to set the thumbnail for a sticker set. +type SetStickerSetThumbConfig struct { + Name string + UserID int64 + Thumb RequestFileData +} + +func (config SetStickerSetThumbConfig) method() string { + return "setStickerSetThumb" +} + +func (config SetStickerSetThumbConfig) params() (Params, error) { + params := make(Params) + + params["name"] = config.Name + params.AddNonZero64("user_id", config.UserID) + + return params, nil +} + +func (config SetStickerSetThumbConfig) files() []RequestFile { + return []RequestFile{{ + Name: "thumb", + Data: config.Thumb, + }} +} + +// SetChatStickerSetConfig allows you to set the sticker set for a supergroup. +type SetChatStickerSetConfig struct { + ChatID int64 + SuperGroupUsername string + + StickerSetName string +} + +func (config SetChatStickerSetConfig) method() string { + return "setChatStickerSet" +} + +func (config SetChatStickerSetConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params["sticker_set_name"] = config.StickerSetName + + return params, nil +} + +// DeleteChatStickerSetConfig allows you to remove a supergroup's sticker set. +type DeleteChatStickerSetConfig struct { + ChatID int64 + SuperGroupUsername string +} + +func (config DeleteChatStickerSetConfig) method() string { + return "deleteChatStickerSet" +} + +func (config DeleteChatStickerSetConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + + return params, nil +} + +// GetForumTopicIconStickersConfig allows you to get custom emoji stickers, +// which can be used as a forum topic icon by any user. +type GetForumTopicIconStickersConfig struct{} + +func (config GetForumTopicIconStickersConfig) method() string { + return "getForumTopicIconStickers" +} + +func (config GetForumTopicIconStickersConfig) params() (Params, error) { + return nil, nil +} + +// BaseForum is a base type for all forum config types. +type BaseForum struct { + ChatID int64 + SuperGroupUsername string +} + +func (config BaseForum) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + + return params, nil +} + +// CreateForumTopicConfig allows you to create a topic +// in a forum supergroup chat. +type CreateForumTopicConfig struct { + BaseForum + Name string + IconColor int + IconCustomEmojiID string +} + +func (config CreateForumTopicConfig) method() string { + return "createForumTopic" +} + +func (config CreateForumTopicConfig) params() (Params, error) { + params := make(Params) + + params.AddNonEmpty("name", config.Name) + params.AddNonZero("icon_color", config.IconColor) + params.AddNonEmpty("icon_custom_emoji_id", config.IconCustomEmojiID) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// EditForumTopicConfig allows you to edit +// name and icon of a topic in a forum supergroup chat. +type EditForumTopicConfig struct { + BaseForum + MessageThreadID int + Name string + IconCustomEmojiID string +} + +func (config EditForumTopicConfig) method() string { + return "editForumTopic" +} + +func (config EditForumTopicConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero("message_thread_id", config.MessageThreadID) + params.AddNonEmpty("name", config.Name) + params.AddNonEmpty("icon_custom_emoji_id", config.IconCustomEmojiID) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// CloseForumTopicConfig allows you to close +// an open topic in a forum supergroup chat. +type CloseForumTopicConfig struct { + BaseForum + MessageThreadID int +} + +func (config CloseForumTopicConfig) method() string { + return "closeForumTopic" +} + +func (config CloseForumTopicConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero("message_thread_id", config.MessageThreadID) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// ReopenForumTopicConfig allows you to reopen +// an closed topic in a forum supergroup chat. +type ReopenForumTopicConfig struct { + BaseForum + MessageThreadID int +} + +func (config ReopenForumTopicConfig) method() string { + return "reopenForumTopic" +} + +func (config ReopenForumTopicConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero("message_thread_id", config.MessageThreadID) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// DeleteForumTopicConfig allows you to delete a forum topic +// along with all its messages in a forum supergroup chat. +type DeleteForumTopicConfig struct { + BaseForum + MessageThreadID int +} + +func (config DeleteForumTopicConfig) method() string { + return "deleteForumTopic" +} + +func (config DeleteForumTopicConfig) params() (Params, error) { + params := make(Params) + + params.AddNonZero("message_thread_id", config.MessageThreadID) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// UnpinAllForumTopicMessagesConfig allows you to clear the list +// of pinned messages in a forum topic. +type UnpinAllForumTopicMessagesConfig struct { + BaseForum + MessageThreadID int +} + +func (config UnpinAllForumTopicMessagesConfig) method() string { + return "unpinAllForumTopicMessages" +} + +func (config UnpinAllForumTopicMessagesConfig) params() (Params, error) { + params := make(Params) + + params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) + params.AddNonZero("message_thread_id", config.MessageThreadID) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// UnpinAllForumTopicMessagesConfig allows you to edit the name of +// the 'General' topic in a forum supergroup chat. +// The bot must be an administrator in the chat for this to work +// and must have can_manage_topics administrator rights. Returns True on success. +type EditGeneralForumTopicConfig struct { + BaseForum + Name string +} + +func (config EditGeneralForumTopicConfig) method() string { + return "editGeneralForumTopic" +} + +func (config EditGeneralForumTopicConfig) params() (Params, error) { + params := make(Params) + + params.AddNonEmpty("name", config.Name) + + p1, _ := config.BaseForum.params() + params.Merge(p1) + + return params, nil +} + +// CloseGeneralForumTopicConfig allows you to to close an open 'General' topic +// in a forum supergroup chat. The bot must be an administrator in the chat +// for this to work and must have the can_manage_topics administrator rights. +// Returns True on success. +type CloseGeneralForumTopicConfig struct{ BaseForum } + +func (config CloseGeneralForumTopicConfig) method() string { + return "closeGeneralForumTopic" +} + +// CloseGeneralForumTopicConfig allows you to reopen a closed 'General' topic +// in a forum supergroup chat. The bot must be an administrator in the chat +// for this to work and must have the can_manage_topics administrator rights. +// The topic will be automatically unhidden if it was hidden. +// Returns True on success. +type ReopenGeneralForumTopicConfig struct{ BaseForum } + +func (config ReopenGeneralForumTopicConfig) method() string { + return "reopenGeneralForumTopic" +} + +// HideGeneralForumTopicConfig allows you to hide the 'General' topic +// in a forum supergroup chat. The bot must be an administrator in the chat +// for this to work and must have the can_manage_topics administrator rights. +// The topic will be automatically closed if it was open. +// Returns True on success. +type HideGeneralForumTopicConfig struct{ BaseForum } + +func (config HideGeneralForumTopicConfig) method() string { + return "hideGeneralForumTopic" +} + +// UnhideGeneralForumTopicConfig allows you to unhide the 'General' topic +// in a forum supergroup chat. The bot must be an administrator in the chat +// for this to work and must have the can_manage_topics administrator rights. +// Returns True on success. +type UnhideGeneralForumTopicConfig struct{ BaseForum } + +func (config UnhideGeneralForumTopicConfig) method() string { + return "unhideGeneralForumTopic" +} + +// MediaGroupConfig allows you to send a group of media. +// +// Media consist of InputMedia items (InputMediaPhoto, InputMediaVideo). +type MediaGroupConfig struct { + BaseChat + Media []interface{} +} + +func (config MediaGroupConfig) method() string { + return "sendMediaGroup" +} + +func (config MediaGroupConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return nil, err + } + + params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params.AddBool("disable_notification", config.DisableNotification) + params.AddNonZero("reply_to_message_id", config.ReplyToMessageID) + + err = params.AddInterface("media", prepareInputMediaForParams(config.Media)) + + return params, err +} + +func (config MediaGroupConfig) files() []RequestFile { + return prepareInputMediaForFiles(config.Media) +} + +// 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 🎳, values 1-5 for 🏀 and ⚽, + // and values 1-64 for 🎰. + // Defaults to “🎲” + Emoji string +} + +func (config DiceConfig) method() string { + return "sendDice" +} + +func (config DiceConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + params.AddNonEmpty("emoji", config.Emoji) + + return params, err +} + +// GetMyCommandsConfig gets a list of the currently registered commands. +type GetMyCommandsConfig struct { + Scope *BotCommandScope + LanguageCode string +} + +func (config GetMyCommandsConfig) method() string { + return "getMyCommands" +} + +func (config GetMyCommandsConfig) params() (Params, error) { + params := make(Params) + + err := params.AddInterface("scope", config.Scope) + params.AddNonEmpty("language_code", config.LanguageCode) + + return params, err +} + +// SetMyCommandsConfig sets a list of commands the bot understands. +type SetMyCommandsConfig struct { + Commands []BotCommand + Scope *BotCommandScope + LanguageCode string +} + +func (config SetMyCommandsConfig) method() string { + return "setMyCommands" +} + +func (config SetMyCommandsConfig) params() (Params, error) { + params := make(Params) + + if err := params.AddInterface("commands", config.Commands); err != nil { + return params, err + } + err := params.AddInterface("scope", config.Scope) + params.AddNonEmpty("language_code", config.LanguageCode) + + return params, err +} + +type DeleteMyCommandsConfig struct { + Scope *BotCommandScope + LanguageCode string +} + +func (config DeleteMyCommandsConfig) method() string { + return "deleteMyCommands" +} + +func (config DeleteMyCommandsConfig) params() (Params, error) { + params := make(Params) + + err := params.AddInterface("scope", config.Scope) + params.AddNonEmpty("language_code", config.LanguageCode) + + return params, err +} + +// SetChatMenuButtonConfig changes the bot's menu button in a private chat, +// or the default menu button. +type SetChatMenuButtonConfig struct { + ChatID int64 + ChannelUsername string + + MenuButton *MenuButton +} + +func (config SetChatMenuButtonConfig) method() string { + return "setChatMenuButton" +} + +func (config SetChatMenuButtonConfig) params() (Params, error) { + params := make(Params) + + if err := params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername); err != nil { + return params, err + } + err := params.AddInterface("menu_button", config.MenuButton) + + return params, err +} + +type GetChatMenuButtonConfig struct { + ChatID int64 + ChannelUsername string +} + +func (config GetChatMenuButtonConfig) method() string { + return "getChatMenuButton" +} + +func (config GetChatMenuButtonConfig) params() (Params, error) { + params := make(Params) + + err := params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + + return params, err +} + +type SetMyDefaultAdministratorRightsConfig struct { + Rights ChatAdministratorRights + ForChannels bool +} + +func (config SetMyDefaultAdministratorRightsConfig) method() string { + return "setMyDefaultAdministratorRights" +} + +func (config SetMyDefaultAdministratorRightsConfig) params() (Params, error) { + params := make(Params) + + err := params.AddInterface("rights", config.Rights) + params.AddBool("for_channels", config.ForChannels) + + return params, err +} + +type GetMyDefaultAdministratorRightsConfig struct { + ForChannels bool +} + +func (config GetMyDefaultAdministratorRightsConfig) method() string { + return "getMyDefaultAdministratorRights" +} + +func (config GetMyDefaultAdministratorRightsConfig) params() (Params, error) { + params := make(Params) + + params.AddBool("for_channels", config.ForChannels) + + return params, nil +} + +// prepareInputMediaParam evaluates a single InputMedia and determines if it +// needs to be modified for a successful upload. If it returns nil, then the +// value does not need to be included in the params. Otherwise, it will return +// the same type as was originally provided. +// +// The idx is used to calculate the file field name. If you only have a single +// file, 0 may be used. It is formatted into "attach://file-%d" for the primary +// media and "attach://file-%d-thumb" for thumbnails. +// +// It is expected to be used in conjunction with prepareInputMediaFile. +func prepareInputMediaParam(inputMedia interface{}, idx int) interface{} { + switch m := inputMedia.(type) { + case InputMediaPhoto: + if m.Media.NeedsUpload() { + m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) + } + + return m + case InputMediaVideo: + if m.Media.NeedsUpload() { + m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) + } + + if m.Thumb != nil && m.Thumb.NeedsUpload() { + m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx)) + } + + return m + case InputMediaAudio: + if m.Media.NeedsUpload() { + m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) + } + + if m.Thumb != nil && m.Thumb.NeedsUpload() { + m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx)) + } + + return m + case InputMediaDocument: + if m.Media.NeedsUpload() { + m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx)) + } + + if m.Thumb != nil && m.Thumb.NeedsUpload() { + m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx)) + } + + return m + } + + return nil +} + +// prepareInputMediaFile generates an array of RequestFile to provide for +// Fileable's files method. It returns an array as a single InputMedia may have +// multiple files, for the primary media and a thumbnail. +// +// The idx parameter is used to generate file field names. It uses the names +// "file-%d" for the main file and "file-%d-thumb" for the thumbnail. +// +// It is expected to be used in conjunction with prepareInputMediaParam. +func prepareInputMediaFile(inputMedia interface{}, idx int) []RequestFile { + files := []RequestFile{} + + switch m := inputMedia.(type) { + case InputMediaPhoto: + if m.Media.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Media, + }) + } + case InputMediaVideo: + if m.Media.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Media, + }) + } + + if m.Thumb != nil && m.Thumb.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Thumb, + }) + } + case InputMediaDocument: + if m.Media.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Media, + }) + } + + if m.Thumb != nil && m.Thumb.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Thumb, + }) + } + case InputMediaAudio: + if m.Media.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Media, + }) + } + + if m.Thumb != nil && m.Thumb.NeedsUpload() { + files = append(files, RequestFile{ + Name: fmt.Sprintf("file-%d", idx), + Data: m.Thumb, + }) + } + } + + return files +} + +// prepareInputMediaForParams calls prepareInputMediaParam for each item +// provided and returns a new array with the correct params for a request. +// +// It is expected that files will get data from the associated function, +// prepareInputMediaForFiles. +func prepareInputMediaForParams(inputMedia []interface{}) []interface{} { + newMedia := make([]interface{}, len(inputMedia)) + copy(newMedia, inputMedia) + + for idx, media := range inputMedia { + if param := prepareInputMediaParam(media, idx); param != nil { + newMedia[idx] = param + } + } + + return newMedia +} + +// prepareInputMediaForFiles calls prepareInputMediaFile for each item +// provided and returns a new array with the correct files for a request. +// +// It is expected that params will get data from the associated function, +// prepareInputMediaForParams. +func prepareInputMediaForFiles(inputMedia []interface{}) []RequestFile { + files := []RequestFile{} + + for idx, media := range inputMedia { + if file := prepareInputMediaFile(media, idx); file != nil { + files = append(files, file...) + } + } + + return files +} diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/helpers.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/helpers.go new file mode 100644 index 00000000..bdf2ee97 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/helpers.go @@ -0,0 +1,989 @@ +package tgbotapi + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "net/url" + "sort" + "strings" +) + +// NewMessage creates a new Message. +// +// chatID is where to send it, text is the message text. +func NewMessage(chatID int64, text string) MessageConfig { + return MessageConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + ReplyToMessageID: 0, + }, + Text: text, + DisableWebPagePreview: false, + } +} + +// NewDeleteMessage creates a request to delete a message. +func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { + return DeleteMessageConfig{ + ChatID: chatID, + MessageID: messageID, + } +} + +// 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, +// and the username should be in the form of `@username`. +func NewMessageToChannel(username string, text string) MessageConfig { + return MessageConfig{ + BaseChat: BaseChat{ + ChannelUsername: username, + }, + Text: text, + } +} + +// NewForward creates a new forward. +// +// chatID is where to send it, fromChatID is the source chat, +// and messageID is the ID of the original message. +func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { + return ForwardConfig{ + BaseChat: BaseChat{ChatID: chatID}, + FromChatID: fromChatID, + MessageID: messageID, + } +} + +// NewCopyMessage creates a new copy message. +// +// chatID is where to send it, fromChatID is the source chat, +// and messageID is the ID of the original message. +func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig { + return CopyMessageConfig{ + BaseChat: BaseChat{ChatID: chatID}, + FromChatID: fromChatID, + MessageID: messageID, + } +} + +// NewPhoto creates a new sendPhoto request. +// +// chatID is where to send it, file is a string path to the file, +// FileReader, or FileBytes. +// +// Note that you must send animated GIFs as a document. +func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { + return PhotoConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewPhotoToChannel creates a new photo uploader to send a photo to a channel. +// +// Note that you must send animated GIFs as a document. +func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { + return PhotoConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ + ChannelUsername: username, + }, + File: file, + }, + } +} + +// NewAudio creates a new sendAudio request. +func NewAudio(chatID int64, file RequestFileData) AudioConfig { + return AudioConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewDocument creates a new sendDocument request. +func NewDocument(chatID int64, file RequestFileData) DocumentConfig { + return DocumentConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewSticker creates a new sendSticker request. +func NewSticker(chatID int64, file RequestFileData) StickerConfig { + return StickerConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewVideo creates a new sendVideo request. +func NewVideo(chatID int64, file RequestFileData) VideoConfig { + return VideoConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewAnimation creates a new sendAnimation request. +func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { + return AnimationConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewVideoNote creates a new sendVideoNote request. +// +// chatID is where to send it, file is a string path to the file, +// FileReader, or FileBytes. +func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig { + return VideoNoteConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + Length: length, + } +} + +// NewVoice creates a new sendVoice request. +func NewVoice(chatID int64, file RequestFileData) VoiceConfig { + return VoiceConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ChatID: chatID}, + File: file, + }, + } +} + +// NewMediaGroup creates a new media group. Files should be an array of +// two to ten InputMediaPhoto or InputMediaVideo. +func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig { + return MediaGroupConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + Media: files, + } +} + +// NewInputMediaPhoto creates a new InputMediaPhoto. +func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto { + return InputMediaPhoto{ + BaseInputMedia{ + Type: "photo", + Media: media, + }, + } +} + +// NewInputMediaVideo creates a new InputMediaVideo. +func NewInputMediaVideo(media RequestFileData) InputMediaVideo { + return InputMediaVideo{ + BaseInputMedia: BaseInputMedia{ + Type: "video", + Media: media, + }, + } +} + +// NewInputMediaAnimation creates a new InputMediaAnimation. +func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation { + return InputMediaAnimation{ + BaseInputMedia: BaseInputMedia{ + Type: "animation", + Media: media, + }, + } +} + +// NewInputMediaAudio creates a new InputMediaAudio. +func NewInputMediaAudio(media RequestFileData) InputMediaAudio { + return InputMediaAudio{ + BaseInputMedia: BaseInputMedia{ + Type: "audio", + Media: media, + }, + } +} + +// NewInputMediaDocument creates a new InputMediaDocument. +func NewInputMediaDocument(media RequestFileData) InputMediaDocument { + return InputMediaDocument{ + BaseInputMedia: BaseInputMedia{ + Type: "document", + Media: media, + }, + } +} + +// NewContact allows you to send a shared contact. +func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig { + return ContactConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + PhoneNumber: phoneNumber, + FirstName: firstName, + } +} + +// NewLocation shares your location. +// +// chatID is where to send it, latitude and longitude are coordinates. +func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig { + return LocationConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + Latitude: latitude, + Longitude: longitude, + } +} + +// NewVenue allows you to send a venue and its location. +func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig { + return VenueConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + Title: title, + Address: address, + Latitude: latitude, + Longitude: longitude, + } +} + +// NewChatAction sets a chat action. +// Actions last for 5 seconds, or until your next action. +// +// chatID is where to send it, action should be set via Chat constants. +func NewChatAction(chatID int64, action string) ChatActionConfig { + return ChatActionConfig{ + BaseChat: BaseChat{ChatID: chatID}, + Action: action, + } +} + +// NewUserProfilePhotos gets user profile photos. +// +// userID is the ID of the user you wish to get profile photos from. +func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig { + return UserProfilePhotosConfig{ + UserID: userID, + Offset: 0, + Limit: 0, + } +} + +// NewUpdate gets updates since the last Offset. +// +// offset is the last Update ID to include. +// You likely want to set this to the last Update ID plus 1. +func NewUpdate(offset int) UpdateConfig { + return UpdateConfig{ + Offset: offset, + Limit: 0, + Timeout: 0, + } +} + +// NewWebhook creates a new webhook. +// +// link is the url parsable link you wish to get the updates. +func NewWebhook(link string) (WebhookConfig, error) { + u, err := url.Parse(link) + + if err != nil { + return WebhookConfig{}, err + } + + return WebhookConfig{ + URL: u, + }, nil +} + +// NewWebhookWithCert creates a new webhook with a certificate. +// +// link is the url you wish to get webhooks, +// file contains a string to a file, FileReader, or FileBytes. +func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) { + u, err := url.Parse(link) + + if err != nil { + return WebhookConfig{}, err + } + + return WebhookConfig{ + URL: u, + Certificate: file, + }, nil +} + +// NewInlineQueryResultArticle creates a new inline query article. +func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle { + return InlineQueryResultArticle{ + Type: "article", + ID: id, + Title: title, + InputMessageContent: InputTextMessageContent{ + Text: messageText, + }, + } +} + +// NewInlineQueryResultArticleMarkdown creates a new inline query article with Markdown parsing. +func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQueryResultArticle { + return InlineQueryResultArticle{ + Type: "article", + ID: id, + Title: title, + InputMessageContent: InputTextMessageContent{ + Text: messageText, + ParseMode: "Markdown", + }, + } +} + +// 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{ + Type: "article", + ID: id, + Title: title, + InputMessageContent: InputTextMessageContent{ + Text: messageText, + ParseMode: "HTML", + }, + } +} + +// NewInlineQueryResultGIF creates a new inline query GIF. +func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF { + return InlineQueryResultGIF{ + Type: "gif", + ID: id, + URL: url, + } +} + +// NewInlineQueryResultCachedGIF create a new inline query with cached photo. +func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF { + return InlineQueryResultCachedGIF{ + Type: "gif", + ID: id, + GIFID: gifID, + } +} + +// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF. +func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF { + return InlineQueryResultMPEG4GIF{ + Type: "mpeg4_gif", + ID: id, + URL: url, + } +} + +// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF. +func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF { + return InlineQueryResultCachedMPEG4GIF{ + Type: "mpeg4_gif", + ID: id, + MPEG4FileID: MPEG4GIFID, + } +} + +// NewInlineQueryResultPhoto creates a new inline query photo. +func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto { + return InlineQueryResultPhoto{ + Type: "photo", + ID: id, + URL: url, + } +} + +// NewInlineQueryResultPhotoWithThumb creates a new inline query photo. +func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResultPhoto { + return InlineQueryResultPhoto{ + Type: "photo", + ID: id, + URL: url, + ThumbURL: thumb, + } +} + +// NewInlineQueryResultCachedPhoto create a new inline query with cached photo. +func NewInlineQueryResultCachedPhoto(id, photoID string) InlineQueryResultCachedPhoto { + return InlineQueryResultCachedPhoto{ + Type: "photo", + ID: id, + PhotoID: photoID, + } +} + +// NewInlineQueryResultVideo creates a new inline query video. +func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo { + return InlineQueryResultVideo{ + Type: "video", + ID: id, + URL: url, + } +} + +// NewInlineQueryResultCachedVideo create a new inline query with cached video. +func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResultCachedVideo { + return InlineQueryResultCachedVideo{ + Type: "video", + ID: id, + VideoID: videoID, + Title: title, + } +} + +// 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{ + Type: "audio", + ID: id, + URL: url, + Title: title, + } +} + +// NewInlineQueryResultCachedAudio create a new inline query with cached photo. +func NewInlineQueryResultCachedAudio(id, audioID string) InlineQueryResultCachedAudio { + return InlineQueryResultCachedAudio{ + Type: "audio", + ID: id, + AudioID: audioID, + } +} + +// NewInlineQueryResultVoice creates a new inline query voice. +func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice { + return InlineQueryResultVoice{ + Type: "voice", + ID: id, + URL: url, + Title: title, + } +} + +// NewInlineQueryResultCachedVoice create a new inline query with cached photo. +func NewInlineQueryResultCachedVoice(id, voiceID, title string) InlineQueryResultCachedVoice { + return InlineQueryResultCachedVoice{ + Type: "voice", + ID: id, + VoiceID: voiceID, + Title: title, + } +} + +// NewInlineQueryResultDocument creates a new inline query document. +func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument { + return InlineQueryResultDocument{ + Type: "document", + ID: id, + URL: url, + Title: title, + MimeType: mimeType, + } +} + +// NewInlineQueryResultCachedDocument create a new inline query with cached photo. +func NewInlineQueryResultCachedDocument(id, documentID, title string) InlineQueryResultCachedDocument { + return InlineQueryResultCachedDocument{ + Type: "document", + ID: id, + DocumentID: documentID, + Title: title, + } +} + +// NewInlineQueryResultLocation creates a new inline query location. +func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation { + return InlineQueryResultLocation{ + Type: "location", + ID: id, + Title: title, + Latitude: latitude, + Longitude: longitude, + } +} + +// 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{ + BaseEdit: BaseEdit{ + ChatID: chatID, + MessageID: messageID, + }, + Text: text, + } +} + +// NewEditMessageTextAndMarkup allows you to edit the text and reply markup 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{ + BaseEdit: BaseEdit{ + ChatID: chatID, + MessageID: messageID, + }, + Caption: caption, + } +} + +// NewEditMessageReplyMarkup allows you to edit the inline +// keyboard markup. +func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig { + return EditMessageReplyMarkupConfig{ + BaseEdit: BaseEdit{ + ChatID: chatID, + MessageID: messageID, + ReplyMarkup: &replyMarkup, + }, + } +} + +// NewRemoveKeyboard hides the keyboard, with the option for being selective +// or hiding for everyone. +func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove { + return ReplyKeyboardRemove{ + RemoveKeyboard: true, + Selective: selective, + } +} + +// NewKeyboardButton creates a regular keyboard button. +func NewKeyboardButton(text string) KeyboardButton { + return KeyboardButton{ + Text: text, + } +} + +// NewKeyboardButtonWebApp creates a keyboard button with text +// which goes to a WebApp. +func NewKeyboardButtonWebApp(text string, webapp WebAppInfo) KeyboardButton { + return KeyboardButton{ + Text: text, + WebApp: &webapp, + } +} + +// NewKeyboardButtonContact creates a keyboard button that requests +// user contact information upon click. +func NewKeyboardButtonContact(text string) KeyboardButton { + return KeyboardButton{ + Text: text, + RequestContact: true, + } +} + +// NewKeyboardButtonLocation creates a keyboard button that requests +// user location information upon click. +func NewKeyboardButtonLocation(text string) KeyboardButton { + return KeyboardButton{ + Text: text, + RequestLocation: true, + } +} + +// NewKeyboardButtonRow creates a row of keyboard buttons. +func NewKeyboardButtonRow(buttons ...KeyboardButton) []KeyboardButton { + var row []KeyboardButton + + row = append(row, buttons...) + + return row +} + +// NewReplyKeyboard creates a new regular keyboard with sane defaults. +func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { + var keyboard [][]KeyboardButton + + keyboard = append(keyboard, rows...) + + return ReplyKeyboardMarkup{ + ResizeKeyboard: true, + Keyboard: keyboard, + } +} + +// NewOneTimeReplyKeyboard creates a new one time keyboard. +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 { + return InlineKeyboardButton{ + Text: text, + CallbackData: &data, + } +} + +// NewInlineKeyboardButtonWebApp creates an inline keyboard button with text +// which goes to a WebApp. +func NewInlineKeyboardButtonWebApp(text string, webapp WebAppInfo) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + WebApp: &webapp, + } +} + +// NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text +// which goes to a LoginURL. +func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + LoginURL: &loginURL, + } +} + +// NewInlineKeyboardButtonURL creates an inline keyboard button with text +// which goes to a URL. +func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + URL: &url, + } +} + +// NewInlineKeyboardButtonSwitch creates an inline keyboard button with +// text which allows the user to switch to a chat or return to a chat. +func NewInlineKeyboardButtonSwitch(text, sw string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + SwitchInlineQuery: &sw, + } +} + +// NewInlineKeyboardRow creates an inline keyboard row with buttons. +func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { + var row []InlineKeyboardButton + + row = append(row, buttons...) + + return row +} + +// NewInlineKeyboardMarkup creates a new inline keyboard. +func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup { + var keyboard [][]InlineKeyboardButton + + keyboard = append(keyboard, rows...) + + return InlineKeyboardMarkup{ + InlineKeyboard: keyboard, + } +} + +// NewCallback creates a new callback message. +func NewCallback(id, text string) CallbackConfig { + return CallbackConfig{ + CallbackQueryID: id, + Text: text, + ShowAlert: false, + } +} + +// NewCallbackWithAlert creates a new callback message that alerts +// the user. +func NewCallbackWithAlert(id, text string) CallbackConfig { + return CallbackConfig{ + CallbackQueryID: id, + Text: text, + ShowAlert: true, + } +} + +// NewInvoice creates a new Invoice request to the user. +func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig { + return InvoiceConfig{ + BaseChat: BaseChat{ChatID: chatID}, + Title: title, + Description: description, + Payload: payload, + ProviderToken: providerToken, + StartParameter: startParameter, + Currency: currency, + Prices: prices} +} + +// NewChatTitle allows you to update the title of a chat. +func NewChatTitle(chatID int64, title string) SetChatTitleConfig { + return SetChatTitleConfig{ + ChatID: chatID, + Title: title, + } +} + +// NewChatDescription allows you to update the description of a chat. +func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig { + return SetChatDescriptionConfig{ + ChatID: chatID, + Description: description, + } +} + +// NewChatPhoto allows you to update the photo for a chat. +func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { + return SetChatPhotoConfig{ + BaseFile: BaseFile{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + File: photo, + }, + } +} + +// NewDeleteChatPhoto allows you to delete the photo for a chat. +func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { + return DeleteChatPhotoConfig{ + ChatID: chatID, + } +} + +// NewPoll allows you to create a new poll. +func NewPoll(chatID int64, question string, options ...string) SendPollConfig { + return SendPollConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + Question: question, + Options: options, + IsAnonymous: true, // This is Telegram's default. + } +} + +// NewStopPoll allows you to stop a poll. +func NewStopPoll(chatID int64, messageID int) StopPollConfig { + return StopPollConfig{ + BaseEdit{ + ChatID: chatID, + MessageID: messageID, + }, + } +} + +// NewDice allows you to send a random dice roll. +func NewDice(chatID int64) DiceConfig { + return DiceConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + } +} + +// NewDiceWithEmoji allows you to send a random roll of one of many types. +// +// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5). +func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig { + return DiceConfig{ + BaseChat: BaseChat{ + ChatID: chatID, + }, + Emoji: emoji, + } +} + +// NewBotCommandScopeDefault represents the default scope of bot commands. +func NewBotCommandScopeDefault() BotCommandScope { + return BotCommandScope{Type: "default"} +} + +// NewBotCommandScopeAllPrivateChats represents the scope of bot commands, +// covering all private chats. +func NewBotCommandScopeAllPrivateChats() BotCommandScope { + return BotCommandScope{Type: "all_private_chats"} +} + +// NewBotCommandScopeAllGroupChats represents the scope of bot commands, +// covering all group and supergroup chats. +func NewBotCommandScopeAllGroupChats() BotCommandScope { + return BotCommandScope{Type: "all_group_chats"} +} + +// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands, +// covering all group and supergroup chat administrators. +func NewBotCommandScopeAllChatAdministrators() BotCommandScope { + return BotCommandScope{Type: "all_chat_administrators"} +} + +// NewBotCommandScopeChat represents the scope of bot commands, covering a +// specific chat. +func NewBotCommandScopeChat(chatID int64) BotCommandScope { + return BotCommandScope{ + Type: "chat", + ChatID: chatID, + } +} + +// NewBotCommandScopeChatAdministrators represents the scope of bot commands, +// covering all administrators of a specific group or supergroup chat. +func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope { + return BotCommandScope{ + Type: "chat_administrators", + ChatID: chatID, + } +} + +// NewBotCommandScopeChatMember represents the scope of bot commands, covering a +// specific member of a group or supergroup chat. +func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope { + return BotCommandScope{ + Type: "chat_member", + ChatID: chatID, + UserID: userID, + } +} + +// NewGetMyCommandsWithScope allows you to set the registered commands for a +// given scope. +func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig { + return GetMyCommandsConfig{Scope: &scope} +} + +// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered +// commands for a given scope and language code. +func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig { + return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} +} + +// NewSetMyCommands allows you to set the registered commands. +func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig { + return SetMyCommandsConfig{Commands: commands} +} + +// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope. +func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig { + return SetMyCommandsConfig{Commands: commands, Scope: &scope} +} + +// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope +// and language code. +func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig { + return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode} +} + +// NewDeleteMyCommands allows you to delete the registered commands. +func NewDeleteMyCommands() DeleteMyCommandsConfig { + return DeleteMyCommandsConfig{} +} + +// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given +// scope. +func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig { + return DeleteMyCommandsConfig{Scope: &scope} +} + +// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given +// scope and language code. +func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig { + return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} +} + +// ValidateWebAppData validate data received via the Web App +// https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app +func ValidateWebAppData(token, telegramInitData string) (bool, error) { + initData, err := url.ParseQuery(telegramInitData) + if err != nil { + return false, fmt.Errorf("error parsing data %w", err) + } + + dataCheckString := make([]string, 0, len(initData)) + for k, v := range initData { + if k == "hash" { + continue + } + if len(v) > 0 { + dataCheckString = append(dataCheckString, fmt.Sprintf("%s=%s", k, v[0])) + } + } + + sort.Strings(dataCheckString) + + secret := hmac.New(sha256.New, []byte("WebAppData")) + secret.Write([]byte(token)) + + hHash := hmac.New(sha256.New, secret.Sum(nil)) + hHash.Write([]byte(strings.Join(dataCheckString, "\n"))) + + hash := hex.EncodeToString(hHash.Sum(nil)) + + if initData.Get("hash") != hash { + return false, errors.New("hash not equal") + } + + return true, nil +} diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/log.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/log.go new file mode 100644 index 00000000..18725514 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/log.go @@ -0,0 +1,27 @@ +package tgbotapi + +import ( + "errors" + stdlog "log" + "os" +) + +// BotLogger is an interface that represents the required methods to log data. +// +// Instead of requiring the standard logger, we can just specify the methods we +// use and allow users to pass anything that implements these. +type BotLogger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + +var log BotLogger = stdlog.New(os.Stderr, "", stdlog.LstdFlags) + +// SetLogger specifies the logger that the package should use. +func SetLogger(logger BotLogger) error { + if logger == nil { + return errors.New("logger is nil") + } + log = logger + return nil +} diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/params.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/params.go new file mode 100644 index 00000000..118af364 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/params.go @@ -0,0 +1,104 @@ +package tgbotapi + +import ( + "encoding/json" + "reflect" + "strconv" +) + +// Params represents a set of parameters that gets passed to a request. +type Params map[string]string + +// AddNonEmpty adds a value if it not an empty string. +func (p Params) AddNonEmpty(key, value string) { + if value != "" { + p[key] = value + } +} + +// AddNonZero adds a value if it is not zero. +func (p Params) AddNonZero(key string, value int) { + if value != 0 { + p[key] = strconv.Itoa(value) + } +} + +// AddNonZero64 is the same as AddNonZero except uses an int64. +func (p Params) AddNonZero64(key string, value int64) { + if value != 0 { + p[key] = strconv.FormatInt(value, 10) + } +} + +// AddBool adds a value of a bool if it is true. +func (p Params) AddBool(key string, value bool) { + if value { + p[key] = strconv.FormatBool(value) + } +} + +// AddNonZeroFloat adds a floating point value that is not zero. +func (p Params) AddNonZeroFloat(key string, value float64) { + if value != 0 { + p[key] = strconv.FormatFloat(value, 'f', 6, 64) + } +} + +// AddInterface adds an interface if it is not nil and can be JSON marshalled. +func (p Params) AddInterface(key string, value interface{}) error { + if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { + return nil + } + + b, err := json.Marshal(value) + if err != nil { + return err + } + + p[key] = string(b) + + return nil +} + +// AddFirstValid attempts to add the first item that is not a default value. +// +// For example, AddFirstValid(0, "", "test") would add "test". +func (p Params) AddFirstValid(key string, args ...interface{}) error { + for _, arg := range args { + switch v := arg.(type) { + case int: + if v != 0 { + p[key] = strconv.Itoa(v) + return nil + } + case int64: + if v != 0 { + p[key] = strconv.FormatInt(v, 10) + return nil + } + case string: + if v != "" { + p[key] = v + return nil + } + case nil: + default: + b, err := json.Marshal(arg) + if err != nil { + return err + } + + p[key] = string(b) + return nil + } + } + + return nil +} + +// Merge merges two sets of parameters. Overwrites old fields if present +func (p *Params) Merge(p1 Params) { + for k, v := range p1 { + (*p)[k] = v + } +} \ No newline at end of file diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/passport.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/passport.go new file mode 100644 index 00000000..4fedb965 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/passport.go @@ -0,0 +1,317 @@ +package tgbotapi + +// PassportRequestInfoConfig allows you to request passport info +type PassportRequestInfoConfig struct { + BotID int `json:"bot_id"` + Scope *PassportScope `json:"scope"` + Nonce string `json:"nonce"` + PublicKey string `json:"public_key"` +} + +// PassportScopeElement supports using one or one of several elements. +type PassportScopeElement interface { + ScopeType() string +} + +// PassportScope is the requested scopes of data. +type PassportScope struct { + V int `json:"v"` + Data []PassportScopeElement `json:"data"` +} + +// PassportScopeElementOneOfSeveral allows you to request any one of the +// requested documents. +type PassportScopeElementOneOfSeveral struct { +} + +// ScopeType is the scope type. +func (eo *PassportScopeElementOneOfSeveral) ScopeType() string { + return "one_of" +} + +// PassportScopeElementOne requires the specified element be provided. +type PassportScopeElementOne struct { + Type string `json:"type"` // One of “personal_details”, “passport”, “driver_license”, “identity_card”, “internal_passport”, “address”, “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration”, “temporary_registration”, “phone_number”, “email” + Selfie bool `json:"selfie"` + Translation bool `json:"translation"` + NativeNames bool `json:"native_name"` +} + +// ScopeType is the scope type. +func (eo *PassportScopeElementOne) ScopeType() string { + return "one" +} + +type ( + // PassportData contains information about Telegram Passport data shared with + // the bot by the user. + PassportData struct { + // Array with information about documents and other Telegram Passport + // elements that was shared with the bot + Data []EncryptedPassportElement `json:"data"` + + // Encrypted credentials required to decrypt the data + Credentials *EncryptedCredentials `json:"credentials"` + } + + // PassportFile represents a file uploaded to Telegram Passport. Currently, all + // Telegram Passport files are in JPEG format when decrypted and don't exceed + // 10MB. + PassportFile struct { + // Unique identifier for this file + FileID string `json:"file_id"` + + FileUniqueID string `json:"file_unique_id"` + + // File size + FileSize int `json:"file_size"` + + // Unix time when the file was uploaded + FileDate int64 `json:"file_date"` + } + + // EncryptedPassportElement contains information about documents or other + // Telegram Passport elements shared with the bot by the user. + EncryptedPassportElement struct { + // Element type. + Type string `json:"type"` + + // Base64-encoded encrypted Telegram Passport element data provided by + // the user, available for "personal_details", "passport", + // "driver_license", "identity_card", "identity_passport" and "address" + // types. Can be decrypted and verified using the accompanying + // EncryptedCredentials. + Data string `json:"data,omitempty"` + + // User's verified phone number, available only for "phone_number" type + PhoneNumber string `json:"phone_number,omitempty"` + + // User's verified email address, available only for "email" type + Email string `json:"email,omitempty"` + + // Array of encrypted files with documents provided by the user, + // available for "utility_bill", "bank_statement", "rental_agreement", + // "passport_registration" and "temporary_registration" types. Files can + // be decrypted and verified using the accompanying EncryptedCredentials. + Files []PassportFile `json:"files,omitempty"` + + // Encrypted file with the front side of the document, provided by the + // user. Available for "passport", "driver_license", "identity_card" and + // "internal_passport". The file can be decrypted and verified using the + // accompanying EncryptedCredentials. + FrontSide *PassportFile `json:"front_side,omitempty"` + + // Encrypted file with the reverse side of the document, provided by the + // user. Available for "driver_license" and "identity_card". The file can + // be decrypted and verified using the accompanying EncryptedCredentials. + ReverseSide *PassportFile `json:"reverse_side,omitempty"` + + // Encrypted file with the selfie of the user holding a document, + // provided by the user; available for "passport", "driver_license", + // "identity_card" and "internal_passport". The file can be decrypted + // and verified using the accompanying EncryptedCredentials. + Selfie *PassportFile `json:"selfie,omitempty"` + } + + // EncryptedCredentials contains data required for decrypting and + // authenticating EncryptedPassportElement. See the Telegram Passport + // Documentation for a complete description of the data decryption and + // authentication processes. + EncryptedCredentials struct { + // Base64-encoded encrypted JSON-serialized data with unique user's + // payload, data hashes and secrets required for EncryptedPassportElement + // decryption and authentication + Data string `json:"data"` + + // Base64-encoded data hash for data authentication + Hash string `json:"hash"` + + // Base64-encoded secret, encrypted with the bot's public RSA key, + // required for data decryption + Secret string `json:"secret"` + } + + // PassportElementError represents an error in the Telegram Passport element + // which was submitted that should be resolved by the user. + PassportElementError interface{} + + // PassportElementErrorDataField represents an issue in one of the data + // fields that was provided by the user. The error is considered resolved + // when the field's value changes. + PassportElementErrorDataField struct { + // Error source, must be data + Source string `json:"source"` + + // The section of the user's Telegram Passport which has the error, one + // of "personal_details", "passport", "driver_license", "identity_card", + // "internal_passport", "address" + Type string `json:"type"` + + // Name of the data field which has the error + FieldName string `json:"field_name"` + + // Base64-encoded data hash + DataHash string `json:"data_hash"` + + // Error message + Message string `json:"message"` + } + + // PassportElementErrorFrontSide represents an issue with the front side of + // a document. The error is considered resolved when the file with the front + // side of the document changes. + PassportElementErrorFrontSide struct { + // Error source, must be front_side + Source string `json:"source"` + + // The section of the user's Telegram Passport which has the issue, one + // of "passport", "driver_license", "identity_card", "internal_passport" + Type string `json:"type"` + + // Base64-encoded hash of the file with the front side of the document + FileHash string `json:"file_hash"` + + // Error message + Message string `json:"message"` + } + + // PassportElementErrorReverseSide represents an issue with the reverse side + // of a document. The error is considered resolved when the file with reverse + // side of the document changes. + PassportElementErrorReverseSide struct { + // Error source, must be reverse_side + Source string `json:"source"` + + // The section of the user's Telegram Passport which has the issue, one + // of "driver_license", "identity_card" + Type string `json:"type"` + + // Base64-encoded hash of the file with the reverse side of the document + FileHash string `json:"file_hash"` + + // Error message + Message string `json:"message"` + } + + // PassportElementErrorSelfie represents an issue with the selfie with a + // document. The error is considered resolved when the file with the selfie + // changes. + PassportElementErrorSelfie struct { + // Error source, must be selfie + Source string `json:"source"` + + // The section of the user's Telegram Passport which has the issue, one + // of "passport", "driver_license", "identity_card", "internal_passport" + Type string `json:"type"` + + // Base64-encoded hash of the file with the selfie + FileHash string `json:"file_hash"` + + // Error message + Message string `json:"message"` + } + + // PassportElementErrorFile represents an issue with a document scan. The + // error is considered resolved when the file with the document scan changes. + PassportElementErrorFile struct { + // Error source, must be a file + Source string `json:"source"` + + // The section of the user's Telegram Passport which has the issue, one + // of "utility_bill", "bank_statement", "rental_agreement", + // "passport_registration", "temporary_registration" + Type string `json:"type"` + + // Base64-encoded file hash + FileHash string `json:"file_hash"` + + // Error message + Message string `json:"message"` + } + + // PassportElementErrorFiles represents an issue with a list of scans. The + // error is considered resolved when the list of files containing the scans + // changes. + PassportElementErrorFiles struct { + // Error source, must be files + Source string `json:"source"` + + // The section of the user's Telegram Passport which has the issue, one + // of "utility_bill", "bank_statement", "rental_agreement", + // "passport_registration", "temporary_registration" + Type string `json:"type"` + + // List of base64-encoded file hashes + FileHashes []string `json:"file_hashes"` + + // Error message + Message string `json:"message"` + } + + // Credentials contains encrypted data. + Credentials struct { + Data SecureData `json:"secure_data"` + // Nonce the same nonce given in the request + Nonce string `json:"nonce"` + } + + // SecureData is a map of the fields and their encrypted values. + SecureData map[string]*SecureValue + // PersonalDetails *SecureValue `json:"personal_details"` + // Passport *SecureValue `json:"passport"` + // InternalPassport *SecureValue `json:"internal_passport"` + // DriverLicense *SecureValue `json:"driver_license"` + // IdentityCard *SecureValue `json:"identity_card"` + // Address *SecureValue `json:"address"` + // UtilityBill *SecureValue `json:"utility_bill"` + // BankStatement *SecureValue `json:"bank_statement"` + // RentalAgreement *SecureValue `json:"rental_agreement"` + // PassportRegistration *SecureValue `json:"passport_registration"` + // TemporaryRegistration *SecureValue `json:"temporary_registration"` + + // SecureValue contains encrypted values for a SecureData item. + SecureValue struct { + Data *DataCredentials `json:"data"` + FrontSide *FileCredentials `json:"front_side"` + ReverseSide *FileCredentials `json:"reverse_side"` + Selfie *FileCredentials `json:"selfie"` + Translation []*FileCredentials `json:"translation"` + Files []*FileCredentials `json:"files"` + } + + // DataCredentials contains information required to decrypt data. + DataCredentials struct { + // DataHash checksum of encrypted data + DataHash string `json:"data_hash"` + // Secret of encrypted data + Secret string `json:"secret"` + } + + // FileCredentials contains information required to decrypt files. + FileCredentials struct { + // FileHash checksum of encrypted data + FileHash string `json:"file_hash"` + // Secret of encrypted data + Secret string `json:"secret"` + } + + // PersonalDetails https://core.telegram.org/passport#personaldetails + PersonalDetails struct { + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + MiddleName string `json:"middle_name"` + BirthDate string `json:"birth_date"` + Gender string `json:"gender"` + CountryCode string `json:"country_code"` + ResidenceCountryCode string `json:"residence_country_code"` + FirstNameNative string `json:"first_name_native"` + LastNameNative string `json:"last_name_native"` + MiddleNameNative string `json:"middle_name_native"` + } + + // IDDocumentData https://core.telegram.org/passport#iddocumentdata + IDDocumentData struct { + DocumentNumber string `json:"document_no"` + ExpiryDate string `json:"expiry_date"` + } +) diff --git a/vendor/github.com/matterbridge/telegram-bot-api/v6/types.go b/vendor/github.com/matterbridge/telegram-bot-api/v6/types.go new file mode 100644 index 00000000..97fce226 --- /dev/null +++ b/vendor/github.com/matterbridge/telegram-bot-api/v6/types.go @@ -0,0 +1,3760 @@ +package tgbotapi + +import ( + "encoding/json" + "errors" + "fmt" + "net/url" + "strings" + "time" +) + +// APIResponse is a response from the Telegram API with the result +// stored raw. +type APIResponse struct { + Ok bool `json:"ok"` + Result json.RawMessage `json:"result,omitempty"` + ErrorCode int `json:"error_code,omitempty"` + Description string `json:"description,omitempty"` + Parameters *ResponseParameters `json:"parameters,omitempty"` +} + +// Error is an error containing extra information returned by the Telegram API. +type Error struct { + Code int + Message string + ResponseParameters +} + +// Error message string. +func (e Error) Error() string { + return e.Message +} + +// Update is an update response, from GetUpdates. +type Update struct { + // UpdateID is the update's unique identifier. + // Update identifiers start from a certain positive number and increase + // sequentially. + // This ID becomes especially handy if you're using Webhooks, + // since it allows you to ignore repeated updates or to restore + // the correct update sequence, should they get out of order. + // If there are no new updates for at least a week, then identifier + // of the next update will be chosen randomly instead of sequentially. + UpdateID int `json:"update_id"` + // Message new incoming message of any kind — text, photo, sticker, etc. + // + // optional + Message *Message `json:"message,omitempty"` + // EditedMessage new version of a message that is known to the bot and was + // edited + // + // optional + EditedMessage *Message `json:"edited_message,omitempty"` + // ChannelPost new version of a message that is known to the bot and was + // edited + // + // optional + ChannelPost *Message `json:"channel_post,omitempty"` + // EditedChannelPost new incoming channel post of any kind — text, photo, + // sticker, etc. + // + // optional + EditedChannelPost *Message `json:"edited_channel_post,omitempty"` + // InlineQuery new incoming inline query + // + // optional + InlineQuery *InlineQuery `json:"inline_query,omitempty"` + // ChosenInlineResult is the result of an inline query + // that was chosen by a user and sent to their chat partner. + // Please see our documentation on the feedback collecting + // for details on how to enable these updates for your bot. + // + // optional + ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result,omitempty"` + // CallbackQuery new incoming callback query + // + // optional + CallbackQuery *CallbackQuery `json:"callback_query,omitempty"` + // ShippingQuery new incoming shipping query. Only for invoices with + // flexible price + // + // optional + ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"` + // PreCheckoutQuery new incoming pre-checkout query. Contains full + // information about checkout + // + // optional + PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"` + // Pool new poll state. Bots receive only updates about stopped polls and + // polls, which are sent by the bot + // + // optional + Poll *Poll `json:"poll,omitempty"` + // PollAnswer user changed their answer in a non-anonymous poll. Bots + // receive new votes only in polls that were sent by the bot itself. + // + // optional + PollAnswer *PollAnswer `json:"poll_answer,omitempty"` + // MyChatMember is the bot's chat member status was updated in a chat. For + // private chats, this update is received only when the bot is blocked or + // unblocked by the user. + // + // optional + MyChatMember *ChatMemberUpdated `json:"my_chat_member,omitempty"` + // ChatMember is a chat member's status was updated in a chat. The bot must + // be an administrator in the chat and must explicitly specify "chat_member" + // in the list of allowed_updates to receive these updates. + // + // optional + ChatMember *ChatMemberUpdated `json:"chat_member,omitempty"` + // ChatJoinRequest is a request to join the chat has been sent. The bot must + // have the can_invite_users administrator right in the chat to receive + // these updates. + // + // optional + ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"` +} + +// SentFrom returns the user who sent an update. Can be nil, if Telegram did not provide information +// about the user in the update object. +func (u *Update) SentFrom() *User { + switch { + case u.Message != nil: + return u.Message.From + case u.EditedMessage != nil: + return u.EditedMessage.From + case u.InlineQuery != nil: + return u.InlineQuery.From + case u.ChosenInlineResult != nil: + return u.ChosenInlineResult.From + case u.CallbackQuery != nil: + return u.CallbackQuery.From + case u.ShippingQuery != nil: + return u.ShippingQuery.From + case u.PreCheckoutQuery != nil: + return u.PreCheckoutQuery.From + default: + return nil + } +} + +// CallbackData returns the callback query data, if it exists. +func (u *Update) CallbackData() string { + if u.CallbackQuery != nil { + return u.CallbackQuery.Data + } + return "" +} + +// FromChat returns the chat where an update occurred. +func (u *Update) FromChat() *Chat { + switch { + case u.Message != nil: + return u.Message.Chat + case u.EditedMessage != nil: + return u.EditedMessage.Chat + case u.ChannelPost != nil: + return u.ChannelPost.Chat + case u.EditedChannelPost != nil: + return u.EditedChannelPost.Chat + case u.CallbackQuery != nil: + return u.CallbackQuery.Message.Chat + default: + return nil + } +} + +// UpdatesChannel is the channel for getting updates. +type UpdatesChannel <-chan Update + +// Clear discards all unprocessed incoming updates. +func (ch UpdatesChannel) Clear() { + for len(ch) != 0 { + <-ch + } +} + +// User represents a Telegram user or bot. +type User struct { + // ID is a unique identifier for this user or bot + ID int64 `json:"id"` + // IsBot true, if this user is a bot + // + // optional + IsBot bool `json:"is_bot,omitempty"` + // IsPremium true, if user has Telegram Premium + // + // optional + IsPremium bool `json:"is_premium,omitempty"` + // AddedToAttachmentMenu true, if this user added the bot to the attachment menu + // + // optional + AddedToAttachmentMenu bool `json:"added_to_attachment_menu,omitempty"` + // FirstName user's or bot's first name + FirstName string `json:"first_name"` + // LastName user's or bot's last name + // + // optional + LastName string `json:"last_name,omitempty"` + // UserName user's or bot's username + // + // optional + UserName string `json:"username,omitempty"` + // LanguageCode IETF language tag of the user's language + // more info: https://en.wikipedia.org/wiki/IETF_language_tag + // + // optional + LanguageCode string `json:"language_code,omitempty"` + // CanJoinGroups is true, if the bot can be invited to groups. + // Returned only in getMe. + // + // optional + CanJoinGroups bool `json:"can_join_groups,omitempty"` + // CanReadAllGroupMessages is true, if privacy mode is disabled for the bot. + // Returned only in getMe. + // + // optional + CanReadAllGroupMessages bool `json:"can_read_all_group_messages,omitempty"` + // SupportsInlineQueries is true, if the bot supports inline queries. + // Returned only in getMe. + // + // optional + SupportsInlineQueries bool `json:"supports_inline_queries,omitempty"` +} + +// String displays a simple text version of a user. +// +// 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 + } + + name := u.FirstName + if u.LastName != "" { + name += " " + u.LastName + } + + return name +} + +// Chat represents a chat. +type Chat struct { + // ID is a unique identifier for this chat + ID int64 `json:"id"` + // Type of chat, can be either “private”, “group”, “supergroup” or “channel” + Type string `json:"type"` + // Title for supergroups, channels and group chats + // + // optional + Title string `json:"title,omitempty"` + // UserName for private chats, supergroups and channels if available + // + // optional + UserName string `json:"username,omitempty"` + // FirstName of the other party in a private chat + // + // optional + FirstName string `json:"first_name,omitempty"` + // LastName of the other party in a private chat + // + // optional + LastName string `json:"last_name,omitempty"` + // IsForum is true if the supergroup chat is a forum (has topics enabled) + // + // optional + IsForum bool `json:"is_forum,omitempty"` + // Photo is a chat photo + Photo *ChatPhoto `json:"photo"` + // If non-empty, the list of all active chat usernames; + // for private chats, supergroups and channels. Returned only in getChat. + // + // optional + ActiveUsernames []string `json:"active_usernames,omitempty"` + // Custom emoji identifier of emoji status of the other party + // in a private chat. Returned only in getChat. + // + // optional + EmojiStatusCustomEmojiID string `json:"emoji_status_custom_emoji_id,omitempty"` + // Bio is the bio of the other party in a private chat. Returned only in + // getChat + // + // optional + Bio string `json:"bio,omitempty"` + // HasPrivateForwards is true if privacy settings of the other party in the + // private chat allows to use tg://user?id= links only in chats + // with the user. Returned only in getChat. + // + // optional + HasPrivateForwards bool `json:"has_private_forwards,omitempty"` + // HasRestrictedVoiceAndVideoMessages if the privacy settings of the other party + // restrict sending voice and video note messages + // in the private chat. Returned only in getChat. + // + // optional + HasRestrictedVoiceAndVideoMessages bool `json:"has_restricted_voice_and_video_messages,omitempty"` + // JoinToSendMessages is true, if users need to join the supergroup + // before they can send messages. + // Returned only in getChat + // + // optional + JoinToSendMessages bool `json:"join_to_send_messages,omitempty"` + // JoinByRequest is true, if all users directly joining the supergroup + // need to be approved by supergroup administrators. + // Returned only in getChat. + // + // optional + JoinByRequest bool `json:"join_by_request,omitempty"` + // Description for groups, supergroups and channel chats + // + // optional + Description string `json:"description,omitempty"` + // InviteLink is a chat invite link, for groups, supergroups and channel chats. + // Each administrator in a chat generates their own invite links, + // so the bot must first generate the link using exportChatInviteLink + // + // optional + InviteLink string `json:"invite_link,omitempty"` + // PinnedMessage is the pinned message, for groups, supergroups and channels + // + // optional + PinnedMessage *Message `json:"pinned_message,omitempty"` + // Permissions are default chat member permissions, for groups and + // supergroups. Returned only in getChat. + // + // optional + Permissions *ChatPermissions `json:"permissions,omitempty"` + // SlowModeDelay is for supergroups, the minimum allowed delay between + // consecutive messages sent by each unprivileged user. Returned only in + // getChat. + // + // optional + SlowModeDelay int `json:"slow_mode_delay,omitempty"` + // MessageAutoDeleteTime is the time after which all messages sent to the + // chat will be automatically deleted; in seconds. Returned only in getChat. + // + // optional + MessageAutoDeleteTime int `json:"message_auto_delete_time,omitempty"` + // HasAggressiveAntiSpamEnabled is true if aggressive anti-spam checks are enabled + // in the supergroup. The field is only available to chat administrators. + // Returned only in getChat. + // + // optional + HasAggressiveAntiSpamEnabled bool `json:"has_aggressive_anti_spam_enabled,omitempty"` + // HasHiddenMembers is true if non-administrators can only get + // the list of bots and administrators in the chat. + // + // optional + HasHiddenMembers bool `json:"has_hidden_members,omitempty"` + // HasProtectedContent is true if messages from the chat can't be forwarded + // to other chats. Returned only in getChat. + // + // optional + HasProtectedContent bool `json:"has_protected_content,omitempty"` + // StickerSetName is for supergroups, name of group sticker set.Returned + // only in getChat. + // + // optional + StickerSetName string `json:"sticker_set_name,omitempty"` + // CanSetStickerSet is true, if the bot can change the group sticker set. + // Returned only in getChat. + // + // optional + CanSetStickerSet bool `json:"can_set_sticker_set,omitempty"` + // LinkedChatID is a unique identifier for the linked chat, i.e. the + // discussion group identifier for a channel and vice versa; for supergroups + // and channel chats. + // + // optional + LinkedChatID int64 `json:"linked_chat_id,omitempty"` + // Location is for supergroups, the location to which the supergroup is + // connected. Returned only in getChat. + // + // optional + Location *ChatLocation `json:"location,omitempty"` +} + +// IsPrivate returns if the Chat is a private conversation. +func (c Chat) IsPrivate() bool { + return c.Type == "private" +} + +// IsGroup returns if the Chat is a group. +func (c Chat) IsGroup() bool { + return c.Type == "group" +} + +// IsSuperGroup returns if the Chat is a supergroup. +func (c Chat) IsSuperGroup() bool { + return c.Type == "supergroup" +} + +// IsChannel returns if the Chat is a channel. +func (c Chat) IsChannel() bool { + return c.Type == "channel" +} + +// ChatConfig returns a ChatConfig struct for chat related methods. +func (c Chat) ChatConfig() ChatConfig { + return ChatConfig{ChatID: c.ID} +} + +// Message represents a message. +type Message struct { + // MessageID is a unique message identifier inside this chat + MessageID int `json:"message_id"` + // Unique identifier of a message thread to which the message belongs; + // for supergroups only + // + // optional + MessageThreadID int `json:"message_thread_id,omitempty"` + // From is a sender, empty for messages sent to channels; + // + // optional + From *User `json:"from,omitempty"` + // SenderChat is the sender of the message, sent on behalf of a chat. The + // channel itself for channel messages. The supergroup itself for messages + // from anonymous group administrators. The linked channel for messages + // automatically forwarded to the discussion group + // + // optional + SenderChat *Chat `json:"sender_chat,omitempty"` + // Date of the message was sent in Unix time + Date int `json:"date"` + // Chat is the conversation the message belongs to + Chat *Chat `json:"chat"` + // ForwardFrom for forwarded messages, sender of the original message; + // + // optional + ForwardFrom *User `json:"forward_from,omitempty"` + // ForwardFromChat for messages forwarded from channels, + // information about the original channel; + // + // optional + ForwardFromChat *Chat `json:"forward_from_chat,omitempty"` + // ForwardFromMessageID for messages forwarded from channels, + // identifier of the original message in the channel; + // + // optional + ForwardFromMessageID int `json:"forward_from_message_id,omitempty"` + // ForwardSignature for messages forwarded from channels, signature of the + // post author if present + // + // optional + ForwardSignature string `json:"forward_signature,omitempty"` + // ForwardSenderName is the sender's name for messages forwarded from users + // who disallow adding a link to their account in forwarded messages + // + // optional + ForwardSenderName string `json:"forward_sender_name,omitempty"` + // ForwardDate for forwarded messages, date the original message was sent in Unix time; + // + // optional + ForwardDate int `json:"forward_date,omitempty"` + // IsTopicMessage true if the message is sent to a forum topic + // + // optional + IsTopicMessage bool `json:"is_topic_message,omitempty"` + // IsAutomaticForward is true if the message is a channel post that was + // automatically forwarded to the connected discussion group. + // + // optional + IsAutomaticForward bool `json:"is_automatic_forward,omitempty"` + // ReplyToMessage for replies, the original message. + // Note that the Message object in this field will not contain further ReplyToMessage fields + // even if it itself is a reply; + // + // optional + ReplyToMessage *Message `json:"reply_to_message,omitempty"` + // ViaBot through which the message was sent; + // + // optional + ViaBot *User `json:"via_bot,omitempty"` + // EditDate of the message was last edited in Unix time; + // + // optional + EditDate int `json:"edit_date,omitempty"` + // HasProtectedContent is true if the message can't be forwarded. + // + // optional + HasProtectedContent bool `json:"has_protected_content,omitempty"` + // MediaGroupID is the unique identifier of a media message group this message belongs to; + // + // optional + MediaGroupID string `json:"media_group_id,omitempty"` + // AuthorSignature is the signature of the post author for messages in channels; + // + // optional + AuthorSignature string `json:"author_signature,omitempty"` + // Text is for text messages, the actual UTF-8 text of the message, 0-4096 characters; + // + // optional + Text string `json:"text,omitempty"` + // Entities are for text messages, special entities like usernames, + // URLs, bot commands, etc. that appear in the text; + // + // optional + Entities []MessageEntity `json:"entities,omitempty"` + // Animation message is an animation, information about the animation. + // For backward compatibility, when this field is set, the document field will also be set; + // + // optional + Animation *Animation `json:"animation,omitempty"` + // PremiumAnimation message is an animation, information about the animation. + // For backward compatibility, when this field is set, the document field will also be set; + // + // optional + PremiumAnimation *Animation `json:"premium_animation,omitempty"` + // Audio message is an audio file, information about the file; + // + // optional + Audio *Audio `json:"audio,omitempty"` + // Document message is a general file, information about the file; + // + // optional + Document *Document `json:"document,omitempty"` + // Photo message is a photo, available sizes of the photo; + // + // optional + Photo []PhotoSize `json:"photo,omitempty"` + // Sticker message is a sticker, information about the sticker; + // + // optional + Sticker *Sticker `json:"sticker,omitempty"` + // Video message is a video, information about the video; + // + // optional + Video *Video `json:"video,omitempty"` + // VideoNote message is a video note, information about the video message; + // + // optional + VideoNote *VideoNote `json:"video_note,omitempty"` + // Voice message is a voice message, information about the file; + // + // optional + Voice *Voice `json:"voice,omitempty"` + // Caption for the animation, audio, document, photo, video or voice, 0-1024 characters; + // + // optional + Caption string `json:"caption,omitempty"` + // CaptionEntities; + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // HasSpoiler True, if the message media is covered by a spoiler animation + // + // optional + HasMediaSpoiler bool `json:"has_media_spoiler,omitempty"` + // Contact message is a shared contact, information about the contact; + // + // optional + Contact *Contact `json:"contact,omitempty"` + // Dice is a dice with random value; + // + // optional + Dice *Dice `json:"dice,omitempty"` + // Game message is a game, information about the game; + // + // optional + Game *Game `json:"game,omitempty"` + // Poll is a native poll, information about the poll; + // + // optional + Poll *Poll `json:"poll,omitempty"` + // Venue message is a venue, information about the venue. + // For backward compatibility, when this field is set, the location field + // will also be set; + // + // optional + Venue *Venue `json:"venue,omitempty"` + // Location message is a shared location, information about the location; + // + // optional + Location *Location `json:"location,omitempty"` + // NewChatMembers that were added to the group or supergroup + // and information about them (the bot itself may be one of these members); + // + // optional + NewChatMembers []User `json:"new_chat_members,omitempty"` + // LeftChatMember is a member was removed from the group, + // information about them (this member may be the bot itself); + // + // optional + LeftChatMember *User `json:"left_chat_member,omitempty"` + // NewChatTitle is a chat title was changed to this value; + // + // optional + NewChatTitle string `json:"new_chat_title,omitempty"` + // NewChatPhoto is a chat photo was change to this value; + // + // optional + NewChatPhoto []PhotoSize `json:"new_chat_photo,omitempty"` + // DeleteChatPhoto is a service message: the chat photo was deleted; + // + // optional + DeleteChatPhoto bool `json:"delete_chat_photo,omitempty"` + // GroupChatCreated is a service message: the group has been created; + // + // optional + GroupChatCreated bool `json:"group_chat_created,omitempty"` + // SuperGroupChatCreated is a service message: the supergroup has been created. + // This field can't be received in a message coming through updates, + // because bot can't be a member of a supergroup when it is created. + // It can only be found in ReplyToMessage if someone replies to a very first message + // in a directly created supergroup; + // + // optional + SuperGroupChatCreated bool `json:"supergroup_chat_created,omitempty"` + // ChannelChatCreated is a service message: the channel has been created. + // This field can't be received in a message coming through updates, + // because bot can't be a member of a channel when it is created. + // It can only be found in ReplyToMessage + // if someone replies to a very first message in a channel; + // + // optional + ChannelChatCreated bool `json:"channel_chat_created,omitempty"` + // MessageAutoDeleteTimerChanged is a service message: auto-delete timer + // settings changed in the chat. + // + // optional + MessageAutoDeleteTimerChanged *MessageAutoDeleteTimerChanged `json:"message_auto_delete_timer_changed,omitempty"` + // MigrateToChatID is the group has been migrated to a supergroup with the specified identifier. + // This number may be greater than 32 bits and some programming languages + // may have difficulty/silent defects in interpreting it. + // But it is smaller than 52 bits, so a signed 64-bit integer + // or double-precision float type are safe for storing this identifier; + // + // optional + MigrateToChatID int64 `json:"migrate_to_chat_id,omitempty"` + // MigrateFromChatID is the supergroup has been migrated from a group with the specified identifier. + // This number may be greater than 32 bits and some programming languages + // may have difficulty/silent defects in interpreting it. + // But it is smaller than 52 bits, so a signed 64-bit integer + // or double-precision float type are safe for storing this identifier; + // + // optional + MigrateFromChatID int64 `json:"migrate_from_chat_id,omitempty"` + // PinnedMessage is a specified message was pinned. + // Note that the Message object in this field will not contain further ReplyToMessage + // fields even if it is itself a reply; + // + // optional + PinnedMessage *Message `json:"pinned_message,omitempty"` + // Invoice message is an invoice for a payment; + // + // optional + Invoice *Invoice `json:"invoice,omitempty"` + // SuccessfulPayment message is a service message about a successful payment, + // information about the payment; + // + // optional + SuccessfulPayment *SuccessfulPayment `json:"successful_payment,omitempty"` + // UserShared is a service message: a user was shared with the bot + // + // optional + UserShared *UserShared `json:"user_shared,omitempty"` + // ChatShared is a service message: a chat was shared with the bot + // + // optional + ChatShared *ChatShared `json:"chat_shared,omitempty"` + // ConnectedWebsite is the domain name of the website on which the user has + // logged in; + // + // optional + ConnectedWebsite string `json:"connected_website,omitempty"` + // WriteAccessAllowed is a service message: the user allowed the bot + // added to the attachment menu to write messages + // + // optional + WriteAccessAllowed *WriteAccessAllowed `json:"write_access_allowed,omitempty"` + // PassportData is a Telegram Passport data; + // + // optional + PassportData *PassportData `json:"passport_data,omitempty"` + // ProximityAlertTriggered is a service message. A user in the chat + // triggered another user's proximity alert while sharing Live Location + // + // optional + ProximityAlertTriggered *ProximityAlertTriggered `json:"proximity_alert_triggered,omitempty"` + // ForumTopicCreated is a service message: forum topic created + // + // optional + ForumTopicCreated *ForumTopicCreated `json:"forum_topic_created,omitempty"` + // ForumTopicClosed is a service message: forum topic edited + // + // optional + ForumTopicEdited *ForumTopicEdited `json:"forum_topic_edited,omitempty"` + // ForumTopicClosed is a service message: forum topic closed + // + // optional + ForumTopicClosed *ForumTopicClosed `json:"forum_topic_closed,omitempty"` + // ForumTopicReopened is a service message: forum topic reopened + // + // optional + ForumTopicReopened *ForumTopicReopened `json:"forum_topic_reopened,omitempty"` + // GeneralForumTopicHidden is a service message: the 'General' forum topic hidden + // + // optional + GeneralForumTopicHidden *GeneralForumTopicHidden `json:"general_forum_topic_hidden,omitempty"` + // GeneralForumTopicUnhidden is a service message: the 'General' forum topic unhidden + // + // optional + GeneralForumTopicUnhidden *GeneralForumTopicUnhidden `json:"general_forum_topic_unhidden,omitempty"` + // VideoChatScheduled is a service message: video chat scheduled. + // + // optional + VideoChatScheduled *VideoChatScheduled `json:"video_chat_scheduled,omitempty"` + // VideoChatStarted is a service message: video chat started. + // + // optional + VideoChatStarted *VideoChatStarted `json:"video_chat_started,omitempty"` + // VideoChatEnded is a service message: video chat ended. + // + // optional + VideoChatEnded *VideoChatEnded `json:"video_chat_ended,omitempty"` + // VideoChatParticipantsInvited is a service message: new participants + // invited to a video chat. + // + // optional + VideoChatParticipantsInvited *VideoChatParticipantsInvited `json:"video_chat_participants_invited,omitempty"` + // WebAppData is a service message: data sent by a Web App. + // + // optional + WebAppData *WebAppData `json:"web_app_data,omitempty"` + // ReplyMarkup is the Inline keyboard attached to the message. + // login_url buttons are represented as ordinary url buttons. + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// Time converts the message timestamp into a Time. +func (m *Message) Time() time.Time { + return time.Unix(int64(m.Date), 0) +} + +// IsCommand returns true if message starts with a "bot_command" entity. +func (m *Message) IsCommand() bool { + if m.Entities == nil || len(m.Entities) == 0 { + return false + } + + entity := m.Entities[0] + return entity.Offset == 0 && entity.IsCommand() +} + +// Command checks if the message was a command and if it was, returns the +// command. If the Message was not a command, it returns an empty string. +// +// If the command contains the at name syntax, it is removed. Use +// CommandWithAt() if you do not want that. +func (m *Message) Command() string { + command := m.CommandWithAt() + + if i := strings.Index(command, "@"); i != -1 { + command = command[:i] + } + + return command +} + +// CommandWithAt checks if the message was a command and if it was, returns the +// command. If the Message was not a command, it returns an empty string. +// +// If the command contains the at name syntax, it is not removed. Use Command() +// if you want that. +func (m *Message) CommandWithAt() string { + if !m.IsCommand() { + return "" + } + + // IsCommand() checks that the message begins with a bot_command entity + entity := m.Entities[0] + return m.Text[1:entity.Length] +} + +// CommandArguments checks if the message was a command and if it was, +// returns all text after the command name. If the Message was not a +// command, it returns an empty string. +// +// Note: The first character after the command name is omitted: +// - "/foo bar baz" yields "bar baz", not " bar baz" +// - "/foo-bar baz" yields "bar baz", too +// Even though the latter is not a command conforming to the spec, the API +// marks "/foo" as command entity. +func (m *Message) CommandArguments() string { + if !m.IsCommand() { + return "" + } + + // IsCommand() checks that the message begins with a bot_command entity + entity := m.Entities[0] + + if len(m.Text) == entity.Length { + return "" // The command makes up the whole message + } + + return m.Text[entity.Length+1:] +} + +// MessageID represents a unique message identifier. +type MessageID struct { + MessageID int `json:"message_id"` +} + +// MessageEntity represents one special entity in a text message. +type MessageEntity struct { + // Type of the entity. + // Can be: + // “mention” (@username), + // “hashtag” (#hashtag), + // “cashtag” ($USD), + // “bot_command” (/start@jobs_bot), + // “url” (https://telegram.org), + // “email” (do-not-reply@telegram.org), + // “phone_number” (+1-212-555-0123), + // “bold” (bold text), + // “italic” (italic text), + // “underline” (underlined text), + // “strikethrough” (strikethrough text), + // "spoiler" (spoiler message), + // “code” (monowidth string), + // “pre” (monowidth block), + // “text_link” (for clickable text URLs), + // “text_mention” (for users without usernames) + // “text_mention” (for inline custom emoji stickers) + Type string `json:"type"` + // Offset in UTF-16 code units to the start of the entity + Offset int `json:"offset"` + // Length + Length int `json:"length"` + // URL for “text_link” only, url that will be opened after user taps on the text + // + // optional + URL string `json:"url,omitempty"` + // User for “text_mention” only, the mentioned user + // + // optional + User *User `json:"user,omitempty"` + // Language for “pre” only, the programming language of the entity text + // + // optional + Language string `json:"language,omitempty"` + // CustomEmojiID for “custom_emoji” only, unique identifier of the custom emoji + // + // optional + CustomEmojiID string `json:"custom_emoji_id"` +} + +// ParseURL attempts to parse a URL contained within a MessageEntity. +func (e MessageEntity) ParseURL() (*url.URL, error) { + if e.URL == "" { + return nil, errors.New(ErrBadURL) + } + + return url.Parse(e.URL) +} + +// IsMention returns true if the type of the message entity is "mention" (@username). +func (e MessageEntity) IsMention() bool { + return e.Type == "mention" +} + +// IsTextMention returns true if the type of the message entity is "text_mention" +// (At this time, the user field exists, and occurs when tagging a member without a username) +func (e MessageEntity) IsTextMention() bool { + return e.Type == "text_mention" +} + +// IsHashtag returns true if the type of the message entity is "hashtag". +func (e MessageEntity) IsHashtag() bool { + return e.Type == "hashtag" +} + +// IsCommand returns true if the type of the message entity is "bot_command". +func (e MessageEntity) IsCommand() bool { + return e.Type == "bot_command" +} + +// IsURL returns true if the type of the message entity is "url". +func (e MessageEntity) IsURL() bool { + return e.Type == "url" +} + +// IsEmail returns true if the type of the message entity is "email". +func (e MessageEntity) IsEmail() bool { + return e.Type == "email" +} + +// IsBold returns true if the type of the message entity is "bold" (bold text). +func (e MessageEntity) IsBold() bool { + return e.Type == "bold" +} + +// IsItalic returns true if the type of the message entity is "italic" (italic text). +func (e MessageEntity) IsItalic() bool { + return e.Type == "italic" +} + +// IsCode returns true if the type of the message entity is "code" (monowidth string). +func (e MessageEntity) IsCode() bool { + return e.Type == "code" +} + +// IsPre returns true if the type of the message entity is "pre" (monowidth block). +func (e MessageEntity) IsPre() bool { + return e.Type == "pre" +} + +// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL). +func (e MessageEntity) IsTextLink() bool { + return e.Type == "text_link" +} + +// PhotoSize represents one size of a photo or a file / sticker thumbnail. +type PhotoSize struct { + // FileID identifier for this file, which can be used to download or reuse + // the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Width photo width + Width int `json:"width"` + // Height photo height + Height int `json:"height"` + // FileSize file size + // + // optional + FileSize int `json:"file_size,omitempty"` +} + +// Animation represents an animation file. +type Animation struct { + // FileID is the identifier for this file, which can be used to download or reuse + // the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Width video width as defined by sender + Width int `json:"width"` + // Height video height as defined by sender + Height int `json:"height"` + // Duration of the video in seconds as defined by sender + Duration int `json:"duration"` + // Thumbnail animation thumbnail as defined by sender + // + // optional + Thumbnail *PhotoSize `json:"thumb,omitempty"` + // FileName original animation filename as defined by sender + // + // optional + FileName string `json:"file_name,omitempty"` + // MimeType of the file as defined by sender + // + // optional + MimeType string `json:"mime_type,omitempty"` + // FileSize file size + // + // optional + FileSize int64 `json:"file_size,omitempty"` +} + +// Audio represents an audio file to be treated as music by the Telegram clients. +type Audio struct { + // FileID is an identifier for this file, which can be used to download or + // reuse the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Duration of the audio in seconds as defined by sender + Duration int `json:"duration"` + // Performer of the audio as defined by sender or by audio tags + // + // optional + Performer string `json:"performer,omitempty"` + // Title of the audio as defined by sender or by audio tags + // + // optional + Title string `json:"title,omitempty"` + // FileName is the original filename as defined by sender + // + // optional + FileName string `json:"file_name,omitempty"` + // MimeType of the file as defined by sender + // + // optional + MimeType string `json:"mime_type,omitempty"` + // FileSize file size + // + // optional + FileSize int64 `json:"file_size,omitempty"` + // Thumbnail is the album cover to which the music file belongs + // + // optional + Thumbnail *PhotoSize `json:"thumb,omitempty"` +} + +// Document represents a general file. +type Document struct { + // FileID is an identifier for this file, which can be used to download or + // reuse the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Thumbnail document thumbnail as defined by sender + // + // optional + Thumbnail *PhotoSize `json:"thumb,omitempty"` + // FileName original filename as defined by sender + // + // optional + FileName string `json:"file_name,omitempty"` + // MimeType of the file as defined by sender + // + // optional + MimeType string `json:"mime_type,omitempty"` + // FileSize file size + // + // optional + FileSize int64 `json:"file_size,omitempty"` +} + +// Video represents a video file. +type Video struct { + // FileID identifier for this file, which can be used to download or reuse + // the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Width video width as defined by sender + Width int `json:"width"` + // Height video height as defined by sender + Height int `json:"height"` + // Duration of the video in seconds as defined by sender + Duration int `json:"duration"` + // Thumbnail video thumbnail + // + // optional + Thumbnail *PhotoSize `json:"thumb,omitempty"` + // FileName is the original filename as defined by sender + // + // optional + FileName string `json:"file_name,omitempty"` + // MimeType of a file as defined by sender + // + // optional + MimeType string `json:"mime_type,omitempty"` + // FileSize file size + // + // optional + FileSize int64 `json:"file_size,omitempty"` +} + +// VideoNote object represents a video message. +type VideoNote struct { + // FileID identifier for this file, which can be used to download or reuse the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Length video width and height (diameter of the video message) as defined by sender + Length int `json:"length"` + // Duration of the video in seconds as defined by sender + Duration int `json:"duration"` + // Thumbnail video thumbnail + // + // optional + Thumbnail *PhotoSize `json:"thumb,omitempty"` + // FileSize file size + // + // optional + FileSize int `json:"file_size,omitempty"` +} + +// Voice represents a voice note. +type Voice struct { + // FileID identifier for this file, which can be used to download or reuse the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Duration of the audio in seconds as defined by sender + Duration int `json:"duration"` + // MimeType of the file as defined by sender + // + // optional + MimeType string `json:"mime_type,omitempty"` + // FileSize file size + // + // optional + FileSize int64 `json:"file_size,omitempty"` +} + +// Contact represents a phone contact. +// +// Note that LastName and UserID may be empty. +type Contact struct { + // PhoneNumber contact's phone number + PhoneNumber string `json:"phone_number"` + // FirstName contact's first name + FirstName string `json:"first_name"` + // LastName contact's last name + // + // optional + LastName string `json:"last_name,omitempty"` + // UserID contact's user identifier in Telegram + // + // optional + UserID int64 `json:"user_id,omitempty"` + // VCard is additional data about the contact in the form of a vCard. + // + // optional + VCard string `json:"vcard,omitempty"` +} + +// Dice represents an animated emoji that displays a random value. +type Dice struct { + // Emoji on which the dice throw animation is based + Emoji string `json:"emoji"` + // Value of the dice + Value int `json:"value"` +} + +// PollOption contains information about one answer option in a poll. +type PollOption struct { + // Text is the option text, 1-100 characters + Text string `json:"text"` + // VoterCount is the number of users that voted for this option + VoterCount int `json:"voter_count"` +} + +// PollAnswer represents an answer of a user in a non-anonymous poll. +type PollAnswer struct { + // PollID is the unique poll identifier + PollID string `json:"poll_id"` + // User who changed the answer to the poll + User User `json:"user"` + // OptionIDs is the 0-based identifiers of poll options chosen by the user. + // May be empty if user retracted vote. + OptionIDs []int `json:"option_ids"` +} + +// Poll contains information about a poll. +type Poll struct { + // ID is the unique poll identifier + ID string `json:"id"` + // Question is the poll question, 1-255 characters + Question string `json:"question"` + // Options is the list of poll options + Options []PollOption `json:"options"` + // TotalVoterCount is the total numbers of users who voted in the poll + TotalVoterCount int `json:"total_voter_count"` + // IsClosed is if the poll is closed + IsClosed bool `json:"is_closed"` + // IsAnonymous is if the poll is anonymous + IsAnonymous bool `json:"is_anonymous"` + // Type is the poll type, currently can be "regular" or "quiz" + Type string `json:"type"` + // AllowsMultipleAnswers is true, if the poll allows multiple answers + AllowsMultipleAnswers bool `json:"allows_multiple_answers"` + // CorrectOptionID is the 0-based identifier of the correct answer option. + // Available only for polls in quiz mode, which are closed, or was sent (not + // forwarded) by the bot or to the private chat with the bot. + // + // optional + CorrectOptionID int `json:"correct_option_id,omitempty"` + // Explanation is text that is shown when a user chooses an incorrect answer + // or taps on the lamp icon in a quiz-style poll, 0-200 characters + // + // optional + Explanation string `json:"explanation,omitempty"` + // ExplanationEntities are special entities like usernames, URLs, bot + // commands, etc. that appear in the explanation + // + // optional + ExplanationEntities []MessageEntity `json:"explanation_entities,omitempty"` + // OpenPeriod is the amount of time in seconds the poll will be active + // after creation + // + // optional + OpenPeriod int `json:"open_period,omitempty"` + // CloseDate is the point in time (unix timestamp) when the poll will be + // automatically closed + // + // optional + CloseDate int `json:"close_date,omitempty"` +} + +// Location represents a point on the map. +type Location struct { + // Longitude as defined by sender + Longitude float64 `json:"longitude"` + // Latitude as defined by sender + Latitude float64 `json:"latitude"` + // HorizontalAccuracy is the radius of uncertainty for the location, + // measured in meters; 0-1500 + // + // optional + HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` + // LivePeriod is time relative to the message sending date, during which the + // location can be updated, in seconds. For active live locations only. + // + // optional + LivePeriod int `json:"live_period,omitempty"` + // Heading is the direction in which user is moving, in degrees; 1-360. For + // active live locations only. + // + // optional + Heading int `json:"heading,omitempty"` + // ProximityAlertRadius is the maximum distance for proximity alerts about + // approaching another chat member, in meters. For sent live locations only. + // + // optional + ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` +} + +// Venue represents a venue. +type Venue struct { + // Location is the venue location + Location Location `json:"location"` + // Title is the name of the venue + Title string `json:"title"` + // Address of the venue + Address string `json:"address"` + // FoursquareID is the foursquare identifier of the venue + // + // optional + FoursquareID string `json:"foursquare_id,omitempty"` + // FoursquareType is the foursquare type of the venue + // + // optional + FoursquareType string `json:"foursquare_type,omitempty"` + // GooglePlaceID is the Google Places identifier of the venue + // + // optional + GooglePlaceID string `json:"google_place_id,omitempty"` + // GooglePlaceType is the Google Places type of the venue + // + // optional + GooglePlaceType string `json:"google_place_type,omitempty"` +} + +// WebAppData Contains data sent from a Web App to the bot. +type WebAppData struct { + // Data is the data. Be aware that a bad client can send arbitrary data in this field. + Data string `json:"data"` + // ButtonText is the text of the web_app keyboard button, from which the Web App + // was opened. Be aware that a bad client can send arbitrary data in this field. + ButtonText string `json:"button_text"` +} + +// ProximityAlertTriggered represents a service message sent when a user in the +// chat triggers a proximity alert sent by another user. +type ProximityAlertTriggered struct { + // Traveler is the user that triggered the alert + Traveler User `json:"traveler"` + // Watcher is the user that set the alert + Watcher User `json:"watcher"` + // Distance is the distance between the users + Distance int `json:"distance"` +} + +// MessageAutoDeleteTimerChanged represents a service message about a change in +// auto-delete timer settings. +type MessageAutoDeleteTimerChanged struct { + // New auto-delete time for messages in the chat. + MessageAutoDeleteTime int `json:"message_auto_delete_time"` +} + +// ForumTopicCreated represents a service message about a new forum topic +// created in the chat. +type ForumTopicCreated struct { + // Name is the name of topic + Name string `json:"name"` + // IconColor is the color of the topic icon in RGB format + IconColor int `json:"icon_color"` + // IconCustomEmojiID is the unique identifier of the custom emoji + // shown as the topic icon + // + // optional + IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"` +} + +// ForumTopicClosed represents a service message about a forum topic +// closed in the chat. Currently holds no information. +type ForumTopicClosed struct { +} + +// ForumTopicEdited object represents a service message about an edited forum topic. +type ForumTopicEdited struct { + // Name is the new name of the topic, if it was edited + // + // optional + Name string `json:"name,omitempty"` + // IconCustomEmojiID is the new identifier of the custom emoji + // shown as the topic icon, if it was edited; + // an empty string if the icon was removed + // + // optional + IconCustomEmojiID *string `json:"icon_custom_emoji_id,omitempty"` +} + +// ForumTopicReopened represents a service message about a forum topic +// reopened in the chat. Currently holds no information. +type ForumTopicReopened struct { +} + +// GeneralForumTopicHidden represents a service message about General forum topic +// hidden in the chat. Currently holds no information. +type GeneralForumTopicHidden struct { +} + +// GeneralForumTopicUnhidden represents a service message about General forum topic +// unhidden in the chat. Currently holds no information. +type GeneralForumTopicUnhidden struct { +} + +// UserShared object contains information about the user whose identifier +// was shared with the bot using a KeyboardButtonRequestUser button. +type UserShared struct { + // RequestID is an indentifier of the request. + RequestID int `json:"request_id"` + // UserID in an identifier of the shared user. + UserID int64 `json:"user_id"` +} + +// ChatShared contains information about the chat whose identifier +// was shared with the bot using a KeyboardButtonRequestChat button. +type ChatShared struct { + // RequestID is an indentifier of the request. + RequestID int `json:"request_id"` + // ChatID is an identifier of the shared chat. + ChatID int64 `json:"chat_id"` +} + +// WriteAccessAllowed represents a service message about a user +// allowing a bot added to the attachment menu to write messages. +// Currently holds no information. +type WriteAccessAllowed struct { +} + +// VideoChatScheduled represents a service message about a voice chat scheduled +// in the chat. +type VideoChatScheduled struct { + // Point in time (Unix timestamp) when the voice chat is supposed to be + // started by a chat administrator + StartDate int `json:"start_date"` +} + +// Time converts the scheduled start date into a Time. +func (m *VideoChatScheduled) Time() time.Time { + return time.Unix(int64(m.StartDate), 0) +} + +// VideoChatStarted represents a service message about a voice chat started in +// the chat. +type VideoChatStarted struct{} + +// VideoChatEnded represents a service message about a voice chat ended in the +// chat. +type VideoChatEnded struct { + // Voice chat duration; in seconds. + Duration int `json:"duration"` +} + +// VideoChatParticipantsInvited represents a service message about new members +// invited to a voice chat. +type VideoChatParticipantsInvited struct { + // New members that were invited to the voice chat. + // + // optional + Users []User `json:"users,omitempty"` +} + +// UserProfilePhotos contains a set of user profile photos. +type UserProfilePhotos struct { + // TotalCount total number of profile pictures the target user has + TotalCount int `json:"total_count"` + // Photos requested profile pictures (in up to 4 sizes each) + Photos [][]PhotoSize `json:"photos"` +} + +// File contains information about a file to download from Telegram. +type File struct { + // FileID identifier for this file, which can be used to download or reuse + // the file + FileID string `json:"file_id"` + // FileUniqueID is the unique identifier for this file, which is supposed to + // be the same over time and for different bots. Can't be used to download + // or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // FileSize file size, if known + // + // optional + FileSize int64 `json:"file_size,omitempty"` + // FilePath file path + // + // optional + FilePath string `json:"file_path,omitempty"` +} + +// Link returns a full path to the download URL for a File. +// +// It requires the Bot token to create the link. +func (f *File) Link(token string) string { + return fmt.Sprintf(FileEndpoint, token, f.FilePath) +} + +// WebAppInfo contains information about a Web App. +type WebAppInfo struct { + // URL is the HTTPS URL of a Web App to be opened with additional data as + // specified in Initializing Web Apps. + URL string `json:"url"` +} + +// ReplyKeyboardMarkup represents a custom keyboard with reply options. +type ReplyKeyboardMarkup struct { + // Keyboard is an array of button rows, each represented by an Array of KeyboardButton objects + Keyboard [][]KeyboardButton `json:"keyboard"` + // IsPersistent requests clients to always show the keyboard + // when the regular keyboard is hidden. + // Defaults to false, in which case the custom keyboard can be hidden + // and opened with a keyboard icon. + // + // optional + IsPersistent bool `json:"is_persistent"` + // ResizeKeyboard requests clients to resize the keyboard vertically for optimal fit + // (e.g., make the keyboard smaller if there are just two rows of buttons). + // Defaults to false, in which case the custom keyboard + // is always of the same height as the app's standard keyboard. + // + // optional + ResizeKeyboard bool `json:"resize_keyboard,omitempty"` + // OneTimeKeyboard requests clients to hide the keyboard as soon as it's been used. + // The keyboard will still be available, but clients will automatically display + // the usual letter-keyboard in the chat – the user can press a special button + // in the input field to see the custom keyboard again. + // Defaults to false. + // + // optional + OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"` + // InputFieldPlaceholder is the placeholder to be shown in the input field when + // the keyboard is active; 1-64 characters. + // + // optional + InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` + // Selective use this parameter if you want to show the keyboard to specific users only. + // Targets: + // 1) users that are @mentioned in the text of the Message object; + // 2) if the bot's message is a reply (has Message.ReplyToMessage not nil), sender of the original message. + // + // Example: A user requests to change the bot's language, + // bot replies to the request with a keyboard to select the new language. + // Other users in the group don't see the keyboard. + // + // optional + Selective bool `json:"selective,omitempty"` +} + +// KeyboardButton represents one button of the reply keyboard. For simple text +// buttons String can be used instead of this object to specify text of the +// button. Optional fields request_contact, request_location, and request_poll +// are mutually exclusive. +type KeyboardButton struct { + // Text of the button. If none of the optional fields are used, + // it will be sent as a message when the button is pressed. + Text string `json:"text"` + // RequestUser if specified, pressing the button will open + // a list of suitable users. Tapping on any user will send + // their identifier to the bot in a "user_shared" service message. + // Available in private chats only. + // + // optional + RequestUser *KeyboardButtonRequestUser `json:"request_user,omitempty"` + // RequestChat if specified, pressing the button will open + // a list of suitable chats. Tapping on a chat will send + // its identifier to the bot in a "chat_shared" service message. + // Available in private chats only. + // + // optional + RequestChat *KeyboardButtonRequestChat `json:"request_chat,omitempty"` + // RequestContact if True, the user's phone number will be sent + // as a contact when the button is pressed. + // Available in private chats only. + // + // optional + RequestContact bool `json:"request_contact,omitempty"` + // RequestLocation if True, the user's current location will be sent when + // the button is pressed. + // Available in private chats only. + // + // optional + RequestLocation bool `json:"request_location,omitempty"` + // RequestPoll if specified, the user will be asked to create a poll and send it + // to the bot when the button is pressed. Available in private chats only + // + // optional + RequestPoll *KeyboardButtonPollType `json:"request_poll,omitempty"` + // WebApp if specified, the described Web App will be launched when the button + // is pressed. The Web App will be able to send a “web_app_data” service + // message. Available in private chats only. + // + // optional + WebApp *WebAppInfo `json:"web_app,omitempty"` +} + +// KeyboardButtonRequestUser defines the criteria used to request +// a suitable user. The identifier of the selected user will be shared +// with the bot when the corresponding button is pressed. +type KeyboardButtonRequestUser struct { + // RequestID is a signed 32-bit identifier of the request. + RequestID int `json:"request_id"` + // UserIsBot pass True to request a bot, + // pass False to request a regular user. + // If not specified, no additional restrictions are applied. + // + // optional + UserIsBot bool `json:"user_is_bot,omitempty"` + // UserIsPremium pass True to request a premium user, + // pass False to request a non-premium user. + // If not specified, no additional restrictions are applied. + // + // optional + UserIsPremium bool `json:"user_is_premium,omitempty"` +} + +// KeyboardButtonRequestChat defines the criteria used to request +// a suitable chat. The identifier of the selected chat will be shared +// with the bot when the corresponding button is pressed. +type KeyboardButtonRequestChat struct { + // RequestID is a signed 32-bit identifier of the request. + RequestID int `json:"request_id"` + // ChatIsChannel pass True to request a channel chat, + // pass False to request a group or a supergroup chat. + ChatIsChannel bool `json:"chat_is_channel"` + // ChatIsForum pass True to request a forum supergroup, + // pass False to request a non-forum chat. + // If not specified, no additional restrictions are applied. + // + // optional + ChatIsForum bool `json:"chat_is_forum,omitempty"` + // ChatHasUsername pass True to request a supergroup or a channel with a username, + // pass False to request a chat without a username. + // If not specified, no additional restrictions are applied. + // + // optional + ChatHasUsername bool `json:"chat_has_username,omitempty"` + // ChatIsCreated pass True to request a chat owned by the user. + // Otherwise, no additional restrictions are applied. + // + // optional + ChatIsCreated bool `json:"chat_is_created,omitempty"` + // UserAdministratorRights is a JSON-serialized object listing + // the required administrator rights of the user in the chat. + // If not specified, no additional restrictions are applied. + // + // optional + UserAdministratorRights *ChatAdministratorRights `json:"user_administrator_rights,omitempty"` + // BotAdministratorRights is a JSON-serialized object listing + // the required administrator rights of the bot in the chat. + // The rights must be a subset of user_administrator_rights. + // If not specified, no additional restrictions are applied. + // + // optional + BotAdministratorRights *ChatAdministratorRights `json:"bot_administrator_rights,omitempty"` + // BotIsMember pass True to request a chat with the bot as a member. + // Otherwise, no additional restrictions are applied. + // + // optional + BotIsMember bool `json:"bot_is_member,omitempty"` +} + +// KeyboardButtonPollType represents type of poll, which is allowed to +// be created and sent when the corresponding button is pressed. +type KeyboardButtonPollType struct { + // Type is if quiz is passed, the user will be allowed to create only polls + // in the quiz mode. If regular is passed, only regular polls will be + // allowed. Otherwise, the user will be allowed to create a poll of any type. + Type string `json:"type"` +} + +// ReplyKeyboardRemove Upon receiving a message with this object, Telegram +// clients will remove the current custom keyboard and display the default +// letter-keyboard. By default, custom keyboards are displayed until a new +// keyboard is sent by a bot. An exception is made for one-time keyboards +// that are hidden immediately after the user presses a button. +type ReplyKeyboardRemove struct { + // RemoveKeyboard requests clients to remove the custom keyboard + // (user will not be able to summon this keyboard; + // if you want to hide the keyboard from sight but keep it accessible, + // use one_time_keyboard in ReplyKeyboardMarkup). + RemoveKeyboard bool `json:"remove_keyboard"` + // Selective use this parameter if you want to remove the keyboard for specific users only. + // Targets: + // 1) users that are @mentioned in the text of the Message object; + // 2) if the bot's message is a reply (has Message.ReplyToMessage not nil), sender of the original message. + // + // Example: A user votes in a poll, bot returns confirmation message + // in reply to the vote and removes the keyboard for that user, + // while still showing the keyboard with poll options to users who haven't voted yet. + // + // optional + Selective bool `json:"selective,omitempty"` +} + +// InlineKeyboardMarkup represents an inline keyboard that appears right next to +// the message it belongs to. +type InlineKeyboardMarkup struct { + // InlineKeyboard array of button rows, each represented by an Array of + // InlineKeyboardButton objects + InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"` +} + +// InlineKeyboardButton represents one button of an inline keyboard. You must +// use exactly one of the optional fields. +// +// Note that some values are references as even an empty string +// will change behavior. +// +// CallbackGame, if set, MUST be first button in first row. +type InlineKeyboardButton struct { + // Text label text on the button + Text string `json:"text"` + // URL HTTP or tg:// url to be opened when button is pressed. + // + // optional + URL *string `json:"url,omitempty"` + // LoginURL is an HTTP URL used to automatically authorize the user. Can be + // used as a replacement for the Telegram Login Widget + // + // optional + LoginURL *LoginURL `json:"login_url,omitempty"` + // CallbackData data to be sent in a callback query to the bot when button is pressed, 1-64 bytes. + // + // optional + CallbackData *string `json:"callback_data,omitempty"` + // WebApp is the Description of the Web App that will be launched when the user presses the button. + // The Web App will be able to send an arbitrary message on behalf of the user using the method + // answerWebAppQuery. Available only in private chats between a user and the bot. + // + // optional + WebApp *WebAppInfo `json:"web_app,omitempty"` + // SwitchInlineQuery if set, pressing the button will prompt the user to select one of their chats, + // open that chat and insert the bot's username and the specified inline query in the input field. + // Can be empty, in which case just the bot's username will be inserted. + // + // This offers an easy way for users to start using your bot + // in inline mode when they are currently in a private chat with it. + // Especially useful when combined with switch_pm… actions – in this case + // the user will be automatically returned to the chat they switched from, + // skipping the chat selection screen. + // + // optional + SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` + // SwitchInlineQueryCurrentChat if set, pressing the button will insert the bot's username + // and the specified inline query in the current chat's input field. + // Can be empty, in which case only the bot's username will be inserted. + // + // This offers a quick way for the user to open your bot in inline mode + // in the same chat – good for selecting something from multiple options. + // + // optional + SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` + // CallbackGame description of the game that will be launched when the user presses the button. + // + // optional + CallbackGame *CallbackGame `json:"callback_game,omitempty"` + // Pay specify True, to send a Pay button. + // + // NOTE: This type of button must always be the first button in the first row. + // + // optional + Pay bool `json:"pay,omitempty"` +} + +// LoginURL represents a parameter of the inline keyboard button used to +// automatically authorize a user. Serves as a great replacement for the +// Telegram Login Widget when the user is coming from Telegram. All the user +// needs to do is tap/click a button and confirm that they want to log in. +type LoginURL struct { + // URL is an HTTP URL to be opened with user authorization data added to the + // query string when the button is pressed. If the user refuses to provide + // authorization data, the original URL without information about the user + // will be opened. The data added is the same as described in Receiving + // authorization data. + // + // NOTE: You must always check the hash of the received data to verify the + // authentication and the integrity of the data as described in Checking + // authorization. + URL string `json:"url"` + // ForwardText is the new text of the button in forwarded messages + // + // optional + ForwardText string `json:"forward_text,omitempty"` + // BotUsername is the username of a bot, which will be used for user + // authorization. See Setting up a bot for more details. If not specified, + // the current bot's username will be assumed. The url's domain must be the + // same as the domain linked with the bot. See Linking your domain to the + // bot for more details. + // + // optional + BotUsername string `json:"bot_username,omitempty"` + // RequestWriteAccess if true requests permission for your bot to send + // messages to the user + // + // optional + RequestWriteAccess bool `json:"request_write_access,omitempty"` +} + +// CallbackQuery represents an incoming callback query from a callback button in +// an inline keyboard. If the button that originated the query was attached to a +// message sent by the bot, the field message will be present. If the button was +// attached to a message sent via the bot (in inline mode), the field +// inline_message_id will be present. Exactly one of the fields data or +// game_short_name will be present. +type CallbackQuery struct { + // ID unique identifier for this query + ID string `json:"id"` + // From sender + From *User `json:"from"` + // Message with the callback button that originated the query. + // Note that message content and message date will not be available if the + // message is too old. + // + // optional + Message *Message `json:"message,omitempty"` + // InlineMessageID identifier of the message sent via the bot in inline + // mode, that originated the query. + // + // optional + InlineMessageID string `json:"inline_message_id,omitempty"` + // ChatInstance global identifier, uniquely corresponding to the chat to + // which the message with the callback button was sent. Useful for high + // scores in games. + ChatInstance string `json:"chat_instance"` + // Data associated with the callback button. Be aware that + // a bad client can send arbitrary data in this field. + // + // optional + Data string `json:"data,omitempty"` + // GameShortName short name of a Game to be returned, serves as the unique identifier for the game. + // + // optional + GameShortName string `json:"game_short_name,omitempty"` +} + +// ForceReply when receiving a message with this object, Telegram clients will +// display a reply interface to the user (act as if the user has selected the +// bot's message and tapped 'Reply'). This can be extremely useful if you want +// to create user-friendly step-by-step interfaces without having to sacrifice +// privacy mode. +type ForceReply struct { + // ForceReply shows reply interface to the user, + // as if they manually selected the bot's message and tapped 'Reply'. + ForceReply bool `json:"force_reply"` + // InputFieldPlaceholder is the placeholder to be shown in the input field when + // the reply is active; 1-64 characters. + // + // optional + InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` + // Selective use this parameter if you want to force reply from specific users only. + // Targets: + // 1) users that are @mentioned in the text of the Message object; + // 2) if the bot's message is a reply (has Message.ReplyToMessage not nil), sender of the original message. + // + // optional + Selective bool `json:"selective,omitempty"` +} + +// ChatPhoto represents a chat photo. +type ChatPhoto struct { + // SmallFileID is a file identifier of small (160x160) chat photo. + // This file_id can be used only for photo download and + // only for as long as the photo is not changed. + SmallFileID string `json:"small_file_id"` + // SmallFileUniqueID is a unique file identifier of small (160x160) chat + // photo, which is supposed to be the same over time and for different bots. + // Can't be used to download or reuse the file. + SmallFileUniqueID string `json:"small_file_unique_id"` + // BigFileID is a file identifier of big (640x640) chat photo. + // This file_id can be used only for photo download and + // only for as long as the photo is not changed. + BigFileID string `json:"big_file_id"` + // BigFileUniqueID is a file identifier of big (640x640) chat photo, which + // is supposed to be the same over time and for different bots. Can't be + // used to download or reuse the file. + BigFileUniqueID string `json:"big_file_unique_id"` +} + +// ChatInviteLink represents an invite link for a chat. +type ChatInviteLink struct { + // InviteLink is the invite link. If the link was created by another chat + // administrator, then the second part of the link will be replaced with “…”. + InviteLink string `json:"invite_link"` + // Creator of the link. + Creator User `json:"creator"` + // CreatesJoinRequest is true if users joining the chat via the link need to + // be approved by chat administrators. + // + // optional + CreatesJoinRequest bool `json:"creates_join_request,omitempty"` + // IsPrimary is true, if the link is primary. + IsPrimary bool `json:"is_primary"` + // IsRevoked is true, if the link is revoked. + IsRevoked bool `json:"is_revoked"` + // Name is the name of the invite link. + // + // optional + Name string `json:"name,omitempty"` + // ExpireDate is the point in time (Unix timestamp) when the link will + // expire or has been expired. + // + // optional + ExpireDate int `json:"expire_date,omitempty"` + // MemberLimit is the maximum number of users that can be members of the + // chat simultaneously after joining the chat via this invite link; 1-99999. + // + // optional + MemberLimit int `json:"member_limit,omitempty"` + // PendingJoinRequestCount is the number of pending join requests created + // using this link. + // + // optional + PendingJoinRequestCount int `json:"pending_join_request_count,omitempty"` +} + +type ChatAdministratorRights struct { + IsAnonymous bool `json:"is_anonymous"` + CanManageChat bool `json:"can_manage_chat"` + CanDeleteMessages bool `json:"can_delete_messages"` + CanManageVideoChats bool `json:"can_manage_video_chats"` + CanRestrictMembers bool `json:"can_restrict_members"` + CanPromoteMembers bool `json:"can_promote_members"` + CanChangeInfo bool `json:"can_change_info"` + CanInviteUsers bool `json:"can_invite_users"` + CanPostMessages bool `json:"can_post_messages"` + CanEditMessages bool `json:"can_edit_messages"` + CanPinMessages bool `json:"can_pin_messages"` + CanManageTopics bool `json:"can_manage_topics"` +} + +// ChatMember contains information about one member of a chat. +type ChatMember struct { + // User information about the user + User *User `json:"user"` + // Status the member's status in the chat. + // Can be + // “creator”, + // “administrator”, + // “member”, + // “restricted”, + // “left” or + // “kicked” + Status string `json:"status"` + // CustomTitle owner and administrators only. Custom title for this user + // + // optional + CustomTitle string `json:"custom_title,omitempty"` + // IsAnonymous owner and administrators only. True, if the user's presence + // in the chat is hidden + // + // optional + IsAnonymous bool `json:"is_anonymous,omitempty"` + // UntilDate restricted and kicked only. + // Date when restrictions will be lifted for this user; + // unix time. + // + // optional + UntilDate int64 `json:"until_date,omitempty"` + // CanBeEdited administrators only. + // True, if the bot is allowed to edit administrator privileges of that user. + // + // optional + CanBeEdited bool `json:"can_be_edited,omitempty"` + // CanManageChat administrators only. + // True, if the administrator can access the chat event log, chat + // statistics, message statistics in channels, see channel members, see + // anonymous administrators in supergroups and ignore slow mode. Implied by + // any other administrator privilege. + // + // optional + CanManageChat bool `json:"can_manage_chat,omitempty"` + // CanPostMessages administrators only. + // True, if the administrator can post in the channel; + // channels only. + // + // optional + CanPostMessages bool `json:"can_post_messages,omitempty"` + // CanEditMessages administrators only. + // True, if the administrator can edit messages of other users and can pin messages; + // channels only. + // + // optional + CanEditMessages bool `json:"can_edit_messages,omitempty"` + // CanDeleteMessages administrators only. + // True, if the administrator can delete messages of other users. + // + // optional + CanDeleteMessages bool `json:"can_delete_messages,omitempty"` + // CanManageVideoChats administrators only. + // True, if the administrator can manage video chats. + // + // optional + CanManageVideoChats bool `json:"can_manage_video_chats,omitempty"` + // CanRestrictMembers administrators only. + // True, if the administrator can restrict, ban or unban chat members. + // + // optional + CanRestrictMembers bool `json:"can_restrict_members,omitempty"` + // CanPromoteMembers administrators only. + // True, if the administrator can add new administrators + // with a subset of their own privileges or demote administrators that he has promoted, + // directly or indirectly (promoted by administrators that were appointed by the user). + // + // optional + CanPromoteMembers bool `json:"can_promote_members,omitempty"` + // CanChangeInfo administrators and restricted only. + // True, if the user is allowed to change the chat title, photo and other settings. + // + // optional + CanChangeInfo bool `json:"can_change_info,omitempty"` + // CanInviteUsers administrators and restricted only. + // True, if the user is allowed to invite new users to the chat. + // + // optional + CanInviteUsers bool `json:"can_invite_users,omitempty"` + // CanPinMessages administrators and restricted only. + // True, if the user is allowed to pin messages; groups and supergroups only + // + // optional + CanPinMessages bool `json:"can_pin_messages,omitempty"` + // CanManageTopics administrators and restricted only. + // True, if the user is allowed to create, rename, + // close, and reopen forum topics; supergroups only + // + // optional + CanManageTopics bool `json:"can_manage_topics,omitempty"` + // IsMember is true, if the user is a member of the chat at the moment of + // the request + IsMember bool `json:"is_member"` + // CanSendMessages + // + // optional + CanSendMessages bool `json:"can_send_messages,omitempty"` + // CanSendAudios restricted only. + // True, if the user is allowed to send audios + // + // optional + CanSendAudios bool + // CanSendDocuments restricted only. + // True, if the user is allowed to send documents + // + // optional + CanSendDocuments bool + // CanSendPhotos is restricted only. + // True, if the user is allowed to send photos + // + // optional + CanSendPhotos bool + // CanSendVideos restricted only. + // True, if the user is allowed to send videos + // + // optional + CanSendVideos bool + // CanSendVideoNotes restricted only. + // True, if the user is allowed to send video notes + // + // optional + CanSendVideoNotes bool + // CanSendVoiceNotes restricted only. + // True, if the user is allowed to send voice notes + // + // optional + CanSendVoiceNotes bool + // CanSendPolls restricted only. + // True, if the user is allowed to send polls + // + // optional + CanSendPolls bool `json:"can_send_polls,omitempty"` + // CanSendOtherMessages restricted only. + // True, if the user is allowed to send audios, documents, + // photos, videos, video notes and voice notes. + // + // optional + CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` + // CanAddWebPagePreviews restricted only. + // True, if the user is allowed to add web page previews to their messages. + // + // optional + CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` +} + +// IsCreator returns if the ChatMember was the creator of the chat. +func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" } + +// IsAdministrator returns if the ChatMember is a chat administrator. +func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" } + +// HasLeft returns if the ChatMember left the chat. +func (chat ChatMember) HasLeft() bool { return chat.Status == "left" } + +// WasKicked returns if the ChatMember was kicked from the chat. +func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" } + +// SetCanSendMediaMessages is a method to replace field "can_send_media_messages". +// It sets CanSendAudio, CanSendDocuments, CanSendPhotos, CanSendVideos, +// CanSendVideoNotes, CanSendVoiceNotes to passed value. +func (chat *ChatMember) SetCanSendMediaMessages(b bool) { + chat.CanSendAudios = b + chat.CanSendDocuments = b + chat.CanSendPhotos = b + chat.CanSendVideos = b + chat.CanSendVideoNotes = b + chat.CanSendVoiceNotes = b +} + +// CanSendMediaMessages method to replace field "can_send_media_messages". +// It returns true if CanSendAudio and CanSendDocuments and CanSendPhotos and CanSendVideos and +// CanSendVideoNotes and CanSendVoiceNotes are true. +func (chat *ChatMember) CanSendMediaMessages() bool { + return chat.CanSendAudios && chat.CanSendDocuments && + chat.CanSendPhotos && chat.CanSendVideos && + chat.CanSendVideoNotes && chat.CanSendVoiceNotes +} + +// ChatMemberUpdated represents changes in the status of a chat member. +type ChatMemberUpdated struct { + // Chat the user belongs to. + Chat Chat `json:"chat"` + // From is the performer of the action, which resulted in the change. + From User `json:"from"` + // Date the change was done in Unix time. + Date int `json:"date"` + // Previous information about the chat member. + OldChatMember ChatMember `json:"old_chat_member"` + // New information about the chat member. + NewChatMember ChatMember `json:"new_chat_member"` + // InviteLink is the link which was used by the user to join the chat; + // for joining by invite link events only. + // + // optional + InviteLink *ChatInviteLink `json:"invite_link,omitempty"` +} + +// ChatJoinRequest represents a join request sent to a chat. +type ChatJoinRequest struct { + // Chat to which the request was sent. + Chat Chat `json:"chat"` + // User that sent the join request. + From User `json:"from"` + // UserChatID identifier of a private chat with the user who sent the join request. + UserChatID int64 `json:"user_chat_id"` + // Date the request was sent in Unix time. + Date int `json:"date"` + // Bio of the user. + // + // optional + Bio string `json:"bio,omitempty"` + // InviteLink is the link that was used by the user to send the join request. + // + // optional + InviteLink *ChatInviteLink `json:"invite_link,omitempty"` +} + +// ChatPermissions describes actions that a non-administrator user is +// allowed to take in a chat. All fields are optional. +type ChatPermissions struct { + // CanSendMessages is true, if the user is allowed to send text messages, + // contacts, locations and venues + // + // optional + CanSendMessages bool `json:"can_send_messages,omitempty"` + // CanSendAudios is true, if the user is allowed to send audios + // + // optional + CanSendAudios bool + // CanSendDocuments is true, if the user is allowed to send documents + // + // optional + CanSendDocuments bool + // CanSendPhotos is true, if the user is allowed to send photos + // + // optional + CanSendPhotos bool + // CanSendVideos is true, if the user is allowed to send videos + // + // optional + CanSendVideos bool + // CanSendVideoNotes is true, if the user is allowed to send video notes + // + // optional + CanSendVideoNotes bool + // CanSendVoiceNotes is true, if the user is allowed to send voice notes + // + // optional + CanSendVoiceNotes bool + // CanSendPolls is true, if the user is allowed to send polls, implies + // can_send_messages + // + // optional + CanSendPolls bool `json:"can_send_polls,omitempty"` + // CanSendOtherMessages is true, if the user is allowed to send animations, + // games, stickers and use inline bots, implies can_send_media_messages + // + // optional + CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` + // CanAddWebPagePreviews is true, if the user is allowed to add web page + // previews to their messages, implies can_send_media_messages + // + // optional + CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` + // CanChangeInfo is true, if the user is allowed to change the chat title, + // photo and other settings. Ignored in public supergroups + // + // optional + CanChangeInfo bool `json:"can_change_info,omitempty"` + // CanInviteUsers is true, if the user is allowed to invite new users to the + // chat + // + // optional + CanInviteUsers bool `json:"can_invite_users,omitempty"` + // CanPinMessages is true, if the user is allowed to pin messages. Ignored + // in public supergroups + // + // optional + CanPinMessages bool `json:"can_pin_messages,omitempty"` + // CanManageTopics is true, if the user is allowed to create forum topics. + // If omitted defaults to the value of can_pin_messages + // + // optional + CanManageTopics bool `json:"can_manage_topics,omitempty"` +} + +// SetCanSendMediaMessages is a method to replace field "can_send_media_messages". +// It sets CanSendAudio, CanSendDocuments, CanSendPhotos, CanSendVideos, +// CanSendVideoNotes, CanSendVoiceNotes to passed value. +func (c *ChatPermissions) SetCanSendMediaMessages(b bool) { + c.CanSendAudios = b + c.CanSendDocuments = b + c.CanSendPhotos = b + c.CanSendVideos = b + c.CanSendVideoNotes = b + c.CanSendVoiceNotes = b +} + +// CanSendMediaMessages method to replace field "can_send_media_messages". +// It returns true if CanSendAudio and CanSendDocuments and CanSendPhotos and CanSendVideos and +// CanSendVideoNotes and CanSendVoiceNotes are true. +func (c *ChatPermissions) CanSendMediaMessages() bool { + return c.CanSendAudios && c.CanSendDocuments && + c.CanSendPhotos && c.CanSendVideos && + c.CanSendVideoNotes && c.CanSendVoiceNotes +} + +// ChatLocation represents a location to which a chat is connected. +type ChatLocation struct { + // Location is the location to which the supergroup is connected. Can't be a + // live location. + Location Location `json:"location"` + // Address is the location address; 1-64 characters, as defined by the chat + // owner + Address string `json:"address"` +} + +// ForumTopic represents a forum topic. +type ForumTopic struct { + // MessageThreadID is the unique identifier of the forum topic + MessageThreadID int `json:"message_thread_id"` + // Name is the name of the topic + Name string `json:"name"` + // IconColor is the color of the topic icon in RGB format + IconColor int `json:"icon_color"` + // IconCustomEmojiID is the unique identifier of the custom emoji + // shown as the topic icon + // + // optional + IconCustomEmojiID string `json:"icon_custom_emoji_id,omitempty"` +} + +// BotCommand represents a bot command. +type BotCommand struct { + // Command text of the command, 1-32 characters. + // Can contain only lowercase English letters, digits and underscores. + Command string `json:"command"` + // Description of the command, 3-256 characters. + Description string `json:"description"` +} + +// BotCommandScope represents the scope to which bot commands are applied. +// +// It contains the fields for all types of scopes, different types only support +// specific (or no) fields. +type BotCommandScope struct { + Type string `json:"type"` + ChatID int64 `json:"chat_id,omitempty"` + UserID int64 `json:"user_id,omitempty"` +} + +// MenuButton describes the bot's menu button in a private chat. +type MenuButton struct { + // Type is the type of menu button, must be one of: + // - `commands` + // - `web_app` + // - `default` + Type string `json:"type"` + // Text is the text on the button, for `web_app` type. + Text string `json:"text,omitempty"` + // WebApp is the description of the Web App that will be launched when the + // user presses the button for the `web_app` type. + WebApp *WebAppInfo `json:"web_app,omitempty"` +} + +// ResponseParameters are various errors that can be returned in APIResponse. +type ResponseParameters struct { + // The group has been migrated to a supergroup with the specified identifier. + // + // optional + MigrateToChatID int64 `json:"migrate_to_chat_id,omitempty"` + // In case of exceeding flood control, the number of seconds left to wait + // before the request can be repeated. + // + // optional + RetryAfter int `json:"retry_after,omitempty"` +} + +// BaseInputMedia is a base type for the InputMedia types. +type BaseInputMedia struct { + // Type of the result. + Type string `json:"type"` + // Media file to send. Pass a file_id to send a file + // that exists on the Telegram servers (recommended), + // pass an HTTP URL for Telegram to get a file from the Internet, + // or pass “attach://” to upload a new one + // using multipart/form-data under name. + Media RequestFileData `json:"media"` + // thumb intentionally missing as it is not currently compatible + + // Caption of the video to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // HasSpoiler pass True, if the photo needs to be covered with a spoiler animation + // + // optional + HasSpoiler bool `json:"has_spoiler,omitempty"` +} + +// InputMediaPhoto is a photo to send as part of a media group. +type InputMediaPhoto struct { + BaseInputMedia +} + +// InputMediaVideo is a video to send as part of a media group. +type InputMediaVideo struct { + BaseInputMedia + // Thumbnail of the file sent; can be ignored if thumbnail generation for + // the file is supported server-side. + // + // optional + Thumb RequestFileData `json:"thumb,omitempty"` + // Width video width + // + // optional + Width int `json:"width,omitempty"` + // Height video height + // + // optional + Height int `json:"height,omitempty"` + // Duration video duration + // + // optional + Duration int `json:"duration,omitempty"` + // SupportsStreaming pass True, if the uploaded video is suitable for streaming. + // + // optional + SupportsStreaming bool `json:"supports_streaming,omitempty"` + // HasSpoiler pass True, if the video needs to be covered with a spoiler animation + // + // optional + HasSpoiler bool `json:"has_spoiler,omitempty"` +} + +// InputMediaAnimation is an animation to send as part of a media group. +type InputMediaAnimation struct { + BaseInputMedia + // Thumbnail of the file sent; can be ignored if thumbnail generation for + // the file is supported server-side. + // + // optional + Thumb RequestFileData `json:"thumb,omitempty"` + // Width video width + // + // optional + Width int `json:"width,omitempty"` + // Height video height + // + // optional + Height int `json:"height,omitempty"` + // Duration video duration + // + // optional + Duration int `json:"duration,omitempty"` + // HasSpoiler pass True, if the photo needs to be covered with a spoiler animation + // + // optional + HasSpoiler bool `json:"has_spoiler,omitempty"` +} + +// InputMediaAudio is an audio to send as part of a media group. +type InputMediaAudio struct { + BaseInputMedia + // Thumbnail of the file sent; can be ignored if thumbnail generation for + // the file is supported server-side. + // + // optional + Thumb RequestFileData `json:"thumb,omitempty"` + // Duration of the audio in seconds + // + // optional + Duration int `json:"duration,omitempty"` + // Performer of the audio + // + // optional + Performer string `json:"performer,omitempty"` + // Title of the audio + // + // optional + Title string `json:"title,omitempty"` +} + +// InputMediaDocument is a general file to send as part of a media group. +type InputMediaDocument struct { + BaseInputMedia + // Thumbnail of the file sent; can be ignored if thumbnail generation for + // the file is supported server-side. + // + // optional + Thumb RequestFileData `json:"thumb,omitempty"` + // DisableContentTypeDetection disables automatic server-side content type + // detection for files uploaded using multipart/form-data. Always true, if + // the document is sent as part of an album + // + // optional + DisableContentTypeDetection bool `json:"disable_content_type_detection,omitempty"` +} + +// Constant values for sticker types +const ( + StickerTypeRegular = "regular" + StickerTypeMask = "mask" + StickerTypeCustomEmoji = "custom_emoji" +) + +// Sticker represents a sticker. +type Sticker struct { + // FileID is an identifier for this file, which can be used to download or + // reuse the file + FileID string `json:"file_id"` + // FileUniqueID is a unique identifier for this file, + // which is supposed to be the same over time and for different bots. + // Can't be used to download or reuse the file. + FileUniqueID string `json:"file_unique_id"` + // Type is a type of the sticker, currently one of “regular”, + // “mask”, “custom_emoji”. The type of the sticker is independent + // from its format, which is determined by the fields is_animated and is_video. + Type string `json:"type"` + // Width sticker width + Width int `json:"width"` + // Height sticker height + Height int `json:"height"` + // IsAnimated true, if the sticker is animated + // + // optional + IsAnimated bool `json:"is_animated,omitempty"` + // IsVideo true, if the sticker is a video sticker + // + // optional + IsVideo bool `json:"is_video,omitempty"` + // Thumbnail sticker thumbnail in the .WEBP or .JPG format + // + // optional + Thumbnail *PhotoSize `json:"thumb,omitempty"` + // Emoji associated with the sticker + // + // optional + Emoji string `json:"emoji,omitempty"` + // SetName of the sticker set to which the sticker belongs + // + // optional + SetName string `json:"set_name,omitempty"` + // PremiumAnimation for premium regular stickers, premium animation for the sticker + // + // optional + PremiumAnimation *File `json:"premium_animation,omitempty"` + // MaskPosition is for mask stickers, the position where the mask should be + // placed + // + // optional + MaskPosition *MaskPosition `json:"mask_position,omitempty"` + // CustomEmojiID for custom emoji stickers, unique identifier of the custom emoji + // + // optional + CustomEmojiID string `json:"custom_emoji_id,omitempty"` + // FileSize + // + // optional + FileSize int `json:"file_size,omitempty"` +} + +// IsRegular returns if the Sticker is regular +func (s Sticker) IsRegular() bool { + return s.Type == StickerTypeRegular +} + +// IsMask returns if the Sticker is mask +func (s Sticker) IsMask() bool { + return s.Type == StickerTypeMask +} + +// IsCustomEmoji returns if the Sticker is custom emoji +func (s Sticker) IsCustomEmoji() bool { + return s.Type == StickerTypeCustomEmoji +} + +// StickerSet represents a sticker set. +type StickerSet struct { + // Name sticker set name + Name string `json:"name"` + // Title sticker set title + Title string `json:"title"` + // StickerType of stickers in the set, currently one of “regular”, “mask”, “custom_emoji” + StickerType string `json:"sticker_type"` + // IsAnimated true, if the sticker set contains animated stickers + IsAnimated bool `json:"is_animated"` + // IsVideo true, if the sticker set contains video stickers + IsVideo bool `json:"is_video"` + // ContainsMasks true, if the sticker set contains masks + // + // deprecated. Use sticker_type instead + ContainsMasks bool `json:"contains_masks"` + // Stickers list of all set stickers + Stickers []Sticker `json:"stickers"` + // Thumb is the sticker set thumbnail in the .WEBP or .TGS format + Thumbnail *PhotoSize `json:"thumb"` +} + +// IsRegular returns if the StickerSet is regular +func (s StickerSet) IsRegular() bool { + return s.StickerType == StickerTypeRegular +} + +// IsMask returns if the StickerSet is mask +func (s StickerSet) IsMask() bool { + return s.StickerType == StickerTypeMask +} + +// IsCustomEmoji returns if the StickerSet is custom emoji +func (s StickerSet) IsCustomEmoji() bool { + return s.StickerType == StickerTypeCustomEmoji +} + +// MaskPosition describes the position on faces where a mask should be placed +// by default. +type MaskPosition struct { + // The part of the face relative to which the mask should be placed. + // One of “forehead”, “eyes”, “mouth”, or “chin”. + Point string `json:"point"` + // Shift by X-axis measured in widths of the mask scaled to the face size, + // from left to right. For example, choosing -1.0 will place mask just to + // the left of the default mask position. + XShift float64 `json:"x_shift"` + // Shift by Y-axis measured in heights of the mask scaled to the face size, + // from top to bottom. For example, 1.0 will place the mask just below the + // default mask position. + YShift float64 `json:"y_shift"` + // Mask scaling coefficient. For example, 2.0 means double size. + Scale float64 `json:"scale"` +} + +// Game represents a game. Use BotFather to create and edit games, their short +// names will act as unique identifiers. +type Game struct { + // Title of the game + Title string `json:"title"` + // Description of the game + Description string `json:"description"` + // Photo that will be displayed in the game message in chats. + Photo []PhotoSize `json:"photo"` + // Text a brief description of the game or high scores included in the game message. + // Can be automatically edited to include current high scores for the game + // when the bot calls setGameScore, or manually edited using editMessageText. 0-4096 characters. + // + // optional + Text string `json:"text,omitempty"` + // TextEntities special entities that appear in text, such as usernames, URLs, bot commands, etc. + // + // optional + TextEntities []MessageEntity `json:"text_entities,omitempty"` + // Animation is an animation that will be displayed in the game message in chats. + // Upload via BotFather (https://t.me/botfather). + // + // optional + Animation Animation `json:"animation,omitempty"` +} + +// GameHighScore is a user's score and position on the leaderboard. +type GameHighScore struct { + // Position in high score table for the game + Position int `json:"position"` + // User user + User User `json:"user"` + // Score score + Score int `json:"score"` +} + +// CallbackGame is for starting a game in an inline keyboard button. +type CallbackGame struct{} + +// WebhookInfo is information about a currently set webhook. +type WebhookInfo struct { + // URL webhook URL, may be empty if webhook is not set up. + URL string `json:"url"` + // HasCustomCertificate true, if a custom certificate was provided for webhook certificate checks. + HasCustomCertificate bool `json:"has_custom_certificate"` + // PendingUpdateCount number of updates awaiting delivery. + PendingUpdateCount int `json:"pending_update_count"` + // IPAddress is the currently used webhook IP address + // + // optional + IPAddress string `json:"ip_address,omitempty"` + // LastErrorDate unix time for the most recent error + // that happened when trying to deliver an update via webhook. + // + // optional + LastErrorDate int `json:"last_error_date,omitempty"` + // LastErrorMessage error message in human-readable format for the most recent error + // that happened when trying to deliver an update via webhook. + // + // optional + LastErrorMessage string `json:"last_error_message,omitempty"` + // LastSynchronizationErrorDate is the unix time of the most recent error that + // happened when trying to synchronize available updates with Telegram datacenters. + LastSynchronizationErrorDate int `json:"last_synchronization_error_date,omitempty"` + // MaxConnections maximum allowed number of simultaneous + // HTTPS connections to the webhook for update delivery. + // + // optional + MaxConnections int `json:"max_connections,omitempty"` + // AllowedUpdates is a list of update types the bot is subscribed to. + // Defaults to all update types + // + // optional + AllowedUpdates []string `json:"allowed_updates,omitempty"` +} + +// IsSet returns true if a webhook is currently set. +func (info WebhookInfo) IsSet() bool { + return info.URL != "" +} + +// InlineQuery is a Query from Telegram for an inline request. +type InlineQuery struct { + // ID unique identifier for this query + ID string `json:"id"` + // From sender + From *User `json:"from"` + // Query text of the query (up to 256 characters). + Query string `json:"query"` + // Offset of the results to be returned, can be controlled by the bot. + Offset string `json:"offset"` + // Type of the chat, from which the inline query was sent. Can be either + // “sender” for a private chat with the inline query sender, “private”, + // “group”, “supergroup”, or “channel”. The chat type should be always known + // for requests sent from official clients and most third-party clients, + // unless the request was sent from a secret chat + // + // optional + ChatType string `json:"chat_type,omitempty"` + // Location sender location, only for bots that request user location. + // + // optional + Location *Location `json:"location,omitempty"` +} + +// InlineQueryResultCachedAudio is an inline query response with cached audio. +type InlineQueryResultCachedAudio struct { + // Type of the result, must be audio + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // AudioID a valid file identifier for the audio file + AudioID string `json:"audio_file_id"` + // Caption 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the audio + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedDocument is an inline query response with cached document. +type InlineQueryResultCachedDocument struct { + // Type of the result, must be a document + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // DocumentID a valid file identifier for the file + DocumentID string `json:"document_file_id"` + // Title for the result + // + // optional + Title string `json:"title,omitempty"` + // Caption of the document to be sent, 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // Description short description of the result + // + // optional + Description string `json:"description,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // // See formatting options for more details + // // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the file + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedGIF is an inline query response with cached gif. +type InlineQueryResultCachedGIF struct { + // Type of the result, must be gif. + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes. + ID string `json:"id"` + // GifID a valid file identifier for the GIF file. + GIFID string `json:"gif_file_id"` + // Title for the result + // + // optional + Title string `json:"title,omitempty"` + // Caption of the GIF file to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message. + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the GIF animation. + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedMPEG4GIF is an inline query response with cached +// H.264/MPEG-4 AVC video without sound gif. +type InlineQueryResultCachedMPEG4GIF struct { + // Type of the result, must be mpeg4_gif + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // MPEG4FileID a valid file identifier for the MP4 file + MPEG4FileID string `json:"mpeg4_file_id"` + // Title for the result + // + // optional + Title string `json:"title,omitempty"` + // Caption of the MPEG-4 file to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message. + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the video animation. + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedPhoto is an inline query response with cached photo. +type InlineQueryResultCachedPhoto struct { + // Type of the result, must be a photo. + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes. + ID string `json:"id"` + // PhotoID a valid file identifier of the photo. + PhotoID string `json:"photo_file_id"` + // Title for the result. + // + // optional + Title string `json:"title,omitempty"` + // Description short description of the result. + // + // optional + Description string `json:"description,omitempty"` + // Caption of the photo to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the photo caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message. + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the photo. + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedSticker is an inline query response with cached sticker. +type InlineQueryResultCachedSticker struct { + // Type of the result, must be a sticker + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // StickerID a valid file identifier of the sticker + StickerID string `json:"sticker_file_id"` + // Title is a title + Title string `json:"title"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the sticker + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedVideo is an inline query response with cached video. +type InlineQueryResultCachedVideo struct { + // Type of the result, must be video + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // VideoID a valid file identifier for the video file + VideoID string `json:"video_file_id"` + // Title for the result + Title string `json:"title"` + // Description short description of the result + // + // optional + Description string `json:"description,omitempty"` + // Caption of the video to be sent, 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the video + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultCachedVoice is an inline query response with cached voice. +type InlineQueryResultCachedVoice struct { + // Type of the result, must be voice + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // VoiceID a valid file identifier for the voice message + VoiceID string `json:"voice_file_id"` + // Title voice message title + Title string `json:"title"` + // Caption 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the voice message + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultArticle represents a link to an article or web page. +type InlineQueryResultArticle struct { + // Type of the result, must be article. + Type string `json:"type"` + // ID unique identifier for this result, 1-64 Bytes. + ID string `json:"id"` + // Title of the result + Title string `json:"title"` + // InputMessageContent content of the message to be sent. + InputMessageContent interface{} `json:"input_message_content,omitempty"` + // ReplyMarkup Inline keyboard attached to the message. + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // URL of the result. + // + // optional + URL string `json:"url,omitempty"` + // HideURL pass True, if you don't want the URL to be shown in the message. + // + // optional + HideURL bool `json:"hide_url,omitempty"` + // Description short description of the result. + // + // optional + Description string `json:"description,omitempty"` + // ThumbURL url of the thumbnail for the result + // + // optional + ThumbURL string `json:"thumb_url,omitempty"` + // ThumbWidth thumbnail width + // + // optional + ThumbWidth int `json:"thumb_width,omitempty"` + // ThumbHeight thumbnail height + // + // optional + ThumbHeight int `json:"thumb_height,omitempty"` +} + +// InlineQueryResultAudio is an inline query response audio. +type InlineQueryResultAudio struct { + // Type of the result, must be audio + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // URL a valid url for the audio file + URL string `json:"audio_url"` + // Title is a title + Title string `json:"title"` + // Caption 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // Performer is a performer + // + // optional + Performer string `json:"performer,omitempty"` + // Duration audio duration in seconds + // + // optional + Duration int `json:"audio_duration,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the audio + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultContact is an inline query response contact. +type InlineQueryResultContact struct { + Type string `json:"type"` // required + ID string `json:"id"` // required + PhoneNumber string `json:"phone_number"` // required + FirstName string `json:"first_name"` // required + LastName string `json:"last_name"` + VCard string `json:"vcard"` + 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 of the result, must be game + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // GameShortName short name of the game + GameShortName string `json:"game_short_name"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// InlineQueryResultDocument is an inline query response document. +type InlineQueryResultDocument struct { + // Type of the result, must be a document + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // Title for the result + Title string `json:"title"` + // Caption of the document to be sent, 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // URL a valid url for the file + URL string `json:"document_url"` + // MimeType of the content of the file, either “application/pdf” or “application/zip” + MimeType string `json:"mime_type"` + // Description short description of the result + // + // optional + Description string `json:"description,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the file + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` + // ThumbURL url of the thumbnail (jpeg only) for the file + // + // optional + ThumbURL string `json:"thumb_url,omitempty"` + // ThumbWidth thumbnail width + // + // optional + ThumbWidth int `json:"thumb_width,omitempty"` + // ThumbHeight thumbnail height + // + // optional + ThumbHeight int `json:"thumb_height,omitempty"` +} + +// InlineQueryResultGIF is an inline query response GIF. +type InlineQueryResultGIF struct { + // Type of the result, must be gif. + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes. + ID string `json:"id"` + // URL a valid URL for the GIF file. File size must not exceed 1MB. + URL string `json:"gif_url"` + // ThumbURL url of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result. + ThumbURL string `json:"thumb_url"` + // Width of the GIF + // + // optional + Width int `json:"gif_width,omitempty"` + // Height of the GIF + // + // optional + Height int `json:"gif_height,omitempty"` + // Duration of the GIF + // + // optional + Duration int `json:"gif_duration,omitempty"` + // Title for the result + // + // optional + Title string `json:"title,omitempty"` + // Caption of the GIF file to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the GIF animation. + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultLocation is an inline query response location. +type InlineQueryResultLocation struct { + // Type of the result, must be location + Type string `json:"type"` + // ID unique identifier for this result, 1-64 Bytes + ID string `json:"id"` + // Latitude of the location in degrees + Latitude float64 `json:"latitude"` + // Longitude of the location in degrees + Longitude float64 `json:"longitude"` + // Title of the location + Title string `json:"title"` + // HorizontalAccuracy is the radius of uncertainty for the location, + // measured in meters; 0-1500 + // + // optional + HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` + // LivePeriod is the period in seconds for which the location can be + // updated, should be between 60 and 86400. + // + // optional + LivePeriod int `json:"live_period,omitempty"` + // Heading is for live locations, a direction in which the user is moving, + // in degrees. Must be between 1 and 360 if specified. + // + // optional + Heading int `json:"heading,omitempty"` + // ProximityAlertRadius is for live locations, a maximum distance for + // proximity alerts about approaching another chat member, in meters. Must + // be between 1 and 100000 if specified. + // + // optional + ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the location + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` + // ThumbURL url of the thumbnail for the result + // + // optional + ThumbURL string `json:"thumb_url,omitempty"` + // ThumbWidth thumbnail width + // + // optional + ThumbWidth int `json:"thumb_width,omitempty"` + // ThumbHeight thumbnail height + // + // optional + ThumbHeight int `json:"thumb_height,omitempty"` +} + +// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF. +type InlineQueryResultMPEG4GIF struct { + // Type of the result, must be mpeg4_gif + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // URL a valid URL for the MP4 file. File size must not exceed 1MB + URL string `json:"mpeg4_url"` + // Width video width + // + // optional + Width int `json:"mpeg4_width,omitempty"` + // Height vVideo height + // + // optional + Height int `json:"mpeg4_height,omitempty"` + // Duration video duration + // + // optional + Duration int `json:"mpeg4_duration,omitempty"` + // ThumbURL url of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result. + ThumbURL string `json:"thumb_url"` + // Title for the result + // + // optional + Title string `json:"title,omitempty"` + // Caption of the MPEG-4 file to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the video animation + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultPhoto is an inline query response photo. +type InlineQueryResultPhoto struct { + // Type of the result, must be article. + Type string `json:"type"` + // ID unique identifier for this result, 1-64 Bytes. + ID string `json:"id"` + // URL a valid URL of the photo. Photo must be in jpeg format. + // Photo size must not exceed 5MB. + URL string `json:"photo_url"` + // MimeType + MimeType string `json:"mime_type"` + // Width of the photo + // + // optional + Width int `json:"photo_width,omitempty"` + // Height of the photo + // + // optional + Height int `json:"photo_height,omitempty"` + // ThumbURL url of the thumbnail for the photo. + // + // optional + ThumbURL string `json:"thumb_url,omitempty"` + // Title for the result + // + // optional + Title string `json:"title,omitempty"` + // Description short description of the result + // + // optional + Description string `json:"description,omitempty"` + // Caption of the photo to be sent, 0-1024 characters after entities parsing. + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the photo caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // ReplyMarkup inline keyboard attached to the message. + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // InputMessageContent content of the message to be sent instead of the photo. + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultVenue is an inline query response venue. +type InlineQueryResultVenue struct { + // Type of the result, must be venue + Type string `json:"type"` + // ID unique identifier for this result, 1-64 Bytes + ID string `json:"id"` + // Latitude of the venue location in degrees + Latitude float64 `json:"latitude"` + // Longitude of the venue location in degrees + Longitude float64 `json:"longitude"` + // Title of the venue + Title string `json:"title"` + // Address of the venue + Address string `json:"address"` + // FoursquareID foursquare identifier of the venue if known + // + // optional + FoursquareID string `json:"foursquare_id,omitempty"` + // FoursquareType foursquare type of the venue, if known. + // (For example, “arts_entertainment/default”, “arts_entertainment/aquarium” or “food/icecream”.) + // + // optional + FoursquareType string `json:"foursquare_type,omitempty"` + // GooglePlaceID is the Google Places identifier of the venue + // + // optional + GooglePlaceID string `json:"google_place_id,omitempty"` + // GooglePlaceType is the Google Places type of the venue + // + // optional + GooglePlaceType string `json:"google_place_type,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the venue + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` + // ThumbURL url of the thumbnail for the result + // + // optional + ThumbURL string `json:"thumb_url,omitempty"` + // ThumbWidth thumbnail width + // + // optional + ThumbWidth int `json:"thumb_width,omitempty"` + // ThumbHeight thumbnail height + // + // optional + ThumbHeight int `json:"thumb_height,omitempty"` +} + +// InlineQueryResultVideo is an inline query response video. +type InlineQueryResultVideo struct { + // Type of the result, must be video + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // URL a valid url for the embedded video player or video file + URL string `json:"video_url"` + // MimeType of the content of video url, “text/html” or “video/mp4” + MimeType string `json:"mime_type"` + // + // ThumbURL url of the thumbnail (jpeg only) for the video + // optional + ThumbURL string `json:"thumb_url,omitempty"` + // Title for the result + Title string `json:"title"` + // Caption of the video to be sent, 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // Width video width + // + // optional + Width int `json:"video_width,omitempty"` + // Height video height + // + // optional + Height int `json:"video_height,omitempty"` + // Duration video duration in seconds + // + // optional + Duration int `json:"video_duration,omitempty"` + // Description short description of the result + // + // optional + Description string `json:"description,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the video. + // This field is required if InlineQueryResultVideo is used to send + // an HTML-page as a result (e.g., a YouTube video). + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// InlineQueryResultVoice is an inline query response voice. +type InlineQueryResultVoice struct { + // Type of the result, must be voice + Type string `json:"type"` + // ID unique identifier for this result, 1-64 bytes + ID string `json:"id"` + // URL a valid URL for the voice recording + URL string `json:"voice_url"` + // Title recording title + Title string `json:"title"` + // Caption 0-1024 characters after entities parsing + // + // optional + Caption string `json:"caption,omitempty"` + // ParseMode mode for parsing entities in the video caption. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // CaptionEntities is a list of special entities that appear in the caption, + // which can be specified instead of parse_mode + // + // optional + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // Duration recording duration in seconds + // + // optional + Duration int `json:"voice_duration,omitempty"` + // ReplyMarkup inline keyboard attached to the message + // + // optional + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + // InputMessageContent content of the message to be sent instead of the voice recording + // + // optional + InputMessageContent interface{} `json:"input_message_content,omitempty"` +} + +// ChosenInlineResult is an inline query result chosen by a User +type ChosenInlineResult struct { + // ResultID the unique identifier for the result that was chosen + ResultID string `json:"result_id"` + // From the user that chose the result + From *User `json:"from"` + // Location sender location, only for bots that require user location + // + // optional + Location *Location `json:"location,omitempty"` + // InlineMessageID identifier of the sent inline message. + // Available only if there is an inline keyboard attached to the message. + // Will be also received in callback queries and can be used to edit the message. + // + // optional + InlineMessageID string `json:"inline_message_id,omitempty"` + // Query the query that was used to obtain the result + Query string `json:"query"` +} + +// SentWebAppMessage contains information about an inline message sent by a Web App +// on behalf of a user. +type SentWebAppMessage struct { + // Identifier of the sent inline message. Available only if there is an inline + // keyboard attached to the message. + // + // optional + InlineMessageID string `json:"inline_message_id,omitempty"` +} + +// InputTextMessageContent contains text for displaying +// as an inline query result. +type InputTextMessageContent struct { + // Text of the message to be sent, 1-4096 characters + Text string `json:"message_text"` + // ParseMode mode for parsing entities in the message text. + // See formatting options for more details + // (https://core.telegram.org/bots/api#formatting-options). + // + // optional + ParseMode string `json:"parse_mode,omitempty"` + // Entities is a list of special entities that appear in message text, which + // can be specified instead of parse_mode + // + // optional + Entities []MessageEntity `json:"entities,omitempty"` + // DisableWebPagePreview disables link previews for links in the sent message + // + // optional + DisableWebPagePreview bool `json:"disable_web_page_preview,omitempty"` +} + +// InputLocationMessageContent contains a location for displaying +// as an inline query result. +type InputLocationMessageContent struct { + // Latitude of the location in degrees + Latitude float64 `json:"latitude"` + // Longitude of the location in degrees + Longitude float64 `json:"longitude"` + // HorizontalAccuracy is the radius of uncertainty for the location, + // measured in meters; 0-1500 + // + // optional + HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` + // LivePeriod is the period in seconds for which the location can be + // updated, should be between 60 and 86400 + // + // optional + LivePeriod int `json:"live_period,omitempty"` + // Heading is for live locations, a direction in which the user is moving, + // in degrees. Must be between 1 and 360 if specified. + // + // optional + Heading int `json:"heading,omitempty"` + // ProximityAlertRadius is for live locations, a maximum distance for + // proximity alerts about approaching another chat member, in meters. Must + // be between 1 and 100000 if specified. + // + // optional + ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` +} + +// InputVenueMessageContent contains a venue for displaying +// as an inline query result. +type InputVenueMessageContent struct { + // Latitude of the venue in degrees + Latitude float64 `json:"latitude"` + // Longitude of the venue in degrees + Longitude float64 `json:"longitude"` + // Title name of the venue + Title string `json:"title"` + // Address of the venue + Address string `json:"address"` + // FoursquareID foursquare identifier of the venue, if known + // + // optional + FoursquareID string `json:"foursquare_id,omitempty"` + // FoursquareType Foursquare type of the venue, if known + // + // optional + FoursquareType string `json:"foursquare_type,omitempty"` + // GooglePlaceID is the Google Places identifier of the venue + // + // optional + GooglePlaceID string `json:"google_place_id,omitempty"` + // GooglePlaceType is the Google Places type of the venue + // + // optional + GooglePlaceType string `json:"google_place_type,omitempty"` +} + +// InputContactMessageContent contains a contact for displaying +// as an inline query result. +type InputContactMessageContent struct { + // PhoneNumber contact's phone number + PhoneNumber string `json:"phone_number"` + // FirstName contact's first name + FirstName string `json:"first_name"` + // LastName contact's last name + // + // optional + LastName string `json:"last_name,omitempty"` + // Additional data about the contact in the form of a vCard + // + // optional + VCard string `json:"vcard,omitempty"` +} + +// InputInvoiceMessageContent represents the content of an invoice message to be +// sent as the result of an inline query. +type InputInvoiceMessageContent struct { + // Product name, 1-32 characters + Title string `json:"title"` + // Product description, 1-255 characters + Description string `json:"description"` + // Bot-defined invoice payload, 1-128 bytes. This will not be displayed to + // the user, use for your internal processes. + Payload string `json:"payload"` + // Payment provider token, obtained via Botfather + ProviderToken string `json:"provider_token"` + // Three-letter ISO 4217 currency code + Currency string `json:"currency"` + // Price breakdown, a JSON-serialized list of components (e.g. product + // price, tax, discount, delivery cost, delivery tax, bonus, etc.) + Prices []LabeledPrice `json:"prices"` + // The maximum accepted amount for tips in the smallest units of the + // currency (integer, not float/double). + // + // optional + MaxTipAmount int `json:"max_tip_amount,omitempty"` + // An array of suggested amounts of tip in the smallest units of the + // currency (integer, not float/double). At most 4 suggested tip amounts can + // be specified. The suggested tip amounts must be positive, passed in a + // strictly increased order and must not exceed max_tip_amount. + // + // optional + SuggestedTipAmounts []int `json:"suggested_tip_amounts,omitempty"` + // A JSON-serialized object for data about the invoice, which will be shared + // with the payment provider. A detailed description of the required fields + // should be provided by the payment provider. + // + // optional + ProviderData string `json:"provider_data,omitempty"` + // URL of the product photo for the invoice. Can be a photo of the goods or + // a marketing image for a service. People like it better when they see what + // they are paying for. + // + // optional + PhotoURL string `json:"photo_url,omitempty"` + // Photo size + // + // optional + PhotoSize int `json:"photo_size,omitempty"` + // Photo width + // + // optional + PhotoWidth int `json:"photo_width,omitempty"` + // Photo height + // + // optional + PhotoHeight int `json:"photo_height,omitempty"` + // Pass True, if you require the user's full name to complete the order + // + // optional + NeedName bool `json:"need_name,omitempty"` + // Pass True, if you require the user's phone number to complete the order + // + // optional + NeedPhoneNumber bool `json:"need_phone_number,omitempty"` + // Pass True, if you require the user's email address to complete the order + // + // optional + NeedEmail bool `json:"need_email,omitempty"` + // Pass True, if you require the user's shipping address to complete the order + // + // optional + NeedShippingAddress bool `json:"need_shipping_address,omitempty"` + // Pass True, if user's phone number should be sent to provider + // + // optional + SendPhoneNumberToProvider bool `json:"send_phone_number_to_provider,omitempty"` + // Pass True, if user's email address should be sent to provider + // + // optional + SendEmailToProvider bool `json:"send_email_to_provider,omitempty"` + // Pass True, if the final price depends on the shipping method + // + // optional + IsFlexible bool `json:"is_flexible,omitempty"` +} + +// LabeledPrice represents a portion of the price for goods or services. +type LabeledPrice struct { + // Label portion label + Label string `json:"label"` + // Amount price of the product in the smallest units of the currency (integer, not float/double). + // For example, for a price of US$ 1.45 pass amount = 145. + // See the exp parameter in currencies.json + // (https://core.telegram.org/bots/payments/currencies.json), + // it shows the number of digits past the decimal point + // for each currency (2 for the majority of currencies). + Amount int `json:"amount"` +} + +// Invoice contains basic information about an invoice. +type Invoice struct { + // Title product name + Title string `json:"title"` + // Description product description + Description string `json:"description"` + // StartParameter unique bot deep-linking parameter that can be used to generate this invoice + StartParameter string `json:"start_parameter"` + // Currency three-letter ISO 4217 currency code + // (see https://core.telegram.org/bots/payments#supported-currencies) + Currency string `json:"currency"` + // TotalAmount total price in the smallest units of the currency (integer, not float/double). + // For example, for a price of US$ 1.45 pass amount = 145. + // See the exp parameter in currencies.json + // (https://core.telegram.org/bots/payments/currencies.json), + // it shows the number of digits past the decimal point + // for each currency (2 for the majority of currencies). + TotalAmount int `json:"total_amount"` +} + +// ShippingAddress represents a shipping address. +type ShippingAddress struct { + // CountryCode ISO 3166-1 alpha-2 country code + CountryCode string `json:"country_code"` + // State if applicable + State string `json:"state"` + // City city + City string `json:"city"` + // StreetLine1 first line for the address + StreetLine1 string `json:"street_line1"` + // StreetLine2 second line for the address + StreetLine2 string `json:"street_line2"` + // PostCode address post code + PostCode string `json:"post_code"` +} + +// OrderInfo represents information about an order. +type OrderInfo struct { + // Name user name + // + // optional + Name string `json:"name,omitempty"` + // PhoneNumber user's phone number + // + // optional + PhoneNumber string `json:"phone_number,omitempty"` + // Email user email + // + // optional + Email string `json:"email,omitempty"` + // ShippingAddress user shipping address + // + // optional + ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` +} + +// ShippingOption represents one shipping option. +type ShippingOption struct { + // ID shipping option identifier + ID string `json:"id"` + // Title option title + Title string `json:"title"` + // Prices list of price portions + Prices []LabeledPrice `json:"prices"` +} + +// SuccessfulPayment contains basic information about a successful payment. +type SuccessfulPayment struct { + // Currency three-letter ISO 4217 currency code + // (see https://core.telegram.org/bots/payments#supported-currencies) + Currency string `json:"currency"` + // TotalAmount total price in the smallest units of the currency (integer, not float/double). + // For example, for a price of US$ 1.45 pass amount = 145. + // See the exp parameter in currencies.json, + // (https://core.telegram.org/bots/payments/currencies.json) + // it shows the number of digits past the decimal point + // for each currency (2 for the majority of currencies). + TotalAmount int `json:"total_amount"` + // InvoicePayload bot specified invoice payload + InvoicePayload string `json:"invoice_payload"` + // ShippingOptionID identifier of the shipping option chosen by the user + // + // optional + ShippingOptionID string `json:"shipping_option_id,omitempty"` + // OrderInfo order info provided by the user + // + // optional + OrderInfo *OrderInfo `json:"order_info,omitempty"` + // TelegramPaymentChargeID telegram payment identifier + TelegramPaymentChargeID string `json:"telegram_payment_charge_id"` + // ProviderPaymentChargeID provider payment identifier + ProviderPaymentChargeID string `json:"provider_payment_charge_id"` +} + +// ShippingQuery contains information about an incoming shipping query. +type ShippingQuery struct { + // ID unique query identifier + ID string `json:"id"` + // From user who sent the query + From *User `json:"from"` + // InvoicePayload bot specified invoice payload + InvoicePayload string `json:"invoice_payload"` + // ShippingAddress user specified shipping address + ShippingAddress *ShippingAddress `json:"shipping_address"` +} + +// PreCheckoutQuery contains information about an incoming pre-checkout query. +type PreCheckoutQuery struct { + // ID unique query identifier + ID string `json:"id"` + // From user who sent the query + From *User `json:"from"` + // Currency three-letter ISO 4217 currency code + // // (see https://core.telegram.org/bots/payments#supported-currencies) + Currency string `json:"currency"` + // TotalAmount total price in the smallest units of the currency (integer, not float/double). + // // For example, for a price of US$ 1.45 pass amount = 145. + // // See the exp parameter in currencies.json, + // // (https://core.telegram.org/bots/payments/currencies.json) + // // it shows the number of digits past the decimal point + // // for each currency (2 for the majority of currencies). + TotalAmount int `json:"total_amount"` + // InvoicePayload bot specified invoice payload + InvoicePayload string `json:"invoice_payload"` + // ShippingOptionID identifier of the shipping option chosen by the user + // + // optional + ShippingOptionID string `json:"shipping_option_id,omitempty"` + // OrderInfo order info provided by the user + // + // optional + OrderInfo *OrderInfo `json:"order_info,omitempty"` +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1b9fa5bf..2f650c86 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -83,9 +83,6 @@ github.com/fsnotify/fsnotify # github.com/go-asn1-ber/asn1-ber v1.5.3 ## explicit; go 1.13 github.com/go-asn1-ber/asn1-ber -# github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 -## explicit; go 1.16 -github.com/go-telegram-bot-api/telegram-bot-api/v5 # github.com/golang-jwt/jwt v3.2.2+incompatible ## explicit github.com/golang-jwt/jwt @@ -234,6 +231,9 @@ github.com/matterbridge/logrus-prefixed-formatter # github.com/matterbridge/matterclient v0.0.0-20221106190440-8bcf49695e0d ## explicit; go 1.17 github.com/matterbridge/matterclient +# github.com/matterbridge/telegram-bot-api/v6 v6.5.0 +## explicit; go 1.16 +github.com/matterbridge/telegram-bot-api/v6 # github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 ## explicit github.com/mattermost/go-i18n/i18n -- cgit v1.2.3