Merge branch 'develop' into multiple-uploads

bot-api-6.1
Syfaro 2021-03-10 12:33:02 -05:00
commit 05db49c9e3
10 changed files with 3199 additions and 869 deletions

33
.github/workflows/test.yml vendored 100644
View File

@ -0,0 +1,33 @@
name: Test
on:
push:
branches:
- master
- develop
pull_request:
jobs:
build:
name: Test
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Build
run: go build -v .
- name: Test
run: go test -coverprofile=coverage.out -covermode=atomic -v .
- name: Upload coverage report
uses: codecov/codecov-action@v1
with:
file: ./coverage.out

View File

@ -1,6 +0,0 @@
language: go
go:
- '1.13'
- '1.14'
- tip

View File

@ -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)
[![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
a pull request.

75
bot.go
View File

@ -17,14 +17,20 @@ import (
"time"
)
// HTTPClient is the type needed for the bot to perform HTTP requests.
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
PostForm(url string, data url.Values) (*http.Response, error)
}
// BotAPI allows you to interact with the Telegram Bot API.
type BotAPI struct {
Token string `json:"token"`
Debug bool `json:"debug"`
Buffer int `json:"buffer"`
Self User `json:"-"`
Client *http.Client `json:"-"`
Self User `json:"-"`
Client HTTPClient `json:"-"`
shutdownChannel chan interface{}
apiEndpoint string
@ -34,21 +40,29 @@ type BotAPI struct {
//
// It requires a token, provided by @BotFather on Telegram.
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
// and allows you to pass a http.Client.
//
// It requires a token, provided by @BotFather on Telegram.
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
// It requires a token, provided by @BotFather on Telegram and API endpoint.
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) {
bot := &BotAPI{
Token: token,
Client: client,
Buffer: 100,
shutdownChannel: make(chan interface{}),
apiEndpoint: APIEndpoint,
apiEndpoint: apiEndpoint,
}
self, err := bot.GetMe()
@ -411,7 +425,7 @@ func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
// GetUpdates fetches updates.
// If a WebHook is set, this will not return any data!
//
// Offset, Limit, and Timeout are optional.
// Offset, Limit, Timeout, and AllowedUpdates are optional.
// To avoid stale items, set Offset to one higher than the previous item.
// Set Timeout to a large number to reduce requests so you can get updates
// instantly instead of having to wait between requests.
@ -449,6 +463,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
for {
select {
case <-bot.shutdownChannel:
close(ch)
return
default:
}
@ -487,21 +502,35 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
ch := make(chan Update, bot.Buffer)
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
ch <- bot.HandleUpdate(w, r)
update, err := bot.HandleUpdate(r)
if err != nil {
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(errMsg)
return
}
ch <- *update
})
return ch
}
// HandleUpdate parses and returns update received via webhook
func (bot *BotAPI) HandleUpdate(res http.ResponseWriter, req *http.Request) Update {
bytes, _ := ioutil.ReadAll(req.Body)
req.Body.Close()
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
if r.Method != http.MethodPost {
err := errors.New("wrong HTTP method required POST")
return nil, err
}
var update Update
json.Unmarshal(bytes, &update)
err := json.NewDecoder(r.Body).Decode(&update)
if err != nil {
return nil, err
}
return update
return &update, nil
}
// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
@ -651,3 +680,23 @@ func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
return commands, err
}
// CopyMessage copy messages of any kind. The method is analogous to the method
// forwardMessage, but the copied message doesn't have a link to the original
// message. Returns the MessageID of the sent message on success.
func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) {
params, err := config.params()
if err != nil {
return MessageID{}, err
}
resp, err := bot.MakeRequest(config.method(), params)
if err != nil {
return MessageID{}, err
}
var messageID MessageID
err = json.Unmarshal(resp.Result, &messageID)
return messageID, err
}

View File

