telegram-bot-api/bot.go

788 lines
20 KiB
Go
Raw Permalink Normal View History

// Package tgbotapi has functions and types used for interacting with
// the Telegram Bot API.
package tgbotapi
import (
2015-11-20 11:42:26 +01:00
"encoding/json"
"errors"
"fmt"
2017-10-29 22:03:48 +01:00
"io"
"mime/multipart"
"net/http"
2015-11-20 11:42:26 +01:00
"net/url"
2015-11-21 14:33:58 +01:00
"strings"
2015-11-21 15:39:19 +01:00
"time"
)
2020-11-06 05:29:48 +01:00
// 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:"-"`
2020-11-06 05:29:48 +01:00
Client HTTPClient `json:"-"`
shutdownChannel chan interface{}
2019-05-24 12:14:48 +02:00
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.
2020-11-06 05:29:48 +01:00
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) {
bot := &BotAPI{
2019-05-24 12:14:48 +02:00
Token: token,
Client: client,
Buffer: 100,
shutdownChannel: make(chan interface{}),
2019-05-24 12:14:48 +02:00
apiEndpoint: apiEndpoint,
}
2015-06-26 06:44:14 +02:00
self, err := bot.GetMe()
if err != nil {
return nil, err
2015-06-26 06:44:14 +02:00
}
bot.Self = self
2015-06-26 06:45:56 +02:00
return bot, nil
}
2015-11-20 11:42:26 +01:00
2020-03-30 22:35:53 +02:00
// SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance.
func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
bot.apiEndpoint = apiEndpoint
2019-05-24 12:14:48 +02:00
}
2021-08-20 22:08:34 +02:00
func buildParams(in Params) url.Values {
if in == nil {
return url.Values{}
}
2021-08-20 22:08:34 +02:00
out := url.Values{}
for key, value := range in {
out.Set(key, value)
}
2021-08-20 22:08:34 +02:00
return out
}
2015-11-20 11:42:26 +01:00
// 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)
}
2019-05-24 12:14:48 +02:00
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
values := buildParams(params)
2021-08-20 22:08:34 +02:00
req, err := http.NewRequest("POST", method, strings.NewReader(values.Encode()))
if err != nil {
2021-08-20 22:08:34 +02:00
return &APIResponse{}, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := bot.Client.Do(req)
2015-11-20 11:42:26 +01:00
if err != nil {
return nil, err
2015-11-20 11:42:26 +01:00
}
defer resp.Body.Close()
2017-10-29 22:03:48 +01:00
var apiResp APIResponse
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
if err != nil {
return &apiResp, err
2017-10-29 22:03:48 +01:00
}
2017-10-31 00:34:34 +01:00
2017-10-29 22:03:48 +01:00
if bot.Debug {
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
2017-10-29 22:03:48 +01:00
}
if !apiResp.Ok {
2018-03-26 19:22:16 +02:00
var parameters ResponseParameters
if apiResp.Parameters != nil {
parameters = *apiResp.Parameters
}
2018-03-26 19:22:16 +02:00
return &apiResp, &Error{
2020-02-15 14:08:58 +01:00
Code: apiResp.ErrorCode,
2018-03-26 19:22:16 +02:00
Message: apiResp.Description,
ResponseParameters: parameters,
}
2015-11-20 11:42:26 +01:00
}
return &apiResp, nil
2017-10-29 22:03:48 +01:00
}
2017-11-07 03:17:06 +01:00
// 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) {
2017-10-29 22:03:48 +01:00
if !bot.Debug {
dec := json.NewDecoder(responseBody)
err := dec.Decode(resp)
return nil, err
2015-11-20 11:42:26 +01:00
}
// if debug, read response body
2022-10-19 10:47:42 +02:00
data, err := io.ReadAll(responseBody)
2017-10-29 22:03:48 +01:00
if err != nil {
return nil, err
2017-10-29 22:03:48 +01:00
}
2015-11-20 11:42:26 +01:00
2017-10-29 22:03:48 +01:00
err = json.Unmarshal(data, resp)
if err != nil {
return nil, err
2015-11-20 11:42:26 +01:00
}
2017-10-31 00:34:34 +01:00
return data, nil
2015-11-20 11:42:26 +01:00
}
// 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)
2015-11-20 12:19:37 +01:00
// 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()
2015-11-20 11:42:26 +01:00
for field, value := range params {
if err := m.WriteField(field, value); err != nil {
2020-07-26 06:36:31 +02:00
w.CloseWithError(err)
return
}
2015-11-20 11:42:26 +01:00
}
for _, file := range files {
2021-08-20 21:31:52 +02:00
if file.Data.NeedsUpload() {
name, reader, err := file.Data.UploadData()
if err != nil {
2020-07-26 06:36:31 +02:00
w.CloseWithError(err)
return
}
2021-08-20 21:31:52 +02:00
part, err := m.CreateFormFile(file.Name, name)
if err != nil {
2020-07-26 06:36:31 +02:00
w.CloseWithError(err)
return
}
2021-08-20 21:31:52 +02:00
if _, err := io.Copy(part, reader); err != nil {
2020-07-26 06:36:31 +02:00
w.CloseWithError(err)
return
}
2015-11-20 11:42:26 +01:00
2021-08-20 21:31:52 +02:00
if closer, ok := reader.(io.ReadCloser); ok {
if err = closer.Close(); err != nil {
w.CloseWithError(err)
return
}
}
2021-08-20 21:31:52 +02:00
} else {
value := file.Data.SendData()
2015-11-20 11:42:26 +01:00
2021-08-20 21:31:52 +02:00
if err := m.WriteField(file.Name, value); err != nil {
2020-07-26 06:36:31 +02:00
w.CloseWithError(err)
return
}
}
}
}()
if bot.Debug {
log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files))
2015-11-20 11:42:26 +01:00
}
2019-05-24 12:14:48 +02:00
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
req, err := http.NewRequest("POST", method, r)
2015-11-20 11:42:26 +01:00
if err != nil {
return nil, err
2015-11-20 11:42:26 +01:00
}
req.Header.Set("Content-Type", m.FormDataContentType())
resp, err := bot.Client.Do(req)
2015-11-20 11:42:26 +01:00
if err != nil {
return nil, err
2015-11-20 11:42:26 +01:00
}
defer resp.Body.Close()
2015-11-20 11:42:26 +01:00
var apiResp APIResponse
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
2015-11-20 11:42:26 +01:00
if err != nil {
return &apiResp, err
2015-11-20 11:42:26 +01:00
}
if bot.Debug {
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
}
2015-11-20 11:42:26 +01:00
if !apiResp.Ok {
var parameters ResponseParameters
if apiResp.Parameters != nil {
parameters = *apiResp.Parameters
}
2015-11-20 11:42:26 +01:00
return &apiResp, &Error{
Message: apiResp.Description,
ResponseParameters: parameters,
}
2015-11-20 11:42:26 +01:00
}
return &apiResp, nil
2015-11-20 11:42:26 +01:00
}
2015-11-21 17:43:24 +01:00
// GetFileDirectURL returns direct URL to file
//
// It requires the FileID.
2015-11-21 17:43:24 +01:00
func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) {
file, err := bot.GetFile(FileConfig{fileID})
2015-11-21 14:25:59 +01:00
if err != nil {
return "", err
}
2015-11-21 17:43:24 +01:00
return file.Link(bot.Token), nil
2015-11-21 14:25:59 +01:00
}
2015-11-20 11:42:26 +01:00
// 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.
2015-11-20 11:42:26 +01:00
func (bot *BotAPI) GetMe() (User, error) {
resp, err := bot.MakeRequest("getMe", nil)
if err != nil {
return User{}, err
}
var user User
2017-12-30 04:55:58 +01:00
err = json.Unmarshal(resp.Result, &user)
2015-11-20 11:42:26 +01:00
2017-12-30 04:55:58 +01:00
return user, err
2015-11-20 11:42:26 +01:00
}
// IsMessageToMe returns true if message directed to this bot.
2015-11-21 17:43:24 +01:00
//
// It requires the Message.
2015-11-21 15:39:19 +01:00
func (bot *BotAPI) IsMessageToMe(message Message) bool {
2015-11-21 14:33:58 +01:00
return strings.Contains(message.Text, "@"+bot.Self.UserName)
}
func hasFilesNeedingUpload(files []RequestFile) bool {
for _, file := range files {
2021-08-20 21:31:52 +02:00
if file.Data.NeedsUpload() {
return true
}
2015-11-20 15:55:32 +01:00
}
2015-11-20 11:42:26 +01:00
return false
2015-11-20 12:50:23 +01:00
}
2017-12-29 08:26:54 +01:00
// Request sends a Chattable to Telegram, and returns the APIResponse.
func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) {
params, err := c.params()
2015-11-20 15:08:53 +01:00
if err != nil {
return nil, err
2015-11-20 15:08:53 +01:00
}
if t, ok := c.(Fileable); ok {
files := t.files()
2015-11-20 15:08:53 +01:00
// 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)
}
2015-11-20 15:08:53 +01:00
// 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 {
2021-08-20 21:31:52 +02:00
params[file.Name] = file.Data.SendData()
}
2015-11-20 15:31:01 +01:00
}
return bot.MakeRequest(c.method(), params)
2015-11-20 15:31:01 +01:00
}
2017-12-29 08:26:54 +01:00
// 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)
2015-11-20 15:31:01 +01:00
if err != nil {
return Message{}, err
}
var message Message
2017-12-29 08:26:54 +01:00
err = json.Unmarshal(resp.Result, &message)
2015-11-20 15:31:01 +01:00
2017-12-29 08:26:54 +01:00
return message, err
2015-11-20 15:31:01 +01:00
}
2018-12-25 22:44:01 +01:00
// SendMediaGroup sends a media group and returns the resulting messages.
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
resp, err := bot.Request(config)
2015-11-20 12:06:51 +01:00
if err != nil {
2018-12-25 22:44:01 +01:00
return nil, err
2015-11-20 11:42:26 +01:00
}
2018-12-25 22:44:01 +01:00
var messages []Message
err = json.Unmarshal(resp.Result, &messages)
2015-11-20 11:42:26 +01:00
2018-12-25 22:44:01 +01:00
return messages, err
2015-11-20 15:08:53 +01:00
}
2015-11-20 11:42:26 +01:00
// GetUserProfilePhotos gets a user's profile photos.
//
// It requires UserID.
2015-11-20 11:42:26 +01:00
// Offset and Limit are optional.
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
resp, err := bot.Request(config)
2015-11-20 11:42:26 +01:00
if err != nil {
return UserProfilePhotos{}, err
}
var profilePhotos UserProfilePhotos
2017-12-30 04:55:58 +01:00
err = json.Unmarshal(resp.Result, &profilePhotos)
2015-11-20 11:42:26 +01:00
2017-12-30 04:55:58 +01:00
return profilePhotos, err
2015-11-20 11:42:26 +01:00
}
// GetFile returns a File which can download a file from Telegram.
2015-11-20 11:42:26 +01:00
//
// Requires FileID.
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
resp, err := bot.Request(config)
2015-11-20 11:42:26 +01:00
if err != nil {
return File{}, err
}
var file File
2017-12-30 04:55:58 +01:00
err = json.Unmarshal(resp.Result, &file)
2015-11-20 11:42:26 +01:00
2017-12-30 04:55:58 +01:00
return file, err
2015-11-20 11:42:26 +01:00
}
// GetUpdates fetches updates.
// If a WebHook is set, this will not return any data!
//
2021-03-09 21:52:22 +01:00
// 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.
2015-11-20 11:42:26 +01:00
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
resp, err := bot.Request(config)
2015-11-20 11:42:26 +01:00
if err != nil {
return []Update{}, err
}
var updates []Update
2017-12-30 04:55:58 +01:00
err = json.Unmarshal(resp.Result, &updates)
2015-11-20 11:42:26 +01:00
2017-12-30 04:55:58 +01:00
return updates, err
2015-11-20 11:42:26 +01:00
}
// 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
}
2015-11-21 17:43:24 +01:00
// GetUpdatesChan starts and returns a channel for getting updates.
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
ch := make(chan Update, bot.Buffer)
2015-11-20 11:42:26 +01:00
go func() {
for {
select {
case <-bot.shutdownChannel:
2020-02-22 23:13:34 +01:00
close(ch)
return
default:
}
2019-05-24 12:14:48 +02:00
2015-11-20 11:42:26 +01:00
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
}
2015-11-20 11:42:26 +01:00
}
}
}()
return ch
2015-11-20 11:42:26 +01:00
}
// 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)
}
2015-11-20 11:42:26 +01:00
// ListenForWebhook registers a http handler for a webhook.
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
ch := make(chan Update, bot.Buffer)
2015-11-20 11:42:26 +01:00
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
}
2015-11-20 11:42:26 +01:00
ch <- *update
2015-11-20 11:42:26 +01:00
})
2015-11-21 12:22:08 +01:00
return ch
2015-11-20 11:42:26 +01:00
}
// ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook.
func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel {
ch := make(chan Update, bot.Buffer)
func(w http.ResponseWriter, r *http.Request) {
defer close(ch)
update, err := bot.HandleUpdate(r)
if err != nil {
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(errMsg)
return
}
ch <- *update
}(w, r)
return ch
}
// HandleUpdate parses and returns update received via webhook
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
if r.Method != http.MethodPost {
err := errors.New("wrong HTTP method required POST")
return nil, err
}
var update Update
err := json.NewDecoder(r.Body).Decode(&update)
if err != nil {
return nil, err
}
return &update, nil
}
// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
//
// It doesn't support uploading files.
//
// See https://core.telegram.org/bots/api#making-requests-when-getting-updates
// for details.
func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error {
params, err := c.params()
if err != nil {
return err
2017-07-01 06:34:09 +02:00
}
if t, ok := c.(Fileable); ok {
if hasFilesNeedingUpload(t.files()) {
2020-03-30 22:35:53 +02:00
return errors.New("unable to use http response to upload files")
}
2016-05-22 17:16:28 +02:00
}
values := buildParams(params)
values.Set("method", c.method())
2016-05-22 17:16:28 +02:00
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
_, err = w.Write([]byte(values.Encode()))
return err
2016-05-22 17:16:28 +02:00
}
// GetChat gets information about a chat.
2024-05-07 16:32:47 +02:00
func (bot *BotAPI) GetChat(config ChatInfoConfig) (ChatFullInfo, error) {
resp, err := bot.Request(config)
2016-05-22 17:16:28 +02:00
if err != nil {
2024-05-07 16:32:47 +02:00
return ChatFullInfo{}, err
2016-05-22 17:16:28 +02:00
}
2024-05-07 16:32:47 +02:00
var chat ChatFullInfo
2016-05-22 17:16:28 +02:00
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)
2016-05-22 17:16:28 +02:00
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)
2016-05-22 17:16:28 +02:00
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)
2016-05-22 17:16:28 +02:00
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
}
2017-06-02 22:18:42 +02:00
// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (ShippingQuery, error) {
resp, err := bot.Request(config)
if err != nil {
return ShippingQuery{}, err
}
var shippingQuery ShippingQuery
err = json.Unmarshal(resp.Result, &shippingQuery)
return shippingQuery, err
}
// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (PreCheckoutQuery, error) {
resp, err := bot.Request(config)
if err != nil {
return PreCheckoutQuery{}, err
}
var preCheckoutQuery PreCheckoutQuery
err = json.Unmarshal(resp.Result, &preCheckoutQuery)
return preCheckoutQuery, err
}
2017-07-17 19:48:51 +02:00
// GetInviteLink get InviteLink for a chat
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
resp, err := bot.Request(config)
2017-11-09 19:51:50 +01:00
if err != nil {
return "", err
}
2017-07-17 19:48:51 +02:00
var inviteLink string
err = json.Unmarshal(resp.Result, &inviteLink)
2017-07-17 19:48:51 +02:00
return inviteLink, err
2017-07-17 19:48:51 +02:00
}
// GetStickerSet returns a StickerSet.
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
resp, err := bot.Request(config)
if err != nil {
return StickerSet{}, err
}
var stickerSet StickerSet
err = json.Unmarshal(resp.Result, &stickerSet)
return stickerSet, err
}
// GetCustomEmojiStickers returns a slice of Sticker objects.
func (bot *BotAPI) GetCustomEmojiStickers(config GetCustomEmojiStickersConfig) ([]Sticker, error) {
resp, err := bot.Request(config)
if err != nil {
return []Sticker{}, err
}
var stickers []Sticker
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
2017-10-29 22:03:48 +01:00
}
2020-03-30 22:35:53 +02:00
// 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 {
2020-03-30 22:35:53 +02:00
return nil, err
}
2020-03-30 22:35:53 +02:00
var commands []BotCommand
err = json.Unmarshal(resp.Result, &commands)
2020-03-30 22:35:53 +02:00
return commands, err
}
2018-03-05 16:04:37 +01:00
2020-11-06 18:36:00 +01:00
// 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) {
2022-04-16 18:36:59 +02:00
resp, err := bot.Request(config)
2018-03-05 16:12:56 +01:00
if err != nil {
2020-11-06 18:36:00 +01:00
return MessageID{}, err
2018-03-05 16:12:56 +01:00
}
2020-11-06 18:36:00 +01:00
var messageID MessageID
err = json.Unmarshal(resp.Result, &messageID)
2020-09-26 22:55:26 +02:00
2020-11-06 18:36:00 +01:00
return messageID, err
2020-09-26 22:55:26 +02:00
}
2020-10-26 17:41:02 +01:00
2022-04-16 18:36:59 +02:00
// AnswerWebAppQuery sets the result of an interaction with a Web App and send a
// corresponding message on behalf of the user to the chat from which the query originated.
func (bot *BotAPI) AnswerWebAppQuery(config AnswerWebAppQueryConfig) (SentWebAppMessage, error) {
var sentWebAppMessage SentWebAppMessage
resp, err := bot.Request(config)
if err != nil {
return sentWebAppMessage, err
}
err = json.Unmarshal(resp.Result, &sentWebAppMessage)
return sentWebAppMessage, err
}
// GetMyDefaultAdministratorRights gets the current default administrator rights of the bot.
func (bot *BotAPI) GetMyDefaultAdministratorRights(config GetMyDefaultAdministratorRightsConfig) (ChatAdministratorRights, error) {
var rights ChatAdministratorRights
resp, err := bot.Request(config)
if err != nil {
return rights, err
}
err = json.Unmarshal(resp.Result, &rights)
return rights, err
}
2020-10-26 17:41:02 +01:00
// 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.
2020-10-26 17:41:02 +01:00
//
// 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 {
2020-10-26 17:41:02 +01:00
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)
}