Bot API 3.2, introduce Request to replace APIResponse methods.
Syfaro syfaro@huefox.com
Fri, 29 Dec 2017 00:44:47 -0600
4 files changed,
433 insertions(+),
158 deletions(-)
M
bot.go
→
bot.go
@@ -109,21 +109,6 @@
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.@@ -262,86 +247,55 @@ // 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() - + resp, err := bot.Request(c) if err != nil { return Message{}, err } - message, err := bot.makeMessageRequest(method, v) - if err != nil { - return Message{}, err - } + var message Message + err = json.Unmarshal(resp.Result, &message) - return message, nil + return message, err } -// 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 - } - - file := config.getFile() - - resp, err := bot.UploadFile(method, params, config.name(), file) - if err != nil { - return Message{}, err - } +// Request makes a request to Telegram that returns an APIResponse, rather than +// a Message. +func (bot *BotAPI) Request(c Chattable) (APIResponse, error) { + switch t := c.(type) { + case Fileable: + if t.useExistingFile() { + v, err := t.values() + if err != nil { + return APIResponse{}, err + } - var message Message - json.Unmarshal(resp.Result, &message) + return bot.MakeRequest(t.method(), v) + } - bot.debugLog(method, nil, message) + p, err := t.params() + if err != nil { + return APIResponse{}, err + } - return message, nil -} + return bot.UploadFile(t.method(), p, t.name(), t.getFile()) + default: + v, err := c.values() + if err != nil { + return APIResponse{}, 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) + return bot.MakeRequest(c.method(), v) } - - return bot.uploadAndSend(config.method(), config) } -// sendChattable sends a Chattable. -func (bot *BotAPI) sendChattable(config Chattable) (Message, error) { - v, err := config.values() - if err != nil { - return Message{}, err +// 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) } - - message, err := bot.makeMessageRequest(config.method(), v) - - if err != nil { - return Message{}, err - } - - return message, nil } // GetUserProfilePhotos gets a user's profile photos.@@ -423,11 +377,6 @@
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!@@ -435,7 +384,6 @@ //
// 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())@@ -806,54 +754,6 @@
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{}@@ -875,26 +775,20 @@
return inviteLink, err } -// PinChatMessage pin message in supergroup -func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) { +// GetStickerSet returns a StickerSet. +func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { v, err := config.values() if err != nil { - return APIResponse{}, err + return StickerSet{}, nil } - 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() + resp, err := bot.MakeRequest(config.method(), v) if err != nil { - return APIResponse{}, err + return StickerSet{}, nil } - bot.debugLog(config.method(), v, nil) + var stickers StickerSet + err = json.Unmarshal(resp.Result, &stickers) - return bot.MakeRequest(config.method(), v) + return stickers, err }
M
bot_test.go
→
bot_test.go
@@ -420,7 +420,7 @@
func TestSendChatConfig(t *testing.T) { bot, _ := getBot(t) - _, err := bot.Send(tgbotapi.NewChatAction(ChatID, tgbotapi.ChatTyping)) + _, err := bot.Request(tgbotapi.NewChatAction(ChatID, tgbotapi.ChatTyping)) if err != nil { t.Error(err)
M
configs.go
→
configs.go
@@ -842,6 +842,18 @@ Certificate interface{}
MaxConnections int } +// RemoveWebhookConfig is a helper to remove a webhook. +type RemoveWebhookConfig struct { +} + +func (config RemoveWebhookConfig) method() string { + return "setWebhook" +} + +func (config RemoveWebhookConfig) values() (url.Values, error) { + return url.Values{}, nil +} + // FileBytes contains information about a set of bytes to upload // as a File. type FileBytes struct {@@ -1038,8 +1050,8 @@ }
// PinChatMessageConfig contains information of a message in a chat to pin. type PinChatMessageConfig struct { - ChatID int64 - MessageID int + ChatID int64 + MessageID int DisableNotification bool }@@ -1072,4 +1084,355 @@
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) return v, nil -}+} + +// SetChatPhotoConfig allows you to set a group, supergroup, or channel's photo. +type SetChatPhotoConfig struct { + ChatID int64 + ChannelUsername string + + Photo interface{} +} + +func (config SetChatPhotoConfig) method() string { + return "setChatPhoto" +} + +func (config SetChatPhotoConfig) name() string { + return "photo" +} + +func (config SetChatPhotoConfig) values() (url.Values, error) { + v := url.Values{} + + if config.ChannelUsername == "" { + v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) + } else { + v.Add("chat_id", config.ChannelUsername) + } + + return v, nil +} + +func (config SetChatPhotoConfig) params() map[string]string { + params := make(map[string]string) + + if config.ChannelUsername == "" { + params["chat_id"] = strconv.FormatInt(config.ChatID, 10) + } else { + params["chat_id"] = config.ChannelUsername + } + + return params +} + +func (config SetChatPhotoConfig) getFile() interface{} { + return config.Photo +} + +func (config SetChatPhotoConfig) useExistingFile() bool { + return false +} + +// 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) values() (url.Values, error) { + v := url.Values{} + + if config.ChannelUsername == "" { + v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) + } else { + v.Add("chat_id", config.ChannelUsername) + } + + return v, nil +} + +// SetChatTitleConfig allows you to set the title of something other than a private chat. +type SetChatTitleConfig struct { + ChatID int64 + ChannelUsername string + + Title string +} + +func (config SetChatTitleConfig) method() string { + return "setChatTitle" +} + +func (config SetChatTitleConfig) values() (url.Values, error) { + v := url.Values{} + + if config.ChannelUsername == "" { + v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) + } else { + v.Add("chat_id", config.ChannelUsername) + } + + v.Add("title", config.Title) + + return v, nil +} + +// SetChatDescriptionConfig allows you to set the description of a supergroup or channel. +type SetChatDescriptionConfig struct { + ChatID int64 + ChannelUsername string + + Description string +} + +func (config SetChatDescriptionConfig) method() string { + return "setChatDescription" +} + +func (config SetChatDescriptionConfig) values() (url.Values, error) { + v := url.Values{} + + if config.ChannelUsername == "" { + v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) + } else { + v.Add("chat_id", config.ChannelUsername) + } + + v.Add("description", config.Description) + + return v, nil +} + +// GetStickerSetConfig allows you to get the stickers in a set. +type GetStickerSetConfig struct { + Name string +} + +func (config GetStickerSetConfig) method() string { + return "getStickerSet" +} + +func (config GetStickerSetConfig) values() (url.Values, error) { + v := url.Values{} + + v.Add("name", config.Name) + + return v, nil +} + +// UploadStickerConfig allows you to upload a sticker for use in a set later. +type UploadStickerConfig struct { + UserID int64 + PNGSticker interface{} +} + +func (config UploadStickerConfig) method() string { + return "uploadStickerFile" +} + +func (config UploadStickerConfig) values() (url.Values, error) { + v := url.Values{} + + v.Add("user_id", strconv.FormatInt(config.UserID, 10)) + + return v, nil +} + +func (config UploadStickerConfig) params() (map[string]string, error) { + params := make(map[string]string) + + params["user_id"] = strconv.FormatInt(config.UserID, 10) + + 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 +} + +// 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) values() (url.Values, error) { + v := url.Values{} + + v.Add("user_id", strconv.FormatInt(config.UserID, 10)) + v.Add("name", config.Name) + v.Add("title", config.Title) + if sticker, ok := config.PNGSticker.(string); ok { + v.Add("png_sticker", sticker) + } + v.Add("emojis", config.Emojis) + if config.ContainsMasks { + v.Add("contains_masks", strconv.FormatBool(config.ContainsMasks)) + + data, err := json.Marshal(config.MaskPosition) + if err != nil { + return v, err + } + + v.Add("mask_position", string(data)) + } + + return v, nil +} + +func (config NewStickerSetConfig) params() (map[string]string, error) { + params := make(map[string]string) + + params["user_id"] = strconv.FormatInt(config.UserID, 10) + params["name"] = config.Name + params["title"] = config.Title + params["emojis"] = config.Emojis + if config.ContainsMasks { + params["contains_masks"] = strconv.FormatBool(config.ContainsMasks) + + data, err := json.Marshal(config.MaskPosition) + if err != nil { + return params, err + } + + params["mask_position"] = string(data) + } + + return params, nil +} + +func (config NewStickerSetConfig) getFile() interface{} { + return config.PNGSticker +} + +func (config NewStickerSetConfig) name() string { + return "png_sticker" +} + +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) values() (url.Values, error) { + v := url.Values{} + + v.Add("user_id", strconv.FormatInt(config.UserID, 10)) + v.Add("name", config.Name) + if sticker, ok := config.PNGSticker.(string); ok { + v.Add("png_sticker", sticker) + } + v.Add("emojis", config.Emojis) + if config.MaskPosition != nil { + data, err := json.Marshal(config.MaskPosition) + if err != nil { + return v, err + } + + v.Add("mask_position", string(data)) + } + + return v, nil +} + +func (config AddStickerConfig) params() (map[string]string, error) { + params := make(map[string]string) + + params["user_id"] = strconv.FormatInt(config.UserID, 10) + params["name"] = config.Name + params["emojis"] = config.Emojis + if config.MaskPosition != nil { + data, err := json.Marshal(config.MaskPosition) + if err != nil { + return params, err + } + + params["mask_position"] = string(data) + } + + return params, nil +} + +func (config AddStickerConfig) name() string { + return "png_sticker" +} + +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) values() (url.Values, error) { + v := url.Values{} + + v.Add("sticker", config.Sticker) + v.Add("position", strconv.Itoa(config.Position)) + + return v, 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) values() (url.Values, error) { + v := url.Values{} + + v.Add("sticker", config.Sticker) + + return v, nil +}
M
types.go
→
types.go
@@ -285,12 +285,22 @@ }
// Sticker contains information about a sticker. type Sticker struct { - FileID string `json:"file_id"` - Width int `json:"width"` - Height int `json:"height"` - Thumbnail *PhotoSize `json:"thumb"` // optional - Emoji string `json:"emoji"` // optional - FileSize int `json:"file_size"` // optional + 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"` } // Video contains information about a video.@@ -772,3 +782,11 @@ InvoicePayload string `json:"invoice_payload"`
ShippingOptionID string `json:"shipping_option_id,omitempty"` 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"` +}