Merge branch 'master' of https://github.com/go-telegram-bot-api/telegram-bot-api into wehook-validation
commit
20b57111fc
|
@ -3,4 +3,6 @@ language: go
|
||||||
go:
|
go:
|
||||||
- '1.10'
|
- '1.10'
|
||||||
- '1.11'
|
- '1.11'
|
||||||
|
- '1.12'
|
||||||
|
- '1.13'
|
||||||
- tip
|
- tip
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
||||||
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
||||||
|
|
||||||
All methods are fairly self explanatory, and reading the godoc page should
|
All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should
|
||||||
explain everything. If something isn't clear, open an issue or submit
|
explain everything. If something isn't clear, open an issue or submit
|
||||||
a pull request.
|
a pull request.
|
||||||
|
|
||||||
|
|
123
bot.go
123
bot.go
|
@ -19,6 +19,10 @@ import (
|
||||||
"github.com/technoweenie/multipartstreamer"
|
"github.com/technoweenie/multipartstreamer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HttpClient interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
// BotAPI allows you to interact with the Telegram Bot API.
|
// BotAPI allows you to interact with the Telegram Bot API.
|
||||||
type BotAPI struct {
|
type BotAPI struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
@ -26,7 +30,7 @@ type BotAPI struct {
|
||||||
Buffer int `json:"buffer"`
|
Buffer int `json:"buffer"`
|
||||||
|
|
||||||
Self User `json:"-"`
|
Self User `json:"-"`
|
||||||
Client *http.Client `json:"-"`
|
Client HttpClient `json:"-"`
|
||||||
shutdownChannel chan interface{}
|
shutdownChannel chan interface{}
|
||||||
|
|
||||||
apiEndpoint string
|
apiEndpoint string
|
||||||
|
@ -36,21 +40,29 @@ type BotAPI struct {
|
||||||
//
|
//
|
||||||
// It requires a token, provided by @BotFather on Telegram.
|
// It requires a token, provided by @BotFather on Telegram.
|
||||||
func NewBotAPI(token string) (*BotAPI, error) {
|
func NewBotAPI(token string) (*BotAPI, error) {
|
||||||
return NewBotAPIWithClient(token, &http.Client{})
|
return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
|
||||||
|
// and allows you to pass API endpoint.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
|
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
|
||||||
|
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBotAPIWithClient creates a new BotAPI instance
|
// NewBotAPIWithClient creates a new BotAPI instance
|
||||||
// and allows you to pass a http.Client.
|
// and allows you to pass a http.Client.
|
||||||
//
|
//
|
||||||
// It requires a token, provided by @BotFather on Telegram.
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, error) {
|
||||||
bot := &BotAPI{
|
bot := &BotAPI{
|
||||||
Token: token,
|
Token: token,
|
||||||
Client: client,
|
Client: client,
|
||||||
Buffer: 100,
|
Buffer: 100,
|
||||||
shutdownChannel: make(chan interface{}),
|
shutdownChannel: make(chan interface{}),
|
||||||
|
|
||||||
apiEndpoint: APIEndpoint,
|
apiEndpoint: apiEndpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
self, err := bot.GetMe()
|
self, err := bot.GetMe()
|
||||||
|
@ -63,15 +75,22 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
||||||
return bot, nil
|
return bot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BotAPI) SetAPIEndpoint(apiEndpoint string) {
|
// SetAPIEndpoint add telegram apiEndpont to Bot
|
||||||
b.apiEndpoint = apiEndpoint
|
func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
|
||||||
|
bot.apiEndpoint = apiEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeRequest makes a request to a specific endpoint with our token.
|
// 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 url.Values) (APIResponse, error) {
|
||||||
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||||
|
|
||||||
resp, err := bot.Client.PostForm(method, params)
|
req, err := http.NewRequest("POST", method, strings.NewReader(params.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return APIResponse{}, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
resp, err := bot.Client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return APIResponse{}, err
|
||||||
}
|
}
|
||||||
|
@ -92,7 +111,7 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse,
|
||||||
if apiResp.Parameters != nil {
|
if apiResp.Parameters != nil {
|
||||||
parameters = *apiResp.Parameters
|
parameters = *apiResp.Parameters
|
||||||
}
|
}
|
||||||
return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
|
return apiResp, &Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiResp, nil
|
return apiResp, nil
|
||||||
|
@ -226,7 +245,11 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
|
||||||
}
|
}
|
||||||
|
|
||||||
if !apiResp.Ok {
|
if !apiResp.Ok {
|
||||||
return APIResponse{}, errors.New(apiResp.Description)
|
parameters := ResponseParameters{}
|
||||||
|
if apiResp.Parameters != nil {
|
||||||
|
parameters = *apiResp.Parameters
|
||||||
|
}
|
||||||
|
return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiResp, nil
|
return apiResp, nil
|
||||||
|
@ -438,7 +461,7 @@ func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
||||||
|
|
||||||
// RemoveWebhook unsets the webhook.
|
// RemoveWebhook unsets the webhook.
|
||||||
func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
|
func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
|
||||||
return bot.MakeRequest("setWebhook", url.Values{})
|
return bot.MakeRequest("deleteWebhook", url.Values{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWebhook sets a webhook.
|
// SetWebhook sets a webhook.
|
||||||
|
@ -495,6 +518,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-bot.shutdownChannel:
|
case <-bot.shutdownChannel:
|
||||||
|
close(ch)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
@ -533,40 +557,46 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
||||||
ch := make(chan Update, bot.Buffer)
|
ch := make(chan Update, bot.Buffer)
|
||||||
|
|
||||||
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != http.MethodPost {
|
update, err := bot.HandleUpdate(r)
|
||||||
errMsg, _ := json.Marshal(map[string]string{"error": "Wrong HTTP method, required POST"})
|
|
||||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.Write(errMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write(errMsg)
|
_, _ = w.Write(errMsg)
|
||||||
return
|
|
||||||
}
|
|
||||||
r.Body.Close()
|
|
||||||
|
|
||||||
var update Update
|
|
||||||
err = json.Unmarshal(bytes, &update)
|
|
||||||
if err != nil {
|
|
||||||
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.Write(errMsg)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- update
|
ch <- *update
|
||||||
})
|
})
|
||||||
|
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleUpdate parses and returns update received via webhook
|
||||||
|
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
err := errors.New("wrong HTTP method required POST")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.Body.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var update Update
|
||||||
|
err = json.Unmarshal(payload, &update)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &update, nil
|
||||||
|
}
|
||||||
|
|
||||||
// AnswerInlineQuery sends a response to an inline query.
|
// AnswerInlineQuery sends a response to an inline query.
|
||||||
//
|
//
|
||||||
// Note that you must respond to an inline query within 30 seconds.
|
// Note that you must respond to an inline query within 30 seconds.
|
||||||
|
@ -762,9 +792,9 @@ func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RestrictChatMember to restrict a user in a supergroup. The bot must be an
|
// 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
|
// administrator in the supergroup for this to work and must have the
|
||||||
//appropriate admin rights. Pass True for all boolean parameters to lift
|
// appropriate admin rights. Pass True for all boolean parameters to lift
|
||||||
//restrictions from a user. Returns True on success.
|
// restrictions from a user. Returns True on success.
|
||||||
func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
|
func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
|
|
||||||
|
@ -884,7 +914,7 @@ func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse
|
||||||
v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
|
v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
|
||||||
v.Add("ok", strconv.FormatBool(config.OK))
|
v.Add("ok", strconv.FormatBool(config.OK))
|
||||||
if config.OK != true {
|
if config.OK != true {
|
||||||
v.Add("error", config.ErrorMessage)
|
v.Add("error_message", config.ErrorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.debugLog("answerPreCheckoutQuery", v, nil)
|
bot.debugLog("answerPreCheckoutQuery", v, nil)
|
||||||
|
@ -996,3 +1026,22 @@ func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, e
|
||||||
|
|
||||||
return bot.MakeRequest(config.method(), v)
|
return bot.MakeRequest(config.method(), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStickerSet get a sticker set.
|
||||||
|
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
||||||
|
v, err := config.values()
|
||||||
|
if err != nil {
|
||||||
|
return StickerSet{}, err
|
||||||
|
}
|
||||||
|
bot.debugLog(config.method(), v, nil)
|
||||||
|
res, err := bot.MakeRequest(config.method(), v)
|
||||||
|
if err != nil {
|
||||||
|
return StickerSet{}, err
|
||||||
|
}
|
||||||
|
stickerSet := StickerSet{}
|
||||||
|
err = json.Unmarshal(res.Result, &stickerSet)
|
||||||
|
if err != nil {
|
||||||
|
return StickerSet{}, err
|
||||||
|
}
|
||||||
|
return stickerSet, nil
|
||||||
|
}
|
||||||
|
|
65
bot_test.go
65
bot_test.go
|
@ -8,7 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -402,6 +402,32 @@ func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendWithDice(t *testing.T) {
|
||||||
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
|
msg := tgbotapi.NewDice(ChatID)
|
||||||
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendWithDiceWithEmoji(t *testing.T) {
|
||||||
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
|
msg := tgbotapi.NewDiceWithEmoji(ChatID, "🏀")
|
||||||
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetFile(t *testing.T) {
|
func TestGetFile(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
|
@ -497,6 +523,9 @@ func TestSetWebhookWithoutCert(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
if info.MaxConnections == 0 {
|
||||||
|
t.Errorf("Expected maximum connections to be greater than 0")
|
||||||
|
}
|
||||||
if info.LastErrorDate != 0 {
|
if info.LastErrorDate != 0 {
|
||||||
t.Errorf("[Telegram callback failed]%s", info.LastErrorMessage)
|
t.Errorf("[Telegram callback failed]%s", info.LastErrorMessage)
|
||||||
}
|
}
|
||||||
|
@ -593,6 +622,40 @@ func ExampleNewWebhook() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleWebhookHandler() {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.HandleFunc("/"+bot.Token, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
update, err := bot.HandleUpdate(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%+v\n", err.Error())
|
||||||
|
} else {
|
||||||
|
log.Printf("%+v\n", *update)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleAnswerInlineQuery() {
|
func ExampleAnswerInlineQuery() {
|
||||||
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") // create new bot
|
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") // create new bot
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
49
configs.go
49
configs.go
|
@ -37,6 +37,7 @@ const (
|
||||||
// Constant values for ParseMode in MessageConfig
|
// Constant values for ParseMode in MessageConfig
|
||||||
const (
|
const (
|
||||||
ModeMarkdown = "Markdown"
|
ModeMarkdown = "Markdown"
|
||||||
|
ModeMarkdownV2 = "MarkdownV2"
|
||||||
ModeHTML = "HTML"
|
ModeHTML = "HTML"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1138,6 +1139,7 @@ type PreCheckoutConfig struct {
|
||||||
|
|
||||||
// DeleteMessageConfig contains information of a message in a chat to delete.
|
// DeleteMessageConfig contains information of a message in a chat to delete.
|
||||||
type DeleteMessageConfig struct {
|
type DeleteMessageConfig struct {
|
||||||
|
ChannelUsername string
|
||||||
ChatID int64
|
ChatID int64
|
||||||
MessageID int
|
MessageID int
|
||||||
}
|
}
|
||||||
|
@ -1149,7 +1151,12 @@ func (config DeleteMessageConfig) method() string {
|
||||||
func (config DeleteMessageConfig) values() (url.Values, error) {
|
func (config DeleteMessageConfig) values() (url.Values, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.ChannelUsername == "" {
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
}
|
||||||
|
|
||||||
v.Add("message_id", strconv.Itoa(config.MessageID))
|
v.Add("message_id", strconv.Itoa(config.MessageID))
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
@ -1262,3 +1269,45 @@ func (config DeleteChatPhotoConfig) values() (url.Values, error) {
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStickerSetConfig contains information for get sticker 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiceConfig contains information about a sendDice request.
|
||||||
|
type DiceConfig struct {
|
||||||
|
BaseChat
|
||||||
|
// Emoji on which the dice throw animation is based.
|
||||||
|
// Currently, must be one of “🎲”, “🎯”, or “🏀”.
|
||||||
|
// Dice can have values 1-6 for “🎲” and “🎯”, and values 1-5 for “🏀”.
|
||||||
|
// Defaults to “🎲”
|
||||||
|
Emoji string
|
||||||
|
}
|
||||||
|
|
||||||
|
// values returns a url.Values representation of DiceConfig.
|
||||||
|
func (config DiceConfig) values() (url.Values, error) {
|
||||||
|
v, err := config.BaseChat.values()
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
if config.Emoji != "" {
|
||||||
|
v.Add("emoji", config.Emoji)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// method returns Telegram API method name for sending Dice.
|
||||||
|
func (config DiceConfig) method() string {
|
||||||
|
return "sendDice"
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module github.com/go-telegram-bot-api/telegram-bot-api
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require github.com/technoweenie/multipartstreamer v1.0.1
|
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||||
|
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
83
helpers.go
83
helpers.go
|
@ -18,6 +18,30 @@ func NewMessage(chatID int64, text string) MessageConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDice creates a new DiceConfig.
|
||||||
|
//
|
||||||
|
// chatID is where to send it
|
||||||
|
func NewDice(chatID int64) DiceConfig {
|
||||||
|
return DiceConfig{
|
||||||
|
BaseChat: BaseChat{
|
||||||
|
ChatID: chatID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiceWithEmoji creates a new DiceConfig.
|
||||||
|
//
|
||||||
|
// chatID is where to send it
|
||||||
|
// emoji is type of the Dice
|
||||||
|
func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig {
|
||||||
|
return DiceConfig{
|
||||||
|
BaseChat: BaseChat{
|
||||||
|
ChatID: chatID,
|
||||||
|
},
|
||||||
|
Emoji: emoji,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewDeleteMessage creates a request to delete a message.
|
// NewDeleteMessage creates a request to delete a message.
|
||||||
func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
|
func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
|
||||||
return DeleteMessageConfig{
|
return DeleteMessageConfig{
|
||||||
|
@ -29,7 +53,8 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
|
||||||
// NewMessageToChannel creates a new Message that is sent to a channel
|
// NewMessageToChannel creates a new Message that is sent to a channel
|
||||||
// by username.
|
// by username.
|
||||||
//
|
//
|
||||||
// username is the username of the channel, text is the message text.
|
// username is the username of the channel, text is the message text,
|
||||||
|
// and the username should be in the form of `@username`.
|
||||||
func NewMessageToChannel(username string, text string) MessageConfig {
|
func NewMessageToChannel(username string, text string) MessageConfig {
|
||||||
return MessageConfig{
|
return MessageConfig{
|
||||||
BaseChat: BaseChat{
|
BaseChat: BaseChat{
|
||||||
|
@ -437,6 +462,19 @@ func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing.
|
||||||
|
func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle {
|
||||||
|
return InlineQueryResultArticle{
|
||||||
|
Type: "article",
|
||||||
|
ID: id,
|
||||||
|
Title: title,
|
||||||
|
InputMessageContent: InputTextMessageContent{
|
||||||
|
Text: messageText,
|
||||||
|
ParseMode: "MarkdownV2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
||||||
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
||||||
return InlineQueryResultArticle{
|
return InlineQueryResultArticle{
|
||||||
|
@ -477,7 +515,7 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultCachedPhoto create a new inline query with cached photo.
|
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
|
||||||
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif {
|
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif {
|
||||||
return InlineQueryResultCachedMpeg4Gif{
|
return InlineQueryResultCachedMpeg4Gif{
|
||||||
Type: "mpeg4_gif",
|
Type: "mpeg4_gif",
|
||||||
|
@ -533,6 +571,16 @@ func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInlineQueryResultCachedSticker create a new inline query with cached sticker.
|
||||||
|
func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker {
|
||||||
|
return InlineQueryResultCachedSticker{
|
||||||
|
Type: "sticker",
|
||||||
|
ID: id,
|
||||||
|
StickerID: stickerID,
|
||||||
|
Title: title,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultAudio creates a new inline query audio.
|
// NewInlineQueryResultAudio creates a new inline query audio.
|
||||||
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
||||||
return InlineQueryResultAudio{
|
return InlineQueryResultAudio{
|
||||||
|
@ -604,6 +652,18 @@ func NewInlineQueryResultLocation(id, title string, latitude, longitude float64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInlineQueryResultVenue creates a new inline query venue.
|
||||||
|
func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue {
|
||||||
|
return InlineQueryResultVenue{
|
||||||
|
Type: "venue",
|
||||||
|
ID: id,
|
||||||
|
Title: title,
|
||||||
|
Address: address,
|
||||||
|
Latitude: latitude,
|
||||||
|
Longitude: longitude,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewEditMessageText allows you to edit the text of a message.
|
// NewEditMessageText allows you to edit the text of a message.
|
||||||
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
|
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
|
||||||
return EditMessageTextConfig{
|
return EditMessageTextConfig{
|
||||||
|
@ -615,6 +675,18 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message.
|
||||||
|
func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig {
|
||||||
|
return EditMessageTextConfig{
|
||||||
|
BaseEdit: BaseEdit{
|
||||||
|
ChatID: chatID,
|
||||||
|
MessageID: messageID,
|
||||||
|
ReplyMarkup: &replyMarkup,
|
||||||
|
},
|
||||||
|
Text: text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewEditMessageCaption allows you to edit the caption of a message.
|
// NewEditMessageCaption allows you to edit the caption of a message.
|
||||||
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
||||||
return EditMessageCaptionConfig{
|
return EditMessageCaptionConfig{
|
||||||
|
@ -704,6 +776,13 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewOneTimeReplyKeyboard creates a new one time keyboard.
|
||||||
|
func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
||||||
|
markup := NewReplyKeyboard(rows...)
|
||||||
|
markup.OneTimeKeyboard = true
|
||||||
|
return markup
|
||||||
|
}
|
||||||
|
|
||||||
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
||||||
// and data for a callback.
|
// and data for a callback.
|
||||||
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package tgbotapi_test
|
package tgbotapi_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewInlineQueryResultArticle(t *testing.T) {
|
func TestNewInlineQueryResultArticle(t *testing.T) {
|
||||||
|
@ -175,3 +176,21 @@ func TestNewEditMessageReplyMarkup(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewDice(t *testing.T) {
|
||||||
|
dice := tgbotapi.NewDice(42)
|
||||||
|
|
||||||
|
if dice.ChatID != 42 ||
|
||||||
|
dice.Emoji != "" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDiceWithEmoji(t *testing.T) {
|
||||||
|
dice := tgbotapi.NewDiceWithEmoji(42, "🏀")
|
||||||
|
|
||||||
|
if dice.ChatID != 42 ||
|
||||||
|
dice.Emoji != "🏀" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
44
types.go
44
types.go
|
@ -64,6 +64,9 @@ type User struct {
|
||||||
// It is normally a user's username, but falls back to a first/last
|
// It is normally a user's username, but falls back to a first/last
|
||||||
// name as available.
|
// name as available.
|
||||||
func (u *User) String() string {
|
func (u *User) String() string {
|
||||||
|
if u == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
if u.UserName != "" {
|
if u.UserName != "" {
|
||||||
return u.UserName
|
return u.UserName
|
||||||
}
|
}
|
||||||
|
@ -338,6 +341,7 @@ type Document struct {
|
||||||
|
|
||||||
// Sticker contains information about a sticker.
|
// Sticker contains information about a sticker.
|
||||||
type Sticker struct {
|
type Sticker struct {
|
||||||
|
FileUniqueID string `json:"file_unique_id"`
|
||||||
FileID string `json:"file_id"`
|
FileID string `json:"file_id"`
|
||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
|
@ -345,6 +349,16 @@ type Sticker struct {
|
||||||
Emoji string `json:"emoji"` // optional
|
Emoji string `json:"emoji"` // optional
|
||||||
FileSize int `json:"file_size"` // optional
|
FileSize int `json:"file_size"` // optional
|
||||||
SetName string `json:"set_name"` // optional
|
SetName string `json:"set_name"` // optional
|
||||||
|
IsAnimated bool `json:"is_animated"` // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
// StickerSet contains information about an sticker set.
|
||||||
|
type StickerSet struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
IsAnimated bool `json:"is_animated"`
|
||||||
|
ContainsMasks bool `json:"contains_masks"`
|
||||||
|
Stickers []Sticker `json:"stickers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChatAnimation contains information about an animation.
|
// ChatAnimation contains information about an animation.
|
||||||
|
@ -570,6 +584,7 @@ type WebhookInfo struct {
|
||||||
PendingUpdateCount int `json:"pending_update_count"`
|
PendingUpdateCount int `json:"pending_update_count"`
|
||||||
LastErrorDate int `json:"last_error_date"` // optional
|
LastErrorDate int `json:"last_error_date"` // optional
|
||||||
LastErrorMessage string `json:"last_error_message"` // optional
|
LastErrorMessage string `json:"last_error_message"` // optional
|
||||||
|
MaxConnections int `json:"max_connections"` // optional
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSet returns true if a webhook is currently set.
|
// IsSet returns true if a webhook is currently set.
|
||||||
|
@ -634,6 +649,7 @@ type InlineQueryResultPhoto struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Caption string `json:"caption"`
|
Caption string `json:"caption"`
|
||||||
|
ParseMode string `json:"parse_mode"`
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -736,6 +752,17 @@ type InlineQueryResultCachedVideo struct {
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InlineQueryResultCachedSticker is an inline query response with cached sticker.
|
||||||
|
type InlineQueryResultCachedSticker struct {
|
||||||
|
Type string `json:"type"` // required
|
||||||
|
ID string `json:"id"` // required
|
||||||
|
StickerID string `json:"sticker_file_id"` // required
|
||||||
|
Title string `json:"title"` // required
|
||||||
|
ParseMode string `json:"parse_mode"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
|
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// InlineQueryResultAudio is an inline query response audio.
|
// InlineQueryResultAudio is an inline query response audio.
|
||||||
type InlineQueryResultAudio struct {
|
type InlineQueryResultAudio struct {
|
||||||
Type string `json:"type"` // required
|
Type string `json:"type"` // required
|
||||||
|
@ -827,6 +854,23 @@ type InlineQueryResultLocation struct {
|
||||||
ThumbHeight int `json:"thumb_height"`
|
ThumbHeight int `json:"thumb_height"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InlineQueryResultVenue is an inline query response venue.
|
||||||
|
type InlineQueryResultVenue 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
|
||||||
|
Address string `json:"address"` // required
|
||||||
|
FoursquareID string `json:"foursquare_id"`
|
||||||
|
FoursquareType string `json:"foursquare_type"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
|
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||||
|
ThumbURL string `json:"thumb_url"`
|
||||||
|
ThumbWidth int `json:"thumb_width"`
|
||||||
|
ThumbHeight int `json:"thumb_height"`
|
||||||
|
}
|
||||||
|
|
||||||
// InlineQueryResultGame is an inline query response game.
|
// InlineQueryResultGame is an inline query response game.
|
||||||
type InlineQueryResultGame struct {
|
type InlineQueryResultGame struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
Loading…
Reference in New Issue