all repos — telegram-bot-api @ ef6e421559d82708b59888ba2022da7602284053

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