@ -23,10 +23,25 @@ const (
ExistingStickerFileID = "BQADAgADcwADjMcoCbdl-6eB--YPAg"
)
type testLogger struct {
t *testing.T
}
func (t testLogger) Println(v ...interface{}) {
t.t.Log(v...)
}
func (t testLogger) Printf(format string, v ...interface{}) {
t.t.Logf(format, v...)
}
func getBot(t *testing.T) (*BotAPI, error) {
bot, err := NewBotAPI(TestToken)
bot.Debug = true
logger := testLogger{t}
SetLogger(logger)
if err != nil {
t.Error(err)
}
@ -58,7 +73,7 @@ func TestSendWithMessage(t *testing.T) {
bot, _ := getBot(t)
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
msg.ParseMode = ModeMarkdown
_, err := bot.Send(msg)
if err != nil {
@ -89,6 +104,26 @@ func TestSendWithMessageForward(t *testing.T) {
}
}
func TestCopyMessage(t *testing.T) {
bot, _ := getBot(t)
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
message, err := bot.Send(msg)
if err != nil {
t.Error(err)
}
copyMessageConfig := NewCopyMessage(SupergroupChatID, message.Chat.ID, message.MessageID)
messageID, err := bot.CopyMessage(copyMessageConfig)
if err != nil {
t.Error(err)
}
if messageID.MessageID == message.MessageID {
t.Error("copied message ID was the same as original message")
}
}
func TestSendWithNewPhoto(t *testing.T) {
bot, _ := getBot(t)
@ -427,6 +462,32 @@ func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
}
}
func TestSendWithDice(t *testing.T) {
bot, _ := getBot(t)
msg := NewDice(ChatID)
_, err := bot.Send(msg)
if err != nil {
t.Error(err)
t.Fail()
}
}
func TestSendWithDiceWithEmoji(t *testing.T) {
bot, _ := getBot(t)
msg := NewDiceWithEmoji(ChatID, "🏀")
_, err := bot.Send(msg)
if err != nil {
t.Error(err)
t.Fail()
}
}
func TestGetFile(t *testing.T) {
bot, _ := getBot(t)
@ -487,7 +548,7 @@ func TestSetWebhookWithCert(t *testing.T) {
time.Sleep(time.Second * 2)
bot.Request(RemoveWebhookConfig{})
bot.Request(DeleteWebhookConfig{})
wh := NewWebhookWithCert("https://example.com/tgbotapi-test/"+bot.Token, "tests/cert.pem")
_, err := bot.Request(wh)
@ -501,7 +562,7 @@ func TestSetWebhookWithCert(t *testing.T) {
t.Error(err)
}
bot.Request(RemoveWebhookConfig{})
bot.Request(DeleteWebhookConfig{})
}
func TestSetWebhookWithoutCert(t *testing.T) {
@ -509,7 +570,7 @@ func TestSetWebhookWithoutCert(t *testing.T) {
time.Sleep(time.Second * 2)
bot.Request(RemoveWebhookConfig{})
bot.Request(DeleteWebhookConfig{})
wh := NewWebhook("https://example.com/tgbotapi-test/" + bot.Token)
_, err := bot.Request(wh)
@ -529,14 +590,14 @@ func TestSetWebhookWithoutCert(t *testing.T) {
t.Errorf("failed to set webhook: %s", info.LastErrorMessage)
}
bot.Request(RemoveWebhookConfig{})
bot.Request(DeleteWebhookConfig{})
}
func TestSendWithMediaGroupPhotoVideo(t *testing.T) {
bot, _ := getBot(t)
cfg := NewMediaGroup(ChatID, []interface{}{
NewInputMediaPhoto(FileURL("https://i.imgur.com/unQLJIb.jpg")),
NewInputMediaPhoto(FileURL("https://github.com/go-telegram-bot-api/telegram-bot-api/raw/0a3a1c8716c4cd8d26a262af9f12dcbab7f3f28c/tests/image.jpg")),
NewInputMediaPhoto("tests/image.jpg"),
NewInputMediaVideo("tests/video.mp4"),
})
@ -689,7 +750,12 @@ func ExampleWebhookHandler() {
}
http.HandleFunc("/"+bot.Token, func(w http.ResponseWriter, r *http.Request) {
log.Printf("%+v\n", bot.HandleUpdate(w, r))
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)
@ -733,7 +799,7 @@ func TestDeleteMessage(t *testing.T) {
bot, _ := getBot(t)
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
msg.ParseMode = ModeMarkdown
message, _ := bot.Send(msg)
deleteMessageConfig := DeleteMessageConfig{
@ -751,7 +817,7 @@ func TestPinChatMessage(t *testing.T) {
bot, _ := getBot(t)
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
msg.ParseMode = ModeMarkdown
message, _ := bot.Send(msg)
pinChatMessageConfig := PinChatMessageConfig{
@ -770,7 +836,7 @@ func TestUnpinChatMessage(t *testing.T) {
bot, _ := getBot(t)
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = "markdown"
msg.ParseMode = ModeMarkdown
message, _ := bot.Send(msg)
// We need pin message to unpin something
@ -785,7 +851,8 @@ func TestUnpinChatMessage(t *testing.T) {
}
unpinChatMessageConfig := UnpinChatMessageConfig{
ChatID: message.Chat.ID,
ChatID: message.Chat.ID,
MessageID: message.MessageID,
}
if _, err := bot.Request(unpinChatMessageConfig); err != nil {
@ -793,6 +860,32 @@ func TestUnpinChatMessage(t *testing.T) {
}
}
func TestUnpinAllChatMessages(t *testing.T) {
bot, _ := getBot(t)
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
msg.ParseMode = ModeMarkdown
message, _ := bot.Send(msg)
pinChatMessageConfig := PinChatMessageConfig{
ChatID: message.Chat.ID,
MessageID: message.MessageID,
DisableNotification: true,
}
if _, err := bot.Request(pinChatMessageConfig); err != nil {
t.Error(err)
}
unpinAllChatMessagesConfig := UnpinAllChatMessagesConfig{
ChatID: message.Chat.ID,
}
if _, err := bot.Request(unpinAllChatMessagesConfig); err != nil {
t.Error(err)
}
}
func TestPolls(t *testing.T) {
bot, _ := getBot(t)

View File

@ -43,6 +43,54 @@ const (
ModeHTML = "HTML"
)
// Constant values for update types
const (
// New incoming message of any kind — text, photo, sticker, etc.
UpdateTypeMessage = "message"
// New version of a message that is known to the bot and was edited
UpdateTypeEditedMessage = "edited_message"
// New incoming channel post of any kind — text, photo, sticker, etc.
UpdateTypeChannelPost = "channel_post"
// New version of a channel post that is known to the bot and was edited
UpdateTypeEditedChannelPost = "edited_channel_post"
// New incoming inline query
UpdateTypeInlineQuery = "inline_query"
// The result of an inline query that was chosen by a user and sent to their
// chat partner. Please see the documentation on the feedback collecting for
// details on how to enable these updates for your bot.
UpdateTypeChosenInlineResult = "chosen_inline_result"
// New incoming callback query
UpdateTypeCallbackQuery = "callback_query"
// New incoming shipping query. Only for invoices with flexible price
UpdateTypeShippingQuery = "shipping_query"
// New incoming pre-checkout query. Contains full information about checkout
UpdateTypePreCheckoutQuery = "pre_checkout_query"
// New poll state. Bots receive only updates about stopped polls and polls
// which are sent by the bot
UpdateTypePoll = "poll"
// A user changed their answer in a non-anonymous poll. Bots receive new votes
// only in polls that were sent by the bot itself.
UpdateTypePollAnswer = "poll_answer"
// The bot's chat member status was updated in a chat. For private chats, this
// update is received only when the bot is blocked or unblocked by the user.
UpdateTypeMyChatMember = "my_chat_member"
// The bot must be an administrator in the chat and must explicitly specify
// this update in the list of allowed_updates to receive these updates.
UpdateTypeChatMember = "chat_member"
)
// Library errors
const (
// ErrBadFileType happens when you pass an unknown type
@ -71,13 +119,41 @@ type Fileable interface {
files() []RequestFile
}
// LogOutConfig is a request to log out of the cloud Bot API server.
//
// Note that you may not log back in for at least 10 minutes.
type LogOutConfig struct{}
func (LogOutConfig) method() string {
return "logOut"
}
func (LogOutConfig) params() (Params, error) {
return nil, nil
}
// CloseConfig is a request to close the bot instance on a local server.
//
// Note that you may not close an instance for the first 10 minutes after the
// bot has started.
type CloseConfig struct{}
func (CloseConfig) method() string {
return "close"
}
func (CloseConfig) params() (Params, error) {
return nil, nil
}
// BaseChat is base type for all chat config types.
type BaseChat struct {
ChatID int64 // required
ChannelUsername string
ReplyToMessageID int
ReplyMarkup interface{}
DisableNotification bool
ChatID int64 // required
ChannelUsername string
ReplyToMessageID int
ReplyMarkup interface{}
DisableNotification bool
AllowSendingWithoutReply bool
}
func (chat *BaseChat) params() (Params, error) {
@ -86,6 +162,7 @@ func (chat *BaseChat) params() (Params, error) {
params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername)
params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID)
params.AddBool("disable_notification", chat.DisableNotification)
params.AddBool("allow_sending_without_reply", chat.AllowSendingWithoutReply)
err := params.AddInterface("reply_markup", chat.ReplyMarkup)
@ -131,6 +208,7 @@ type MessageConfig struct {
BaseChat
Text string
ParseMode string
Entities []MessageEntity
DisableWebPagePreview bool
}
@ -143,8 +221,9 @@ func (config MessageConfig) params() (Params, error) {
params.AddNonEmpty("text", config.Text)
params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("entities", config.Entities)
return params, nil
return params, err
}
func (config MessageConfig) method() string {
@ -175,19 +254,54 @@ func (config ForwardConfig) method() string {
return "forwardMessage"
}
// CopyMessageConfig contains information about a copyMessage request.
type CopyMessageConfig struct {
BaseChat
FromChatID int64
FromChannelUsername string
MessageID int
Caption string
ParseMode string
CaptionEntities []MessageEntity
}
func (config CopyMessageConfig) params() (Params, error) {
params, err := config.BaseChat.params()
if err != nil {
return params, err
}
params.AddFirstValid("from_chat_id", config.FromChatID, config.FromChannelUsername)
params.AddNonZero("message_id", config.MessageID)
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, err
}
func (config CopyMessageConfig) method() string {
return "copyMessage"
}
// PhotoConfig contains information about a SendPhoto request.
type PhotoConfig struct {
BaseFile
Thumb interface{}
Caption string
ParseMode string
Thumb interface{}
Caption string
ParseMode string
CaptionEntities []MessageEntity
}
func (config PhotoConfig) params() (Params, error) {
params, err := config.BaseFile.params()
if err != nil {
return params, err
}
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, err
}
@ -215,12 +329,13 @@ func (config PhotoConfig) files() []RequestFile {
// AudioConfig contains information about a SendAudio request.
type AudioConfig struct {
BaseFile
Thumb interface{}
Caption string
ParseMode string
Duration int
Performer string
Title string
Thumb interface{}
Caption string
ParseMode string
CaptionEntities []MessageEntity
Duration int
Performer string
Title string
}
func (config AudioConfig) params() (Params, error) {
@ -234,8 +349,9 @@ func (config AudioConfig) params() (Params, error) {
params.AddNonEmpty("title", config.Title)
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, nil
return params, err
}
func (config AudioConfig) method() string {
@ -261,9 +377,11 @@ func (config AudioConfig) files() []RequestFile {
// DocumentConfig contains information about a SendDocument request.
type DocumentConfig struct {
BaseFile
Thumb interface{}
Caption string
ParseMode string
Thumb interface{}
Caption string
ParseMode string
CaptionEntities []MessageEntity
DisableContentTypeDetection bool
}
func (config DocumentConfig) params() (Params, error) {
@ -271,6 +389,7 @@ func (config DocumentConfig) params() (Params, error) {
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
params.AddBool("disable_content_type_detection", config.DisableContentTypeDetection)
return params, err
}
@ -322,16 +441,21 @@ type VideoConfig struct {
Duration int
Caption string
ParseMode string
CaptionEntities []MessageEntity
SupportsStreaming bool
}
func (config VideoConfig) params() (Params, error) {
params, err := config.BaseChat.params()
if err != nil {
return params, err
}
params.AddNonZero("duration", config.Duration)
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
params.AddBool("supports_streaming", config.SupportsStreaming)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, err
}
@ -359,18 +483,23 @@ func (config VideoConfig) files() []RequestFile {
// AnimationConfig contains information about a SendAnimation request.
type AnimationConfig struct {
BaseFile
Duration int
Thumb interface{}
Caption string
ParseMode string
Duration int
Thumb interface{}
Caption string
ParseMode string
CaptionEntities []MessageEntity
}
func (config AnimationConfig) params() (Params, error) {
params, err := config.BaseChat.params()
if err != nil {
return params, err
}
params.AddNonZero("duration", config.Duration)
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, err
}
@ -435,18 +564,23 @@ func (config VideoNoteConfig) files() []RequestFile {
// VoiceConfig contains information about a SendVoice request.
type VoiceConfig struct {
BaseFile
Thumb interface{}
Caption string
ParseMode string
Duration int
Thumb interface{}
Caption string
ParseMode string
CaptionEntities []MessageEntity
Duration int
}
func (config VoiceConfig) params() (Params, error) {
params, err := config.BaseChat.params()
if err != nil {
return params, err
}
params.AddNonZero("duration", config.Duration)
params.AddNonEmpty("caption", config.Caption)
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, err
}
@ -474,9 +608,12 @@ func (config VoiceConfig) files() []RequestFile {
// LocationConfig contains information about a SendLocation request.
type LocationConfig struct {
BaseChat
Latitude float64 // required
Longitude float64 // required
LivePeriod int // optional
Latitude float64 // required
Longitude float64 // required
HorizontalAccuracy float64 // optional
LivePeriod int // optional
Heading int // optional
ProximityAlertRadius int // optional
}
func (config LocationConfig) params() (Params, error) {
@ -484,7 +621,10 @@ func (config LocationConfig) params() (Params, error) {
params.AddNonZeroFloat("latitude", config.Latitude)
params.AddNonZeroFloat("longitude", config.Longitude)
params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy)
params.AddNonZero("live_period", config.LivePeriod)
params.AddNonZero("heading", config.Heading)
params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius)
return params, err
}
@ -496,8 +636,11 @@ func (config LocationConfig) method() string {
// EditMessageLiveLocationConfig allows you to update a live location.
type EditMessageLiveLocationConfig struct {
BaseEdit
Latitude float64 // required
Longitude float64 // required
Latitude float64 // required
Longitude float64 // required
HorizontalAccuracy float64 // optional
Heading int // optional
ProximityAlertRadius int // optional
}
func (config EditMessageLiveLocationConfig) params() (Params, error) {
@ -505,6 +648,9 @@ func (config EditMessageLiveLocationConfig) params() (Params, error) {
params.AddNonZeroFloat("latitude", config.Latitude)
params.AddNonZeroFloat("longitude", config.Longitude)
params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy)
params.AddNonZero("heading", config.Heading)
params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius)
return params, err
}
@ -529,11 +675,14 @@ func (config StopMessageLiveLocationConfig) method() string {
// VenueConfig contains information about a SendVenue request.
type VenueConfig struct {
BaseChat
Latitude float64 // required
Longitude float64 // required
Title string // required
Address string // required
FoursquareID string
Latitude float64 // required
Longitude float64 // required
Title string // required
Address string // required
FoursquareID string
FoursquareType string
GooglePlaceID string
GooglePlaceType string
}
func (config VenueConfig) params() (Params, error) {
@ -544,6 +693,9 @@ func (config VenueConfig) params() (Params, error) {
params["title"] = config.Title
params["address"] = config.Address
params.AddNonEmpty("foursquare_id", config.FoursquareID)
params.AddNonEmpty("foursquare_type", config.FoursquareType)
params.AddNonEmpty("google_place_id", config.GooglePlaceID)
params.AddNonEmpty("google_place_type", config.GooglePlaceType)
return params, err
}
@ -588,6 +740,7 @@ type SendPollConfig struct {
CorrectOptionID int64
Explanation string
ExplanationParseMode string
ExplanationEntities []MessageEntity
OpenPeriod int
CloseDate int
IsClosed bool
@ -600,7 +753,9 @@ func (config SendPollConfig) params() (Params, error) {
}
params["question"] = config.Question
err = params.AddInterface("options", config.Options)
if err = params.AddInterface("options", config.Options); err != nil {
return params, err
}
params["is_anonymous"] = strconv.FormatBool(config.IsAnonymous)
params.AddNonEmpty("type", config.Type)
params["allows_multiple_answers"] = strconv.FormatBool(config.AllowsMultipleAnswers)
@ -610,6 +765,7 @@ func (config SendPollConfig) params() (Params, error) {
params.AddNonEmpty("explanation_parse_mode", config.ExplanationParseMode)
params.AddNonZero("open_period", config.OpenPeriod)
params.AddNonZero("close_date", config.CloseDate)
err = params.AddInterface("explanation_entities", config.ExplanationEntities)
return params, err
}
@ -720,15 +876,20 @@ type EditMessageTextConfig struct {
BaseEdit
Text string
ParseMode string
Entities []MessageEntity
DisableWebPagePreview bool
}
func (config EditMessageTextConfig) params() (Params, error) {
params, err := config.BaseEdit.params()
if err != nil {
return params, err
}
params["text"] = config.Text
params.AddNonEmpty("parse_mode", config.ParseMode)
params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
err = params.AddInterface("entities", config.Entities)
return params, err
}
@ -740,15 +901,20 @@ func (config EditMessageTextConfig) method() string {
// EditMessageCaptionConfig allows you to modify the caption of a message.
type EditMessageCaptionConfig struct {
BaseEdit
Caption string
ParseMode string
Caption string
ParseMode string
CaptionEntities []MessageEntity
}
func (config EditMessageCaptionConfig) params() (Params, error) {
params, err := config.BaseEdit.params()
if err != nil {
return params, err
}
params["caption"] = config.Caption
params.AddNonEmpty("parse_mode", config.ParseMode)
err = params.AddInterface("caption_entities", config.CaptionEntities)
return params, err
}
@ -851,9 +1017,10 @@ func (config FileConfig) params() (Params, error) {
// UpdateConfig contains information about a GetUpdates request.
type UpdateConfig struct {
Offset int
Limit int
Timeout int
Offset int
Limit int
Timeout int
AllowedUpdates []string
}
func (UpdateConfig) method() string {
@ -866,16 +1033,19 @@ func (config UpdateConfig) params() (Params, error) {
params.AddNonZero("offset", config.Offset)
params.AddNonZero("limit", config.Limit)
params.AddNonZero("timeout", config.Timeout)
params.AddInterface("allowed_updates", config.AllowedUpdates)
return params, nil
}
// WebhookConfig contains information about a SetWebhook request.
type WebhookConfig struct {
URL *url.URL
Certificate interface{}
MaxConnections int
AllowedUpdates []string
URL *url.URL
Certificate interface{}
IPAddress string
MaxConnections int
AllowedUpdates []string
DropPendingUpdates bool
}
func (config WebhookConfig) method() string {
@ -889,8 +1059,10 @@ func (config WebhookConfig) params() (Params, error) {
params["url"] = config.URL.String()
}
params.AddNonEmpty("ip_address", config.IPAddress)
params.AddNonZero("max_connections", config.MaxConnections)
err := params.AddInterface("allowed_updates", config.AllowedUpdates)
params.AddBool("drop_pending_updates", config.DropPendingUpdates)
return params, err
}
@ -906,16 +1078,21 @@ func (config WebhookConfig) files() []RequestFile {
return nil
}
// RemoveWebhookConfig is a helper to remove a webhook.
type RemoveWebhookConfig struct {
// DeleteWebhookConfig is a helper to delete a webhook.
type DeleteWebhookConfig struct {
DropPendingUpdates bool
}
func (config RemoveWebhookConfig) method() string {
return "setWebhook"
func (config DeleteWebhookConfig) method() string {
return "deleteWebhook"
}
func (config RemoveWebhookConfig) params() (Params, error) {
return nil, nil
func (config DeleteWebhookConfig) params() (Params, error) {
params := make(Params)
params.AddBool("drop_pending_updates", config.DropPendingUpdates)
return params, nil
}
// FileBytes contains information about a set of bytes to upload
@ -961,12 +1138,9 @@ func (config InlineConfig) params() (Params, error) {
params.AddNonEmpty("next_offset", config.NextOffset)
params.AddNonEmpty("switch_pm_text", config.SwitchPMText)
params.AddNonEmpty("switch_pm_parameter", config.SwitchPMParameter)
err := params.AddInterface("results", config.Results)
if err := params.AddInterface("results", config.Results); err != nil {
return params, err
}
return params, nil
return params, err
}
// CallbackConfig contains information on making a CallbackQuery response.
@ -1006,6 +1180,7 @@ type ChatMemberConfig struct {
// UnbanChatMemberConfig allows you to unban a user.
type UnbanChatMemberConfig struct {
ChatMemberConfig
OnlyIfBanned bool
}
func (config UnbanChatMemberConfig) method() string {
@ -1017,6 +1192,7 @@ func (config UnbanChatMemberConfig) params() (Params, error) {
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
params.AddNonZero("user_id", config.UserID)
params.AddBool("only_if_banned", config.OnlyIfBanned)
return params, nil
}
@ -1024,7 +1200,8 @@ func (config UnbanChatMemberConfig) params() (Params, error) {
// KickChatMemberConfig contains extra fields to kick user
type KickChatMemberConfig struct {
ChatMemberConfig
UntilDate int64
UntilDate int64
RevokeMessages bool
}
func (config KickChatMemberConfig) method() string {
@ -1037,6 +1214,7 @@ func (config KickChatMemberConfig) params() (Params, error) {
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
params.AddNonZero("user_id", config.UserID)
params.AddNonZero64("until_date", config.UntilDate)
params.AddBool("revoke_messages", config.RevokeMessages)
return params, nil
}
@ -1058,25 +1236,26 @@ func (config RestrictChatMemberConfig) params() (Params, error) {
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
params.AddNonZero("user_id", config.UserID)
if err := params.AddInterface("permissions", config.Permissions); err != nil {
return params, err
}
err := params.AddInterface("permissions", config.Permissions)
params.AddNonZero64("until_date", config.UntilDate)
return params, nil
return params, err
}
// PromoteChatMemberConfig contains fields to promote members of chat
type PromoteChatMemberConfig struct {
ChatMemberConfig
CanChangeInfo bool
CanPostMessages bool
CanEditMessages bool
CanDeleteMessages bool
CanInviteUsers bool
CanRestrictMembers bool
CanPinMessages bool
CanPromoteMembers bool
IsAnonymous bool
CanManageChat bool
CanChangeInfo bool
CanPostMessages bool
CanEditMessages bool
CanDeleteMessages bool
CanManageVoiceChats bool
CanInviteUsers bool
CanRestrictMembers bool
CanPinMessages bool
CanPromoteMembers bool
}
func (config PromoteChatMemberConfig) method() string {
@ -1089,10 +1268,13 @@ func (config PromoteChatMemberConfig) params() (Params, error) {
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
params.AddNonZero("user_id", config.UserID)
params.AddBool("is_anonymous", config.IsAnonymous)
params.AddBool("can_manage_chat", config.CanManageChat)
params.AddBool("can_change_info", config.CanChangeInfo)
params.AddBool("can_post_messages", config.CanPostMessages)
params.AddBool("can_edit_messages", config.CanEditMessages)
params.AddBool("can_delete_messages", config.CanDeleteMessages)
params.AddBool("can_manage_voice_chats", config.CanManageVoiceChats)
params.AddBool("can_invite_users", config.CanInviteUsers)
params.AddBool("can_restrict_members", config.CanRestrictMembers)
params.AddBool("can_pin_messages", config.CanPinMessages)
@ -1203,6 +1385,77 @@ func (config ChatInviteLinkConfig) params() (Params, error) {
return params, nil
}
// CreateChatInviteLinkConfig allows you to create an additional invite link for
// a chat. The bot must be an administrator in the chat for this to work and
// must have the appropriate admin rights. The link can be revoked using the
// RevokeChatInviteLinkConfig.
type CreateChatInviteLinkConfig struct {
ChatConfig
ExpireDate int
MemberLimit int
}
func (CreateChatInviteLinkConfig) method() string {
return "createChatInviteLink"
}
func (config CreateChatInviteLinkConfig) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
params.AddNonZero("expire_date", config.ExpireDate)
params.AddNonZero("member_limit", config.MemberLimit)
return params, nil
}
// EditChatInviteLinkConfig allows you to edit a non-primary invite link created
// by the bot. The bot must be an administrator in the chat for this to work and
// must have the appropriate admin rights.
type EditChatInviteLinkConfig struct {
ChatConfig
InviteLink string
ExpireDate int
MemberLimit int
}
func (EditChatInviteLinkConfig) method() string {
return "editChatInviteLink"
}
func (config EditChatInviteLinkConfig) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
params["invite_link"] = config.InviteLink
params.AddNonZero("expire_date", config.ExpireDate)
params.AddNonZero("member_limit", config.MemberLimit)
return params, nil
}
// RevokeChatInviteLinkConfig allows you to revoke an invite link created by the
// bot. If the primary link is revoked, a new link is automatically generated.
// The bot must be an administrator in the chat for this to work and must have
// the appropriate admin rights.
type RevokeChatInviteLinkConfig struct {
ChatConfig
InviteLink string
}
func (RevokeChatInviteLinkConfig) method() string {
return "revokeChatInviteLink"
}
func (config RevokeChatInviteLinkConfig) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
params["invite_link"] = config.InviteLink
return params, nil
}
// LeaveChatConfig allows you to leave a chat.
type LeaveChatConfig struct {
ChatID int64
@ -1283,10 +1536,7 @@ func (config InvoiceConfig) params() (Params, error) {
params["start_parameter"] = config.StartParameter
params["currency"] = config.Currency
if err = params.AddInterface("prices", config.Prices); err != nil {
return params, err
}
err = params.AddInterface("prices", config.Prices)
params.AddNonEmpty("provider_data", config.ProviderData)
params.AddNonEmpty("photo_url", config.PhotoURL)
params.AddNonZero("photo_size", config.PhotoSize)
@ -1300,7 +1550,7 @@ func (config InvoiceConfig) params() (Params, error) {
params.AddBool("send_phone_number_to_provider", config.SendPhoneNumberToProvider)
params.AddBool("send_email_to_provider", config.SendEmailToProvider)
return params, nil
return params, err
}
func (config InvoiceConfig) method() string {
@ -1315,6 +1565,21 @@ type ShippingConfig struct {
ErrorMessage string
}
func (config ShippingConfig) method() string {
return "answerShippingQuery"
}
func (config ShippingConfig) params() (Params, error) {
params := make(Params)
params["shipping_query_id"] = config.ShippingQueryID
params.AddBool("ok", config.OK)
err := params.AddInterface("shipping_options", config.ShippingOptions)
params.AddNonEmpty("error_message", config.ErrorMessage)
return params, err
}
// PreCheckoutConfig conatins information for answerPreCheckoutQuery request.
type PreCheckoutConfig struct {
PreCheckoutQueryID string // required
@ -1322,6 +1587,20 @@ type PreCheckoutConfig struct {
ErrorMessage string
}
func (config PreCheckoutConfig) method() string {
return "answerPreCheckoutQuery"
}
func (config PreCheckoutConfig) params() (Params, error) {
params := make(Params)
params["pre_checkout_query_id"] = config.PreCheckoutQueryID
params.AddBool("ok", config.OK)
params.AddNonEmpty("error_message", config.ErrorMessage)
return params, nil
}
// DeleteMessageConfig contains information of a message in a chat to delete.
type DeleteMessageConfig struct {
ChannelUsername string
@ -1364,10 +1643,13 @@ func (config PinChatMessageConfig) params() (Params, error) {
return params, nil
}
// UnpinChatMessageConfig contains information of chat to unpin.
// UnpinChatMessageConfig contains information of a chat message to unpin.
//
// If MessageID is not specified, it will unpin the most recent pin.
type UnpinChatMessageConfig struct {
ChatID int64
ChannelUsername string
MessageID int
}
func (config UnpinChatMessageConfig) method() string {
@ -1377,6 +1659,26 @@ func (config UnpinChatMessageConfig) method() string {
func (config UnpinChatMessageConfig) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
params.AddNonZero("message_id", config.MessageID)
return params, nil
}
// UnpinAllChatMessagesConfig contains information of all messages to unpin in
// a chat.
type UnpinAllChatMessagesConfig struct {
ChatID int64
ChannelUsername string
}
func (config UnpinAllChatMessagesConfig) method() string {
return "unpinAllChatMessages"
}
func (config UnpinAllChatMessagesConfig) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
return params, nil
@ -1723,12 +2025,14 @@ func (config MediaGroupConfig) files() []RequestFile {
return prepareInputMediaForFiles(config.Media)
}
// DiceConfig allows you to send a random dice roll to Telegram.
//
// Emoji may be one of the following: 🎲 (1-6), 🎯 (1-6), 🏀 (1-5).
// DiceConfig contains information about a sendDice request.
type DiceConfig struct {
BaseChat
// Emoji on which the dice throw animation is based.
// Currently, must be one of 🎲, 🎯, 🏀, ⚽, 🎳, or 🎰.
// Dice can have values 1-6 for 🎲, 🎯, and 🎳, values 1-5 for 🏀 and ⚽,
// and values 1-64 for 🎰.
// Defaults to “🎲”
Emoji string
}
@ -1755,7 +2059,7 @@ func (config GetMyCommandsConfig) method() string {
}
func (config GetMyCommandsConfig) params() (Params, error) {
return make(Params), nil
return nil, nil
}
// SetMyCommandsConfig sets a list of commands the bot understands.

View File

@ -29,7 +29,8 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
// NewMessageToChannel creates a new Message that is sent to a channel
// by username.
//
// username is the username of the channel, text is the message text.
// username is the username of the channel, text is the message text,
// and the username should be in the form of `@username`.
func NewMessageToChannel(username string, text string) MessageConfig {
return MessageConfig{
BaseChat: BaseChat{
@ -51,8 +52,23 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
}
}
// NewCopyMessage creates a new copy message.
//
// chatID is where to send it, fromChatID is the source chat,
// and messageID is the ID of the original message.
func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig {
return CopyMessageConfig{
BaseChat: BaseChat{ChatID: chatID},
FromChatID: fromChatID,
MessageID: messageID,
}
}
// NewPhoto creates a new sendPhoto request.
//
// chatID is where to send it, file is a string path to the file,
// FileReader, or FileBytes.
//
// Note that you must send animated GIFs as a document.
func NewPhoto(chatID int64, file interface{}) PhotoConfig {
return PhotoConfig{
@ -370,7 +386,7 @@ func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF
return InlineQueryResultCachedGIF{
Type: "gif",
ID: id,
GifID: gifID,
GIFID: gifID,
}
}
@ -383,12 +399,12 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
}
}
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached photo.
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif {
return InlineQueryResultCachedMpeg4Gif{
Type: "mpeg4_gif",
ID: id,
MGifID: MPEG4GifID,
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF {
return InlineQueryResultCachedMPEG4GIF{
Type: "mpeg4_gif",
ID: id,
MPEG4FileID: MPEG4GIFID,
}
}
@ -543,6 +559,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.
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
return EditMessageCaptionConfig{
@ -566,17 +594,6 @@ func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKe
}
}
// NewHideKeyboard hides the keyboard, with the option for being selective
// or hiding for everyone.
func NewHideKeyboard(selective bool) ReplyKeyboardHide {
log.Println("NewHideKeyboard is deprecated, please use NewRemoveKeyboard")
return ReplyKeyboardHide{
HideKeyboard: true,
Selective: selective,
}
}
// NewRemoveKeyboard hides the keyboard, with the option for being selective
// or hiding for everyone.
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {

View File

@ -174,3 +174,21 @@ func TestNewEditMessageReplyMarkup(t *testing.T) {
}
}
func TestNewDice(t *testing.T) {
dice := NewDice(42)
if dice.ChatID != 42 ||
dice.Emoji != "" {
t.Fail()
}
}
func TestNewDiceWithEmoji(t *testing.T) {
dice := NewDiceWithEmoji(42, "🏀")
if dice.ChatID != 42 ||
dice.Emoji != "🏀" {
t.Fail()
}
}

3282
types.go

File diff suppressed because it is too large Load Diff

View File

@ -282,15 +282,20 @@ var (
_ Chattable = AnimationConfig{}
_ Chattable = AudioConfig{}
_ Chattable = CallbackConfig{}
_ Chattable = ChatAdministratorsConfig{}
_ Chattable = ChatActionConfig{}
_ Chattable = ChatAdministratorsConfig{}
_ Chattable = ChatInfoConfig{}
_ Chattable = ChatInviteLinkConfig{}
_ Chattable = CloseConfig{}
_ Chattable = ContactConfig{}
_ Chattable = CopyMessageConfig{}
_ Chattable = CreateChatInviteLinkConfig{}
_ Chattable = DeleteChatPhotoConfig{}
_ Chattable = DeleteChatStickerSetConfig{}
_ Chattable = DeleteMessageConfig{}
_ Chattable = DeleteWebhookConfig{}
_ Chattable = DocumentConfig{}
_ Chattable = EditChatInviteLinkConfig{}
_ Chattable = EditMessageCaptionConfig{}
_ Chattable = EditMessageLiveLocationConfig{}
_ Chattable = EditMessageMediaConfig{}
@ -306,21 +311,24 @@ var (
_ Chattable = KickChatMemberConfig{}
_ Chattable = LeaveChatConfig{}
_ Chattable = LocationConfig{}
_ Chattable = LogOutConfig{}
_ Chattable = MediaGroupConfig{}
_ Chattable = MessageConfig{}
_ Chattable = PhotoConfig{}
_ Chattable = PinChatMessageConfig{}
_ Chattable = PreCheckoutConfig{}
_ Chattable = PromoteChatMemberConfig{}
_ Chattable = RemoveWebhookConfig{}
_ Chattable = RestrictChatMemberConfig{}
_ Chattable = RevokeChatInviteLinkConfig{}
_ Chattable = SendPollConfig{}
_ Chattable = SetChatDescriptionConfig{}
_ Chattable = SetChatPhotoConfig{}
_ Chattable = SetChatTitleConfig{}
_ Chattable = SetGameScoreConfig{}
_ Chattable = ShippingConfig{}
_ Chattable = StickerConfig{}
_ Chattable = StopPollConfig{}
_ Chattable = StopMessageLiveLocationConfig{}
_ Chattable = StopPollConfig{}
_ Chattable = UnbanChatMemberConfig{}
_ Chattable = UnpinChatMessageConfig{}
_ Chattable = UpdateConfig{}