summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5')
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/.gitignore4
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/LICENSE.txt21
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/README.md121
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml9
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go726
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go2468
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/helpers.go927
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/log.go27
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go97
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/passport.go317
-rw-r--r--vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go3225
11 files changed, 7942 insertions, 0 deletions
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
new file mode 100644
index 00000000..eb7a23b2
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/.gitignore
@@ -0,0 +1,4 @@
+.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
new file mode 100644
index 00000000..b1fef93b
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/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/go-telegram-bot-api/telegram-bot-api/v5/README.md b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/README.md
new file mode 100644
index 00000000..45d3e1db
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/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.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
new file mode 100644
index 00000000..841d5ba6
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/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/go-telegram-bot-api/telegram-bot-api/v5/bot.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
new file mode 100644
index 00000000..c58afec4
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
@@ -0,0 +1,726 @@
+// 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("<", "&lt;", ">", "&gt;", "&", "&amp;")
+ } 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
new file mode 100644
index 00000000..5e43af49
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
@@ -0,0 +1,2468 @@
+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
new file mode 100644
index 00000000..8220e74e
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/helpers.go
@@ -0,0 +1,927 @@
+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
new file mode 100644
index 00000000..18725514
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/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/go-telegram-bot-api/telegram-bot-api/v5/params.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
new file mode 100644
index 00000000..134f85e4
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
@@ -0,0 +1,97 @@
+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
new file mode 100644
index 00000000..4fedb965
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/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/go-telegram-bot-api/telegram-bot-api/v5/types.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go
new file mode 100644
index 00000000..18b4decb
--- /dev/null
+++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go
@@ -0,0 +1,3225 @@
+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=<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:"user"`
+ // 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://<file_attach_name>” to upload a new one
+ // using multipart/form-data under <file_attach_name> 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"`
+}