all repos — telegram-bot-api @ 50273c947a159739315bf468b26e230e22eb8e06

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