all repos — telegram-bot-api @ f413d8270c948a197381f60309f667cf41df015d

Golang bindings for the Telegram Bot API

configs.go (view raw)

   1package tgbotapi
   2
   3import (
   4	"bytes"
   5	"fmt"
   6	"io"
   7	"net/url"
   8	"os"
   9	"strconv"
  10)
  11
  12// Telegram constants
  13const (
  14	// APIEndpoint is the endpoint for all API methods,
  15	// with formatting for Sprintf.
  16	APIEndpoint = "https://api.telegram.org/bot%s/%s"
  17	// FileEndpoint is the endpoint for downloading a file from Telegram.
  18	FileEndpoint = "https://api.telegram.org/file/bot%s/%s"
  19)
  20
  21// Constant values for ChatActions
  22const (
  23	ChatTyping      = "typing"
  24	ChatUploadPhoto = "upload_photo"
  25	ChatRecordVideo = "record_video"
  26	ChatUploadVideo = "upload_video"
  27	ChatRecordVoice = "record_voice"
  28	ChatUploadVoice = "upload_voice"
  29	// Deprecated: use ChatRecordVoice instead.
  30	ChatRecordAudio = "record_audio"
  31	// Deprecated: use ChatUploadVoice instead.
  32	ChatUploadAudio     = "upload_audio"
  33	ChatUploadDocument  = "upload_document"
  34	ChatChooseSticker   = "choose_sticker"
  35	ChatFindLocation    = "find_location"
  36	ChatRecordVideoNote = "record_video_note"
  37	ChatUploadVideoNote = "upload_video_note"
  38)
  39
  40// API errors
  41const (
  42	// ErrAPIForbidden happens when a token is bad
  43	ErrAPIForbidden = "forbidden"
  44)
  45
  46// Constant values for ParseMode in MessageConfig
  47const (
  48	ModeMarkdown   = "Markdown"
  49	ModeMarkdownV2 = "MarkdownV2"
  50	ModeHTML       = "HTML"
  51)
  52
  53// Constant values for update types
  54const (
  55	// New incoming message of any kind — text, photo, sticker, etc.
  56	UpdateTypeMessage = "message"
  57
  58	// New version of a message that is known to the bot and was edited
  59	UpdateTypeEditedMessage = "edited_message"
  60
  61	// New incoming channel post of any kind — text, photo, sticker, etc.
  62	UpdateTypeChannelPost = "channel_post"
  63
  64	// New version of a channel post that is known to the bot and was edited
  65	UpdateTypeEditedChannelPost = "edited_channel_post"
  66
  67	// New incoming inline query
  68	UpdateTypeInlineQuery = "inline_query"
  69
  70	// The result of an inline query that was chosen by a user and sent to their
  71	// chat partner. Please see the documentation on the feedback collecting for
  72	// details on how to enable these updates for your bot.
  73	UpdateTypeChosenInlineResult = "chosen_inline_result"
  74
  75	// New incoming callback query
  76	UpdateTypeCallbackQuery = "callback_query"
  77
  78	// New incoming shipping query. Only for invoices with flexible price
  79	UpdateTypeShippingQuery = "shipping_query"
  80
  81	// New incoming pre-checkout query. Contains full information about checkout
  82	UpdateTypePreCheckoutQuery = "pre_checkout_query"
  83
  84	// New poll state. Bots receive only updates about stopped polls and polls
  85	// which are sent by the bot
  86	UpdateTypePoll = "poll"
  87
  88	// A user changed their answer in a non-anonymous poll. Bots receive new votes
  89	// only in polls that were sent by the bot itself.
  90	UpdateTypePollAnswer = "poll_answer"
  91
  92	// The bot's chat member status was updated in a chat. For private chats, this
  93	// update is received only when the bot is blocked or unblocked by the user.
  94	UpdateTypeMyChatMember = "my_chat_member"
  95
  96	// The bot must be an administrator in the chat and must explicitly specify
  97	// this update in the list of allowed_updates to receive these updates.
  98	UpdateTypeChatMember = "chat_member"
  99)
 100
 101// Library errors
 102const (
 103	ErrBadURL = "bad or empty url"
 104)
 105
 106// Chattable is any config type that can be sent.
 107type Chattable interface {
 108	params() (Params, error)
 109	method() string
 110}
 111
 112// Fileable is any config type that can be sent that includes a file.
 113type Fileable interface {
 114	Chattable
 115	files() []RequestFile
 116}
 117
 118// RequestFile represents a file associated with a field name.
 119type RequestFile struct {
 120	// The file field name.
 121	Name string
 122	// The file data to include.
 123	Data RequestFileData
 124}
 125
 126// RequestFileData represents the data to be used for a file.
 127type RequestFileData interface {
 128	// If the file needs to be uploaded.
 129	NeedsUpload() bool
 130
 131	// Get the file name and an `io.Reader` for the file to be uploaded. This
 132	// must only be called when the file needs to be uploaded.
 133	UploadData() (string, io.Reader, error)
 134	// Get the file data to send when a file does not need to be uploaded. This
 135	// must only be called when the file does not need to be uploaded.
 136	SendData() string
 137}
 138
 139// FileBytes contains information about a set of bytes to upload
 140// as a File.
 141type FileBytes struct {
 142	Name  string
 143	Bytes []byte
 144}
 145
 146func (fb FileBytes) NeedsUpload() bool {
 147	return true
 148}
 149
 150func (fb FileBytes) UploadData() (string, io.Reader, error) {
 151	return fb.Name, bytes.NewReader(fb.Bytes), nil
 152}
 153
 154func (fb FileBytes) SendData() string {
 155	panic("FileBytes must be uploaded")
 156}
 157
 158// FileReader contains information about a reader to upload as a File.
 159type FileReader struct {
 160	Name   string
 161	Reader io.Reader
 162}
 163
 164func (fr FileReader) NeedsUpload() bool {
 165	return true
 166}
 167
 168func (fr FileReader) UploadData() (string, io.Reader, error) {
 169	return fr.Name, fr.Reader, nil
 170}
 171
 172func (fr FileReader) SendData() string {
 173	panic("FileReader must be uploaded")
 174}
 175
 176// FilePath is a path to a local file.
 177type FilePath string
 178
 179func (fp FilePath) NeedsUpload() bool {
 180	return true
 181}
 182
 183func (fp FilePath) UploadData() (string, io.Reader, error) {
 184	fileHandle, err := os.Open(string(fp))
 185	if err != nil {
 186		return "", nil, err
 187	}
 188
 189	name := fileHandle.Name()
 190	return name, fileHandle, err
 191}
 192
 193func (fp FilePath) SendData() string {
 194	panic("FilePath must be uploaded")
 195}
 196
 197// FileURL is a URL to use as a file for a request.
 198type FileURL string
 199
 200func (fu FileURL) NeedsUpload() bool {
 201	return false
 202}
 203
 204func (fu FileURL) UploadData() (string, io.Reader, error) {
 205	panic("FileURL cannot be uploaded")
 206}
 207
 208func (fu FileURL) SendData() string {
 209	return string(fu)
 210}
 211
 212// FileID is an ID of a file already uploaded to Telegram.
 213type FileID string
 214
 215func (fi FileID) NeedsUpload() bool {
 216	return false
 217}
 218
 219func (fi FileID) UploadData() (string, io.Reader, error) {
 220	panic("FileID cannot be uploaded")
 221}
 222
 223func (fi FileID) SendData() string {
 224	return string(fi)
 225}
 226
 227// fileAttach is a internal file type used for processed media groups.
 228type fileAttach string
 229
 230func (fa fileAttach) NeedsUpload() bool {
 231	return false
 232}
 233
 234func (fa fileAttach) UploadData() (string, io.Reader, error) {
 235	panic("fileAttach cannot be uploaded")
 236}
 237
 238func (fa fileAttach) SendData() string {
 239	return string(fa)
 240}
 241
 242// LogOutConfig is a request to log out of the cloud Bot API server.
 243//
 244// Note that you may not log back in for at least 10 minutes.
 245type LogOutConfig struct{}
 246
 247func (LogOutConfig) method() string {
 248	return "logOut"
 249}
 250
 251func (LogOutConfig) params() (Params, error) {
 252	return nil, nil
 253}
 254
 255// CloseConfig is a request to close the bot instance on a local server.
 256//
 257// Note that you may not close an instance for the first 10 minutes after the
 258// bot has started.
 259type CloseConfig struct{}
 260
 261func (CloseConfig) method() string {
 262	return "close"
 263}
 264
 265func (CloseConfig) params() (Params, error) {
 266	return nil, nil
 267}
 268
 269// BaseChat is base type for all chat config types.
 270type BaseChat struct {
 271	ChatID                   int64 // required
 272	ChannelUsername          string
 273	ReplyToMessageID         int
 274	ReplyMarkup              interface{}
 275	DisableNotification      bool
 276	AllowSendingWithoutReply bool
 277}
 278
 279func (chat *BaseChat) params() (Params, error) {
 280	params := make(Params)
 281
 282	params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername)
 283	params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID)
 284	params.AddBool("disable_notification", chat.DisableNotification)
 285	params.AddBool("allow_sending_without_reply", chat.AllowSendingWithoutReply)
 286
 287	err := params.AddInterface("reply_markup", chat.ReplyMarkup)
 288
 289	return params, err
 290}
 291
 292// BaseFile is a base type for all file config types.
 293type BaseFile struct {
 294	BaseChat
 295	File RequestFileData
 296}
 297
 298func (file BaseFile) params() (Params, error) {
 299	return file.BaseChat.params()
 300}
 301
 302// BaseEdit is base type of all chat edits.
 303type BaseEdit struct {
 304	ChatID          int64
 305	ChannelUsername string
 306	MessageID       int
 307	InlineMessageID string
 308	ReplyMarkup     *InlineKeyboardMarkup
 309}
 310
 311func (edit BaseEdit) params() (Params, error) {
 312	params := make(Params)
 313
 314	if edit.InlineMessageID != "" {
 315		params["inline_message_id"] = edit.InlineMessageID
 316	} else {
 317		params.AddFirstValid("chat_id", edit.ChatID, edit.ChannelUsername)
 318		params.AddNonZero("message_id", edit.MessageID)
 319	}
 320
 321	err := params.AddInterface("reply_markup", edit.ReplyMarkup)
 322
 323	return params, err
 324}
 325
 326// MessageConfig contains information about a SendMessage request.
 327type MessageConfig struct {
 328	BaseChat
 329	Text                  string
 330	ParseMode             string
 331	Entities              []MessageEntity
 332	DisableWebPagePreview bool
 333}
 334
 335func (config MessageConfig) params() (Params, error) {
 336	params, err := config.BaseChat.params()
 337	if err != nil {
 338		return params, err
 339	}
 340
 341	params.AddNonEmpty("text", config.Text)
 342	params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
 343	params.AddNonEmpty("parse_mode", config.ParseMode)
 344	err = params.AddInterface("entities", config.Entities)
 345
 346	return params, err
 347}
 348
 349func (config MessageConfig) method() string {
 350	return "sendMessage"
 351}
 352
 353// ForwardConfig contains information about a ForwardMessage request.
 354type ForwardConfig struct {
 355	BaseChat
 356	FromChatID          int64 // required
 357	FromChannelUsername string
 358	MessageID           int // required
 359}
 360
 361func (config ForwardConfig) params() (Params, error) {
 362	params, err := config.BaseChat.params()
 363	if err != nil {
 364		return params, err
 365	}
 366
 367	params.AddNonZero64("from_chat_id", config.FromChatID)
 368	params.AddNonZero("message_id", config.MessageID)
 369
 370	return params, nil
 371}
 372
 373func (config ForwardConfig) method() string {
 374	return "forwardMessage"
 375}
 376
 377// CopyMessageConfig contains information about a copyMessage request.
 378type CopyMessageConfig struct {
 379	BaseChat
 380	FromChatID          int64
 381	FromChannelUsername string
 382	MessageID           int
 383	Caption             string
 384	ParseMode           string
 385	CaptionEntities     []MessageEntity
 386}
 387
 388func (config CopyMessageConfig) params() (Params, error) {
 389	params, err := config.BaseChat.params()
 390	if err != nil {
 391		return params, err
 392	}
 393
 394	params.AddFirstValid("from_chat_id", config.FromChatID, config.FromChannelUsername)
 395	params.AddNonZero("message_id", config.MessageID)
 396	params.AddNonEmpty("caption", config.Caption)
 397	params.AddNonEmpty("parse_mode", config.ParseMode)
 398	err = params.AddInterface("caption_entities", config.CaptionEntities)
 399
 400	return params, err
 401}
 402
 403func (config CopyMessageConfig) method() string {
 404	return "copyMessage"
 405}
 406
 407// PhotoConfig contains information about a SendPhoto request.
 408type PhotoConfig struct {
 409	BaseFile
 410	Thumb           RequestFileData
 411	Caption         string
 412	ParseMode       string
 413	CaptionEntities []MessageEntity
 414}
 415
 416func (config PhotoConfig) params() (Params, error) {
 417	params, err := config.BaseFile.params()
 418	if err != nil {
 419		return params, err
 420	}
 421
 422	params.AddNonEmpty("caption", config.Caption)
 423	params.AddNonEmpty("parse_mode", config.ParseMode)
 424	err = params.AddInterface("caption_entities", config.CaptionEntities)
 425
 426	return params, err
 427}
 428
 429func (config PhotoConfig) method() string {
 430	return "sendPhoto"
 431}
 432
 433func (config PhotoConfig) files() []RequestFile {
 434	files := []RequestFile{{
 435		Name: "photo",
 436		Data: config.File,
 437	}}
 438
 439	if config.Thumb != nil {
 440		files = append(files, RequestFile{
 441			Name: "thumb",
 442			Data: config.Thumb,
 443		})
 444	}
 445
 446	return files
 447}
 448
 449// AudioConfig contains information about a SendAudio request.
 450type AudioConfig struct {
 451	BaseFile
 452	Thumb           RequestFileData
 453	Caption         string
 454	ParseMode       string
 455	CaptionEntities []MessageEntity
 456	Duration        int
 457	Performer       string
 458	Title           string
 459}
 460
 461func (config AudioConfig) params() (Params, error) {
 462	params, err := config.BaseChat.params()
 463	if err != nil {
 464		return params, err
 465	}
 466
 467	params.AddNonZero("duration", config.Duration)
 468	params.AddNonEmpty("performer", config.Performer)
 469	params.AddNonEmpty("title", config.Title)
 470	params.AddNonEmpty("caption", config.Caption)
 471	params.AddNonEmpty("parse_mode", config.ParseMode)
 472	err = params.AddInterface("caption_entities", config.CaptionEntities)
 473
 474	return params, err
 475}
 476
 477func (config AudioConfig) method() string {
 478	return "sendAudio"
 479}
 480
 481func (config AudioConfig) files() []RequestFile {
 482	files := []RequestFile{{
 483		Name: "audio",
 484		Data: config.File,
 485	}}
 486
 487	if config.Thumb != nil {
 488		files = append(files, RequestFile{
 489			Name: "thumb",
 490			Data: config.Thumb,
 491		})
 492	}
 493
 494	return files
 495}
 496
 497// DocumentConfig contains information about a SendDocument request.
 498type DocumentConfig struct {
 499	BaseFile
 500	Thumb                       RequestFileData
 501	Caption                     string
 502	ParseMode                   string
 503	CaptionEntities             []MessageEntity
 504	DisableContentTypeDetection bool
 505}
 506
 507func (config DocumentConfig) params() (Params, error) {
 508	params, err := config.BaseFile.params()
 509
 510	params.AddNonEmpty("caption", config.Caption)
 511	params.AddNonEmpty("parse_mode", config.ParseMode)
 512	params.AddBool("disable_content_type_detection", config.DisableContentTypeDetection)
 513
 514	return params, err
 515}
 516
 517func (config DocumentConfig) method() string {
 518	return "sendDocument"
 519}
 520
 521func (config DocumentConfig) files() []RequestFile {
 522	files := []RequestFile{{
 523		Name: "document",
 524		Data: config.File,
 525	}}
 526
 527	if config.Thumb != nil {
 528		files = append(files, RequestFile{
 529			Name: "thumb",
 530			Data: config.Thumb,
 531		})
 532	}
 533
 534	return files
 535}
 536
 537// StickerConfig contains information about a SendSticker request.
 538type StickerConfig struct {
 539	BaseFile
 540}
 541
 542func (config StickerConfig) params() (Params, error) {
 543	return config.BaseChat.params()
 544}
 545
 546func (config StickerConfig) method() string {
 547	return "sendSticker"
 548}
 549
 550func (config StickerConfig) files() []RequestFile {
 551	return []RequestFile{{
 552		Name: "sticker",
 553		Data: config.File,
 554	}}
 555}
 556
 557// VideoConfig contains information about a SendVideo request.
 558type VideoConfig struct {
 559	BaseFile
 560	Thumb             RequestFileData
 561	Duration          int
 562	Caption           string
 563	ParseMode         string
 564	CaptionEntities   []MessageEntity
 565	SupportsStreaming bool
 566}
 567
 568func (config VideoConfig) params() (Params, error) {
 569	params, err := config.BaseChat.params()
 570	if err != nil {
 571		return params, err
 572	}
 573
 574	params.AddNonZero("duration", config.Duration)
 575	params.AddNonEmpty("caption", config.Caption)
 576	params.AddNonEmpty("parse_mode", config.ParseMode)
 577	params.AddBool("supports_streaming", config.SupportsStreaming)
 578	err = params.AddInterface("caption_entities", config.CaptionEntities)
 579
 580	return params, err
 581}
 582
 583func (config VideoConfig) method() string {
 584	return "sendVideo"
 585}
 586
 587func (config VideoConfig) files() []RequestFile {
 588	files := []RequestFile{{
 589		Name: "video",
 590		Data: config.File,
 591	}}
 592
 593	if config.Thumb != nil {
 594		files = append(files, RequestFile{
 595			Name: "thumb",
 596			Data: config.Thumb,
 597		})
 598	}
 599
 600	return files
 601}
 602
 603// AnimationConfig contains information about a SendAnimation request.
 604type AnimationConfig struct {
 605	BaseFile
 606	Duration        int
 607	Thumb           RequestFileData
 608	Caption         string
 609	ParseMode       string
 610	CaptionEntities []MessageEntity
 611}
 612
 613func (config AnimationConfig) params() (Params, error) {
 614	params, err := config.BaseChat.params()
 615	if err != nil {
 616		return params, err
 617	}
 618
 619	params.AddNonZero("duration", config.Duration)
 620	params.AddNonEmpty("caption", config.Caption)
 621	params.AddNonEmpty("parse_mode", config.ParseMode)
 622	err = params.AddInterface("caption_entities", config.CaptionEntities)
 623
 624	return params, err
 625}
 626
 627func (config AnimationConfig) method() string {
 628	return "sendAnimation"
 629}
 630
 631func (config AnimationConfig) files() []RequestFile {
 632	files := []RequestFile{{
 633		Name: "animation",
 634		Data: config.File,
 635	}}
 636
 637	if config.Thumb != nil {
 638		files = append(files, RequestFile{
 639			Name: "thumb",
 640			Data: config.Thumb,
 641		})
 642	}
 643
 644	return files
 645}
 646
 647// VideoNoteConfig contains information about a SendVideoNote request.
 648type VideoNoteConfig struct {
 649	BaseFile
 650	Thumb    RequestFileData
 651	Duration int
 652	Length   int
 653}
 654
 655func (config VideoNoteConfig) params() (Params, error) {
 656	params, err := config.BaseChat.params()
 657
 658	params.AddNonZero("duration", config.Duration)
 659	params.AddNonZero("length", config.Length)
 660
 661	return params, err
 662}
 663
 664func (config VideoNoteConfig) method() string {
 665	return "sendVideoNote"
 666}
 667
 668func (config VideoNoteConfig) files() []RequestFile {
 669	files := []RequestFile{{
 670		Name: "video_note",
 671		Data: config.File,
 672	}}
 673
 674	if config.Thumb != nil {
 675		files = append(files, RequestFile{
 676			Name: "thumb",
 677			Data: config.Thumb,
 678		})
 679	}
 680
 681	return files
 682}
 683
 684// VoiceConfig contains information about a SendVoice request.
 685type VoiceConfig struct {
 686	BaseFile
 687	Thumb           RequestFileData
 688	Caption         string
 689	ParseMode       string
 690	CaptionEntities []MessageEntity
 691	Duration        int
 692}
 693
 694func (config VoiceConfig) params() (Params, error) {
 695	params, err := config.BaseChat.params()
 696	if err != nil {
 697		return params, err
 698	}
 699
 700	params.AddNonZero("duration", config.Duration)
 701	params.AddNonEmpty("caption", config.Caption)
 702	params.AddNonEmpty("parse_mode", config.ParseMode)
 703	err = params.AddInterface("caption_entities", config.CaptionEntities)
 704
 705	return params, err
 706}
 707
 708func (config VoiceConfig) method() string {
 709	return "sendVoice"
 710}
 711
 712func (config VoiceConfig) files() []RequestFile {
 713	files := []RequestFile{{
 714		Name: "voice",
 715		Data: config.File,
 716	}}
 717
 718	if config.Thumb != nil {
 719		files = append(files, RequestFile{
 720			Name: "thumb",
 721			Data: config.Thumb,
 722		})
 723	}
 724
 725	return files
 726}
 727
 728// LocationConfig contains information about a SendLocation request.
 729type LocationConfig struct {
 730	BaseChat
 731	Latitude             float64 // required
 732	Longitude            float64 // required
 733	HorizontalAccuracy   float64 // optional
 734	LivePeriod           int     // optional
 735	Heading              int     // optional
 736	ProximityAlertRadius int     // optional
 737}
 738
 739func (config LocationConfig) params() (Params, error) {
 740	params, err := config.BaseChat.params()
 741
 742	params.AddNonZeroFloat("latitude", config.Latitude)
 743	params.AddNonZeroFloat("longitude", config.Longitude)
 744	params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy)
 745	params.AddNonZero("live_period", config.LivePeriod)
 746	params.AddNonZero("heading", config.Heading)
 747	params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius)
 748
 749	return params, err
 750}
 751
 752func (config LocationConfig) method() string {
 753	return "sendLocation"
 754}
 755
 756// EditMessageLiveLocationConfig allows you to update a live location.
 757type EditMessageLiveLocationConfig struct {
 758	BaseEdit
 759	Latitude             float64 // required
 760	Longitude            float64 // required
 761	HorizontalAccuracy   float64 // optional
 762	Heading              int     // optional
 763	ProximityAlertRadius int     // optional
 764}
 765
 766func (config EditMessageLiveLocationConfig) params() (Params, error) {
 767	params, err := config.BaseEdit.params()
 768
 769	params.AddNonZeroFloat("latitude", config.Latitude)
 770	params.AddNonZeroFloat("longitude", config.Longitude)
 771	params.AddNonZeroFloat("horizontal_accuracy", config.HorizontalAccuracy)
 772	params.AddNonZero("heading", config.Heading)
 773	params.AddNonZero("proximity_alert_radius", config.ProximityAlertRadius)
 774
 775	return params, err
 776}
 777
 778func (config EditMessageLiveLocationConfig) method() string {
 779	return "editMessageLiveLocation"
 780}
 781
 782// StopMessageLiveLocationConfig stops updating a live location.
 783type StopMessageLiveLocationConfig struct {
 784	BaseEdit
 785}
 786
 787func (config StopMessageLiveLocationConfig) params() (Params, error) {
 788	return config.BaseEdit.params()
 789}
 790
 791func (config StopMessageLiveLocationConfig) method() string {
 792	return "stopMessageLiveLocation"
 793}
 794
 795// VenueConfig contains information about a SendVenue request.
 796type VenueConfig struct {
 797	BaseChat
 798	Latitude        float64 // required
 799	Longitude       float64 // required
 800	Title           string  // required
 801	Address         string  // required
 802	FoursquareID    string
 803	FoursquareType  string
 804	GooglePlaceID   string
 805	GooglePlaceType string
 806}
 807
 808func (config VenueConfig) params() (Params, error) {
 809	params, err := config.BaseChat.params()
 810
 811	params.AddNonZeroFloat("latitude", config.Latitude)
 812	params.AddNonZeroFloat("longitude", config.Longitude)
 813	params["title"] = config.Title
 814	params["address"] = config.Address
 815	params.AddNonEmpty("foursquare_id", config.FoursquareID)
 816	params.AddNonEmpty("foursquare_type", config.FoursquareType)
 817	params.AddNonEmpty("google_place_id", config.GooglePlaceID)
 818	params.AddNonEmpty("google_place_type", config.GooglePlaceType)
 819
 820	return params, err
 821}
 822
 823func (config VenueConfig) method() string {
 824	return "sendVenue"
 825}
 826
 827// ContactConfig allows you to send a contact.
 828type ContactConfig struct {
 829	BaseChat
 830	PhoneNumber string
 831	FirstName   string
 832	LastName    string
 833	VCard       string
 834}
 835
 836func (config ContactConfig) params() (Params, error) {
 837	params, err := config.BaseChat.params()
 838
 839	params["phone_number"] = config.PhoneNumber
 840	params["first_name"] = config.FirstName
 841
 842	params.AddNonEmpty("last_name", config.LastName)
 843	params.AddNonEmpty("vcard", config.VCard)
 844
 845	return params, err
 846}
 847
 848func (config ContactConfig) method() string {
 849	return "sendContact"
 850}
 851
 852// SendPollConfig allows you to send a poll.
 853type SendPollConfig struct {
 854	BaseChat
 855	Question              string
 856	Options               []string
 857	IsAnonymous           bool
 858	Type                  string
 859	AllowsMultipleAnswers bool
 860	CorrectOptionID       int64
 861	Explanation           string
 862	ExplanationParseMode  string
 863	ExplanationEntities   []MessageEntity
 864	OpenPeriod            int
 865	CloseDate             int
 866	IsClosed              bool
 867}
 868
 869func (config SendPollConfig) params() (Params, error) {
 870	params, err := config.BaseChat.params()
 871	if err != nil {
 872		return params, err
 873	}
 874
 875	params["question"] = config.Question
 876	if err = params.AddInterface("options", config.Options); err != nil {
 877		return params, err
 878	}
 879	params["is_anonymous"] = strconv.FormatBool(config.IsAnonymous)
 880	params.AddNonEmpty("type", config.Type)
 881	params["allows_multiple_answers"] = strconv.FormatBool(config.AllowsMultipleAnswers)
 882	params["correct_option_id"] = strconv.FormatInt(config.CorrectOptionID, 10)
 883	params.AddBool("is_closed", config.IsClosed)
 884	params.AddNonEmpty("explanation", config.Explanation)
 885	params.AddNonEmpty("explanation_parse_mode", config.ExplanationParseMode)
 886	params.AddNonZero("open_period", config.OpenPeriod)
 887	params.AddNonZero("close_date", config.CloseDate)
 888	err = params.AddInterface("explanation_entities", config.ExplanationEntities)
 889
 890	return params, err
 891}
 892
 893func (SendPollConfig) method() string {
 894	return "sendPoll"
 895}
 896
 897// GameConfig allows you to send a game.
 898type GameConfig struct {
 899	BaseChat
 900	GameShortName string
 901}
 902
 903func (config GameConfig) params() (Params, error) {
 904	params, err := config.BaseChat.params()
 905
 906	params["game_short_name"] = config.GameShortName
 907
 908	return params, err
 909}
 910
 911func (config GameConfig) method() string {
 912	return "sendGame"
 913}
 914
 915// SetGameScoreConfig allows you to update the game score in a chat.
 916type SetGameScoreConfig struct {
 917	UserID             int64
 918	Score              int
 919	Force              bool
 920	DisableEditMessage bool
 921	ChatID             int64
 922	ChannelUsername    string
 923	MessageID          int
 924	InlineMessageID    string
 925}
 926
 927func (config SetGameScoreConfig) params() (Params, error) {
 928	params := make(Params)
 929
 930	params.AddNonZero64("user_id", config.UserID)
 931	params.AddNonZero("scrore", config.Score)
 932	params.AddBool("disable_edit_message", config.DisableEditMessage)
 933
 934	if config.InlineMessageID != "" {
 935		params["inline_message_id"] = config.InlineMessageID
 936	} else {
 937		params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
 938		params.AddNonZero("message_id", config.MessageID)
 939	}
 940
 941	return params, nil
 942}
 943
 944func (config SetGameScoreConfig) method() string {
 945	return "setGameScore"
 946}
 947
 948// GetGameHighScoresConfig allows you to fetch the high scores for a game.
 949type GetGameHighScoresConfig struct {
 950	UserID          int64
 951	ChatID          int64
 952	ChannelUsername string
 953	MessageID       int
 954	InlineMessageID string
 955}
 956
 957func (config GetGameHighScoresConfig) params() (Params, error) {
 958	params := make(Params)
 959
 960	params.AddNonZero64("user_id", config.UserID)
 961
 962	if config.InlineMessageID != "" {
 963		params["inline_message_id"] = config.InlineMessageID
 964	} else {
 965		params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
 966		params.AddNonZero("message_id", config.MessageID)
 967	}
 968
 969	return params, nil
 970}
 971
 972func (config GetGameHighScoresConfig) method() string {
 973	return "getGameHighScores"
 974}
 975
 976// ChatActionConfig contains information about a SendChatAction request.
 977type ChatActionConfig struct {
 978	BaseChat
 979	Action string // required
 980}
 981
 982func (config ChatActionConfig) params() (Params, error) {
 983	params, err := config.BaseChat.params()
 984
 985	params["action"] = config.Action
 986
 987	return params, err
 988}
 989
 990func (config ChatActionConfig) method() string {
 991	return "sendChatAction"
 992}
 993
 994// EditMessageTextConfig allows you to modify the text in a message.
 995type EditMessageTextConfig struct {
 996	BaseEdit
 997	Text                  string
 998	ParseMode             string
 999	Entities              []MessageEntity
1000	DisableWebPagePreview bool
1001}
1002
1003func (config EditMessageTextConfig) params() (Params, error) {
1004	params, err := config.BaseEdit.params()
1005	if err != nil {
1006		return params, err
1007	}
1008
1009	params["text"] = config.Text
1010	params.AddNonEmpty("parse_mode", config.ParseMode)
1011	params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
1012	err = params.AddInterface("entities", config.Entities)
1013
1014	return params, err
1015}
1016
1017func (config EditMessageTextConfig) method() string {
1018	return "editMessageText"
1019}
1020
1021// EditMessageCaptionConfig allows you to modify the caption of a message.
1022type EditMessageCaptionConfig struct {
1023	BaseEdit
1024	Caption         string
1025	ParseMode       string
1026	CaptionEntities []MessageEntity
1027}
1028
1029func (config EditMessageCaptionConfig) params() (Params, error) {
1030	params, err := config.BaseEdit.params()
1031	if err != nil {
1032		return params, err
1033	}
1034
1035	params["caption"] = config.Caption
1036	params.AddNonEmpty("parse_mode", config.ParseMode)
1037	err = params.AddInterface("caption_entities", config.CaptionEntities)
1038
1039	return params, err
1040}
1041
1042func (config EditMessageCaptionConfig) method() string {
1043	return "editMessageCaption"
1044}
1045
1046// EditMessageMediaConfig allows you to make an editMessageMedia request.
1047type EditMessageMediaConfig struct {
1048	BaseEdit
1049
1050	Media interface{}
1051}
1052
1053func (EditMessageMediaConfig) method() string {
1054	return "editMessageMedia"
1055}
1056
1057func (config EditMessageMediaConfig) params() (Params, error) {
1058	params, err := config.BaseEdit.params()
1059	if err != nil {
1060		return params, err
1061	}
1062
1063	err = params.AddInterface("media", prepareInputMediaParam(config.Media, 0))
1064
1065	return params, err
1066}
1067
1068func (config EditMessageMediaConfig) files() []RequestFile {
1069	return prepareInputMediaFile(config.Media, 0)
1070}
1071
1072// EditMessageReplyMarkupConfig allows you to modify the reply markup
1073// of a message.
1074type EditMessageReplyMarkupConfig struct {
1075	BaseEdit
1076}
1077
1078func (config EditMessageReplyMarkupConfig) params() (Params, error) {
1079	return config.BaseEdit.params()
1080}
1081
1082func (config EditMessageReplyMarkupConfig) method() string {
1083	return "editMessageReplyMarkup"
1084}
1085
1086// StopPollConfig allows you to stop a poll sent by the bot.
1087type StopPollConfig struct {
1088	BaseEdit
1089}
1090
1091func (config StopPollConfig) params() (Params, error) {
1092	return config.BaseEdit.params()
1093}
1094
1095func (StopPollConfig) method() string {
1096	return "stopPoll"
1097}
1098
1099// UserProfilePhotosConfig contains information about a
1100// GetUserProfilePhotos request.
1101type UserProfilePhotosConfig struct {
1102	UserID int64
1103	Offset int
1104	Limit  int
1105}
1106
1107func (UserProfilePhotosConfig) method() string {
1108	return "getUserProfilePhotos"
1109}
1110
1111func (config UserProfilePhotosConfig) params() (Params, error) {
1112	params := make(Params)
1113
1114	params.AddNonZero64("user_id", config.UserID)
1115	params.AddNonZero("offset", config.Offset)
1116	params.AddNonZero("limit", config.Limit)
1117
1118	return params, nil
1119}
1120
1121// FileConfig has information about a file hosted on Telegram.
1122type FileConfig struct {
1123	FileID string
1124}
1125
1126func (FileConfig) method() string {
1127	return "getFile"
1128}
1129
1130func (config FileConfig) params() (Params, error) {
1131	params := make(Params)
1132
1133	params["file_id"] = config.FileID
1134
1135	return params, nil
1136}
1137
1138// UpdateConfig contains information about a GetUpdates request.
1139type UpdateConfig struct {
1140	Offset         int
1141	Limit          int
1142	Timeout        int
1143	AllowedUpdates []string
1144}
1145
1146func (UpdateConfig) method() string {
1147	return "getUpdates"
1148}
1149
1150func (config UpdateConfig) params() (Params, error) {
1151	params := make(Params)
1152
1153	params.AddNonZero("offset", config.Offset)
1154	params.AddNonZero("limit", config.Limit)
1155	params.AddNonZero("timeout", config.Timeout)
1156	params.AddInterface("allowed_updates", config.AllowedUpdates)
1157
1158	return params, nil
1159}
1160
1161// WebhookConfig contains information about a SetWebhook request.
1162type WebhookConfig struct {
1163	URL                *url.URL
1164	Certificate        RequestFileData
1165	IPAddress          string
1166	MaxConnections     int
1167	AllowedUpdates     []string
1168	DropPendingUpdates bool
1169}
1170
1171func (config WebhookConfig) method() string {
1172	return "setWebhook"
1173}
1174
1175func (config WebhookConfig) params() (Params, error) {
1176	params := make(Params)
1177
1178	if config.URL != nil {
1179		params["url"] = config.URL.String()
1180	}
1181
1182	params.AddNonEmpty("ip_address", config.IPAddress)
1183	params.AddNonZero("max_connections", config.MaxConnections)
1184	err := params.AddInterface("allowed_updates", config.AllowedUpdates)
1185	params.AddBool("drop_pending_updates", config.DropPendingUpdates)
1186
1187	return params, err
1188}
1189
1190func (config WebhookConfig) files() []RequestFile {
1191	if config.Certificate != nil {
1192		return []RequestFile{{
1193			Name: "certificate",
1194			Data: config.Certificate,
1195		}}
1196	}
1197
1198	return nil
1199}
1200
1201// DeleteWebhookConfig is a helper to delete a webhook.
1202type DeleteWebhookConfig struct {
1203	DropPendingUpdates bool
1204}
1205
1206func (config DeleteWebhookConfig) method() string {
1207	return "deleteWebhook"
1208}
1209
1210func (config DeleteWebhookConfig) params() (Params, error) {
1211	params := make(Params)
1212
1213	params.AddBool("drop_pending_updates", config.DropPendingUpdates)
1214
1215	return params, nil
1216}
1217
1218// InlineConfig contains information on making an InlineQuery response.
1219type InlineConfig struct {
1220	InlineQueryID     string        `json:"inline_query_id"`
1221	Results           []interface{} `json:"results"`
1222	CacheTime         int           `json:"cache_time"`
1223	IsPersonal        bool          `json:"is_personal"`
1224	NextOffset        string        `json:"next_offset"`
1225	SwitchPMText      string        `json:"switch_pm_text"`
1226	SwitchPMParameter string        `json:"switch_pm_parameter"`
1227}
1228
1229func (config InlineConfig) method() string {
1230	return "answerInlineQuery"
1231}
1232
1233func (config InlineConfig) params() (Params, error) {
1234	params := make(Params)
1235
1236	params["inline_query_id"] = config.InlineQueryID
1237	params.AddNonZero("cache_time", config.CacheTime)
1238	params.AddBool("is_personal", config.IsPersonal)
1239	params.AddNonEmpty("next_offset", config.NextOffset)
1240	params.AddNonEmpty("switch_pm_text", config.SwitchPMText)
1241	params.AddNonEmpty("switch_pm_parameter", config.SwitchPMParameter)
1242	err := params.AddInterface("results", config.Results)
1243
1244	return params, err
1245}
1246
1247// CallbackConfig contains information on making a CallbackQuery response.
1248type CallbackConfig struct {
1249	CallbackQueryID string `json:"callback_query_id"`
1250	Text            string `json:"text"`
1251	ShowAlert       bool   `json:"show_alert"`
1252	URL             string `json:"url"`
1253	CacheTime       int    `json:"cache_time"`
1254}
1255
1256func (config CallbackConfig) method() string {
1257	return "answerCallbackQuery"
1258}
1259
1260func (config CallbackConfig) params() (Params, error) {
1261	params := make(Params)
1262
1263	params["callback_query_id"] = config.CallbackQueryID
1264	params.AddNonEmpty("text", config.Text)
1265	params.AddBool("show_alert", config.ShowAlert)
1266	params.AddNonEmpty("url", config.URL)
1267	params.AddNonZero("cache_time", config.CacheTime)
1268
1269	return params, nil
1270}
1271
1272// ChatMemberConfig contains information about a user in a chat for use
1273// with administrative functions such as kicking or unbanning a user.
1274type ChatMemberConfig struct {
1275	ChatID             int64
1276	SuperGroupUsername string
1277	ChannelUsername    string
1278	UserID             int64
1279}
1280
1281// UnbanChatMemberConfig allows you to unban a user.
1282type UnbanChatMemberConfig struct {
1283	ChatMemberConfig
1284	OnlyIfBanned bool
1285}
1286
1287func (config UnbanChatMemberConfig) method() string {
1288	return "unbanChatMember"
1289}
1290
1291func (config UnbanChatMemberConfig) params() (Params, error) {
1292	params := make(Params)
1293
1294	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1295	params.AddNonZero64("user_id", config.UserID)
1296	params.AddBool("only_if_banned", config.OnlyIfBanned)
1297
1298	return params, nil
1299}
1300
1301// KickChatMemberConfig contains extra fields to kick user
1302type KickChatMemberConfig struct {
1303	ChatMemberConfig
1304	UntilDate      int64
1305	RevokeMessages bool
1306}
1307
1308func (config KickChatMemberConfig) method() string {
1309	return "kickChatMember"
1310}
1311
1312func (config KickChatMemberConfig) params() (Params, error) {
1313	params := make(Params)
1314
1315	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1316	params.AddNonZero64("user_id", config.UserID)
1317	params.AddNonZero64("until_date", config.UntilDate)
1318	params.AddBool("revoke_messages", config.RevokeMessages)
1319
1320	return params, nil
1321}
1322
1323// RestrictChatMemberConfig contains fields to restrict members of chat
1324type RestrictChatMemberConfig struct {
1325	ChatMemberConfig
1326	UntilDate   int64
1327	Permissions *ChatPermissions
1328}
1329
1330func (config RestrictChatMemberConfig) method() string {
1331	return "restrictChatMember"
1332}
1333
1334func (config RestrictChatMemberConfig) params() (Params, error) {
1335	params := make(Params)
1336
1337	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1338	params.AddNonZero64("user_id", config.UserID)
1339
1340	err := params.AddInterface("permissions", config.Permissions)
1341	params.AddNonZero64("until_date", config.UntilDate)
1342
1343	return params, err
1344}
1345
1346// PromoteChatMemberConfig contains fields to promote members of chat
1347type PromoteChatMemberConfig struct {
1348	ChatMemberConfig
1349	IsAnonymous         bool
1350	CanManageChat       bool
1351	CanChangeInfo       bool
1352	CanPostMessages     bool
1353	CanEditMessages     bool
1354	CanDeleteMessages   bool
1355	CanManageVoiceChats bool
1356	CanInviteUsers      bool
1357	CanRestrictMembers  bool
1358	CanPinMessages      bool
1359	CanPromoteMembers   bool
1360}
1361
1362func (config PromoteChatMemberConfig) method() string {
1363	return "promoteChatMember"
1364}
1365
1366func (config PromoteChatMemberConfig) params() (Params, error) {
1367	params := make(Params)
1368
1369	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1370	params.AddNonZero64("user_id", config.UserID)
1371
1372	params.AddBool("is_anonymous", config.IsAnonymous)
1373	params.AddBool("can_manage_chat", config.CanManageChat)
1374	params.AddBool("can_change_info", config.CanChangeInfo)
1375	params.AddBool("can_post_messages", config.CanPostMessages)
1376	params.AddBool("can_edit_messages", config.CanEditMessages)
1377	params.AddBool("can_delete_messages", config.CanDeleteMessages)
1378	params.AddBool("can_manage_voice_chats", config.CanManageVoiceChats)
1379	params.AddBool("can_invite_users", config.CanInviteUsers)
1380	params.AddBool("can_restrict_members", config.CanRestrictMembers)
1381	params.AddBool("can_pin_messages", config.CanPinMessages)
1382	params.AddBool("can_promote_members", config.CanPromoteMembers)
1383
1384	return params, nil
1385}
1386
1387// SetChatAdministratorCustomTitle sets the title of an administrative user
1388// promoted by the bot for a chat.
1389type SetChatAdministratorCustomTitle struct {
1390	ChatMemberConfig
1391	CustomTitle string
1392}
1393
1394func (SetChatAdministratorCustomTitle) method() string {
1395	return "setChatAdministratorCustomTitle"
1396}
1397
1398func (config SetChatAdministratorCustomTitle) params() (Params, error) {
1399	params := make(Params)
1400
1401	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1402	params.AddNonZero64("user_id", config.UserID)
1403	params.AddNonEmpty("custom_title", config.CustomTitle)
1404
1405	return params, nil
1406}
1407
1408// ChatConfig contains information about getting information on a chat.
1409type ChatConfig struct {
1410	ChatID             int64
1411	SuperGroupUsername string
1412}
1413
1414func (config ChatConfig) params() (Params, error) {
1415	params := make(Params)
1416
1417	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1418
1419	return params, nil
1420}
1421
1422// ChatInfoConfig contains information about getting chat information.
1423type ChatInfoConfig struct {
1424	ChatConfig
1425}
1426
1427func (ChatInfoConfig) method() string {
1428	return "getChat"
1429}
1430
1431// ChatMemberCountConfig contains information about getting the number of users in a chat.
1432type ChatMemberCountConfig struct {
1433	ChatConfig
1434}
1435
1436func (ChatMemberCountConfig) method() string {
1437	return "getChatMembersCount"
1438}
1439
1440// ChatAdministratorsConfig contains information about getting chat administrators.
1441type ChatAdministratorsConfig struct {
1442	ChatConfig
1443}
1444
1445func (ChatAdministratorsConfig) method() string {
1446	return "getChatAdministrators"
1447}
1448
1449// SetChatPermissionsConfig allows you to set default permissions for the
1450// members in a group. The bot must be an administrator and have rights to
1451// restrict members.
1452type SetChatPermissionsConfig struct {
1453	ChatConfig
1454	Permissions *ChatPermissions
1455}
1456
1457func (SetChatPermissionsConfig) method() string {
1458	return "setChatPermissions"
1459}
1460
1461func (config SetChatPermissionsConfig) params() (Params, error) {
1462	params := make(Params)
1463
1464	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1465	err := params.AddInterface("permissions", config.Permissions)
1466
1467	return params, err
1468}
1469
1470// ChatInviteLinkConfig contains information about getting a chat link.
1471//
1472// Note that generating a new link will revoke any previous links.
1473type ChatInviteLinkConfig struct {
1474	ChatConfig
1475}
1476
1477func (ChatInviteLinkConfig) method() string {
1478	return "exportChatInviteLink"
1479}
1480
1481func (config ChatInviteLinkConfig) params() (Params, error) {
1482	params := make(Params)
1483
1484	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1485
1486	return params, nil
1487}
1488
1489// CreateChatInviteLinkConfig allows you to create an additional invite link for
1490// a chat. The bot must be an administrator in the chat for this to work and
1491// must have the appropriate admin rights. The link can be revoked using the
1492// RevokeChatInviteLinkConfig.
1493type CreateChatInviteLinkConfig struct {
1494	ChatConfig
1495	Name               string
1496	ExpireDate         int
1497	MemberLimit        int
1498	CreatesJoinRequest bool
1499}
1500
1501func (CreateChatInviteLinkConfig) method() string {
1502	return "createChatInviteLink"
1503}
1504
1505func (config CreateChatInviteLinkConfig) params() (Params, error) {
1506	params := make(Params)
1507
1508	params.AddNonEmpty("name", config.Name)
1509	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1510	params.AddNonZero("expire_date", config.ExpireDate)
1511	params.AddNonZero("member_limit", config.MemberLimit)
1512	params.AddBool("creates_join_request", config.CreatesJoinRequest)
1513
1514	return params, nil
1515}
1516
1517// EditChatInviteLinkConfig allows you to edit a non-primary invite link created
1518// by the bot. The bot must be an administrator in the chat for this to work and
1519// must have the appropriate admin rights.
1520type EditChatInviteLinkConfig struct {
1521	ChatConfig
1522	InviteLink         string
1523	Name               string
1524	ExpireDate         int
1525	MemberLimit        int
1526	CreatesJoinRequest bool
1527}
1528
1529func (EditChatInviteLinkConfig) method() string {
1530	return "editChatInviteLink"
1531}
1532
1533func (config EditChatInviteLinkConfig) params() (Params, error) {
1534	params := make(Params)
1535
1536	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1537	params.AddNonEmpty("name", config.Name)
1538	params["invite_link"] = config.InviteLink
1539	params.AddNonZero("expire_date", config.ExpireDate)
1540	params.AddNonZero("member_limit", config.MemberLimit)
1541	params.AddBool("creates_join_request", config.CreatesJoinRequest)
1542
1543	return params, nil
1544}
1545
1546// RevokeChatInviteLinkConfig allows you to revoke an invite link created by the
1547// bot. If the primary link is revoked, a new link is automatically generated.
1548// The bot must be an administrator in the chat for this to work and must have
1549// the appropriate admin rights.
1550type RevokeChatInviteLinkConfig struct {
1551	ChatConfig
1552	InviteLink string
1553}
1554
1555func (RevokeChatInviteLinkConfig) method() string {
1556	return "revokeChatInviteLink"
1557}
1558
1559func (config RevokeChatInviteLinkConfig) params() (Params, error) {
1560	params := make(Params)
1561
1562	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1563	params["invite_link"] = config.InviteLink
1564
1565	return params, nil
1566}
1567
1568// ApproveChatJoinRequestConfig allows you to approve a chat join request.
1569type ApproveChatJoinRequestConfig struct {
1570	ChatConfig
1571	UserID int64
1572}
1573
1574func (ApproveChatJoinRequestConfig) method() string {
1575	return "approveChatJoinRequest"
1576}
1577
1578func (config ApproveChatJoinRequestConfig) params() (Params, error) {
1579	params := make(Params)
1580
1581	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1582	params.AddNonZero("user_id", int(config.UserID))
1583
1584	return params, nil
1585}
1586
1587// DeclineChatJoinRequest allows you to decline a chat join request.
1588type DeclineChatJoinRequest struct {
1589	ChatConfig
1590	UserID int64
1591}
1592
1593func (DeclineChatJoinRequest) method() string {
1594	return "declineChatJoinRequest"
1595}
1596
1597func (config DeclineChatJoinRequest) params() (Params, error) {
1598	params := make(Params)
1599
1600	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1601	params.AddNonZero("user_id", int(config.UserID))
1602
1603	return params, nil
1604}
1605
1606// LeaveChatConfig allows you to leave a chat.
1607type LeaveChatConfig struct {
1608	ChatID          int64
1609	ChannelUsername string
1610}
1611
1612func (config LeaveChatConfig) method() string {
1613	return "leaveChat"
1614}
1615
1616func (config LeaveChatConfig) params() (Params, error) {
1617	params := make(Params)
1618
1619	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1620
1621	return params, nil
1622}
1623
1624// ChatConfigWithUser contains information about a chat and a user.
1625type ChatConfigWithUser struct {
1626	ChatID             int64
1627	SuperGroupUsername string
1628	UserID             int64
1629}
1630
1631func (config ChatConfigWithUser) params() (Params, error) {
1632	params := make(Params)
1633
1634	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1635	params.AddNonZero64("user_id", config.UserID)
1636
1637	return params, nil
1638}
1639
1640// GetChatMemberConfig is information about getting a specific member in a chat.
1641type GetChatMemberConfig struct {
1642	ChatConfigWithUser
1643}
1644
1645func (GetChatMemberConfig) method() string {
1646	return "getChatMember"
1647}
1648
1649// InvoiceConfig contains information for sendInvoice request.
1650type InvoiceConfig struct {
1651	BaseChat
1652	Title                     string         // required
1653	Description               string         // required
1654	Payload                   string         // required
1655	ProviderToken             string         // required
1656	Currency                  string         // required
1657	Prices                    []LabeledPrice // required
1658	MaxTipAmount              int
1659	SuggestedTipAmounts       []int
1660	StartParameter            string
1661	ProviderData              string
1662	PhotoURL                  string
1663	PhotoSize                 int
1664	PhotoWidth                int
1665	PhotoHeight               int
1666	NeedName                  bool
1667	NeedPhoneNumber           bool
1668	NeedEmail                 bool
1669	NeedShippingAddress       bool
1670	SendPhoneNumberToProvider bool
1671	SendEmailToProvider       bool
1672	IsFlexible                bool
1673}
1674
1675func (config InvoiceConfig) params() (Params, error) {
1676	params, err := config.BaseChat.params()
1677	if err != nil {
1678		return params, err
1679	}
1680
1681	params["title"] = config.Title
1682	params["description"] = config.Description
1683	params["payload"] = config.Payload
1684	params["provider_token"] = config.ProviderToken
1685	params["currency"] = config.Currency
1686	if err = params.AddInterface("prices", config.Prices); err != nil {
1687		return params, err
1688	}
1689
1690	params.AddNonZero("max_tip_amount", config.MaxTipAmount)
1691	err = params.AddInterface("suggested_tip_amounts", config.SuggestedTipAmounts)
1692	params.AddNonEmpty("start_parameter", config.StartParameter)
1693	params.AddNonEmpty("provider_data", config.ProviderData)
1694	params.AddNonEmpty("photo_url", config.PhotoURL)
1695	params.AddNonZero("photo_size", config.PhotoSize)
1696	params.AddNonZero("photo_width", config.PhotoWidth)
1697	params.AddNonZero("photo_height", config.PhotoHeight)
1698	params.AddBool("need_name", config.NeedName)
1699	params.AddBool("need_phone_number", config.NeedPhoneNumber)
1700	params.AddBool("need_email", config.NeedEmail)
1701	params.AddBool("need_shipping_address", config.NeedShippingAddress)
1702	params.AddBool("is_flexible", config.IsFlexible)
1703	params.AddBool("send_phone_number_to_provider", config.SendPhoneNumberToProvider)
1704	params.AddBool("send_email_to_provider", config.SendEmailToProvider)
1705
1706	return params, err
1707}
1708
1709func (config InvoiceConfig) method() string {
1710	return "sendInvoice"
1711}
1712
1713// ShippingConfig contains information for answerShippingQuery request.
1714type ShippingConfig struct {
1715	ShippingQueryID string // required
1716	OK              bool   // required
1717	ShippingOptions []ShippingOption
1718	ErrorMessage    string
1719}
1720
1721func (config ShippingConfig) method() string {
1722	return "answerShippingQuery"
1723}
1724
1725func (config ShippingConfig) params() (Params, error) {
1726	params := make(Params)
1727
1728	params["shipping_query_id"] = config.ShippingQueryID
1729	params.AddBool("ok", config.OK)
1730	err := params.AddInterface("shipping_options", config.ShippingOptions)
1731	params.AddNonEmpty("error_message", config.ErrorMessage)
1732
1733	return params, err
1734}
1735
1736// PreCheckoutConfig conatins information for answerPreCheckoutQuery request.
1737type PreCheckoutConfig struct {
1738	PreCheckoutQueryID string // required
1739	OK                 bool   // required
1740	ErrorMessage       string
1741}
1742
1743func (config PreCheckoutConfig) method() string {
1744	return "answerPreCheckoutQuery"
1745}
1746
1747func (config PreCheckoutConfig) params() (Params, error) {
1748	params := make(Params)
1749
1750	params["pre_checkout_query_id"] = config.PreCheckoutQueryID
1751	params.AddBool("ok", config.OK)
1752	params.AddNonEmpty("error_message", config.ErrorMessage)
1753
1754	return params, nil
1755}
1756
1757// DeleteMessageConfig contains information of a message in a chat to delete.
1758type DeleteMessageConfig struct {
1759	ChannelUsername string
1760	ChatID          int64
1761	MessageID       int
1762}
1763
1764func (config DeleteMessageConfig) method() string {
1765	return "deleteMessage"
1766}
1767
1768func (config DeleteMessageConfig) params() (Params, error) {
1769	params := make(Params)
1770
1771	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1772	params.AddNonZero("message_id", config.MessageID)
1773
1774	return params, nil
1775}
1776
1777// PinChatMessageConfig contains information of a message in a chat to pin.
1778type PinChatMessageConfig struct {
1779	ChatID              int64
1780	ChannelUsername     string
1781	MessageID           int
1782	DisableNotification bool
1783}
1784
1785func (config PinChatMessageConfig) method() string {
1786	return "pinChatMessage"
1787}
1788
1789func (config PinChatMessageConfig) params() (Params, error) {
1790	params := make(Params)
1791
1792	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1793	params.AddNonZero("message_id", config.MessageID)
1794	params.AddBool("disable_notification", config.DisableNotification)
1795
1796	return params, nil
1797}
1798
1799// UnpinChatMessageConfig contains information of a chat message to unpin.
1800//
1801// If MessageID is not specified, it will unpin the most recent pin.
1802type UnpinChatMessageConfig struct {
1803	ChatID          int64
1804	ChannelUsername string
1805	MessageID       int
1806}
1807
1808func (config UnpinChatMessageConfig) method() string {
1809	return "unpinChatMessage"
1810}
1811
1812func (config UnpinChatMessageConfig) params() (Params, error) {
1813	params := make(Params)
1814
1815	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1816	params.AddNonZero("message_id", config.MessageID)
1817
1818	return params, nil
1819}
1820
1821// UnpinAllChatMessagesConfig contains information of all messages to unpin in
1822// a chat.
1823type UnpinAllChatMessagesConfig struct {
1824	ChatID          int64
1825	ChannelUsername string
1826}
1827
1828func (config UnpinAllChatMessagesConfig) method() string {
1829	return "unpinAllChatMessages"
1830}
1831
1832func (config UnpinAllChatMessagesConfig) params() (Params, error) {
1833	params := make(Params)
1834
1835	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1836
1837	return params, nil
1838}
1839
1840// SetChatPhotoConfig allows you to set a group, supergroup, or channel's photo.
1841type SetChatPhotoConfig struct {
1842	BaseFile
1843}
1844
1845func (config SetChatPhotoConfig) method() string {
1846	return "setChatPhoto"
1847}
1848
1849func (config SetChatPhotoConfig) files() []RequestFile {
1850	return []RequestFile{{
1851		Name: "photo",
1852		Data: config.File,
1853	}}
1854}
1855
1856// DeleteChatPhotoConfig allows you to delete a group, supergroup, or channel's photo.
1857type DeleteChatPhotoConfig struct {
1858	ChatID          int64
1859	ChannelUsername string
1860}
1861
1862func (config DeleteChatPhotoConfig) method() string {
1863	return "deleteChatPhoto"
1864}
1865
1866func (config DeleteChatPhotoConfig) params() (Params, error) {
1867	params := make(Params)
1868
1869	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1870
1871	return params, nil
1872}
1873
1874// SetChatTitleConfig allows you to set the title of something other than a private chat.
1875type SetChatTitleConfig struct {
1876	ChatID          int64
1877	ChannelUsername string
1878
1879	Title string
1880}
1881
1882func (config SetChatTitleConfig) method() string {
1883	return "setChatTitle"
1884}
1885
1886func (config SetChatTitleConfig) params() (Params, error) {
1887	params := make(Params)
1888
1889	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1890	params["title"] = config.Title
1891
1892	return params, nil
1893}
1894
1895// SetChatDescriptionConfig allows you to set the description of a supergroup or channel.
1896type SetChatDescriptionConfig struct {
1897	ChatID          int64
1898	ChannelUsername string
1899
1900	Description string
1901}
1902
1903func (config SetChatDescriptionConfig) method() string {
1904	return "setChatDescription"
1905}
1906
1907func (config SetChatDescriptionConfig) params() (Params, error) {
1908	params := make(Params)
1909
1910	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1911	params["description"] = config.Description
1912
1913	return params, nil
1914}
1915
1916// GetStickerSetConfig allows you to get the stickers in a set.
1917type GetStickerSetConfig struct {
1918	Name string
1919}
1920
1921func (config GetStickerSetConfig) method() string {
1922	return "getStickerSet"
1923}
1924
1925func (config GetStickerSetConfig) params() (Params, error) {
1926	params := make(Params)
1927
1928	params["name"] = config.Name
1929
1930	return params, nil
1931}
1932
1933// UploadStickerConfig allows you to upload a sticker for use in a set later.
1934type UploadStickerConfig struct {
1935	UserID     int64
1936	PNGSticker RequestFileData
1937}
1938
1939func (config UploadStickerConfig) method() string {
1940	return "uploadStickerFile"
1941}
1942
1943func (config UploadStickerConfig) params() (Params, error) {
1944	params := make(Params)
1945
1946	params.AddNonZero64("user_id", config.UserID)
1947
1948	return params, nil
1949}
1950
1951func (config UploadStickerConfig) files() []RequestFile {
1952	return []RequestFile{{
1953		Name: "png_sticker",
1954		Data: config.PNGSticker,
1955	}}
1956}
1957
1958// NewStickerSetConfig allows creating a new sticker set.
1959//
1960// You must set either PNGSticker or TGSSticker.
1961type NewStickerSetConfig struct {
1962	UserID        int64
1963	Name          string
1964	Title         string
1965	PNGSticker    RequestFileData
1966	TGSSticker    RequestFileData
1967	Emojis        string
1968	ContainsMasks bool
1969	MaskPosition  *MaskPosition
1970}
1971
1972func (config NewStickerSetConfig) method() string {
1973	return "createNewStickerSet"
1974}
1975
1976func (config NewStickerSetConfig) params() (Params, error) {
1977	params := make(Params)
1978
1979	params.AddNonZero64("user_id", config.UserID)
1980	params["name"] = config.Name
1981	params["title"] = config.Title
1982
1983	params["emojis"] = config.Emojis
1984
1985	params.AddBool("contains_masks", config.ContainsMasks)
1986
1987	err := params.AddInterface("mask_position", config.MaskPosition)
1988
1989	return params, err
1990}
1991
1992func (config NewStickerSetConfig) files() []RequestFile {
1993	if config.PNGSticker != nil {
1994		return []RequestFile{{
1995			Name: "png_sticker",
1996			Data: config.PNGSticker,
1997		}}
1998	}
1999
2000	return []RequestFile{{
2001		Name: "tgs_sticker",
2002		Data: config.TGSSticker,
2003	}}
2004}
2005
2006// AddStickerConfig allows you to add a sticker to a set.
2007type AddStickerConfig struct {
2008	UserID       int64
2009	Name         string
2010	PNGSticker   RequestFileData
2011	TGSSticker   RequestFileData
2012	Emojis       string
2013	MaskPosition *MaskPosition
2014}
2015
2016func (config AddStickerConfig) method() string {
2017	return "addStickerToSet"
2018}
2019
2020func (config AddStickerConfig) params() (Params, error) {
2021	params := make(Params)
2022
2023	params.AddNonZero64("user_id", config.UserID)
2024	params["name"] = config.Name
2025	params["emojis"] = config.Emojis
2026
2027	err := params.AddInterface("mask_position", config.MaskPosition)
2028
2029	return params, err
2030}
2031
2032func (config AddStickerConfig) files() []RequestFile {
2033	if config.PNGSticker != nil {
2034		return []RequestFile{{
2035			Name: "png_sticker",
2036			Data: config.PNGSticker,
2037		}}
2038	}
2039
2040	return []RequestFile{{
2041		Name: "tgs_sticker",
2042		Data: config.TGSSticker,
2043	}}
2044
2045}
2046
2047// SetStickerPositionConfig allows you to change the position of a sticker in a set.
2048type SetStickerPositionConfig struct {
2049	Sticker  string
2050	Position int
2051}
2052
2053func (config SetStickerPositionConfig) method() string {
2054	return "setStickerPositionInSet"
2055}
2056
2057func (config SetStickerPositionConfig) params() (Params, error) {
2058	params := make(Params)
2059
2060	params["sticker"] = config.Sticker
2061	params.AddNonZero("position", config.Position)
2062
2063	return params, nil
2064}
2065
2066// DeleteStickerConfig allows you to delete a sticker from a set.
2067type DeleteStickerConfig struct {
2068	Sticker string
2069}
2070
2071func (config DeleteStickerConfig) method() string {
2072	return "deleteStickerFromSet"
2073}
2074
2075func (config DeleteStickerConfig) params() (Params, error) {
2076	params := make(Params)
2077
2078	params["sticker"] = config.Sticker
2079
2080	return params, nil
2081}
2082
2083// SetStickerSetThumbConfig allows you to set the thumbnail for a sticker set.
2084type SetStickerSetThumbConfig struct {
2085	Name   string
2086	UserID int64
2087	Thumb  RequestFileData
2088}
2089
2090func (config SetStickerSetThumbConfig) method() string {
2091	return "setStickerSetThumb"
2092}
2093
2094func (config SetStickerSetThumbConfig) params() (Params, error) {
2095	params := make(Params)
2096
2097	params["name"] = config.Name
2098	params.AddNonZero64("user_id", config.UserID)
2099
2100	return params, nil
2101}
2102
2103func (config SetStickerSetThumbConfig) files() []RequestFile {
2104	return []RequestFile{{
2105		Name: "thumb",
2106		Data: config.Thumb,
2107	}}
2108}
2109
2110// SetChatStickerSetConfig allows you to set the sticker set for a supergroup.
2111type SetChatStickerSetConfig struct {
2112	ChatID             int64
2113	SuperGroupUsername string
2114
2115	StickerSetName string
2116}
2117
2118func (config SetChatStickerSetConfig) method() string {
2119	return "setChatStickerSet"
2120}
2121
2122func (config SetChatStickerSetConfig) params() (Params, error) {
2123	params := make(Params)
2124
2125	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
2126	params["sticker_set_name"] = config.StickerSetName
2127
2128	return params, nil
2129}
2130
2131// DeleteChatStickerSetConfig allows you to remove a supergroup's sticker set.
2132type DeleteChatStickerSetConfig struct {
2133	ChatID             int64
2134	SuperGroupUsername string
2135}
2136
2137func (config DeleteChatStickerSetConfig) method() string {
2138	return "deleteChatStickerSet"
2139}
2140
2141func (config DeleteChatStickerSetConfig) params() (Params, error) {
2142	params := make(Params)
2143
2144	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
2145
2146	return params, nil
2147}
2148
2149// MediaGroupConfig allows you to send a group of media.
2150//
2151// Media consist of InputMedia items (InputMediaPhoto, InputMediaVideo).
2152type MediaGroupConfig struct {
2153	ChatID          int64
2154	ChannelUsername string
2155
2156	Media               []interface{}
2157	DisableNotification bool
2158	ReplyToMessageID    int
2159}
2160
2161func (config MediaGroupConfig) method() string {
2162	return "sendMediaGroup"
2163}
2164
2165func (config MediaGroupConfig) params() (Params, error) {
2166	params := make(Params)
2167
2168	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
2169	params.AddBool("disable_notification", config.DisableNotification)
2170	params.AddNonZero("reply_to_message_id", config.ReplyToMessageID)
2171
2172	err := params.AddInterface("media", prepareInputMediaForParams(config.Media))
2173
2174	return params, err
2175}
2176
2177func (config MediaGroupConfig) files() []RequestFile {
2178	return prepareInputMediaForFiles(config.Media)
2179}
2180
2181// DiceConfig contains information about a sendDice request.
2182type DiceConfig struct {
2183	BaseChat
2184	// Emoji on which the dice throw animation is based.
2185	// Currently, must be one of 🎲, 🎯, 🏀, ⚽, 🎳, or 🎰.
2186	// Dice can have values 1-6 for 🎲, 🎯, and 🎳, values 1-5 for 🏀 and ⚽,
2187	// and values 1-64 for 🎰.
2188	// Defaults to “🎲”
2189	Emoji string
2190}
2191
2192func (config DiceConfig) method() string {
2193	return "sendDice"
2194}
2195
2196func (config DiceConfig) params() (Params, error) {
2197	params, err := config.BaseChat.params()
2198	if err != nil {
2199		return params, err
2200	}
2201
2202	params.AddNonEmpty("emoji", config.Emoji)
2203
2204	return params, err
2205}
2206
2207// GetMyCommandsConfig gets a list of the currently registered commands.
2208type GetMyCommandsConfig struct {
2209	Scope        *BotCommandScope
2210	LanguageCode string
2211}
2212
2213func (config GetMyCommandsConfig) method() string {
2214	return "getMyCommands"
2215}
2216
2217func (config GetMyCommandsConfig) params() (Params, error) {
2218	params := make(Params)
2219
2220	err := params.AddInterface("scope", config.Scope)
2221	params.AddNonEmpty("language_code", config.LanguageCode)
2222
2223	return params, err
2224}
2225
2226// SetMyCommandsConfig sets a list of commands the bot understands.
2227type SetMyCommandsConfig struct {
2228	Commands     []BotCommand
2229	Scope        *BotCommandScope
2230	LanguageCode string
2231}
2232
2233func (config SetMyCommandsConfig) method() string {
2234	return "setMyCommands"
2235}
2236
2237func (config SetMyCommandsConfig) params() (Params, error) {
2238	params := make(Params)
2239
2240	if err := params.AddInterface("commands", config.Commands); err != nil {
2241		return params, err
2242	}
2243	err := params.AddInterface("scope", config.Scope)
2244	params.AddNonEmpty("language_code", config.LanguageCode)
2245
2246	return params, err
2247}
2248
2249type DeleteMyCommandsConfig struct {
2250	Scope        *BotCommandScope
2251	LanguageCode string
2252}
2253
2254func (config DeleteMyCommandsConfig) method() string {
2255	return "deleteMyCommands"
2256}
2257
2258func (config DeleteMyCommandsConfig) params() (Params, error) {
2259	params := make(Params)
2260
2261	err := params.AddInterface("scope", config.Scope)
2262	params.AddNonEmpty("language_code", config.LanguageCode)
2263
2264	return params, err
2265}
2266
2267// prepareInputMediaParam evaluates a single InputMedia and determines if it
2268// needs to be modified for a successful upload. If it returns nil, then the
2269// value does not need to be included in the params. Otherwise, it will return
2270// the same type as was originally provided.
2271//
2272// The idx is used to calculate the file field name. If you only have a single
2273// file, 0 may be used. It is formatted into "attach://file-%d" for the primary
2274// media and "attach://file-%d-thumb" for thumbnails.
2275//
2276// It is expected to be used in conjunction with prepareInputMediaFile.
2277func prepareInputMediaParam(inputMedia interface{}, idx int) interface{} {
2278	switch m := inputMedia.(type) {
2279	case InputMediaPhoto:
2280		if m.Media.NeedsUpload() {
2281			m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx))
2282		}
2283
2284		return m
2285	case InputMediaVideo:
2286		if m.Media.NeedsUpload() {
2287			m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx))
2288		}
2289
2290		if m.Thumb != nil && m.Thumb.NeedsUpload() {
2291			m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx))
2292		}
2293
2294		return m
2295	case InputMediaAudio:
2296		if m.Media.NeedsUpload() {
2297			m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx))
2298		}
2299
2300		if m.Thumb != nil && m.Thumb.NeedsUpload() {
2301			m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx))
2302		}
2303
2304		return m
2305	case InputMediaDocument:
2306		if m.Media.NeedsUpload() {
2307			m.Media = fileAttach(fmt.Sprintf("attach://file-%d", idx))
2308		}
2309
2310		if m.Thumb != nil && m.Thumb.NeedsUpload() {
2311			m.Thumb = fileAttach(fmt.Sprintf("attach://file-%d-thumb", idx))
2312		}
2313
2314		return m
2315	}
2316
2317	return nil
2318}
2319
2320// prepareInputMediaFile generates an array of RequestFile to provide for
2321// Fileable's files method. It returns an array as a single InputMedia may have
2322// multiple files, for the primary media and a thumbnail.
2323//
2324// The idx parameter is used to generate file field names. It uses the names
2325// "file-%d" for the main file and "file-%d-thumb" for the thumbnail.
2326//
2327// It is expected to be used in conjunction with prepareInputMediaParam.
2328func prepareInputMediaFile(inputMedia interface{}, idx int) []RequestFile {
2329	files := []RequestFile{}
2330
2331	switch m := inputMedia.(type) {
2332	case InputMediaPhoto:
2333		if m.Media.NeedsUpload() {
2334			files = append(files, RequestFile{
2335				Name: fmt.Sprintf("file-%d", idx),
2336				Data: m.Media,
2337			})
2338		}
2339	case InputMediaVideo:
2340		if m.Media.NeedsUpload() {
2341			files = append(files, RequestFile{
2342				Name: fmt.Sprintf("file-%d", idx),
2343				Data: m.Media,
2344			})
2345		}
2346
2347		if m.Thumb != nil && m.Thumb.NeedsUpload() {
2348			files = append(files, RequestFile{
2349				Name: fmt.Sprintf("file-%d", idx),
2350				Data: m.Thumb,
2351			})
2352		}
2353	case InputMediaDocument:
2354		if m.Media.NeedsUpload() {
2355			files = append(files, RequestFile{
2356				Name: fmt.Sprintf("file-%d", idx),
2357				Data: m.Media,
2358			})
2359		}
2360
2361		if m.Thumb != nil && m.Thumb.NeedsUpload() {
2362			files = append(files, RequestFile{
2363				Name: fmt.Sprintf("file-%d", idx),
2364				Data: m.Thumb,
2365			})
2366		}
2367	case InputMediaAudio:
2368		if m.Media.NeedsUpload() {
2369			files = append(files, RequestFile{
2370				Name: fmt.Sprintf("file-%d", idx),
2371				Data: m.Media,
2372			})
2373		}
2374
2375		if m.Thumb != nil && m.Thumb.NeedsUpload() {
2376			files = append(files, RequestFile{
2377				Name: fmt.Sprintf("file-%d", idx),
2378				Data: m.Thumb,
2379			})
2380		}
2381	}
2382
2383	return files
2384}
2385
2386// prepareInputMediaForParams calls prepareInputMediaParam for each item
2387// provided and returns a new array with the correct params for a request.
2388//
2389// It is expected that files will get data from the associated function,
2390// prepareInputMediaForFiles.
2391func prepareInputMediaForParams(inputMedia []interface{}) []interface{} {
2392	newMedia := make([]interface{}, len(inputMedia))
2393	copy(newMedia, inputMedia)
2394
2395	for idx, media := range inputMedia {
2396		if param := prepareInputMediaParam(media, idx); param != nil {
2397			newMedia[idx] = param
2398		}
2399	}
2400
2401	return newMedia
2402}
2403
2404// prepareInputMediaForFiles calls prepareInputMediaFile for each item
2405// provided and returns a new array with the correct files for a request.
2406//
2407// It is expected that params will get data from the associated function,
2408// prepareInputMediaForParams.
2409func prepareInputMediaForFiles(inputMedia []interface{}) []RequestFile {
2410	files := []RequestFile{}
2411
2412	for idx, media := range inputMedia {
2413		if file := prepareInputMediaFile(media, idx); file != nil {
2414			files = append(files, file...)
2415		}
2416	}
2417
2418	return files
2419}