diff --git a/README.md b/README.md
index 9325061..02cab2d 100644
--- a/README.md
+++ b/README.md
@@ -62,60 +62,7 @@ func main() {
}
```
-There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki)
-with detailed information on how to do many differen kinds of things.
+There are more examples on the [site](https://go-telegram-bot-api.github.io/)
+with detailed information on how to do many different kinds of things.
It's a great place to get started on using keyboards, commands, or other
kinds of reply markup.
-
-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"
-)
-
-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)
-
- _, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
- if err != nil {
- log.Fatal(err)
- }
- info, err := bot.GetWebhookInfo()
- if err != nil {
- log.Fatal(err)
- }
- if info.LastErrorDate != 0 {
- log.Printf("Telegram callback failed: %s", info.LastErrorMessage)
- }
- 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 certficate, 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/bot.go b/bot.go
index 85e16c1..e635e64 100644
--- a/bot.go
+++ b/bot.go
@@ -12,7 +12,6 @@ import (
"net/http"
"net/url"
"os"
- "strconv"
"strings"
"time"
@@ -25,8 +24,8 @@ type BotAPI struct {
Debug bool `json:"debug"`
Buffer int `json:"buffer"`
- Self User `json:"-"`
- Client *http.Client `json:"-"`
+ Self User `json:"-"`
+ Client *http.Client `json:"-"`
shutdownChannel chan interface{}
}
@@ -43,9 +42,9 @@ func NewBotAPI(token string) (*BotAPI, error) {
// It requires a token, provided by @BotFather on Telegram.
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
bot := &BotAPI{
- Token: token,
- Client: client,
- Buffer: 100,
+ Token: token,
+ Client: client,
+ Buffer: 100,
shutdownChannel: make(chan interface{}),
}
@@ -59,11 +58,31 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
return bot, nil
}
+func buildParams(in Params) (out url.Values) {
+ if in == nil {
+ return url.Values{}
+ }
+
+ out = url.Values{}
+
+ for key, value := range in {
+ out.Set(key, value)
+ }
+
+ return
+}
+
// MakeRequest makes a request to a specific endpoint with our token.
-func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
+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(APIEndpoint, bot.Token, endpoint)
- resp, err := bot.Client.PostForm(method, params)
+ values := buildParams(params)
+
+ resp, err := bot.Client.PostForm(method, values)
if err != nil {
return APIResponse{}, err
}
@@ -76,15 +95,20 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse,
}
if bot.Debug {
- log.Printf("%s resp: %s", endpoint, bytes)
+ log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
}
if !apiResp.Ok {
- parameters := ResponseParameters{}
+ var parameters ResponseParameters
+
if apiResp.Parameters != nil {
parameters = *apiResp.Parameters
}
- return apiResp, Error{apiResp.Description, parameters}
+
+ return apiResp, Error{
+ Message: apiResp.Description,
+ ResponseParameters: parameters,
+ }
}
return apiResp, nil
@@ -114,21 +138,6 @@ func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse)
return data, nil
}
-// makeMessageRequest makes a request to a method that returns a Message.
-func (bot *BotAPI) makeMessageRequest(endpoint string, params url.Values) (Message, error) {
- resp, err := bot.MakeRequest(endpoint, params)
- if err != nil {
- return Message{}, err
- }
-
- var message Message
- json.Unmarshal(resp.Result, &message)
-
- bot.debugLog(endpoint, params, message)
-
- return message, nil
-}
-
// UploadFile makes a request to the API with a file.
//
// Requires the parameter to hold the file not be in the params.
@@ -137,7 +146,7 @@ func (bot *BotAPI) makeMessageRequest(endpoint string, params url.Values) (Messa
//
// Note that if your FileReader has a size set to -1, it will read
// the file into memory to calculate a size.
-func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, file interface{}) (APIResponse, error) {
+func (bot *BotAPI) UploadFile(endpoint string, params Params, fieldname string, file interface{}) (APIResponse, error) {
ms := multipartstreamer.New()
switch f := file.(type) {
@@ -186,6 +195,10 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
return APIResponse{}, errors.New(ErrBadFileType)
}
+ if bot.Debug {
+ log.Printf("Endpoint: %s, fieldname: %s, params: %v, file: %T\n", endpoint, fieldname, params, file)
+ }
+
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint)
req, err := http.NewRequest("POST", method, nil)
@@ -207,7 +220,7 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
}
if bot.Debug {
- log.Println(string(bytes))
+ log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
}
var apiResp APIResponse
@@ -249,11 +262,9 @@ func (bot *BotAPI) GetMe() (User, error) {
}
var user User
- json.Unmarshal(resp.Result, &user)
-
- bot.debugLog("getMe", nil, user)
+ err = json.Unmarshal(resp.Result, &user)
- return user, nil
+ return user, err
}
// IsMessageToMe returns true if message directed to this bot.
@@ -263,90 +274,52 @@ func (bot *BotAPI) IsMessageToMe(message Message) bool {
return strings.Contains(message.Text, "@"+bot.Self.UserName)
}
-// Send will send a Chattable item to Telegram.
-//
-// It requires the Chattable to send.
-func (bot *BotAPI) Send(c Chattable) (Message, error) {
- switch c.(type) {
- case Fileable:
- return bot.sendFile(c.(Fileable))
- default:
- return bot.sendChattable(c)
- }
-}
-
-// debugLog checks if the bot is currently running in debug mode, and if
-// so will display information about the request and response in the
-// debug log.
-func (bot *BotAPI) debugLog(context string, v url.Values, message interface{}) {
- if bot.Debug {
- log.Printf("%s req : %+v\n", context, v)
- log.Printf("%s resp: %+v\n", context, message)
- }
-}
-
-// sendExisting will send a Message with an existing file to Telegram.
-func (bot *BotAPI) sendExisting(method string, config Fileable) (Message, error) {
- v, err := config.values()
-
+// 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 Message{}, err
- }
-
- message, err := bot.makeMessageRequest(method, v)
- if err != nil {
- return Message{}, err
+ return APIResponse{}, err
}
- return message, nil
-}
+ switch t := c.(type) {
+ case Fileable:
+ if t.useExistingFile() {
+ return bot.MakeRequest(t.method(), params)
+ }
-// uploadAndSend will send a Message with a new file to Telegram.
-func (bot *BotAPI) uploadAndSend(method string, config Fileable) (Message, error) {
- params, err := config.params()
- if err != nil {
- return Message{}, err
+ return bot.UploadFile(t.method(), params, t.name(), t.getFile())
+ default:
+ return bot.MakeRequest(c.method(), params)
}
+}
- file := config.getFile()
-
- resp, err := bot.UploadFile(method, params, config.name(), file)
+// 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
- json.Unmarshal(resp.Result, &message)
-
- bot.debugLog(method, nil, message)
+ err = json.Unmarshal(resp.Result, &message)
- return message, nil
+ return message, err
}
-// sendFile determines if the file is using an existing file or uploading
-// a new file, then sends it as needed.
-func (bot *BotAPI) sendFile(config Fileable) (Message, error) {
- if config.useExistingFile() {
- return bot.sendExisting(config.method(), config)
- }
+// SendMediaGroup sends a media group and returns the resulting messages.
+func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
+ params, _ := config.params()
- return bot.uploadAndSend(config.method(), config)
-}
-
-// sendChattable sends a Chattable.
-func (bot *BotAPI) sendChattable(config Chattable) (Message, error) {
- v, err := config.values()
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
- return Message{}, err
+ return nil, err
}
- message, err := bot.makeMessageRequest(config.method(), v)
+ var messages []Message
+ err = json.Unmarshal(resp.Result, &messages)
- if err != nil {
- return Message{}, err
- }
-
- return message, nil
+ return messages, err
}
// GetUserProfilePhotos gets a user's profile photos.
@@ -354,46 +327,34 @@ func (bot *BotAPI) sendChattable(config Chattable) (Message, error) {
// It requires UserID.
// Offset and Limit are optional.
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
- v := url.Values{}
- v.Add("user_id", strconv.Itoa(config.UserID))
- if config.Offset != 0 {
- v.Add("offset", strconv.Itoa(config.Offset))
- }
- if config.Limit != 0 {
- v.Add("limit", strconv.Itoa(config.Limit))
- }
+ params, _ := config.params()
- resp, err := bot.MakeRequest("getUserProfilePhotos", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return UserProfilePhotos{}, err
}
var profilePhotos UserProfilePhotos
- json.Unmarshal(resp.Result, &profilePhotos)
-
- bot.debugLog("GetUserProfilePhoto", v, profilePhotos)
+ err = json.Unmarshal(resp.Result, &profilePhotos)
- return profilePhotos, nil
+ return profilePhotos, err
}
// GetFile returns a File which can download a file from Telegram.
//
// Requires FileID.
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
- v := url.Values{}
- v.Add("file_id", config.FileID)
+ params, _ := config.params()
- resp, err := bot.MakeRequest("getFile", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return File{}, err
}
var file File
- json.Unmarshal(resp.Result, &file)
+ err = json.Unmarshal(resp.Result, &file)
- bot.debugLog("GetFile", v, file)
-
- return file, nil
+ return file, err
}
// GetUpdates fetches updates.
@@ -404,71 +365,23 @@ func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
// 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) {
- v := url.Values{}
- if config.Offset != 0 {
- v.Add("offset", strconv.Itoa(config.Offset))
- }
- if config.Limit > 0 {
- v.Add("limit", strconv.Itoa(config.Limit))
- }
- if config.Timeout > 0 {
- v.Add("timeout", strconv.Itoa(config.Timeout))
- }
+ params, _ := config.params()
- resp, err := bot.MakeRequest("getUpdates", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return []Update{}, err
}
var updates []Update
- json.Unmarshal(resp.Result, &updates)
-
- bot.debugLog("getUpdates", v, updates)
-
- return updates, nil
-}
-
-// RemoveWebhook unsets the webhook.
-func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
- return bot.MakeRequest("setWebhook", url.Values{})
-}
-
-// SetWebhook sets a webhook.
-//
-// If this is set, GetUpdates will not get any data!
-//
-// If you do not have a legitimate TLS certificate, you need to include
-// your self signed certificate with the config.
-func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) {
-
- if config.Certificate == nil {
- v := url.Values{}
- v.Add("url", config.URL.String())
- if config.MaxConnections != 0 {
- v.Add("max_connections", strconv.Itoa(config.MaxConnections))
- }
+ err = json.Unmarshal(resp.Result, &updates)
- return bot.MakeRequest("setWebhook", v)
- }
-
- params := make(map[string]string)
- params["url"] = config.URL.String()
- if config.MaxConnections != 0 {
- params["max_connections"] = strconv.Itoa(config.MaxConnections)
- }
-
- resp, err := bot.UploadFile("setWebhook", params, "certificate", config.Certificate)
- if err != nil {
- return APIResponse{}, err
- }
-
- return resp, nil
+ 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", url.Values{})
+ resp, err := bot.MakeRequest("getWebhookInfo", nil)
if err != nil {
return WebhookInfo{}, err
}
@@ -480,7 +393,7 @@ func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
}
// GetUpdatesChan starts and returns a channel for getting updates.
-func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
+func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
ch := make(chan Update, bot.Buffer)
go func() {
@@ -490,7 +403,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
return
default:
}
-
+
updates, err := bot.GetUpdates(config)
if err != nil {
log.Println(err)
@@ -509,7 +422,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
}
}()
- return ch, nil
+ return ch
}
// StopReceivingUpdates stops the go routine which receives updates
@@ -537,96 +450,11 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
return ch
}
-// AnswerInlineQuery sends a response to an inline query.
-//
-// Note that you must respond to an inline query within 30 seconds.
-func (bot *BotAPI) AnswerInlineQuery(config InlineConfig) (APIResponse, error) {
- v := url.Values{}
-
- v.Add("inline_query_id", config.InlineQueryID)
- v.Add("cache_time", strconv.Itoa(config.CacheTime))
- v.Add("is_personal", strconv.FormatBool(config.IsPersonal))
- v.Add("next_offset", config.NextOffset)
- data, err := json.Marshal(config.Results)
- if err != nil {
- return APIResponse{}, err
- }
- v.Add("results", string(data))
- v.Add("switch_pm_text", config.SwitchPMText)
- v.Add("switch_pm_parameter", config.SwitchPMParameter)
-
- bot.debugLog("answerInlineQuery", v, nil)
-
- return bot.MakeRequest("answerInlineQuery", v)
-}
-
-// AnswerCallbackQuery sends a response to an inline query callback.
-func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, error) {
- v := url.Values{}
-
- v.Add("callback_query_id", config.CallbackQueryID)
- if config.Text != "" {
- v.Add("text", config.Text)
- }
- v.Add("show_alert", strconv.FormatBool(config.ShowAlert))
- if config.URL != "" {
- v.Add("url", config.URL)
- }
- v.Add("cache_time", strconv.Itoa(config.CacheTime))
-
- bot.debugLog("answerCallbackQuery", v, nil)
-
- return bot.MakeRequest("answerCallbackQuery", v)
-}
-
-// KickChatMember kicks a user from a chat. Note that this only will work
-// in supergroups, and requires the bot to be an admin. Also note they
-// will be unable to rejoin until they are unbanned.
-func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
- v.Add("user_id", strconv.Itoa(config.UserID))
-
- if config.UntilDate != 0 {
- v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
- }
-
- bot.debugLog("kickChatMember", v, nil)
-
- return bot.MakeRequest("kickChatMember", v)
-}
-
-// LeaveChat makes the bot leave the chat.
-func (bot *BotAPI) LeaveChat(config ChatConfig) (APIResponse, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
-
- bot.debugLog("leaveChat", v, nil)
-
- return bot.MakeRequest("leaveChat", v)
-}
-
// GetChat gets information about a chat.
-func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
+func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
+ params, _ := config.params()
- resp, err := bot.MakeRequest("getChat", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return Chat{}, err
}
@@ -634,8 +462,6 @@ func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
var chat Chat
err = json.Unmarshal(resp.Result, &chat)
- bot.debugLog("getChat", v, chat)
-
return chat, err
}
@@ -643,16 +469,10 @@ func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
//
// 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 ChatConfig) ([]ChatMember, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
+func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) {
+ params, _ := config.params()
- resp, err := bot.MakeRequest("getChatAdministrators", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return []ChatMember{}, err
}
@@ -660,22 +480,14 @@ func (bot *BotAPI) GetChatAdministrators(config ChatConfig) ([]ChatMember, error
var members []ChatMember
err = json.Unmarshal(resp.Result, &members)
- bot.debugLog("getChatAdministrators", v, members)
-
return members, err
}
// GetChatMembersCount gets the number of users in a chat.
-func (bot *BotAPI) GetChatMembersCount(config ChatConfig) (int, error) {
- v := url.Values{}
+func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
+ params, _ := config.params()
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
-
- resp, err := bot.MakeRequest("getChatMembersCount", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return -1, err
}
@@ -683,23 +495,14 @@ func (bot *BotAPI) GetChatMembersCount(config ChatConfig) (int, error) {
var count int
err = json.Unmarshal(resp.Result, &count)
- bot.debugLog("getChatMembersCount", v, count)
-
return count, err
}
// GetChatMember gets a specific chat member.
-func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error) {
- v := url.Values{}
+func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
+ params, _ := config.params()
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
- v.Add("user_id", strconv.Itoa(config.UserID))
-
- resp, err := bot.MakeRequest("getChatMember", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return ChatMember{}, err
}
@@ -707,115 +510,14 @@ func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error)
var member ChatMember
err = json.Unmarshal(resp.Result, &member)
- bot.debugLog("getChatMember", v, member)
-
return member, err
}
-// UnbanChatMember unbans a user from a chat. Note that this only will work
-// in supergroups and channels, and requires the bot to be an admin.
-func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername != "" {
- v.Add("chat_id", config.SuperGroupUsername)
- } else if config.ChannelUsername != "" {
- v.Add("chat_id", config.ChannelUsername)
- } else {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- }
- v.Add("user_id", strconv.Itoa(config.UserID))
-
- bot.debugLog("unbanChatMember", v, nil)
-
- return bot.MakeRequest("unbanChatMember", v)
-}
-
-// RestrictChatMember to restrict a user in a supergroup. The bot must be an
-//administrator in the supergroup for this to work and must have the
-//appropriate admin rights. Pass True for all boolean parameters to lift
-//restrictions from a user. Returns True on success.
-func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername != "" {
- v.Add("chat_id", config.SuperGroupUsername)
- } else if config.ChannelUsername != "" {
- v.Add("chat_id", config.ChannelUsername)
- } else {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- }
- v.Add("user_id", strconv.Itoa(config.UserID))
-
- if config.CanSendMessages != nil {
- v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
- }
- if config.CanSendMediaMessages != nil {
- v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
- }
- if config.CanSendOtherMessages != nil {
- v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
- }
- if config.CanAddWebPagePreviews != nil {
- v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
- }
- if config.UntilDate != 0 {
- v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
- }
-
- bot.debugLog("restrictChatMember", v, nil)
-
- return bot.MakeRequest("restrictChatMember", v)
-}
-
-// PromoteChatMember add admin rights to user
-func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername != "" {
- v.Add("chat_id", config.SuperGroupUsername)
- } else if config.ChannelUsername != "" {
- v.Add("chat_id", config.ChannelUsername)
- } else {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- }
- v.Add("user_id", strconv.Itoa(config.UserID))
-
- if config.CanChangeInfo != nil {
- v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
- }
- if config.CanPostMessages != nil {
- v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
- }
- if config.CanEditMessages != nil {
- v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
- }
- if config.CanDeleteMessages != nil {
- v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
- }
- if config.CanInviteUsers != nil {
- v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
- }
- if config.CanRestrictMembers != nil {
- v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
- }
- if config.CanPinMessages != nil {
- v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
- }
- if config.CanPromoteMembers != nil {
- v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
- }
-
- bot.debugLog("promoteChatMember", v, nil)
-
- return bot.MakeRequest("promoteChatMember", v)
-}
-
// GetGameHighScores allows you to get the high scores for a game.
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
- v, _ := config.values()
+ params, _ := config.params()
- resp, err := bot.MakeRequest(config.method(), v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return []GameHighScore{}, err
}
@@ -826,65 +528,11 @@ func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHigh
return highScores, err
}
-// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
-func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) {
- v := url.Values{}
-
- v.Add("shipping_query_id", config.ShippingQueryID)
- v.Add("ok", strconv.FormatBool(config.OK))
- if config.OK == true {
- data, err := json.Marshal(config.ShippingOptions)
- if err != nil {
- return APIResponse{}, err
- }
- v.Add("shipping_options", string(data))
- } else {
- v.Add("error_message", config.ErrorMessage)
- }
-
- bot.debugLog("answerShippingQuery", v, nil)
-
- return bot.MakeRequest("answerShippingQuery", v)
-}
-
-// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
-func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) {
- v := url.Values{}
-
- v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
- v.Add("ok", strconv.FormatBool(config.OK))
- if config.OK != true {
- v.Add("error", config.ErrorMessage)
- }
-
- bot.debugLog("answerPreCheckoutQuery", v, nil)
-
- return bot.MakeRequest("answerPreCheckoutQuery", v)
-}
-
-// DeleteMessage deletes a message in a chat
-func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) {
- v, err := config.values()
- if err != nil {
- return APIResponse{}, err
- }
-
- bot.debugLog(config.method(), v, nil)
-
- return bot.MakeRequest(config.method(), v)
-}
-
// GetInviteLink get InviteLink for a chat
-func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
- v := url.Values{}
-
- if config.SuperGroupUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.SuperGroupUsername)
- }
+func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
+ params, _ := config.params()
- resp, err := bot.MakeRequest("exportChatInviteLink", v)
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return "", err
}
@@ -895,74 +543,35 @@ func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
return inviteLink, err
}
-// PinChatMessage pin message in supergroup
-func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) {
- v, err := config.values()
- if err != nil {
- return APIResponse{}, err
- }
-
- bot.debugLog(config.method(), v, nil)
-
- return bot.MakeRequest(config.method(), v)
-}
-
-// UnpinChatMessage unpin message in supergroup
-func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) {
- v, err := config.values()
- if err != nil {
- return APIResponse{}, err
- }
-
- bot.debugLog(config.method(), v, nil)
-
- return bot.MakeRequest(config.method(), v)
-}
+// GetStickerSet returns a StickerSet.
+func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
+ params, _ := config.params()
-// SetChatTitle change title of chat.
-func (bot *BotAPI) SetChatTitle(config SetChatTitleConfig) (APIResponse, error) {
- v, err := config.values()
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
- return APIResponse{}, err
+ return StickerSet{}, err
}
- bot.debugLog(config.method(), v, nil)
+ var stickers StickerSet
+ err = json.Unmarshal(resp.Result, &stickers)
- return bot.MakeRequest(config.method(), v)
+ return stickers, err
}
-// SetChatDescription change description of chat.
-func (bot *BotAPI) SetChatDescription(config SetChatDescriptionConfig) (APIResponse, error) {
- v, err := config.values()
- if err != nil {
- return APIResponse{}, err
- }
-
- bot.debugLog(config.method(), v, nil)
-
- return bot.MakeRequest(config.method(), v)
-}
-
-// SetChatPhoto change photo of chat.
-func (bot *BotAPI) SetChatPhoto(config SetChatPhotoConfig) (APIResponse, error) {
+// StopPoll stops a poll and returns the result.
+func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
params, err := config.params()
if err != nil {
- return APIResponse{}, err
+ return Poll{}, err
}
- file := config.getFile()
-
- return bot.UploadFile(config.method(), params, config.name(), file)
-}
-
-// DeleteChatPhoto delete photo of chat.
-func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, error) {
- v, err := config.values()
+ resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
- return APIResponse{}, err
+ return Poll{}, err
}
- bot.debugLog(config.method(), v, nil)
+ var poll Poll
+ err = json.Unmarshal(resp.Result, &poll)
- return bot.MakeRequest(config.method(), v)
+ return poll, err
}
diff --git a/bot_test.go b/bot_test.go
index 60f3e65..fe1fd55 100644
--- a/bot_test.go
+++ b/bot_test.go
@@ -1,14 +1,11 @@
-package tgbotapi_test
+package tgbotapi
import (
"io/ioutil"
- "log"
"net/http"
"os"
"testing"
"time"
-
- "github.com/go-telegram-bot-api/telegram-bot-api"
)
const (
@@ -25,8 +22,8 @@ const (
ExistingStickerFileID = "BQADAgADcwADjMcoCbdl-6eB--YPAg"
)
-func getBot(t *testing.T) (*tgbotapi.BotAPI, error) {
- bot, err := tgbotapi.NewBotAPI(TestToken)
+func getBot(t *testing.T) (*BotAPI, error) {
+ bot, err := NewBotAPI(TestToken)
bot.Debug = true
if err != nil {
@@ -38,7 +35,7 @@ func getBot(t *testing.T) (*tgbotapi.BotAPI, error) {
}
func TestNewBotAPI_notoken(t *testing.T) {
- _, err := tgbotapi.NewBotAPI("")
+ _, err := NewBotAPI("")
if err == nil {
t.Error(err)
@@ -49,7 +46,7 @@ func TestNewBotAPI_notoken(t *testing.T) {
func TestGetUpdates(t *testing.T) {
bot, _ := getBot(t)
- u := tgbotapi.NewUpdate(0)
+ u := NewUpdate(0)
_, err := bot.GetUpdates(u)
@@ -62,7 +59,7 @@ func TestGetUpdates(t *testing.T) {
func TestSendWithMessage(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
+ msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
_, err := bot.Send(msg)
@@ -75,7 +72,7 @@ func TestSendWithMessage(t *testing.T) {
func TestSendWithMessageReply(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
+ msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
msg.ReplyToMessageID = ReplyToMessageID
_, err := bot.Send(msg)
@@ -88,7 +85,7 @@ func TestSendWithMessageReply(t *testing.T) {
func TestSendWithMessageForward(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewForward(ChatID, ChatID, ReplyToMessageID)
+ msg := NewForward(ChatID, ChatID, ReplyToMessageID)
_, err := bot.Send(msg)
if err != nil {
@@ -100,7 +97,7 @@ func TestSendWithMessageForward(t *testing.T) {
func TestSendWithNewPhoto(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewPhotoUpload(ChatID, "tests/image.jpg")
+ msg := NewPhotoUpload(ChatID, "tests/image.jpg")
msg.Caption = "Test"
_, err := bot.Send(msg)
@@ -114,9 +111,9 @@ func TestSendWithNewPhotoWithFileBytes(t *testing.T) {
bot, _ := getBot(t)
data, _ := ioutil.ReadFile("tests/image.jpg")
- b := tgbotapi.FileBytes{Name: "image.jpg", Bytes: data}
+ b := FileBytes{Name: "image.jpg", Bytes: data}
- msg := tgbotapi.NewPhotoUpload(ChatID, b)
+ msg := NewPhotoUpload(ChatID, b)
msg.Caption = "Test"
_, err := bot.Send(msg)
@@ -130,9 +127,9 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
bot, _ := getBot(t)
f, _ := os.Open("tests/image.jpg")
- reader := tgbotapi.FileReader{Name: "image.jpg", Reader: f, Size: -1}
+ reader := FileReader{Name: "image.jpg", Reader: f, Size: -1}
- msg := tgbotapi.NewPhotoUpload(ChatID, reader)
+ msg := NewPhotoUpload(ChatID, reader)
msg.Caption = "Test"
_, err := bot.Send(msg)
@@ -145,7 +142,7 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
func TestSendWithNewPhotoReply(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewPhotoUpload(ChatID, "tests/image.jpg")
+ msg := NewPhotoUpload(ChatID, "tests/image.jpg")
msg.ReplyToMessageID = ReplyToMessageID
_, err := bot.Send(msg)
@@ -159,7 +156,7 @@ func TestSendWithNewPhotoReply(t *testing.T) {
func TestSendWithExistingPhoto(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewPhotoShare(ChatID, ExistingPhotoFileID)
+ msg := NewPhotoShare(ChatID, ExistingPhotoFileID)
msg.Caption = "Test"
_, err := bot.Send(msg)
@@ -172,7 +169,7 @@ func TestSendWithExistingPhoto(t *testing.T) {
func TestSendWithNewDocument(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewDocumentUpload(ChatID, "tests/image.jpg")
+ msg := NewDocumentUpload(ChatID, "tests/image.jpg")
_, err := bot.Send(msg)
if err != nil {
@@ -184,7 +181,7 @@ func TestSendWithNewDocument(t *testing.T) {
func TestSendWithExistingDocument(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewDocumentShare(ChatID, ExistingDocumentFileID)
+ msg := NewDocumentShare(ChatID, ExistingDocumentFileID)
_, err := bot.Send(msg)
if err != nil {
@@ -196,7 +193,7 @@ func TestSendWithExistingDocument(t *testing.T) {
func TestSendWithNewAudio(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewAudioUpload(ChatID, "tests/audio.mp3")
+ msg := NewAudioUpload(ChatID, "tests/audio.mp3")
msg.Title = "TEST"
msg.Duration = 10
msg.Performer = "TEST"
@@ -213,7 +210,7 @@ func TestSendWithNewAudio(t *testing.T) {
func TestSendWithExistingAudio(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewAudioShare(ChatID, ExistingAudioFileID)
+ msg := NewAudioShare(ChatID, ExistingAudioFileID)
msg.Title = "TEST"
msg.Duration = 10
msg.Performer = "TEST"
@@ -229,7 +226,7 @@ func TestSendWithExistingAudio(t *testing.T) {
func TestSendWithNewVoice(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewVoiceUpload(ChatID, "tests/voice.ogg")
+ msg := NewVoiceUpload(ChatID, "tests/voice.ogg")
msg.Duration = 10
_, err := bot.Send(msg)
@@ -242,7 +239,7 @@ func TestSendWithNewVoice(t *testing.T) {
func TestSendWithExistingVoice(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewVoiceShare(ChatID, ExistingVoiceFileID)
+ msg := NewVoiceShare(ChatID, ExistingVoiceFileID)
msg.Duration = 10
_, err := bot.Send(msg)
@@ -255,7 +252,7 @@ func TestSendWithExistingVoice(t *testing.T) {
func TestSendWithContact(t *testing.T) {
bot, _ := getBot(t)
- contact := tgbotapi.NewContact(ChatID, "5551234567", "Test")
+ contact := NewContact(ChatID, "5551234567", "Test")
if _, err := bot.Send(contact); err != nil {
t.Error(err)
@@ -266,7 +263,7 @@ func TestSendWithContact(t *testing.T) {
func TestSendWithLocation(t *testing.T) {
bot, _ := getBot(t)
- _, err := bot.Send(tgbotapi.NewLocation(ChatID, 40, 40))
+ _, err := bot.Send(NewLocation(ChatID, 40, 40))
if err != nil {
t.Error(err)
@@ -277,7 +274,7 @@ func TestSendWithLocation(t *testing.T) {
func TestSendWithVenue(t *testing.T) {
bot, _ := getBot(t)
- venue := tgbotapi.NewVenue(ChatID, "A Test Location", "123 Test Street", 40, 40)
+ venue := NewVenue(ChatID, "A Test Location", "123 Test Street", 40, 40)
if _, err := bot.Send(venue); err != nil {
t.Error(err)
@@ -288,7 +285,7 @@ func TestSendWithVenue(t *testing.T) {
func TestSendWithNewVideo(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewVideoUpload(ChatID, "tests/video.mp4")
+ msg := NewVideoUpload(ChatID, "tests/video.mp4")
msg.Duration = 10
msg.Caption = "TEST"
@@ -303,7 +300,7 @@ func TestSendWithNewVideo(t *testing.T) {
func TestSendWithExistingVideo(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewVideoShare(ChatID, ExistingVideoFileID)
+ msg := NewVideoShare(ChatID, ExistingVideoFileID)
msg.Duration = 10
msg.Caption = "TEST"
@@ -318,7 +315,7 @@ func TestSendWithExistingVideo(t *testing.T) {
func TestSendWithNewVideoNote(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewVideoNoteUpload(ChatID, 240, "tests/videonote.mp4")
+ msg := NewVideoNoteUpload(ChatID, 240, "tests/videonote.mp4")
msg.Duration = 10
_, err := bot.Send(msg)
@@ -332,7 +329,7 @@ func TestSendWithNewVideoNote(t *testing.T) {
func TestSendWithExistingVideoNote(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewVideoNoteShare(ChatID, 240, ExistingVideoNoteFileID)
+ msg := NewVideoNoteShare(ChatID, 240, ExistingVideoNoteFileID)
msg.Duration = 10
_, err := bot.Send(msg)
@@ -346,7 +343,7 @@ func TestSendWithExistingVideoNote(t *testing.T) {
func TestSendWithNewSticker(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewStickerUpload(ChatID, "tests/image.jpg")
+ msg := NewStickerUpload(ChatID, "tests/image.jpg")
_, err := bot.Send(msg)
@@ -359,7 +356,7 @@ func TestSendWithNewSticker(t *testing.T) {
func TestSendWithExistingSticker(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewStickerShare(ChatID, ExistingStickerFileID)
+ msg := NewStickerShare(ChatID, ExistingStickerFileID)
_, err := bot.Send(msg)
@@ -372,8 +369,8 @@ func TestSendWithExistingSticker(t *testing.T) {
func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewStickerUpload(ChatID, "tests/image.jpg")
- msg.ReplyMarkup = tgbotapi.ReplyKeyboardRemove{
+ msg := NewStickerUpload(ChatID, "tests/image.jpg")
+ msg.ReplyMarkup = ReplyKeyboardRemove{
RemoveKeyboard: true,
Selective: false,
}
@@ -388,8 +385,8 @@ func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewStickerShare(ChatID, ExistingStickerFileID)
- msg.ReplyMarkup = tgbotapi.ReplyKeyboardRemove{
+ msg := NewStickerShare(ChatID, ExistingStickerFileID)
+ msg.ReplyMarkup = ReplyKeyboardRemove{
RemoveKeyboard: true,
Selective: false,
}
@@ -405,7 +402,9 @@ func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
func TestGetFile(t *testing.T) {
bot, _ := getBot(t)
- file := tgbotapi.FileConfig{FileID: ExistingPhotoFileID}
+ file := FileConfig{
+ FileID: ExistingPhotoFileID,
+ }
_, err := bot.GetFile(file)
@@ -418,7 +417,7 @@ func TestGetFile(t *testing.T) {
func TestSendChatConfig(t *testing.T) {
bot, _ := getBot(t)
- _, err := bot.Send(tgbotapi.NewChatAction(ChatID, tgbotapi.ChatTyping))
+ _, err := bot.Request(NewChatAction(ChatID, ChatTyping))
if err != nil {
t.Error(err)
@@ -429,14 +428,14 @@ func TestSendChatConfig(t *testing.T) {
func TestSendEditMessage(t *testing.T) {
bot, _ := getBot(t)
- msg, err := bot.Send(tgbotapi.NewMessage(ChatID, "Testing editing."))
+ msg, err := bot.Send(NewMessage(ChatID, "Testing editing."))
if err != nil {
t.Error(err)
t.Fail()
}
- edit := tgbotapi.EditMessageTextConfig{
- BaseEdit: tgbotapi.BaseEdit{
+ edit := EditMessageTextConfig{
+ BaseEdit: BaseEdit{
ChatID: ChatID,
MessageID: msg.MessageID,
},
@@ -453,7 +452,7 @@ func TestSendEditMessage(t *testing.T) {
func TestGetUserProfilePhotos(t *testing.T) {
bot, _ := getBot(t)
- _, err := bot.GetUserProfilePhotos(tgbotapi.NewUserProfilePhotos(ChatID))
+ _, err := bot.GetUserProfilePhotos(NewUserProfilePhotos(ChatID))
if err != nil {
t.Error(err)
t.Fail()
@@ -465,19 +464,22 @@ func TestSetWebhookWithCert(t *testing.T) {
time.Sleep(time.Second * 2)
- bot.RemoveWebhook()
+ bot.Request(RemoveWebhookConfig{})
- wh := tgbotapi.NewWebhookWithCert("https://example.com/tgbotapi-test/"+bot.Token, "tests/cert.pem")
- _, err := bot.SetWebhook(wh)
+ wh := NewWebhookWithCert("https://example.com/tgbotapi-test/"+bot.Token, "tests/cert.pem")
+ _, err := bot.Request(wh)
if err != nil {
t.Error(err)
t.Fail()
}
+
_, err = bot.GetWebhookInfo()
+
if err != nil {
t.Error(err)
}
- bot.RemoveWebhook()
+
+ bot.Request(RemoveWebhookConfig{})
}
func TestSetWebhookWithoutCert(t *testing.T) {
@@ -485,65 +487,65 @@ func TestSetWebhookWithoutCert(t *testing.T) {
time.Sleep(time.Second * 2)
- bot.RemoveWebhook()
+ bot.Request(RemoveWebhookConfig{})
- wh := tgbotapi.NewWebhook("https://example.com/tgbotapi-test/" + bot.Token)
- _, err := bot.SetWebhook(wh)
+ wh := NewWebhook("https://example.com/tgbotapi-test/" + bot.Token)
+ _, err := bot.Request(wh)
if err != nil {
t.Error(err)
t.Fail()
}
+
info, err := bot.GetWebhookInfo()
+
if err != nil {
t.Error(err)
}
+
if info.LastErrorDate != 0 {
- t.Errorf("[Telegram callback failed]%s", info.LastErrorMessage)
+ t.Errorf("failed to set webhook: %s", info.LastErrorMessage)
}
- bot.RemoveWebhook()
+
+ bot.Request(RemoveWebhookConfig{})
}
-func TestUpdatesChan(t *testing.T) {
+func TestSendWithMediaGroup(t *testing.T) {
bot, _ := getBot(t)
- var ucfg tgbotapi.UpdateConfig = tgbotapi.NewUpdate(0)
- ucfg.Timeout = 60
- _, err := bot.GetUpdatesChan(ucfg)
+ cfg := NewMediaGroup(ChatID, []interface{}{
+ NewInputMediaPhoto("https://i.imgur.com/unQLJIb.jpg"),
+ NewInputMediaPhoto("https://i.imgur.com/J5qweNZ.jpg"),
+ NewInputMediaVideo("https://i.imgur.com/F6RmI24.mp4"),
+ })
+ messages, err := bot.SendMediaGroup(cfg)
if err != nil {
t.Error(err)
- t.Fail()
}
-}
-func TestSendWithMediaGroup(t *testing.T) {
- bot, _ := getBot(t)
+ if messages == nil {
+ t.Error()
+ }
- cfg := tgbotapi.NewMediaGroup(ChatID, []interface{}{
- tgbotapi.NewInputMediaPhoto("https://i.imgur.com/unQLJIb.jpg"),
- tgbotapi.NewInputMediaPhoto("https://i.imgur.com/J5qweNZ.jpg"),
- tgbotapi.NewInputMediaVideo("https://i.imgur.com/F6RmI24.mp4"),
- })
- _, err := bot.Send(cfg)
- if err != nil {
- t.Error(err)
+ if len(messages) != 3 {
+ t.Error()
}
}
func ExampleNewBotAPI() {
- bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
+ bot, err := NewBotAPI("MyAwesomeBotToken")
if err != nil {
- log.Panic(err)
+ panic(err)
}
bot.Debug = true
log.Printf("Authorized on account %s", bot.Self.UserName)
- u := tgbotapi.NewUpdate(0)
+ u := NewUpdate(0)
u.Timeout = 60
- updates, err := bot.GetUpdatesChan(u)
+ updates := bot.GetUpdatesChan(u)
// Optional: wait for updates and clear them if you don't want to handle
// a large backlog of old messages
@@ -557,7 +559,7 @@ func ExampleNewBotAPI() {
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
- msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
+ msg := NewMessage(update.Message.Chat.ID, update.Message.Text)
msg.ReplyToMessageID = update.Message.MessageID
bot.Send(msg)
@@ -565,26 +567,30 @@ func ExampleNewBotAPI() {
}
func ExampleNewWebhook() {
- bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
+ bot, err := NewBotAPI("MyAwesomeBotToken")
if err != nil {
- log.Fatal(err)
+ panic(err)
}
bot.Debug = true
log.Printf("Authorized on account %s", bot.Self.UserName)
- _, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
+ _, err = bot.Request(NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
if err != nil {
- log.Fatal(err)
+ panic(err)
}
+
info, err := bot.GetWebhookInfo()
+
if err != nil {
- log.Fatal(err)
+ panic(err)
}
+
if info.LastErrorDate != 0 {
- log.Printf("[Telegram callback failed]%s", info.LastErrorMessage)
+ log.Printf("failed to set webhook: %s", info.LastErrorMessage)
}
+
updates := bot.ListenForWebhook("/" + bot.Token)
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
@@ -593,35 +599,35 @@ func ExampleNewWebhook() {
}
}
-func ExampleAnswerInlineQuery() {
- bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") // create new bot
+func ExampleInlineConfig() {
+ bot, err := NewBotAPI("MyAwesomeBotToken") // create new bot
if err != nil {
- log.Panic(err)
+ panic(err)
}
log.Printf("Authorized on account %s", bot.Self.UserName)
- u := tgbotapi.NewUpdate(0)
+ u := NewUpdate(0)
u.Timeout = 60
- updates, err := bot.GetUpdatesChan(u)
+ updates := bot.GetUpdatesChan(u)
for update := range updates {
if update.InlineQuery == nil { // if no inline query, ignore it
continue
}
- article := tgbotapi.NewInlineQueryResultArticle(update.InlineQuery.ID, "Echo", update.InlineQuery.Query)
+ article := NewInlineQueryResultArticle(update.InlineQuery.ID, "Echo", update.InlineQuery.Query)
article.Description = update.InlineQuery.Query
- inlineConf := tgbotapi.InlineConfig{
+ inlineConf := InlineConfig{
InlineQueryID: update.InlineQuery.ID,
IsPersonal: true,
CacheTime: 0,
Results: []interface{}{article},
}
- if _, err := bot.AnswerInlineQuery(inlineConf); err != nil {
+ if _, err := bot.Request(inlineConf); err != nil {
log.Println(err)
}
}
@@ -630,15 +636,15 @@ func ExampleAnswerInlineQuery() {
func TestDeleteMessage(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
+ msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
message, _ := bot.Send(msg)
- deleteMessageConfig := tgbotapi.DeleteMessageConfig{
+ deleteMessageConfig := DeleteMessageConfig{
ChatID: message.Chat.ID,
MessageID: message.MessageID,
}
- _, err := bot.DeleteMessage(deleteMessageConfig)
+ _, err := bot.Request(deleteMessageConfig)
if err != nil {
t.Error(err)
@@ -649,16 +655,16 @@ func TestDeleteMessage(t *testing.T) {
func TestPinChatMessage(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
+ msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
message, _ := bot.Send(msg)
- pinChatMessageConfig := tgbotapi.PinChatMessageConfig{
+ pinChatMessageConfig := PinChatMessageConfig{
ChatID: message.Chat.ID,
MessageID: message.MessageID,
DisableNotification: false,
}
- _, err := bot.PinChatMessage(pinChatMessageConfig)
+ _, err := bot.Request(pinChatMessageConfig)
if err != nil {
t.Error(err)
@@ -669,25 +675,61 @@ func TestPinChatMessage(t *testing.T) {
func TestUnpinChatMessage(t *testing.T) {
bot, _ := getBot(t)
- msg := tgbotapi.NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
+ msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
message, _ := bot.Send(msg)
// We need pin message to unpin something
- pinChatMessageConfig := tgbotapi.PinChatMessageConfig{
+ pinChatMessageConfig := PinChatMessageConfig{
ChatID: message.Chat.ID,
MessageID: message.MessageID,
DisableNotification: false,
}
- _, err := bot.PinChatMessage(pinChatMessageConfig)
- unpinChatMessageConfig := tgbotapi.UnpinChatMessageConfig{
+ if _, err := bot.Request(pinChatMessageConfig); err != nil {
+ t.Error(err)
+ t.Fail()
+ }
+
+ unpinChatMessageConfig := UnpinChatMessageConfig{
ChatID: message.Chat.ID,
}
- _, err = bot.UnpinChatMessage(unpinChatMessageConfig)
+ if _, err := bot.Request(unpinChatMessageConfig); err != nil {
+ t.Error(err)
+ t.Fail()
+ }
+}
+
+func TestPolls(t *testing.T) {
+ bot, _ := getBot(t)
+
+ poll := NewPoll(SupergroupChatID, "Are polls working?", "Yes", "No")
+
+ msg, err := bot.Send(poll)
+ if err != nil {
+ t.Error(err)
+ t.Fail()
+ }
+
+ result, err := bot.StopPoll(NewStopPoll(SupergroupChatID, msg.MessageID))
if err != nil {
t.Error(err)
t.Fail()
}
+
+ if result.Question != "Are polls working?" {
+ t.Error("Poll question did not match")
+ t.Fail()
+ }
+
+ if !result.IsClosed {
+ t.Error("Poll did not end")
+ t.Fail()
+ }
+
+ if result.Options[0].Text != "Yes" || result.Options[0].VoterCount != 0 || result.Options[1].Text != "No" || result.Options[1].VoterCount != 0 {
+ t.Error("Poll options were incorrect")
+ t.Fail()
+ }
}
diff --git a/configs.go b/configs.go
index 181d4e4..0258d74 100644
--- a/configs.go
+++ b/configs.go
@@ -1,10 +1,8 @@
package tgbotapi
import (
- "encoding/json"
"io"
"net/url"
- "strconv"
)
// Telegram constants
@@ -49,14 +47,13 @@ const (
// Chattable is any config type that can be sent.
type Chattable interface {
- values() (url.Values, error)
+ params() (Params, error)
method() string
}
// Fileable is any config type that can be sent that includes a file.
type Fileable interface {
Chattable
- params() (map[string]string, error)
name() string
getFile() interface{}
useExistingFile() bool
@@ -71,31 +68,16 @@ type BaseChat struct {
DisableNotification bool
}
-// values returns url.Values representation of BaseChat
-func (chat *BaseChat) values() (url.Values, error) {
- v := url.Values{}
- if chat.ChannelUsername != "" {
- v.Add("chat_id", chat.ChannelUsername)
- } else {
- v.Add("chat_id", strconv.FormatInt(chat.ChatID, 10))
- }
-
- if chat.ReplyToMessageID != 0 {
- v.Add("reply_to_message_id", strconv.Itoa(chat.ReplyToMessageID))
- }
+func (chat *BaseChat) params() (Params, error) {
+ params := make(Params)
- if chat.ReplyMarkup != nil {
- data, err := json.Marshal(chat.ReplyMarkup)
- if err != nil {
- return v, err
- }
+ params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername)
+ params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID)
+ params.AddBool("disable_notification", chat.DisableNotification)
- v.Add("reply_markup", string(data))
- }
-
- v.Add("disable_notification", strconv.FormatBool(chat.DisableNotification))
+ err := params.AddInterface("reply_markup", chat.ReplyMarkup)
- return v, nil
+ return params, err
}
// BaseFile is a base type for all file config types.
@@ -108,48 +90,19 @@ type BaseFile struct {
FileSize int
}
-// params returns a map[string]string representation of BaseFile.
-func (file BaseFile) params() (map[string]string, error) {
- params := make(map[string]string)
-
- if file.ChannelUsername != "" {
- params["chat_id"] = file.ChannelUsername
- } else {
- params["chat_id"] = strconv.FormatInt(file.ChatID, 10)
- }
-
- if file.ReplyToMessageID != 0 {
- params["reply_to_message_id"] = strconv.Itoa(file.ReplyToMessageID)
- }
-
- if file.ReplyMarkup != nil {
- data, err := json.Marshal(file.ReplyMarkup)
- if err != nil {
- return params, err
- }
+func (file BaseFile) params() (Params, error) {
+ params, err := file.BaseChat.params()
- params["reply_markup"] = string(data)
- }
-
- if file.MimeType != "" {
- params["mime_type"] = file.MimeType
- }
+ params.AddNonEmpty("mime_type", file.MimeType)
+ params.AddNonZero("file_size", file.FileSize)
- if file.FileSize > 0 {
- params["file_size"] = strconv.Itoa(file.FileSize)
- }
-
- params["disable_notification"] = strconv.FormatBool(file.DisableNotification)
-
- return params, nil
+ return params, err
}
-// getFile returns the file.
func (file BaseFile) getFile() interface{} {
return file.File
}
-// useExistingFile returns if the BaseFile has already been uploaded.
func (file BaseFile) useExistingFile() bool {
return file.UseExisting
}
@@ -163,29 +116,19 @@ type BaseEdit struct {
ReplyMarkup *InlineKeyboardMarkup
}
-func (edit BaseEdit) values() (url.Values, error) {
- v := url.Values{}
+func (edit BaseEdit) params() (Params, error) {
+ params := make(Params)
- if edit.InlineMessageID == "" {
- if edit.ChannelUsername != "" {
- v.Add("chat_id", edit.ChannelUsername)
- } else {
- v.Add("chat_id", strconv.FormatInt(edit.ChatID, 10))
- }
- v.Add("message_id", strconv.Itoa(edit.MessageID))
+ if edit.InlineMessageID != "" {
+ params["inline_message_id"] = edit.InlineMessageID
} else {
- v.Add("inline_message_id", edit.InlineMessageID)
+ params.AddFirstValid("chat_id", edit.ChatID, edit.ChannelUsername)
+ params.AddNonZero("message_id", edit.MessageID)
}
- if edit.ReplyMarkup != nil {
- data, err := json.Marshal(edit.ReplyMarkup)
- if err != nil {
- return v, err
- }
- v.Add("reply_markup", string(data))
- }
+ err := params.AddInterface("reply_markup", edit.ReplyMarkup)
- return v, nil
+ return params, err
}
// MessageConfig contains information about a SendMessage request.
@@ -196,22 +139,19 @@ type MessageConfig struct {
DisableWebPagePreview bool
}
-// values returns a url.Values representation of MessageConfig.
-func (config MessageConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
+func (config MessageConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
if err != nil {
- return v, err
- }
- v.Add("text", config.Text)
- v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
+ return params, err
}
- return v, nil
+ params.AddNonEmpty("text", config.Text)
+ params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
+ params.AddNonEmpty("parse_mode", config.ParseMode)
+
+ return params, nil
}
-// method returns Telegram API method name for sending Message.
func (config MessageConfig) method() string {
return "sendMessage"
}
@@ -224,18 +164,18 @@ type ForwardConfig struct {
MessageID int // required
}
-// values returns a url.Values representation of ForwardConfig.
-func (config ForwardConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
+func (config ForwardConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
if err != nil {
- return v, err
+ return params, err
}
- v.Add("from_chat_id", strconv.FormatInt(config.FromChatID, 10))
- v.Add("message_id", strconv.Itoa(config.MessageID))
- return v, nil
+
+ params.AddNonZero64("from_chat_id", config.FromChatID)
+ params.AddNonZero("message_id", config.MessageID)
+
+ return params, nil
}
-// method returns Telegram API method name for sending Forward.
func (config ForwardConfig) method() string {
return "forwardMessage"
}
@@ -247,44 +187,20 @@ type PhotoConfig struct {
ParseMode string
}
-// Params returns a map[string]string representation of PhotoConfig.
-func (config PhotoConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
-
- if config.Caption != "" {
- params["caption"] = config.Caption
- if config.ParseMode != "" {
- params["parse_mode"] = config.ParseMode
- }
- }
-
- return params, nil
-}
-
-// Values returns a url.Values representation of PhotoConfig.
-func (config PhotoConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config PhotoConfig) params() (Params, error) {
+ params, err := config.BaseFile.params()
- v.Add(config.name(), config.FileID)
- if config.Caption != "" {
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ params.AddNonEmpty("caption", config.Caption)
+ params.AddNonEmpty("parse_mode", config.ParseMode)
- return v, nil
+ return params, err
}
-// name returns the field name for the Photo.
func (config PhotoConfig) name() string {
return "photo"
}
-// method returns Telegram API method name for sending Photo.
func (config PhotoConfig) method() string {
return "sendPhoto"
}
@@ -299,64 +215,26 @@ type AudioConfig struct {
Title string
}
-// values returns a url.Values representation of AudioConfig.
-func (config AudioConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
+func (config AudioConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
if err != nil {
- return v, err
- }
-
- v.Add(config.name(), config.FileID)
- if config.Duration != 0 {
- v.Add("duration", strconv.Itoa(config.Duration))
- }
-
- if config.Performer != "" {
- v.Add("performer", config.Performer)
+ return params, err
}
- if config.Title != "" {
- v.Add("title", config.Title)
- }
- if config.Caption != "" {
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
- }
-
- return v, nil
-}
-// params returns a map[string]string representation of AudioConfig.
-func (config AudioConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
-
- if config.Duration != 0 {
- params["duration"] = strconv.Itoa(config.Duration)
- }
-
- if config.Performer != "" {
- params["performer"] = config.Performer
- }
- if config.Title != "" {
- params["title"] = config.Title
- }
- if config.Caption != "" {
- params["caption"] = config.Caption
- if config.ParseMode != "" {
- params["parse_mode"] = config.ParseMode
- }
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ 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)
return params, nil
}
-// name returns the field name for the Audio.
func (config AudioConfig) name() string {
return "audio"
}
-// method returns Telegram API method name for sending Audio.
func (config AudioConfig) method() string {
return "sendAudio"
}
@@ -368,44 +246,20 @@ type DocumentConfig struct {
ParseMode string
}
-// values returns a url.Values representation of DocumentConfig.
-func (config DocumentConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config DocumentConfig) params() (Params, error) {
+ params, err := config.BaseFile.params()
- v.Add(config.name(), config.FileID)
- if config.Caption != "" {
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ params.AddNonEmpty("caption", config.Caption)
+ params.AddNonEmpty("parse_mode", config.ParseMode)
- return v, nil
+ return params, err
}
-// params returns a map[string]string representation of DocumentConfig.
-func (config DocumentConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
-
- if config.Caption != "" {
- params["caption"] = config.Caption
- if config.ParseMode != "" {
- params["parse_mode"] = config.ParseMode
- }
- }
-
- return params, nil
-}
-
-// name returns the field name for the Document.
func (config DocumentConfig) name() string {
return "document"
}
-// method returns Telegram API method name for sending Document.
func (config DocumentConfig) method() string {
return "sendDocument"
}
@@ -415,31 +269,18 @@ type StickerConfig struct {
BaseFile
}
-// values returns a url.Values representation of StickerConfig.
-func (config StickerConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
-
- v.Add(config.name(), config.FileID)
-
- return v, nil
-}
+func (config StickerConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
-// params returns a map[string]string representation of StickerConfig.
-func (config StickerConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
+ params.AddNonEmpty(config.name(), config.FileID)
- return params, nil
+ return params, err
}
-// name returns the field name for the Sticker.
func (config StickerConfig) name() string {
return "sticker"
}
-// method returns Telegram API method name for sending Sticker.
func (config StickerConfig) method() string {
return "sendSticker"
}
@@ -447,52 +288,28 @@ func (config StickerConfig) method() string {
// VideoConfig contains information about a SendVideo request.
type VideoConfig struct {
BaseFile
- Duration int
- Caption string
- ParseMode string
-}
-
-// values returns a url.Values representation of VideoConfig.
-func (config VideoConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
-
- v.Add(config.name(), config.FileID)
- if config.Duration != 0 {
- v.Add("duration", strconv.Itoa(config.Duration))
- }
- if config.Caption != "" {
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
- }
-
- return v, nil
+ Duration int
+ Caption string
+ ParseMode string
+ SupportsStreaming bool
}
-// params returns a map[string]string representation of VideoConfig.
-func (config VideoConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
+func (config VideoConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- if config.Caption != "" {
- params["caption"] = config.Caption
- if config.ParseMode != "" {
- params["parse_mode"] = config.ParseMode
- }
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ params.AddNonZero("duration", config.Duration)
+ params.AddNonEmpty("caption", config.Caption)
+ params.AddNonEmpty("parse_mode", config.ParseMode)
+ params.AddBool("supports_streaming", config.SupportsStreaming)
- return params, nil
+ return params, err
}
-// name returns the field name for the Video.
func (config VideoConfig) name() string {
return "video"
}
-// method returns Telegram API method name for sending Video.
func (config VideoConfig) method() string {
return "sendVideo"
}
@@ -505,47 +322,21 @@ type AnimationConfig struct {
ParseMode string
}
-// values returns a url.Values representation of AnimationConfig.
-func (config AnimationConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config AnimationConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- v.Add(config.name(), config.FileID)
- if config.Duration != 0 {
- v.Add("duration", strconv.Itoa(config.Duration))
- }
- if config.Caption != "" {
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ params.AddNonZero("duration", config.Duration)
+ params.AddNonEmpty("caption", config.Caption)
+ params.AddNonEmpty("parse_mode", config.ParseMode)
- return v, nil
+ return params, err
}
-// params returns a map[string]string representation of AnimationConfig.
-func (config AnimationConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
-
- if config.Caption != "" {
- params["caption"] = config.Caption
- if config.ParseMode != "" {
- params["parse_mode"] = config.ParseMode
- }
- }
-
- return params, nil
-}
-
-// name returns the field name for the Animation.
func (config AnimationConfig) name() string {
return "animation"
}
-// method returns Telegram API method name for sending Animation.
func (config AnimationConfig) method() string {
return "sendAnimation"
}
@@ -557,46 +348,20 @@ type VideoNoteConfig struct {
Length int
}
-// values returns a url.Values representation of VideoNoteConfig.
-func (config VideoNoteConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
-
- v.Add(config.name(), config.FileID)
- if config.Duration != 0 {
- v.Add("duration", strconv.Itoa(config.Duration))
- }
-
- // Telegram API seems to have a bug, if no length is provided or it is 0, it will send an error response
- if config.Length != 0 {
- v.Add("length", strconv.Itoa(config.Length))
- }
-
- return v, nil
-}
-
-// params returns a map[string]string representation of VideoNoteConfig.
-func (config VideoNoteConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
+func (config VideoNoteConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- if config.Length != 0 {
- params["length"] = strconv.Itoa(config.Length)
- }
- if config.Duration != 0 {
- params["duration"] = strconv.Itoa(config.Duration)
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ params.AddNonZero("duration", config.Duration)
+ params.AddNonZero("length", config.Length)
- return params, nil
+ return params, err
}
-// name returns the field name for the VideoNote.
func (config VideoNoteConfig) name() string {
return "video_note"
}
-// method returns Telegram API method name for sending VideoNote.
func (config VideoNoteConfig) method() string {
return "sendVideoNote"
}
@@ -609,103 +374,78 @@ type VoiceConfig struct {
Duration int
}
-// values returns a url.Values representation of VoiceConfig.
-func (config VoiceConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config VoiceConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- v.Add(config.name(), config.FileID)
- if config.Duration != 0 {
- v.Add("duration", strconv.Itoa(config.Duration))
- }
- if config.Caption != "" {
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
- }
+ params.AddNonEmpty(config.name(), config.FileID)
+ params.AddNonZero("duration", config.Duration)
+ params.AddNonEmpty("caption", config.Caption)
+ params.AddNonEmpty("parse_mode", config.ParseMode)
- return v, nil
+ return params, err
}
-// params returns a map[string]string representation of VoiceConfig.
-func (config VoiceConfig) params() (map[string]string, error) {
- params, _ := config.BaseFile.params()
-
- if config.Duration != 0 {
- params["duration"] = strconv.Itoa(config.Duration)
- }
- if config.Caption != "" {
- params["caption"] = config.Caption
- if config.ParseMode != "" {
- params["parse_mode"] = config.ParseMode
- }
- }
-
- return params, nil
-}
-
-// name returns the field name for the Voice.
func (config VoiceConfig) name() string {
return "voice"
}
-// method returns Telegram API method name for sending Voice.
func (config VoiceConfig) method() string {
return "sendVoice"
}
-// MediaGroupConfig contains information about a sendMediaGroup request.
-type MediaGroupConfig struct {
+// LocationConfig contains information about a SendLocation request.
+type LocationConfig struct {
BaseChat
- InputMedia []interface{}
+ Latitude float64 // required
+ Longitude float64 // required
+ LivePeriod int // optional
}
-func (config MediaGroupConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config LocationConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- data, err := json.Marshal(config.InputMedia)
- if err != nil {
- return v, err
- }
+ params.AddNonZeroFloat("latitude", config.Latitude)
+ params.AddNonZeroFloat("longitude", config.Longitude)
+ params.AddNonZero("live_period", config.LivePeriod)
- v.Add("media", string(data))
-
- return v, nil
+ return params, err
}
-func (config MediaGroupConfig) method() string {
- return "sendMediaGroup"
+func (config LocationConfig) method() string {
+ return "sendLocation"
}
-// LocationConfig contains information about a SendLocation request.
-type LocationConfig struct {
- BaseChat
+// EditMessageLiveLocationConfig allows you to update a live location.
+type EditMessageLiveLocationConfig struct {
+ BaseEdit
Latitude float64 // required
Longitude float64 // required
}
-// values returns a url.Values representation of LocationConfig.
-func (config LocationConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config EditMessageLiveLocationConfig) params() (Params, error) {
+ params, err := config.BaseEdit.params()
- v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
- v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
+ params.AddNonZeroFloat("latitude", config.Latitude)
+ params.AddNonZeroFloat("longitude", config.Longitude)
- return v, nil
+ return params, err
}
-// method returns Telegram API method name for sending Location.
-func (config LocationConfig) method() string {
- return "sendLocation"
+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.
@@ -718,21 +458,16 @@ type VenueConfig struct {
FoursquareID string
}
-func (config VenueConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config VenueConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
- v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
- v.Add("title", config.Title)
- v.Add("address", config.Address)
- if config.FoursquareID != "" {
- v.Add("foursquare_id", config.FoursquareID)
- }
+ params.AddNonZeroFloat("latitude", config.Latitude)
+ params.AddNonZeroFloat("longitude", config.Longitude)
+ params["title"] = config.Title
+ params["address"] = config.Address
+ params.AddNonEmpty("foursquare_id", config.FoursquareID)
- return v, nil
+ return params, err
}
func (config VenueConfig) method() string {
@@ -745,40 +480,60 @@ type ContactConfig struct {
PhoneNumber string
FirstName string
LastName string
+ VCard string
}
-func (config ContactConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config ContactConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- v.Add("phone_number", config.PhoneNumber)
- v.Add("first_name", config.FirstName)
- v.Add("last_name", config.LastName)
+ params["phone_number"] = config.PhoneNumber
+ params["first_name"] = config.FirstName
- return v, nil
+ 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
+}
+
+func (config SendPollConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
+ if err != nil {
+ return params, err
+ }
+
+ params["question"] = config.Question
+ err = params.AddInterface("options", config.Options)
+
+ 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) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
+func (config GameConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
- v.Add("game_short_name", config.GameShortName)
+ params["game_short_name"] = config.GameShortName
- return v, nil
+ return params, err
}
func (config GameConfig) method() string {
@@ -797,24 +552,21 @@ type SetGameScoreConfig struct {
InlineMessageID string
}
-func (config SetGameScoreConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config SetGameScoreConfig) params() (Params, error) {
+ params := make(Params)
+
+ params.AddNonZero("user_id", config.UserID)
+ params.AddNonZero("scrore", config.Score)
+ params.AddBool("disable_edit_message", config.DisableEditMessage)
- v.Add("user_id", strconv.Itoa(config.UserID))
- v.Add("score", strconv.Itoa(config.Score))
- if config.InlineMessageID == "" {
- if config.ChannelUsername == "" {
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- } else {
- v.Add("chat_id", config.ChannelUsername)
- }
- v.Add("message_id", strconv.Itoa(config.MessageID))
+ if config.InlineMessageID != "" {
+ params["inline_message_id"] = config.InlineMessageID
} else {
- v.Add("inline_message_id", config.InlineMessageID)
+ params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
+ params.AddNonZero("message_id", config.MessageID)
}
- v.Add("disable_edit_message", strconv.FormatBool(config.DisableEditMessage))
- return v, nil
+ return params, nil
}
func (config SetGameScoreConfig) method() string {
@@ -830,22 +582,19 @@ type GetGameHighScoresConfig struct {
InlineMessageID string
}
-func (config GetGameHighScoresConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config GetGameHighScoresConfig) params() (Params, error) {
+ params := make(Params)
+
+ params.AddNonZero("user_id", config.UserID)
- v.Add("user_id", strconv.Itoa(config.UserID))
- if config.InlineMessageID == "" {
- if config.ChannelUsername == "" {
- v.Add("chat_id", strconv.Itoa(config.ChatID))
- } else {
- v.Add("chat_id", config.ChannelUsername)
- }
- v.Add("message_id", strconv.Itoa(config.MessageID))
+ if config.InlineMessageID != "" {
+ params["inline_message_id"] = config.InlineMessageID
} else {
- v.Add("inline_message_id", config.InlineMessageID)
+ params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
+ params.AddNonZero("message_id", config.MessageID)
}
- return v, nil
+ return params, nil
}
func (config GetGameHighScoresConfig) method() string {
@@ -858,17 +607,14 @@ type ChatActionConfig struct {
Action string // required
}
-// values returns a url.Values representation of ChatActionConfig.
-func (config ChatActionConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
- if err != nil {
- return v, err
- }
- v.Add("action", config.Action)
- return v, nil
+func (config ChatActionConfig) params() (Params, error) {
+ params, err := config.BaseChat.params()
+
+ params["action"] = config.Action
+
+ return params, err
}
-// method returns Telegram API method name for sending ChatAction.
func (config ChatActionConfig) method() string {
return "sendChatAction"
}
@@ -881,17 +627,14 @@ type EditMessageTextConfig struct {
DisableWebPagePreview bool
}
-func (config EditMessageTextConfig) values() (url.Values, error) {
- v, err := config.BaseEdit.values()
- if err != nil {
- return v, err
- }
+func (config EditMessageTextConfig) params() (Params, error) {
+ params, err := config.BaseEdit.params()
- v.Add("text", config.Text)
- v.Add("parse_mode", config.ParseMode)
- v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
+ params["text"] = config.Text
+ params.AddNonEmpty("parse_mode", config.ParseMode)
+ params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
- return v, nil
+ return params, err
}
func (config EditMessageTextConfig) method() string {
@@ -905,35 +648,65 @@ type EditMessageCaptionConfig struct {
ParseMode string
}
-func (config EditMessageCaptionConfig) values() (url.Values, error) {
- v, _ := config.BaseEdit.values()
+func (config EditMessageCaptionConfig) params() (Params, error) {
+ params, err := config.BaseEdit.params()
- v.Add("caption", config.Caption)
- if config.ParseMode != "" {
- v.Add("parse_mode", config.ParseMode)
- }
+ params["caption"] = config.Caption
+ params.AddNonEmpty("parse_mode", config.ParseMode)
- return v, nil
+ return params, err
}
func (config EditMessageCaptionConfig) method() string {
return "editMessageCaption"
}
+// EditMessageMediaConfig contains information about editing a message's media.
+type EditMessageMediaConfig struct {
+ BaseEdit
+
+ Media interface{}
+}
+
+func (EditMessageMediaConfig) method() string {
+ return "editMessageMedia"
+}
+
+func (config EditMessageMediaConfig) params() (Params, error) {
+ params, err := config.BaseEdit.params()
+
+ params.AddInterface("media", config.Media)
+
+ return params, err
+}
+
// EditMessageReplyMarkupConfig allows you to modify the reply markup
// of a message.
type EditMessageReplyMarkupConfig struct {
BaseEdit
}
-func (config EditMessageReplyMarkupConfig) values() (url.Values, error) {
- return config.BaseEdit.values()
+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 {
@@ -942,11 +715,37 @@ type UserProfilePhotosConfig struct {
Limit int
}
+func (UserProfilePhotosConfig) method() string {
+ return "getUserProfilePhotos"
+}
+
+func (config UserProfilePhotosConfig) params() (Params, error) {
+ params := make(Params)
+
+ params.AddNonZero("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
@@ -954,11 +753,67 @@ type UpdateConfig struct {
Timeout int
}
+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)
+
+ return params, nil
+}
+
// WebhookConfig contains information about a SetWebhook request.
type WebhookConfig struct {
URL *url.URL
Certificate interface{}
MaxConnections int
+ AllowedUpdates []string
+}
+
+func (config WebhookConfig) method() string {
+ return "setWebhook"
+}
+
+func (config WebhookConfig) params() (Params, error) {
+ params := make(Params)
+
+ if config.URL != nil {
+ params["url"] = config.URL.String()
+ }
+
+ params.AddNonZero("max_connections", config.MaxConnections)
+ params.AddInterface("allowed_updates", config.AllowedUpdates)
+
+ return params, nil
+}
+
+func (config WebhookConfig) name() string {
+ return "certificate"
+}
+
+func (config WebhookConfig) getFile() interface{} {
+ return config.Certificate
+}
+
+func (config WebhookConfig) useExistingFile() bool {
+ return config.URL != nil
+}
+
+// RemoveWebhookConfig is a helper to remove a webhook.
+type RemoveWebhookConfig struct {
+}
+
+func (config RemoveWebhookConfig) method() string {
+ return "setWebhook"
+}
+
+func (config RemoveWebhookConfig) params() (Params, error) {
+ return nil, nil
}
// FileBytes contains information about a set of bytes to upload
@@ -988,6 +843,27 @@ type InlineConfig struct {
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)
+
+ if err := params.AddInterface("results", config.Results); err != nil {
+ return params, err
+ }
+
+ return params, nil
+}
+
// CallbackConfig contains information on making a CallbackQuery response.
type CallbackConfig struct {
CallbackQueryID string `json:"callback_query_id"`
@@ -997,6 +873,22 @@ type CallbackConfig struct {
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 {
@@ -1006,12 +898,44 @@ type ChatMemberConfig struct {
UserID int
}
+// UnbanChatMemberConfig allows you to unban a user.
+type UnbanChatMemberConfig struct {
+ ChatMemberConfig
+}
+
+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.AddNonZero("user_id", config.UserID)
+
+ return params, nil
+}
+
// KickChatMemberConfig contains extra fields to kick user
type KickChatMemberConfig struct {
ChatMemberConfig
UntilDate int64
}
+func (config KickChatMemberConfig) method() string {
+ return "kickChatMember"
+}
+
+func (config KickChatMemberConfig) params() (Params, error) {
+ params := make(Params)
+
+ params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
+ params.AddNonZero("user_id", config.UserID)
+ params.AddNonZero64("until_date", config.UntilDate)
+
+ return params, nil
+}
+
// RestrictChatMemberConfig contains fields to restrict members of chat
type RestrictChatMemberConfig struct {
ChatMemberConfig
@@ -1022,6 +946,25 @@ type RestrictChatMemberConfig struct {
CanAddWebPagePreviews *bool
}
+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.AddNonZero("user_id", config.UserID)
+
+ params.AddNonNilBool("can_send_messages", config.CanSendMessages)
+ params.AddNonNilBool("can_send_media_messages", config.CanSendMediaMessages)
+ params.AddNonNilBool("can_send_other_messages", config.CanSendOtherMessages)
+ params.AddNonNilBool("can_add_web_page_previews", config.CanAddWebPagePreviews)
+ params.AddNonZero64("until_date", config.UntilDate)
+
+ return params, nil
+}
+
// PromoteChatMemberConfig contains fields to promote members of chat
type PromoteChatMemberConfig struct {
ChatMemberConfig
@@ -1035,86 +978,186 @@ type PromoteChatMemberConfig struct {
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.AddNonZero("user_id", config.UserID)
+
+ params.AddNonNilBool("can_change_info", config.CanChangeInfo)
+ params.AddNonNilBool("can_post_messages", config.CanPostMessages)
+ params.AddNonNilBool("can_edit_messages", config.CanEditMessages)
+ params.AddNonNilBool("can_delete_messages", config.CanDeleteMessages)
+ params.AddNonNilBool("can_invite_users", config.CanInviteUsers)
+ params.AddNonNilBool("can_restrict_members", config.CanRestrictMembers)
+ params.AddNonNilBool("can_pin_messages", config.CanPinMessages)
+ params.AddNonNilBool("can_promote_members", config.CanPromoteMembers)
+
+ return params, nil
+}
+
// ChatConfig contains information about getting information on a chat.
type ChatConfig struct {
ChatID int64
SuperGroupUsername string
}
-// ChatConfigWithUser contains information about getting information on
-// a specific user within a chat.
+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"
+}
+
+// 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
+}
+
+// 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 int
}
+func (config ChatConfigWithUser) params() (Params, error) {
+ params := make(Params)
+
+ params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
+ params.AddNonZero("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
- StartParameter string // required
- Currency string // required
- Prices *[]LabeledPrice // required
- PhotoURL string
- PhotoSize int
- PhotoWidth int
- PhotoHeight int
- NeedName bool
- NeedPhoneNumber bool
- NeedEmail bool
- NeedShippingAddress bool
- IsFlexible bool
-}
-
-func (config InvoiceConfig) values() (url.Values, error) {
- v, err := config.BaseChat.values()
+ Title string // required
+ Description string // required
+ Payload string // required
+ ProviderToken string // required
+ StartParameter string // required
+ Currency string // required
+ Prices []LabeledPrice // required
+ 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 v, err
- }
- v.Add("title", config.Title)
- v.Add("description", config.Description)
- v.Add("payload", config.Payload)
- v.Add("provider_token", config.ProviderToken)
- v.Add("start_parameter", config.StartParameter)
- v.Add("currency", config.Currency)
- data, err := json.Marshal(config.Prices)
- if err != nil {
- return v, err
- }
- v.Add("prices", string(data))
- if config.PhotoURL != "" {
- v.Add("photo_url", config.PhotoURL)
- }
- if config.PhotoSize != 0 {
- v.Add("photo_size", strconv.Itoa(config.PhotoSize))
+ return params, err
}
- if config.PhotoWidth != 0 {
- v.Add("photo_width", strconv.Itoa(config.PhotoWidth))
- }
- if config.PhotoHeight != 0 {
- v.Add("photo_height", strconv.Itoa(config.PhotoHeight))
- }
- if config.NeedName != false {
- v.Add("need_name", strconv.FormatBool(config.NeedName))
- }
- if config.NeedPhoneNumber != false {
- v.Add("need_phone_number", strconv.FormatBool(config.NeedPhoneNumber))
- }
- if config.NeedEmail != false {
- v.Add("need_email", strconv.FormatBool(config.NeedEmail))
- }
- if config.NeedShippingAddress != false {
- v.Add("need_shipping_address", strconv.FormatBool(config.NeedShippingAddress))
- }
- if config.IsFlexible != false {
- v.Add("is_flexible", strconv.FormatBool(config.IsFlexible))
+
+ params["title"] = config.Title
+ params["description"] = config.Description
+ params["payload"] = config.Payload
+ params["provider_token"] = config.ProviderToken
+ params["start_parameter"] = config.StartParameter
+ params["currency"] = config.Currency
+
+ if err = params.AddInterface("prices", config.Prices); err != nil {
+ return params, err
}
- return v, nil
+ 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, nil
}
func (config InvoiceConfig) method() string {
@@ -1125,7 +1168,7 @@ func (config InvoiceConfig) method() string {
type ShippingConfig struct {
ShippingQueryID string // required
OK bool // required
- ShippingOptions *[]ShippingOption
+ ShippingOptions []ShippingOption
ErrorMessage string
}
@@ -1146,18 +1189,19 @@ func (config DeleteMessageConfig) method() string {
return "deleteMessage"
}
-func (config DeleteMessageConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config DeleteMessageConfig) params() (Params, error) {
+ params := make(Params)
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- v.Add("message_id", strconv.Itoa(config.MessageID))
+ params.AddNonZero64("chat_id", config.ChatID)
+ params.AddNonZero("message_id", config.MessageID)
- return v, nil
+ 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
}
@@ -1166,55 +1210,99 @@ func (config PinChatMessageConfig) method() string {
return "pinChatMessage"
}
-func (config PinChatMessageConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config PinChatMessageConfig) params() (Params, error) {
+ params := make(Params)
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- v.Add("message_id", strconv.Itoa(config.MessageID))
- v.Add("disable_notification", strconv.FormatBool(config.DisableNotification))
+ params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
+ params.AddNonZero("message_id", config.MessageID)
+ params.AddBool("disable_notification", config.DisableNotification)
- return v, nil
+ return params, nil
}
// UnpinChatMessageConfig contains information of chat to unpin.
type UnpinChatMessageConfig struct {
- ChatID int64
+ ChatID int64
+ ChannelUsername string
}
func (config UnpinChatMessageConfig) method() string {
return "unpinChatMessage"
}
-func (config UnpinChatMessageConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config UnpinChatMessageConfig) params() (Params, error) {
+ params := make(Params)
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
+ params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
- return v, nil
+ 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) name() string {
+ return "photo"
+}
+
+func (config SetChatPhotoConfig) getFile() interface{} {
+ return config.File
+}
+
+func (config SetChatPhotoConfig) useExistingFile() bool {
+ return config.UseExisting
+}
+
+// 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 contains information for change chat title.
+// SetChatTitleConfig allows you to set the title of something other than a private chat.
type SetChatTitleConfig struct {
- ChatID int64
- Title string
+ ChatID int64
+ ChannelUsername string
+
+ Title string
}
func (config SetChatTitleConfig) method() string {
return "setChatTitle"
}
-func (config SetChatTitleConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config SetChatTitleConfig) params() (Params, error) {
+ params := make(Params)
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- v.Add("title", config.Title)
+ params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
+ params["title"] = config.Title
- return v, nil
+ return params, nil
}
-// SetChatDescriptionConfig contains information for change chat description.
+// SetChatDescriptionConfig allows you to set the description of a supergroup or channel.
type SetChatDescriptionConfig struct {
- ChatID int64
+ ChatID int64
+ ChannelUsername string
+
Description string
}
@@ -1222,43 +1310,252 @@ func (config SetChatDescriptionConfig) method() string {
return "setChatDescription"
}
-func (config SetChatDescriptionConfig) values() (url.Values, error) {
- v := url.Values{}
+func (config SetChatDescriptionConfig) params() (Params, error) {
+ params := make(Params)
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
- v.Add("description", config.Description)
+ params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
+ params["description"] = config.Description
- return v, nil
+ return params, nil
}
-// SetChatPhotoConfig contains information for change chat photo
-type SetChatPhotoConfig struct {
- BaseFile
+// GetStickerSetConfig allows you to get the stickers in a set.
+type GetStickerSetConfig struct {
+ Name string
}
-// name returns the field name for the Photo.
-func (config SetChatPhotoConfig) name() string {
- return "photo"
+func (config GetStickerSetConfig) method() string {
+ return "getStickerSet"
}
-// method returns Telegram API method name for sending Photo.
-func (config SetChatPhotoConfig) method() string {
- return "setChatPhoto"
+func (config GetStickerSetConfig) params() (Params, error) {
+ params := make(Params)
+
+ params["name"] = config.Name
+
+ return params, nil
}
-// DeleteChatPhotoConfig contains information for delete chat photo.
-type DeleteChatPhotoConfig struct {
- ChatID int64
+// UploadStickerConfig allows you to upload a sticker for use in a set later.
+type UploadStickerConfig struct {
+ UserID int64
+ PNGSticker interface{}
}
-func (config DeleteChatPhotoConfig) method() string {
- return "deleteChatPhoto"
+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) name() string {
+ return "png_sticker"
+}
+
+func (config UploadStickerConfig) getFile() interface{} {
+ return config.PNGSticker
+}
+
+func (config UploadStickerConfig) useExistingFile() bool {
+ return false
}
-func (config DeleteChatPhotoConfig) values() (url.Values, error) {
- v := url.Values{}
+// NewStickerSetConfig allows creating a new sticker set.
+type NewStickerSetConfig struct {
+ UserID int64
+ Name string
+ Title string
+ PNGSticker interface{}
+ 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
+
+ if sticker, ok := config.PNGSticker.(string); ok {
+ params[config.name()] = sticker
+ }
+
+ params["emojis"] = config.Emojis
+
+ params.AddBool("contains_masks", config.ContainsMasks)
+
+ err := params.AddInterface("mask_position", config.MaskPosition)
+
+ return params, err
+}
+
+func (config NewStickerSetConfig) getFile() interface{} {
+ return config.PNGSticker
+}
+
+func (config NewStickerSetConfig) name() string {
+ return "png_sticker"
+}
- v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
+func (config NewStickerSetConfig) useExistingFile() bool {
+ _, ok := config.PNGSticker.(string)
+
+ return ok
+}
+
+// AddStickerConfig allows you to add a sticker to a set.
+type AddStickerConfig struct {
+ UserID int64
+ Name string
+ PNGSticker interface{}
+ 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
+
+ if sticker, ok := config.PNGSticker.(string); ok {
+ params[config.name()] = sticker
+ }
+
+ err := params.AddInterface("mask_position", config.MaskPosition)
+
+ return params, err
+}
+
+func (config AddStickerConfig) name() string {
+ return "png_sticker"
+}
- return v, nil
+func (config AddStickerConfig) getFile() interface{} {
+ return config.PNGSticker
+}
+
+func (config AddStickerConfig) useExistingFile() bool {
+ return false
+}
+
+// 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
+}
+
+// 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)
+ if err := params.AddInterface("media", config.Media); err != nil {
+ return params, nil
+ }
+ params.AddBool("disable_notification", config.DisableNotification)
+ params.AddNonZero("reply_to_message_id", config.ReplyToMessageID)
+
+ return params, nil
}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..b63227e
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/go-telegram-bot-api/telegram-bot-api/v5
+
+require github.com/technoweenie/multipartstreamer v1.0.1
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..8660600
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
+github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
diff --git a/helpers.go b/helpers.go
index 3dabe11..09fc8fd 100644
--- a/helpers.go
+++ b/helpers.go
@@ -294,26 +294,58 @@ func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
// two to ten InputMediaPhoto or InputMediaVideo.
func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
return MediaGroupConfig{
- BaseChat: BaseChat{
- ChatID: chatID,
- },
- InputMedia: files,
+ ChatID: chatID,
+ Media: files,
}
}
// NewInputMediaPhoto creates a new InputMediaPhoto.
func NewInputMediaPhoto(media string) InputMediaPhoto {
return InputMediaPhoto{
- Type: "photo",
- Media: media,
+ BaseInputMedia{
+ Type: "photo",
+ Media: media,
+ },
}
}
// NewInputMediaVideo creates a new InputMediaVideo.
func NewInputMediaVideo(media string) InputMediaVideo {
return InputMediaVideo{
- Type: "video",
- Media: media,
+ BaseInputMedia: BaseInputMedia{
+ Type: "video",
+ Media: media,
+ },
+ }
+}
+
+// NewInputMediaAnimation creates a new InputMediaAnimation.
+func NewInputMediaAnimation(media string) InputMediaAnimation {
+ return InputMediaAnimation{
+ BaseInputMedia: BaseInputMedia{
+ Type: "animation",
+ Media: media,
+ },
+ }
+}
+
+// NewInputMediaAudio creates a new InputMediaAudio.
+func NewInputMediaAudio(media string) InputMediaAudio {
+ return InputMediaAudio{
+ BaseInputMedia: BaseInputMedia{
+ Type: "audio",
+ Media: media,
+ },
+ }
+}
+
+// NewInputMediaDocument creates a new InputMediaDocument.
+func NewInputMediaDocument(media string) InputMediaDocument {
+ return InputMediaDocument{
+ BaseInputMedia: BaseInputMedia{
+ Type: "document",
+ Media: media,
+ },
}
}
@@ -771,7 +803,7 @@ func NewCallbackWithAlert(id, text string) CallbackConfig {
}
// NewInvoice creates a new Invoice request to the user.
-func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig {
+func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig {
return InvoiceConfig{
BaseChat: BaseChat{ChatID: chatID},
Title: title,
@@ -813,3 +845,59 @@ func NewSetChatPhotoShare(chatID int64, fileID string) SetChatPhotoConfig {
},
}
}
+
+// 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 interface{}) 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, photo interface{}) 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,
+ }
+}
+
+// NewStopPoll allows you to stop a poll.
+func NewStopPoll(chatID int64, messageID int) StopPollConfig {
+ return StopPollConfig{
+ BaseEdit{
+ ChatID: chatID,
+ MessageID: messageID,
+ },
+ }
+}
diff --git a/helpers_test.go b/helpers_test.go
index 9542f02..8e4508b 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -1,47 +1,46 @@
-package tgbotapi_test
+package tgbotapi
import (
- "github.com/go-telegram-bot-api/telegram-bot-api"
"testing"
)
func TestNewInlineQueryResultArticle(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultArticle("id", "title", "message")
+ result := NewInlineQueryResultArticle("id", "title", "message")
if result.Type != "article" ||
result.ID != "id" ||
result.Title != "title" ||
- result.InputMessageContent.(tgbotapi.InputTextMessageContent).Text != "message" {
+ result.InputMessageContent.(InputTextMessageContent).Text != "message" {
t.Fail()
}
}
func TestNewInlineQueryResultArticleMarkdown(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultArticleMarkdown("id", "title", "*message*")
+ result := NewInlineQueryResultArticleMarkdown("id", "title", "*message*")
if result.Type != "article" ||
result.ID != "id" ||
result.Title != "title" ||
- result.InputMessageContent.(tgbotapi.InputTextMessageContent).Text != "*message*" ||
- result.InputMessageContent.(tgbotapi.InputTextMessageContent).ParseMode != "Markdown" {
+ result.InputMessageContent.(InputTextMessageContent).Text != "*message*" ||
+ result.InputMessageContent.(InputTextMessageContent).ParseMode != "Markdown" {
t.Fail()
}
}
func TestNewInlineQueryResultArticleHTML(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultArticleHTML("id", "title", "message")
+ result := NewInlineQueryResultArticleHTML("id", "title", "message")
if result.Type != "article" ||
result.ID != "id" ||
result.Title != "title" ||
- result.InputMessageContent.(tgbotapi.InputTextMessageContent).Text != "message" ||
- result.InputMessageContent.(tgbotapi.InputTextMessageContent).ParseMode != "HTML" {
+ result.InputMessageContent.(InputTextMessageContent).Text != "message" ||
+ result.InputMessageContent.(InputTextMessageContent).ParseMode != "HTML" {
t.Fail()
}
}
func TestNewInlineQueryResultGIF(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultGIF("id", "google.com")
+ result := NewInlineQueryResultGIF("id", "google.com")
if result.Type != "gif" ||
result.ID != "id" ||
@@ -51,7 +50,7 @@ func TestNewInlineQueryResultGIF(t *testing.T) {
}
func TestNewInlineQueryResultMPEG4GIF(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultMPEG4GIF("id", "google.com")
+ result := NewInlineQueryResultMPEG4GIF("id", "google.com")
if result.Type != "mpeg4_gif" ||
result.ID != "id" ||
@@ -61,7 +60,7 @@ func TestNewInlineQueryResultMPEG4GIF(t *testing.T) {
}
func TestNewInlineQueryResultPhoto(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultPhoto("id", "google.com")
+ result := NewInlineQueryResultPhoto("id", "google.com")
if result.Type != "photo" ||
result.ID != "id" ||
@@ -71,7 +70,7 @@ func TestNewInlineQueryResultPhoto(t *testing.T) {
}
func TestNewInlineQueryResultPhotoWithThumb(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultPhotoWithThumb("id", "google.com", "thumb.com")
+ result := NewInlineQueryResultPhotoWithThumb("id", "google.com", "thumb.com")
if result.Type != "photo" ||
result.ID != "id" ||
@@ -82,7 +81,7 @@ func TestNewInlineQueryResultPhotoWithThumb(t *testing.T) {
}
func TestNewInlineQueryResultVideo(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultVideo("id", "google.com")
+ result := NewInlineQueryResultVideo("id", "google.com")
if result.Type != "video" ||
result.ID != "id" ||
@@ -92,7 +91,7 @@ func TestNewInlineQueryResultVideo(t *testing.T) {
}
func TestNewInlineQueryResultAudio(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultAudio("id", "google.com", "title")
+ result := NewInlineQueryResultAudio("id", "google.com", "title")
if result.Type != "audio" ||
result.ID != "id" ||
@@ -103,7 +102,7 @@ func TestNewInlineQueryResultAudio(t *testing.T) {
}
func TestNewInlineQueryResultVoice(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultVoice("id", "google.com", "title")
+ result := NewInlineQueryResultVoice("id", "google.com", "title")
if result.Type != "voice" ||
result.ID != "id" ||
@@ -114,7 +113,7 @@ func TestNewInlineQueryResultVoice(t *testing.T) {
}
func TestNewInlineQueryResultDocument(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultDocument("id", "google.com", "title", "mime/type")
+ result := NewInlineQueryResultDocument("id", "google.com", "title", "mime/type")
if result.Type != "document" ||
result.ID != "id" ||
@@ -126,7 +125,7 @@ func TestNewInlineQueryResultDocument(t *testing.T) {
}
func TestNewInlineQueryResultLocation(t *testing.T) {
- result := tgbotapi.NewInlineQueryResultLocation("id", "name", 40, 50)
+ result := NewInlineQueryResultLocation("id", "name", 40, 50)
if result.Type != "location" ||
result.ID != "id" ||
@@ -138,7 +137,7 @@ func TestNewInlineQueryResultLocation(t *testing.T) {
}
func TestNewEditMessageText(t *testing.T) {
- edit := tgbotapi.NewEditMessageText(ChatID, ReplyToMessageID, "new text")
+ edit := NewEditMessageText(ChatID, ReplyToMessageID, "new text")
if edit.Text != "new text" ||
edit.BaseEdit.ChatID != ChatID ||
@@ -148,7 +147,7 @@ func TestNewEditMessageText(t *testing.T) {
}
func TestNewEditMessageCaption(t *testing.T) {
- edit := tgbotapi.NewEditMessageCaption(ChatID, ReplyToMessageID, "new caption")
+ edit := NewEditMessageCaption(ChatID, ReplyToMessageID, "new caption")
if edit.Caption != "new caption" ||
edit.BaseEdit.ChatID != ChatID ||
@@ -158,15 +157,15 @@ func TestNewEditMessageCaption(t *testing.T) {
}
func TestNewEditMessageReplyMarkup(t *testing.T) {
- markup := tgbotapi.InlineKeyboardMarkup{
- InlineKeyboard: [][]tgbotapi.InlineKeyboardButton{
- []tgbotapi.InlineKeyboardButton{
- tgbotapi.InlineKeyboardButton{Text: "test"},
+ markup := InlineKeyboardMarkup{
+ InlineKeyboard: [][]InlineKeyboardButton{
+ []InlineKeyboardButton{
+ InlineKeyboardButton{Text: "test"},
},
},
}
- edit := tgbotapi.NewEditMessageReplyMarkup(ChatID, ReplyToMessageID, markup)
+ edit := NewEditMessageReplyMarkup(ChatID, ReplyToMessageID, markup)
if edit.ReplyMarkup.InlineKeyboard[0][0].Text != "test" ||
edit.BaseEdit.ChatID != ChatID ||
diff --git a/params.go b/params.go
new file mode 100644
index 0000000..599c8eb
--- /dev/null
+++ b/params.go
@@ -0,0 +1,100 @@
+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)
+ }
+}
+
+// AddNonNilBool adds the value of a bool pointer if not nil.
+func (p Params) AddNonNilBool(key string, value *bool) {
+ if value != nil {
+ 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 nill 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)
+ }
+ case int64:
+ if v != 0 {
+ p[key] = strconv.FormatInt(v, 10)
+ }
+ case string:
+ if v != "" {
+ p[key] = v
+ }
+ case nil:
+ default:
+ b, err := json.Marshal(arg)
+ if err != nil {
+ return err
+ }
+
+ p[key] = string(b)
+ }
+ }
+
+ return nil
+}
diff --git a/types.go b/types.go
index c6cd642..de68174 100644
--- a/types.go
+++ b/types.go
@@ -37,6 +37,7 @@ type Update struct {
CallbackQuery *CallbackQuery `json:"callback_query"`
ShippingQuery *ShippingQuery `json:"shipping_query"`
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query"`
+ Poll *Poll `json:"poll"`
}
// UpdatesChannel is the channel for getting updates.
@@ -97,9 +98,12 @@ type Chat struct {
FirstName string `json:"first_name"` // optional
LastName string `json:"last_name"` // optional
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
- Photo *ChatPhoto `json:"photo"`
- Description string `json:"description,omitempty"` // optional
- InviteLink string `json:"invite_link,omitempty"` // optional
+ Photo *ChatPhoto `json:"photo"` // optional
+ Description string `json:"description,omitempty"` // optional
+ InviteLink string `json:"invite_link,omitempty"` // optional
+ PinnedMessage *Message `json:"pinned_message"` // optional
+ StickerSetName string `json:"sticker_set_name"` // optional
+ CanSetStickerSet bool `json:"can_set_sticker_set"` // optional
}
// IsPrivate returns if the Chat is a private conversation.
@@ -137,16 +141,21 @@ type Message struct {
ForwardFrom *User `json:"forward_from"` // optional
ForwardFromChat *Chat `json:"forward_from_chat"` // optional
ForwardFromMessageID int `json:"forward_from_message_id"` // optional
+ ForwardSignature string `json:"forward_signature"` // optional
+ ForwardSenderName string `json:"forward_sender_name"` // optional
ForwardDate int `json:"forward_date"` // optional
ReplyToMessage *Message `json:"reply_to_message"` // optional
EditDate int `json:"edit_date"` // optional
+ MediaGroupID string `json:"media_group_id"` // optional
+ AuthorSignature string `json:"author_signature"` // optional
Text string `json:"text"` // optional
- Entities *[]MessageEntity `json:"entities"` // optional
+ Entities []MessageEntity `json:"entities"` // optional
+ CaptionEntities []MessageEntity `json:"caption_entities"` // optional
Audio *Audio `json:"audio"` // optional
Document *Document `json:"document"` // optional
Animation *ChatAnimation `json:"animation"` // optional
Game *Game `json:"game"` // optional
- Photo *[]PhotoSize `json:"photo"` // optional
+ Photo []PhotoSize `json:"photo"` // optional
Sticker *Sticker `json:"sticker"` // optional
Video *Video `json:"video"` // optional
VideoNote *VideoNote `json:"video_note"` // optional
@@ -155,10 +164,11 @@ type Message struct {
Contact *Contact `json:"contact"` // optional
Location *Location `json:"location"` // optional
Venue *Venue `json:"venue"` // optional
- NewChatMembers *[]User `json:"new_chat_members"` // optional
+ Poll *Poll `json:"poll"` // optional
+ NewChatMembers []User `json:"new_chat_members"` // optional
LeftChatMember *User `json:"left_chat_member"` // optional
NewChatTitle string `json:"new_chat_title"` // optional
- NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
+ NewChatPhoto []PhotoSize `json:"new_chat_photo"` // optional
DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
GroupChatCreated bool `json:"group_chat_created"` // optional
SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
@@ -168,6 +178,7 @@ type Message struct {
PinnedMessage *Message `json:"pinned_message"` // optional
Invoice *Invoice `json:"invoice"` // optional
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
+ ConnectedWebsite string `json:"connected_website"` // optional
PassportData *PassportData `json:"passport_data,omitempty"` // optional
}
@@ -178,11 +189,11 @@ func (m *Message) Time() time.Time {
// IsCommand returns true if message starts with a "bot_command" entity.
func (m *Message) IsCommand() bool {
- if m.Entities == nil || len(*m.Entities) == 0 {
+ if m.Entities == nil || len(m.Entities) == 0 {
return false
}
- entity := (*m.Entities)[0]
+ entity := m.Entities[0]
return entity.Offset == 0 && entity.Type == "bot_command"
}
@@ -212,7 +223,7 @@ func (m *Message) CommandWithAt() string {
}
// IsCommand() checks that the message begins with a bot_command entity
- entity := (*m.Entities)[0]
+ entity := m.Entities[0]
return m.Text[1:entity.Length]
}
@@ -231,7 +242,8 @@ func (m *Message) CommandArguments() string {
}
// IsCommand() checks that the message begins with a bot_command entity
- entity := (*m.Entities)[0]
+ entity := m.Entities[0]
+
if len(m.Text) == entity.Length {
return "" // The command makes up the whole message
}
@@ -286,6 +298,22 @@ type Document struct {
// Sticker contains information about a sticker.
type Sticker struct {
+ FileID string `json:"file_id"`
+ Width int `json:"width"`
+ Height int `json:"height"`
+ Thumbnail *PhotoSize `json:"thumb"` // optional
+ Emoji string `json:"emoji"` // optional
+ SetName string `json:"set_name"` // optional
+ MaskPosition MaskPosition `json:"mask_position"` //optional
+ FileSize int `json:"file_size"` // optional
+}
+
+// MaskPosition is the position of a mask.
+type MaskPosition struct {
+ Point string `json:"point"`
+ XShift float32 `json:"x_shift"`
+ YShift float32 `json:"y_shift"`
+ Scale float32 `json:"scale"`
FileID string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
@@ -343,6 +371,7 @@ type Contact struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"` // optional
UserID int `json:"user_id"` // optional
+ VCard string `json:"vcard"` // optional
}
// Location contains information about a place.
@@ -359,6 +388,20 @@ type Venue struct {
FoursquareID string `json:"foursquare_id"` // optional
}
+// PollOption contains information about one answer option in a poll.
+type PollOption struct {
+ Text string `json:"text"`
+ VoterCount int `json:"voter_count"`
+}
+
+// Poll contains information about a poll.
+type Poll struct {
+ ID string `json:"id"`
+ Question string `json:"question"`
+ Options []PollOption `json:"options"`
+ IsClosed bool `json:"is_closed"`
+}
+
// UserProfilePhotos contains a set of user profile photos.
type UserProfilePhotos struct {
TotalCount int `json:"total_count"`
@@ -461,6 +504,7 @@ type ChatMember struct {
CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // optional
CanPinMessages bool `json:"can_pin_messages,omitempty"` // optional
CanPromoteMembers bool `json:"can_promote_members,omitempty"` // optional
+ IsChatMember bool `json:"is_member"` // optional
CanSendMessages bool `json:"can_send_messages,omitempty"` // optional
CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` // optional
CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` // optional
@@ -525,27 +569,6 @@ func (info WebhookInfo) IsSet() bool {
return info.URL != ""
}
-// InputMediaPhoto contains a photo for displaying as part of a media group.
-type InputMediaPhoto struct {
- Type string `json:"type"`
- Media string `json:"media"`
- Caption string `json:"caption"`
- ParseMode string `json:"parse_mode"`
-}
-
-// InputMediaVideo contains a video for displaying as part of a media group.
-type InputMediaVideo struct {
- Type string `json:"type"`
- Media string `json:"media"`
- // thumb intentionally missing as it is not currently compatible
- Caption string `json:"caption"`
- ParseMode string `json:"parse_mode"`
- Width int `json:"width"`
- Height int `json:"height"`
- Duration int `json:"duration"`
- SupportsStreaming bool `json:"supports_streaming"`
-}
-
// InlineQuery is a Query from Telegram for an inline request.
type InlineQuery struct {
ID string `json:"id"`
@@ -763,11 +786,27 @@ type InlineQueryResultCachedDocument struct {
// InlineQueryResultLocation is an inline query response location.
type InlineQueryResultLocation struct {
- Type string `json:"type"` // required
- ID string `json:"id"` // required
- Latitude float64 `json:"latitude"` // required
- Longitude float64 `json:"longitude"` // required
- Title string `json:"title"` // required
+ Type string `json:"type"` // required
+ ID string `json:"id"` // required
+ Latitude float64 `json:"latitude"` // required
+ Longitude float64 `json:"longitude"` // required
+ LivePeriod int `json:"live_period"` // optional
+ Title string `json:"title"` // required
+ 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"`
+}
+
+// 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"`
@@ -823,6 +862,7 @@ type InputContactMessageContent struct {
PhoneNumber string `json:"phone_number"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
+ VCard string `json:"vcard"`
}
// Invoice contains basic information about an invoice.
@@ -860,9 +900,9 @@ type OrderInfo struct {
// ShippingOption represents one shipping option.
type ShippingOption struct {
- ID string `json:"id"`
- Title string `json:"title"`
- Prices *[]LabeledPrice `json:"prices"`
+ ID string `json:"id"`
+ Title string `json:"title"`
+ Prices []LabeledPrice `json:"prices"`
}
// SuccessfulPayment contains basic information about a successful payment.
@@ -895,12 +935,64 @@ type PreCheckoutQuery struct {
OrderInfo *OrderInfo `json:"order_info,omitempty"`
}
+// StickerSet is a collection of stickers.
+type StickerSet struct {
+ Name string `json:"name"`
+ Title string `json:"title"`
+ ContainsMasks bool `json:"contains_masks"`
+ Stickers []Sticker `json:"stickers"`
+}
+
+// BaseInputMedia is a base type for the InputMedia types.
+type BaseInputMedia struct {
+ Type string `json:"type"`
+ Media string `json:"media"`
+ Caption string `json:"caption"`
+ ParseMode string `json:"parse_mode"`
+}
+
+// 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
+ Width int `json:"width"`
+ Height int `json:"height"`
+ Duration int `json:"duration"`
+ SupportsStreaming bool `json:"supports_streaming"`
+}
+
+// InputMediaAnimation is an animation to send as part of a media group.
+type InputMediaAnimation struct {
+ BaseInputMedia
+ Width int `json:"width"`
+ Height int `json:"height"`
+ Duration int `json:"duration"`
+}
+
+// InputMediaAudio is a audio to send as part of a media group.
+type InputMediaAudio struct {
+ BaseInputMedia
+ Duration int `json:"duration"`
+ Performer string `json:"performer"`
+ Title string `json:"title"`
+}
+
+// InputMediaDocument is a audio to send as part of a media group.
+type InputMediaDocument struct {
+ BaseInputMedia
+}
+
// Error is an error containing extra information returned by the Telegram API.
type Error struct {
Message string
ResponseParameters
}
+// Error message string.
func (e Error) Error() string {
return e.Message
}
diff --git a/types_test.go b/types_test.go
index bb7bb64..b418874 100644
--- a/types_test.go
+++ b/types_test.go
@@ -1,14 +1,12 @@
-package tgbotapi_test
+package tgbotapi
import (
"testing"
"time"
-
- "github.com/go-telegram-bot-api/telegram-bot-api"
)
func TestUserStringWith(t *testing.T) {
- user := tgbotapi.User{
+ user := User{
ID: 0,
FirstName: "Test",
LastName: "Test",
@@ -23,7 +21,7 @@ func TestUserStringWith(t *testing.T) {
}
func TestUserStringWithUserName(t *testing.T) {
- user := tgbotapi.User{
+ user := User{
ID: 0,
FirstName: "Test",
LastName: "Test",
@@ -37,7 +35,7 @@ func TestUserStringWithUserName(t *testing.T) {
}
func TestMessageTime(t *testing.T) {
- message := tgbotapi.Message{Date: 0}
+ message := Message{Date: 0}
date := time.Unix(0, 0)
if message.Time() != date {
@@ -46,33 +44,33 @@ func TestMessageTime(t *testing.T) {
}
func TestMessageIsCommandWithCommand(t *testing.T) {
- message := tgbotapi.Message{Text: "/command"}
- message.Entities = &[]tgbotapi.MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
+ message := Message{Text: "/command"}
+ message.Entities = []MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
- if message.IsCommand() != true {
+ if !message.IsCommand() {
t.Fail()
}
}
func TestIsCommandWithText(t *testing.T) {
- message := tgbotapi.Message{Text: "some text"}
+ message := Message{Text: "some text"}
- if message.IsCommand() != false {
+ if message.IsCommand() {
t.Fail()
}
}
func TestIsCommandWithEmptyText(t *testing.T) {
- message := tgbotapi.Message{Text: ""}
+ message := Message{Text: ""}
- if message.IsCommand() != false {
+ if message.IsCommand() {
t.Fail()
}
}
func TestCommandWithCommand(t *testing.T) {
- message := tgbotapi.Message{Text: "/command"}
- message.Entities = &[]tgbotapi.MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
+ message := Message{Text: "/command"}
+ message.Entities = []MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
if message.Command() != "command" {
t.Fail()
@@ -80,7 +78,7 @@ func TestCommandWithCommand(t *testing.T) {
}
func TestCommandWithEmptyText(t *testing.T) {
- message := tgbotapi.Message{Text: ""}
+ message := Message{Text: ""}
if message.Command() != "" {
t.Fail()
@@ -88,7 +86,7 @@ func TestCommandWithEmptyText(t *testing.T) {
}
func TestCommandWithNonCommand(t *testing.T) {
- message := tgbotapi.Message{Text: "test text"}
+ message := Message{Text: "test text"}
if message.Command() != "" {
t.Fail()
@@ -96,8 +94,8 @@ func TestCommandWithNonCommand(t *testing.T) {
}
func TestCommandWithBotName(t *testing.T) {
- message := tgbotapi.Message{Text: "/command@testbot"}
- message.Entities = &[]tgbotapi.MessageEntity{{Type: "bot_command", Offset: 0, Length: 16}}
+ message := Message{Text: "/command@testbot"}
+ message.Entities = []MessageEntity{{Type: "bot_command", Offset: 0, Length: 16}}
if message.Command() != "command" {
t.Fail()
@@ -105,8 +103,8 @@ func TestCommandWithBotName(t *testing.T) {
}
func TestCommandWithAtWithBotName(t *testing.T) {
- message := tgbotapi.Message{Text: "/command@testbot"}
- message.Entities = &[]tgbotapi.MessageEntity{{Type: "bot_command", Offset: 0, Length: 16}}
+ message := Message{Text: "/command@testbot"}
+ message.Entities = []MessageEntity{{Type: "bot_command", Offset: 0, Length: 16}}
if message.CommandWithAt() != "command@testbot" {
t.Fail()
@@ -114,37 +112,37 @@ func TestCommandWithAtWithBotName(t *testing.T) {
}
func TestMessageCommandArgumentsWithArguments(t *testing.T) {
- message := tgbotapi.Message{Text: "/command with arguments"}
- message.Entities = &[]tgbotapi.MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
+ message := Message{Text: "/command with arguments"}
+ message.Entities = []MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
if message.CommandArguments() != "with arguments" {
t.Fail()
}
}
func TestMessageCommandArgumentsWithMalformedArguments(t *testing.T) {
- message := tgbotapi.Message{Text: "/command-without argument space"}
- message.Entities = &[]tgbotapi.MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
+ message := Message{Text: "/command-without argument space"}
+ message.Entities = []MessageEntity{{Type: "bot_command", Offset: 0, Length: 8}}
if message.CommandArguments() != "without argument space" {
t.Fail()
}
}
func TestMessageCommandArgumentsWithoutArguments(t *testing.T) {
- message := tgbotapi.Message{Text: "/command"}
+ message := Message{Text: "/command"}
if message.CommandArguments() != "" {
t.Fail()
}
}
func TestMessageCommandArgumentsForNonCommand(t *testing.T) {
- message := tgbotapi.Message{Text: "test text"}
+ message := Message{Text: "test text"}
if message.CommandArguments() != "" {
t.Fail()
}
}
func TestMessageEntityParseURLGood(t *testing.T) {
- entity := tgbotapi.MessageEntity{URL: "https://www.google.com"}
+ entity := MessageEntity{URL: "https://www.google.com"}
if _, err := entity.ParseURL(); err != nil {
t.Fail()
@@ -152,7 +150,7 @@ func TestMessageEntityParseURLGood(t *testing.T) {
}
func TestMessageEntityParseURLBad(t *testing.T) {
- entity := tgbotapi.MessageEntity{URL: ""}
+ entity := MessageEntity{URL: ""}
if _, err := entity.ParseURL(); err == nil {
t.Fail()
@@ -160,31 +158,31 @@ func TestMessageEntityParseURLBad(t *testing.T) {
}
func TestChatIsPrivate(t *testing.T) {
- chat := tgbotapi.Chat{ID: 10, Type: "private"}
+ chat := Chat{ID: 10, Type: "private"}
- if chat.IsPrivate() != true {
+ if !chat.IsPrivate() {
t.Fail()
}
}
func TestChatIsGroup(t *testing.T) {
- chat := tgbotapi.Chat{ID: 10, Type: "group"}
+ chat := Chat{ID: 10, Type: "group"}
- if chat.IsGroup() != true {
+ if !chat.IsGroup() {
t.Fail()
}
}
func TestChatIsChannel(t *testing.T) {
- chat := tgbotapi.Chat{ID: 10, Type: "channel"}
+ chat := Chat{ID: 10, Type: "channel"}
- if chat.IsChannel() != true {
+ if !chat.IsChannel() {
t.Fail()
}
}
func TestChatIsSuperGroup(t *testing.T) {
- chat := tgbotapi.Chat{ID: 10, Type: "supergroup"}
+ chat := Chat{ID: 10, Type: "supergroup"}
if !chat.IsSuperGroup() {
t.Fail()
@@ -192,9 +190,50 @@ func TestChatIsSuperGroup(t *testing.T) {
}
func TestFileLink(t *testing.T) {
- file := tgbotapi.File{FilePath: "test/test.txt"}
+ file := File{FilePath: "test/test.txt"}
if file.Link("token") != "https://api.telegram.org/file/bottoken/test/test.txt" {
t.Fail()
}
}
+
+// Ensure all configs are sendable
+var (
+ _ Chattable = AnimationConfig{}
+ _ Chattable = AudioConfig{}
+ _ Chattable = CallbackConfig{}
+ _ Chattable = ChatActionConfig{}
+ _ Chattable = ContactConfig{}
+ _ Chattable = DeleteChatPhotoConfig{}
+ _ Chattable = DeleteChatStickerSetConfig{}
+ _ Chattable = DeleteMessageConfig{}
+ _ Chattable = DocumentConfig{}
+ _ Chattable = EditMessageCaptionConfig{}
+ _ Chattable = EditMessageLiveLocationConfig{}
+ _ Chattable = EditMessageReplyMarkupConfig{}
+ _ Chattable = EditMessageTextConfig{}
+ _ Chattable = ForwardConfig{}
+ _ Chattable = GameConfig{}
+ _ Chattable = GetGameHighScoresConfig{}
+ _ Chattable = InlineConfig{}
+ _ Chattable = InvoiceConfig{}
+ _ Chattable = KickChatMemberConfig{}
+ _ Chattable = LocationConfig{}
+ _ Chattable = MediaGroupConfig{}
+ _ Chattable = MessageConfig{}
+ _ Chattable = PhotoConfig{}
+ _ Chattable = PinChatMessageConfig{}
+ _ Chattable = SetChatDescriptionConfig{}
+ _ Chattable = SetChatPhotoConfig{}
+ _ Chattable = SetChatTitleConfig{}
+ _ Chattable = SetGameScoreConfig{}
+ _ Chattable = StickerConfig{}
+ _ Chattable = UnpinChatMessageConfig{}
+ _ Chattable = UpdateConfig{}
+ _ Chattable = UserProfilePhotosConfig{}
+ _ Chattable = VenueConfig{}
+ _ Chattable = VideoConfig{}
+ _ Chattable = VideoNoteConfig{}
+ _ Chattable = VoiceConfig{}
+ _ Chattable = WebhookConfig{}
+)