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.

73
bot.go
View File

@ -17,6 +17,12 @@ 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"`
@ -24,7 +30,7 @@ type BotAPI struct {
Buffer int `json:"buffer"`
Self User `json:"-"`
Client *http.Client `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
@ -786,6 +852,7 @@ func TestUnpinChatMessage(t *testing.T) {
unpinChatMessageConfig := UnpinChatMessageConfig{
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,6 +119,33 @@ 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
@ -78,6 +153,7 @@ type BaseChat struct {
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
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
}
@ -218,6 +332,7 @@ type AudioConfig struct {
Thumb interface{}
Caption string
ParseMode string
CaptionEntities []MessageEntity
Duration int
Performer string
Title string
@ -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 {
@ -264,6 +380,8 @@ type DocumentConfig struct {
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
}
@ -363,14 +487,19 @@ type AnimationConfig struct {
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
}
@ -438,15 +567,20 @@ type VoiceConfig struct {
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
}
@ -476,7 +610,10 @@ type LocationConfig struct {
BaseChat
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
}
@ -498,6 +638,9 @@ type EditMessageLiveLocationConfig struct {
BaseEdit
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
}
@ -534,6 +680,9 @@ type VenueConfig struct {
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
}
@ -742,13 +903,18 @@ type EditMessageCaptionConfig struct {
BaseEdit
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
}
@ -854,6 +1020,7 @@ type UpdateConfig struct {
Offset int
Limit int
Timeout int
AllowedUpdates []string
}
func (UpdateConfig) method() string {
@ -866,6 +1033,7 @@ 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
}
@ -874,8 +1042,10 @@ func (config UpdateConfig) params() (Params, error) {
type WebhookConfig struct {
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
}
// 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
}
@ -1025,6 +1201,7 @@ func (config UnbanChatMemberConfig) params() (Params, error) {
type KickChatMemberConfig struct {
ChatMemberConfig
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,21 +1236,22 @@ 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
IsAnonymous bool
CanManageChat bool
CanChangeInfo bool
CanPostMessages bool
CanEditMessages bool
CanDeleteMessages bool
CanManageVoiceChats bool
CanInviteUsers bool
CanRestrictMembers bool
CanPinMessages bool
@ -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{
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF {
return InlineQueryResultCachedMPEG4GIF{
Type: "mpeg4_gif",
ID: id,
MGifID: MPEG4GifID,
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()
}
}

2962
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{}