all repos — telegram-bot-api @ 47a0a16eb32eb8a57ab89c80a8a35b14e24bd13c

Golang bindings for the Telegram Bot API

configs.go (view raw)

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