all repos — telegram-bot-api @ f2cd95670dcea2b0416090fcffab9e4940cce341

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// Library errors
  47const (
  48	// ErrBadFileType happens when you pass an unknown type
  49	ErrBadFileType = "bad file type"
  50	ErrBadURL      = "bad or empty url"
  51)
  52
  53// Chattable is any config type that can be sent.
  54type Chattable interface {
  55	params() (Params, error)
  56	method() string
  57}
  58
  59// RequestFile represents a file associated with a request. May involve
  60// uploading a file, or passing an existing ID.
  61type RequestFile struct {
  62	// The multipart upload field name.
  63	Name string
  64	// The file to upload.
  65	File interface{}
  66}
  67
  68// Fileable is any config type that can be sent that includes a file.
  69type Fileable interface {
  70	Chattable
  71	files() []RequestFile
  72}
  73
  74// BaseChat is base type for all chat config types.
  75type BaseChat struct {
  76	ChatID              int64 // required
  77	ChannelUsername     string
  78	ReplyToMessageID    int
  79	ReplyMarkup         interface{}
  80	DisableNotification bool
  81}
  82
  83func (chat *BaseChat) params() (Params, error) {
  84	params := make(Params)
  85
  86	params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername)
  87	params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID)
  88	params.AddBool("disable_notification", chat.DisableNotification)
  89
  90	err := params.AddInterface("reply_markup", chat.ReplyMarkup)
  91
  92	return params, err
  93}
  94
  95// BaseFile is a base type for all file config types.
  96type BaseFile struct {
  97	BaseChat
  98	File interface{}
  99}
 100
 101func (file BaseFile) params() (Params, error) {
 102	return file.BaseChat.params()
 103}
 104
 105// BaseEdit is base type of all chat edits.
 106type BaseEdit struct {
 107	ChatID          int64
 108	ChannelUsername string
 109	MessageID       int
 110	InlineMessageID string
 111	ReplyMarkup     *InlineKeyboardMarkup
 112}
 113
 114func (edit BaseEdit) params() (Params, error) {
 115	params := make(Params)
 116
 117	if edit.InlineMessageID != "" {
 118		params["inline_message_id"] = edit.InlineMessageID
 119	} else {
 120		params.AddFirstValid("chat_id", edit.ChatID, edit.ChannelUsername)
 121		params.AddNonZero("message_id", edit.MessageID)
 122	}
 123
 124	err := params.AddInterface("reply_markup", edit.ReplyMarkup)
 125
 126	return params, err
 127}
 128
 129// MessageConfig contains information about a SendMessage request.
 130type MessageConfig struct {
 131	BaseChat
 132	Text                  string
 133	ParseMode             string
 134	DisableWebPagePreview bool
 135}
 136
 137func (config MessageConfig) params() (Params, error) {
 138	params, err := config.BaseChat.params()
 139	if err != nil {
 140		return params, err
 141	}
 142
 143	params.AddNonEmpty("text", config.Text)
 144	params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
 145	params.AddNonEmpty("parse_mode", config.ParseMode)
 146
 147	return params, nil
 148}
 149
 150func (config MessageConfig) method() string {
 151	return "sendMessage"
 152}
 153
 154// ForwardConfig contains information about a ForwardMessage request.
 155type ForwardConfig struct {
 156	BaseChat
 157	FromChatID          int64 // required
 158	FromChannelUsername string
 159	MessageID           int // required
 160}
 161
 162func (config ForwardConfig) params() (Params, error) {
 163	params, err := config.BaseChat.params()
 164	if err != nil {
 165		return params, err
 166	}
 167
 168	params.AddNonZero64("from_chat_id", config.FromChatID)
 169	params.AddNonZero("message_id", config.MessageID)
 170
 171	return params, nil
 172}
 173
 174func (config ForwardConfig) method() string {
 175	return "forwardMessage"
 176}
 177
 178// PhotoConfig contains information about a SendPhoto request.
 179type PhotoConfig struct {
 180	BaseFile
 181	Thumb     interface{}
 182	Caption   string
 183	ParseMode string
 184}
 185
 186func (config PhotoConfig) params() (Params, error) {
 187	params, err := config.BaseFile.params()
 188
 189	params.AddNonEmpty("caption", config.Caption)
 190	params.AddNonEmpty("parse_mode", config.ParseMode)
 191
 192	return params, err
 193}
 194
 195func (config PhotoConfig) method() string {
 196	return "sendPhoto"
 197}
 198
 199func (config PhotoConfig) files() []RequestFile {
 200	files := []RequestFile{{
 201		Name: "photo",
 202		File: config.File,
 203	}}
 204
 205	if config.Thumb != nil {
 206		files = append(files, RequestFile{
 207			Name: "thumb",
 208			File: config.Thumb,
 209		})
 210	}
 211
 212	return files
 213}
 214
 215// AudioConfig contains information about a SendAudio request.
 216type AudioConfig struct {
 217	BaseFile
 218	Thumb     interface{}
 219	Caption   string
 220	ParseMode string
 221	Duration  int
 222	Performer string
 223	Title     string
 224}
 225
 226func (config AudioConfig) params() (Params, error) {
 227	params, err := config.BaseChat.params()
 228	if err != nil {
 229		return params, err
 230	}
 231
 232	params.AddNonZero("duration", config.Duration)
 233	params.AddNonEmpty("performer", config.Performer)
 234	params.AddNonEmpty("title", config.Title)
 235	params.AddNonEmpty("caption", config.Caption)
 236	params.AddNonEmpty("parse_mode", config.ParseMode)
 237
 238	return params, nil
 239}
 240
 241func (config AudioConfig) method() string {
 242	return "sendAudio"
 243}
 244
 245func (config AudioConfig) files() []RequestFile {
 246	files := []RequestFile{{
 247		Name: "audio",
 248		File: config.File,
 249	}}
 250
 251	if config.Thumb != nil {
 252		files = append(files, RequestFile{
 253			Name: "thumb",
 254			File: config.Thumb,
 255		})
 256	}
 257
 258	return files
 259}
 260
 261// DocumentConfig contains information about a SendDocument request.
 262type DocumentConfig struct {
 263	BaseFile
 264	Thumb     interface{}
 265	Caption   string
 266	ParseMode string
 267}
 268
 269func (config DocumentConfig) params() (Params, error) {
 270	params, err := config.BaseFile.params()
 271
 272	params.AddNonEmpty("caption", config.Caption)
 273	params.AddNonEmpty("parse_mode", config.ParseMode)
 274
 275	return params, err
 276}
 277
 278func (config DocumentConfig) method() string {
 279	return "sendDocument"
 280}
 281
 282func (config DocumentConfig) files() []RequestFile {
 283	files := []RequestFile{{
 284		Name: "document",
 285		File: config.File,
 286	}}
 287
 288	if config.Thumb != nil {
 289		files = append(files, RequestFile{
 290			Name: "thumb",
 291			File: config.Thumb,
 292		})
 293	}
 294
 295	return files
 296}
 297
 298// StickerConfig contains information about a SendSticker request.
 299type StickerConfig struct {
 300	BaseFile
 301}
 302
 303func (config StickerConfig) params() (Params, error) {
 304	return config.BaseChat.params()
 305}
 306
 307func (config StickerConfig) method() string {
 308	return "sendSticker"
 309}
 310
 311func (config StickerConfig) files() []RequestFile {
 312	return []RequestFile{{
 313		Name: "sticker",
 314		File: config.File,
 315	}}
 316}
 317
 318// VideoConfig contains information about a SendVideo request.
 319type VideoConfig struct {
 320	BaseFile
 321	Thumb             interface{}
 322	Duration          int
 323	Caption           string
 324	ParseMode         string
 325	SupportsStreaming bool
 326}
 327
 328func (config VideoConfig) params() (Params, error) {
 329	params, err := config.BaseChat.params()
 330
 331	params.AddNonZero("duration", config.Duration)
 332	params.AddNonEmpty("caption", config.Caption)
 333	params.AddNonEmpty("parse_mode", config.ParseMode)
 334	params.AddBool("supports_streaming", config.SupportsStreaming)
 335
 336	return params, err
 337}
 338
 339func (config VideoConfig) method() string {
 340	return "sendVideo"
 341}
 342
 343func (config VideoConfig) files() []RequestFile {
 344	files := []RequestFile{{
 345		Name: "video",
 346		File: config.File,
 347	}}
 348
 349	if config.Thumb != nil {
 350		files = append(files, RequestFile{
 351			Name: "thumb",
 352			File: config.Thumb,
 353		})
 354	}
 355
 356	return files
 357}
 358
 359// AnimationConfig contains information about a SendAnimation request.
 360type AnimationConfig struct {
 361	BaseFile
 362	Duration  int
 363	Thumb     interface{}
 364	Caption   string
 365	ParseMode string
 366}
 367
 368func (config AnimationConfig) params() (Params, error) {
 369	params, err := config.BaseChat.params()
 370
 371	params.AddNonZero("duration", config.Duration)
 372	params.AddNonEmpty("caption", config.Caption)
 373	params.AddNonEmpty("parse_mode", config.ParseMode)
 374
 375	return params, err
 376}
 377
 378func (config AnimationConfig) method() string {
 379	return "sendAnimation"
 380}
 381
 382func (config AnimationConfig) files() []RequestFile {
 383	files := []RequestFile{{
 384		Name: "animation",
 385		File: config.File,
 386	}}
 387
 388	if config.Thumb != nil {
 389		files = append(files, RequestFile{
 390			Name: "thumb",
 391			File: config.Thumb,
 392		})
 393	}
 394
 395	return files
 396}
 397
 398// VideoNoteConfig contains information about a SendVideoNote request.
 399type VideoNoteConfig struct {
 400	BaseFile
 401	Thumb    interface{}
 402	Duration int
 403	Length   int
 404}
 405
 406func (config VideoNoteConfig) params() (Params, error) {
 407	params, err := config.BaseChat.params()
 408
 409	params.AddNonZero("duration", config.Duration)
 410	params.AddNonZero("length", config.Length)
 411
 412	return params, err
 413}
 414
 415func (config VideoNoteConfig) method() string {
 416	return "sendVideoNote"
 417}
 418
 419func (config VideoNoteConfig) files() []RequestFile {
 420	files := []RequestFile{{
 421		Name: "video_note",
 422		File: config.File,
 423	}}
 424
 425	if config.Thumb != nil {
 426		files = append(files, RequestFile{
 427			Name: "thumb",
 428			File: config.Thumb,
 429		})
 430	}
 431
 432	return files
 433}
 434
 435// VoiceConfig contains information about a SendVoice request.
 436type VoiceConfig struct {
 437	BaseFile
 438	Thumb     interface{}
 439	Caption   string
 440	ParseMode string
 441	Duration  int
 442}
 443
 444func (config VoiceConfig) params() (Params, error) {
 445	params, err := config.BaseChat.params()
 446
 447	params.AddNonZero("duration", config.Duration)
 448	params.AddNonEmpty("caption", config.Caption)
 449	params.AddNonEmpty("parse_mode", config.ParseMode)
 450
 451	return params, err
 452}
 453
 454func (config VoiceConfig) method() string {
 455	return "sendVoice"
 456}
 457
 458func (config VoiceConfig) files() []RequestFile {
 459	files := []RequestFile{{
 460		Name: "voice",
 461		File: config.File,
 462	}}
 463
 464	if config.Thumb != nil {
 465		files = append(files, RequestFile{
 466			Name: "thumb",
 467			File: config.Thumb,
 468		})
 469	}
 470
 471	return files
 472}
 473
 474// LocationConfig contains information about a SendLocation request.
 475type LocationConfig struct {
 476	BaseChat
 477	Latitude   float64 // required
 478	Longitude  float64 // required
 479	LivePeriod int     // optional
 480}
 481
 482func (config LocationConfig) params() (Params, error) {
 483	params, err := config.BaseChat.params()
 484
 485	params.AddNonZeroFloat("latitude", config.Latitude)
 486	params.AddNonZeroFloat("longitude", config.Longitude)
 487	params.AddNonZero("live_period", config.LivePeriod)
 488
 489	return params, err
 490}
 491
 492func (config LocationConfig) method() string {
 493	return "sendLocation"
 494}
 495
 496// EditMessageLiveLocationConfig allows you to update a live location.
 497type EditMessageLiveLocationConfig struct {
 498	BaseEdit
 499	Latitude  float64 // required
 500	Longitude float64 // required
 501}
 502
 503func (config EditMessageLiveLocationConfig) params() (Params, error) {
 504	params, err := config.BaseEdit.params()
 505
 506	params.AddNonZeroFloat("latitude", config.Latitude)
 507	params.AddNonZeroFloat("longitude", config.Longitude)
 508
 509	return params, err
 510}
 511
 512func (config EditMessageLiveLocationConfig) method() string {
 513	return "editMessageLiveLocation"
 514}
 515
 516// StopMessageLiveLocationConfig stops updating a live location.
 517type StopMessageLiveLocationConfig struct {
 518	BaseEdit
 519}
 520
 521func (config StopMessageLiveLocationConfig) params() (Params, error) {
 522	return config.BaseEdit.params()
 523}
 524
 525func (config StopMessageLiveLocationConfig) method() string {
 526	return "stopMessageLiveLocation"
 527}
 528
 529// VenueConfig contains information about a SendVenue request.
 530type VenueConfig struct {
 531	BaseChat
 532	Latitude     float64 // required
 533	Longitude    float64 // required
 534	Title        string  // required
 535	Address      string  // required
 536	FoursquareID string
 537}
 538
 539func (config VenueConfig) params() (Params, error) {
 540	params, err := config.BaseChat.params()
 541
 542	params.AddNonZeroFloat("latitude", config.Latitude)
 543	params.AddNonZeroFloat("longitude", config.Longitude)
 544	params["title"] = config.Title
 545	params["address"] = config.Address
 546	params.AddNonEmpty("foursquare_id", config.FoursquareID)
 547
 548	return params, err
 549}
 550
 551func (config VenueConfig) method() string {
 552	return "sendVenue"
 553}
 554
 555// ContactConfig allows you to send a contact.
 556type ContactConfig struct {
 557	BaseChat
 558	PhoneNumber string
 559	FirstName   string
 560	LastName    string
 561	VCard       string
 562}
 563
 564func (config ContactConfig) params() (Params, error) {
 565	params, err := config.BaseChat.params()
 566
 567	params["phone_number"] = config.PhoneNumber
 568	params["first_name"] = config.FirstName
 569
 570	params.AddNonEmpty("last_name", config.LastName)
 571	params.AddNonEmpty("vcard", config.VCard)
 572
 573	return params, err
 574}
 575
 576func (config ContactConfig) method() string {
 577	return "sendContact"
 578}
 579
 580// SendPollConfig allows you to send a poll.
 581type SendPollConfig struct {
 582	BaseChat
 583	Question              string
 584	Options               []string
 585	IsAnonymous           bool
 586	Type                  string
 587	AllowsMultipleAnswers bool
 588	CorrectOptionID       int64
 589	Explanation           string
 590	ExplanationParseMode  string
 591	OpenPeriod            int
 592	CloseDate             int
 593	IsClosed              bool
 594}
 595
 596func (config SendPollConfig) params() (Params, error) {
 597	params, err := config.BaseChat.params()
 598	if err != nil {
 599		return params, err
 600	}
 601
 602	params["question"] = config.Question
 603	err = params.AddInterface("options", config.Options)
 604	params["is_anonymous"] = strconv.FormatBool(config.IsAnonymous)
 605	params.AddNonEmpty("type", config.Type)
 606	params["allows_multiple_answers"] = strconv.FormatBool(config.AllowsMultipleAnswers)
 607	params["correct_option_id"] = strconv.FormatInt(config.CorrectOptionID, 10)
 608	params.AddBool("is_closed", config.IsClosed)
 609	params.AddNonEmpty("explanation", config.Explanation)
 610	params.AddNonEmpty("explanation_parse_mode", config.ExplanationParseMode)
 611	params.AddNonZero("open_period", config.OpenPeriod)
 612	params.AddNonZero("close_date", config.CloseDate)
 613
 614	return params, err
 615}
 616
 617func (SendPollConfig) method() string {
 618	return "sendPoll"
 619}
 620
 621// GameConfig allows you to send a game.
 622type GameConfig struct {
 623	BaseChat
 624	GameShortName string
 625}
 626
 627func (config GameConfig) params() (Params, error) {
 628	params, err := config.BaseChat.params()
 629
 630	params["game_short_name"] = config.GameShortName
 631
 632	return params, err
 633}
 634
 635func (config GameConfig) method() string {
 636	return "sendGame"
 637}
 638
 639// SetGameScoreConfig allows you to update the game score in a chat.
 640type SetGameScoreConfig struct {
 641	UserID             int
 642	Score              int
 643	Force              bool
 644	DisableEditMessage bool
 645	ChatID             int64
 646	ChannelUsername    string
 647	MessageID          int
 648	InlineMessageID    string
 649}
 650
 651func (config SetGameScoreConfig) params() (Params, error) {
 652	params := make(Params)
 653
 654	params.AddNonZero("user_id", config.UserID)
 655	params.AddNonZero("scrore", config.Score)
 656	params.AddBool("disable_edit_message", config.DisableEditMessage)
 657
 658	if config.InlineMessageID != "" {
 659		params["inline_message_id"] = config.InlineMessageID
 660	} else {
 661		params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
 662		params.AddNonZero("message_id", config.MessageID)
 663	}
 664
 665	return params, nil
 666}
 667
 668func (config SetGameScoreConfig) method() string {
 669	return "setGameScore"
 670}
 671
 672// GetGameHighScoresConfig allows you to fetch the high scores for a game.
 673type GetGameHighScoresConfig struct {
 674	UserID          int
 675	ChatID          int
 676	ChannelUsername string
 677	MessageID       int
 678	InlineMessageID string
 679}
 680
 681func (config GetGameHighScoresConfig) params() (Params, error) {
 682	params := make(Params)
 683
 684	params.AddNonZero("user_id", config.UserID)
 685
 686	if config.InlineMessageID != "" {
 687		params["inline_message_id"] = config.InlineMessageID
 688	} else {
 689		params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
 690		params.AddNonZero("message_id", config.MessageID)
 691	}
 692
 693	return params, nil
 694}
 695
 696func (config GetGameHighScoresConfig) method() string {
 697	return "getGameHighScores"
 698}
 699
 700// ChatActionConfig contains information about a SendChatAction request.
 701type ChatActionConfig struct {
 702	BaseChat
 703	Action string // required
 704}
 705
 706func (config ChatActionConfig) params() (Params, error) {
 707	params, err := config.BaseChat.params()
 708
 709	params["action"] = config.Action
 710
 711	return params, err
 712}
 713
 714func (config ChatActionConfig) method() string {
 715	return "sendChatAction"
 716}
 717
 718// EditMessageTextConfig allows you to modify the text in a message.
 719type EditMessageTextConfig struct {
 720	BaseEdit
 721	Text                  string
 722	ParseMode             string
 723	DisableWebPagePreview bool
 724}
 725
 726func (config EditMessageTextConfig) params() (Params, error) {
 727	params, err := config.BaseEdit.params()
 728
 729	params["text"] = config.Text
 730	params.AddNonEmpty("parse_mode", config.ParseMode)
 731	params.AddBool("disable_web_page_preview", config.DisableWebPagePreview)
 732
 733	return params, err
 734}
 735
 736func (config EditMessageTextConfig) method() string {
 737	return "editMessageText"
 738}
 739
 740// EditMessageCaptionConfig allows you to modify the caption of a message.
 741type EditMessageCaptionConfig struct {
 742	BaseEdit
 743	Caption   string
 744	ParseMode string
 745}
 746
 747func (config EditMessageCaptionConfig) params() (Params, error) {
 748	params, err := config.BaseEdit.params()
 749
 750	params["caption"] = config.Caption
 751	params.AddNonEmpty("parse_mode", config.ParseMode)
 752
 753	return params, err
 754}
 755
 756func (config EditMessageCaptionConfig) method() string {
 757	return "editMessageCaption"
 758}
 759
 760// EditMessageMediaConfig allows you to make an editMessageMedia request.
 761type EditMessageMediaConfig struct {
 762	BaseEdit
 763
 764	Media interface{}
 765}
 766
 767func (EditMessageMediaConfig) method() string {
 768	return "editMessageMedia"
 769}
 770
 771func (config EditMessageMediaConfig) params() (Params, error) {
 772	params, err := config.BaseEdit.params()
 773	if err != nil {
 774		return params, err
 775	}
 776
 777	err = params.AddInterface("media", prepareInputMediaParam(config.Media, 0))
 778
 779	return params, err
 780}
 781
 782func (config EditMessageMediaConfig) files() []RequestFile {
 783	return prepareInputMediaFile(config.Media, 0)
 784}
 785
 786// EditMessageReplyMarkupConfig allows you to modify the reply markup
 787// of a message.
 788type EditMessageReplyMarkupConfig struct {
 789	BaseEdit
 790}
 791
 792func (config EditMessageReplyMarkupConfig) params() (Params, error) {
 793	return config.BaseEdit.params()
 794}
 795
 796func (config EditMessageReplyMarkupConfig) method() string {
 797	return "editMessageReplyMarkup"
 798}
 799
 800// StopPollConfig allows you to stop a poll sent by the bot.
 801type StopPollConfig struct {
 802	BaseEdit
 803}
 804
 805func (config StopPollConfig) params() (Params, error) {
 806	return config.BaseEdit.params()
 807}
 808
 809func (StopPollConfig) method() string {
 810	return "stopPoll"
 811}
 812
 813// UserProfilePhotosConfig contains information about a
 814// GetUserProfilePhotos request.
 815type UserProfilePhotosConfig struct {
 816	UserID int
 817	Offset int
 818	Limit  int
 819}
 820
 821func (UserProfilePhotosConfig) method() string {
 822	return "getUserProfilePhotos"
 823}
 824
 825func (config UserProfilePhotosConfig) params() (Params, error) {
 826	params := make(Params)
 827
 828	params.AddNonZero("user_id", config.UserID)
 829	params.AddNonZero("offset", config.Offset)
 830	params.AddNonZero("limit", config.Limit)
 831
 832	return params, nil
 833}
 834
 835// FileConfig has information about a file hosted on Telegram.
 836type FileConfig struct {
 837	FileID string
 838}
 839
 840func (FileConfig) method() string {
 841	return "getFile"
 842}
 843
 844func (config FileConfig) params() (Params, error) {
 845	params := make(Params)
 846
 847	params["file_id"] = config.FileID
 848
 849	return params, nil
 850}
 851
 852// UpdateConfig contains information about a GetUpdates request.
 853type UpdateConfig struct {
 854	Offset  int
 855	Limit   int
 856	Timeout int
 857}
 858
 859func (UpdateConfig) method() string {
 860	return "getUpdates"
 861}
 862
 863func (config UpdateConfig) params() (Params, error) {
 864	params := make(Params)
 865
 866	params.AddNonZero("offset", config.Offset)
 867	params.AddNonZero("limit", config.Limit)
 868	params.AddNonZero("timeout", config.Timeout)
 869
 870	return params, nil
 871}
 872
 873// WebhookConfig contains information about a SetWebhook request.
 874type WebhookConfig struct {
 875	URL            *url.URL
 876	Certificate    interface{}
 877	MaxConnections int
 878	AllowedUpdates []string
 879}
 880
 881func (config WebhookConfig) method() string {
 882	return "setWebhook"
 883}
 884
 885func (config WebhookConfig) params() (Params, error) {
 886	params := make(Params)
 887
 888	if config.URL != nil {
 889		params["url"] = config.URL.String()
 890	}
 891
 892	params.AddNonZero("max_connections", config.MaxConnections)
 893	err := params.AddInterface("allowed_updates", config.AllowedUpdates)
 894
 895	return params, err
 896}
 897
 898func (config WebhookConfig) files() []RequestFile {
 899	if config.Certificate != nil {
 900		return []RequestFile{{
 901			Name: "certificate",
 902			File: config.Certificate,
 903		}}
 904	}
 905
 906	return nil
 907}
 908
 909// RemoveWebhookConfig is a helper to remove a webhook.
 910type RemoveWebhookConfig struct {
 911}
 912
 913func (config RemoveWebhookConfig) method() string {
 914	return "setWebhook"
 915}
 916
 917func (config RemoveWebhookConfig) params() (Params, error) {
 918	return nil, nil
 919}
 920
 921// FileBytes contains information about a set of bytes to upload
 922// as a File.
 923type FileBytes struct {
 924	Name  string
 925	Bytes []byte
 926}
 927
 928// FileReader contains information about a reader to upload as a File.
 929type FileReader struct {
 930	Name   string
 931	Reader io.Reader
 932}
 933
 934// FileURL is a URL to use as a file for a request.
 935type FileURL string
 936
 937// FileID is an ID of a file already uploaded to Telegram.
 938type FileID string
 939
 940// InlineConfig contains information on making an InlineQuery response.
 941type InlineConfig struct {
 942	InlineQueryID     string        `json:"inline_query_id"`
 943	Results           []interface{} `json:"results"`
 944	CacheTime         int           `json:"cache_time"`
 945	IsPersonal        bool          `json:"is_personal"`
 946	NextOffset        string        `json:"next_offset"`
 947	SwitchPMText      string        `json:"switch_pm_text"`
 948	SwitchPMParameter string        `json:"switch_pm_parameter"`
 949}
 950
 951func (config InlineConfig) method() string {
 952	return "answerInlineQuery"
 953}
 954
 955func (config InlineConfig) params() (Params, error) {
 956	params := make(Params)
 957
 958	params["inline_query_id"] = config.InlineQueryID
 959	params.AddNonZero("cache_time", config.CacheTime)
 960	params.AddBool("is_personal", config.IsPersonal)
 961	params.AddNonEmpty("next_offset", config.NextOffset)
 962	params.AddNonEmpty("switch_pm_text", config.SwitchPMText)
 963	params.AddNonEmpty("switch_pm_parameter", config.SwitchPMParameter)
 964
 965	if err := params.AddInterface("results", config.Results); err != nil {
 966		return params, err
 967	}
 968
 969	return params, nil
 970}
 971
 972// CallbackConfig contains information on making a CallbackQuery response.
 973type CallbackConfig struct {
 974	CallbackQueryID string `json:"callback_query_id"`
 975	Text            string `json:"text"`
 976	ShowAlert       bool   `json:"show_alert"`
 977	URL             string `json:"url"`
 978	CacheTime       int    `json:"cache_time"`
 979}
 980
 981func (config CallbackConfig) method() string {
 982	return "answerCallbackQuery"
 983}
 984
 985func (config CallbackConfig) params() (Params, error) {
 986	params := make(Params)
 987
 988	params["callback_query_id"] = config.CallbackQueryID
 989	params.AddNonEmpty("text", config.Text)
 990	params.AddBool("show_alert", config.ShowAlert)
 991	params.AddNonEmpty("url", config.URL)
 992	params.AddNonZero("cache_time", config.CacheTime)
 993
 994	return params, nil
 995}
 996
 997// ChatMemberConfig contains information about a user in a chat for use
 998// with administrative functions such as kicking or unbanning a user.
 999type ChatMemberConfig struct {
1000	ChatID             int64
1001	SuperGroupUsername string
1002	ChannelUsername    string
1003	UserID             int
1004}
1005
1006// UnbanChatMemberConfig allows you to unban a user.
1007type UnbanChatMemberConfig struct {
1008	ChatMemberConfig
1009}
1010
1011func (config UnbanChatMemberConfig) method() string {
1012	return "unbanChatMember"
1013}
1014
1015func (config UnbanChatMemberConfig) params() (Params, error) {
1016	params := make(Params)
1017
1018	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1019	params.AddNonZero("user_id", config.UserID)
1020
1021	return params, nil
1022}
1023
1024// KickChatMemberConfig contains extra fields to kick user
1025type KickChatMemberConfig struct {
1026	ChatMemberConfig
1027	UntilDate int64
1028}
1029
1030func (config KickChatMemberConfig) method() string {
1031	return "kickChatMember"
1032}
1033
1034func (config KickChatMemberConfig) params() (Params, error) {
1035	params := make(Params)
1036
1037	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1038	params.AddNonZero("user_id", config.UserID)
1039	params.AddNonZero64("until_date", config.UntilDate)
1040
1041	return params, nil
1042}
1043
1044// RestrictChatMemberConfig contains fields to restrict members of chat
1045type RestrictChatMemberConfig struct {
1046	ChatMemberConfig
1047	UntilDate   int64
1048	Permissions *ChatPermissions
1049}
1050
1051func (config RestrictChatMemberConfig) method() string {
1052	return "restrictChatMember"
1053}
1054
1055func (config RestrictChatMemberConfig) params() (Params, error) {
1056	params := make(Params)
1057
1058	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1059	params.AddNonZero("user_id", config.UserID)
1060
1061	if err := params.AddInterface("permissions", config.Permissions); err != nil {
1062		return params, err
1063	}
1064	params.AddNonZero64("until_date", config.UntilDate)
1065
1066	return params, nil
1067}
1068
1069// PromoteChatMemberConfig contains fields to promote members of chat
1070type PromoteChatMemberConfig struct {
1071	ChatMemberConfig
1072	CanChangeInfo      bool
1073	CanPostMessages    bool
1074	CanEditMessages    bool
1075	CanDeleteMessages  bool
1076	CanInviteUsers     bool
1077	CanRestrictMembers bool
1078	CanPinMessages     bool
1079	CanPromoteMembers  bool
1080}
1081
1082func (config PromoteChatMemberConfig) method() string {
1083	return "promoteChatMember"
1084}
1085
1086func (config PromoteChatMemberConfig) params() (Params, error) {
1087	params := make(Params)
1088
1089	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1090	params.AddNonZero("user_id", config.UserID)
1091
1092	params.AddBool("can_change_info", config.CanChangeInfo)
1093	params.AddBool("can_post_messages", config.CanPostMessages)
1094	params.AddBool("can_edit_messages", config.CanEditMessages)
1095	params.AddBool("can_delete_messages", config.CanDeleteMessages)
1096	params.AddBool("can_invite_users", config.CanInviteUsers)
1097	params.AddBool("can_restrict_members", config.CanRestrictMembers)
1098	params.AddBool("can_pin_messages", config.CanPinMessages)
1099	params.AddBool("can_promote_members", config.CanPromoteMembers)
1100
1101	return params, nil
1102}
1103
1104// SetChatAdministratorCustomTitle sets the title of an administrative user
1105// promoted by the bot for a chat.
1106type SetChatAdministratorCustomTitle struct {
1107	ChatMemberConfig
1108	CustomTitle string
1109}
1110
1111func (SetChatAdministratorCustomTitle) method() string {
1112	return "setChatAdministratorCustomTitle"
1113}
1114
1115func (config SetChatAdministratorCustomTitle) params() (Params, error) {
1116	params := make(Params)
1117
1118	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
1119	params.AddNonZero("user_id", config.UserID)
1120	params.AddNonEmpty("custom_title", config.CustomTitle)
1121
1122	return params, nil
1123}
1124
1125// ChatConfig contains information about getting information on a chat.
1126type ChatConfig struct {
1127	ChatID             int64
1128	SuperGroupUsername string
1129}
1130
1131func (config ChatConfig) params() (Params, error) {
1132	params := make(Params)
1133
1134	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1135
1136	return params, nil
1137}
1138
1139// ChatInfoConfig contains information about getting chat information.
1140type ChatInfoConfig struct {
1141	ChatConfig
1142}
1143
1144func (ChatInfoConfig) method() string {
1145	return "getChat"
1146}
1147
1148// ChatMemberCountConfig contains information about getting the number of users in a chat.
1149type ChatMemberCountConfig struct {
1150	ChatConfig
1151}
1152
1153func (ChatMemberCountConfig) method() string {
1154	return "getChatMembersCount"
1155}
1156
1157// ChatAdministratorsConfig contains information about getting chat administrators.
1158type ChatAdministratorsConfig struct {
1159	ChatConfig
1160}
1161
1162func (ChatAdministratorsConfig) method() string {
1163	return "getChatAdministrators"
1164}
1165
1166// SetChatPermissionsConfig allows you to set default permissions for the
1167// members in a group. The bot must be an administrator and have rights to
1168// restrict members.
1169type SetChatPermissionsConfig struct {
1170	ChatConfig
1171	Permissions *ChatPermissions
1172}
1173
1174func (SetChatPermissionsConfig) method() string {
1175	return "setChatPermissions"
1176}
1177
1178func (config SetChatPermissionsConfig) params() (Params, error) {
1179	params := make(Params)
1180
1181	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1182	err := params.AddInterface("permissions", config.Permissions)
1183
1184	return params, err
1185}
1186
1187// ChatInviteLinkConfig contains information about getting a chat link.
1188//
1189// Note that generating a new link will revoke any previous links.
1190type ChatInviteLinkConfig struct {
1191	ChatConfig
1192}
1193
1194func (ChatInviteLinkConfig) method() string {
1195	return "exportChatInviteLink"
1196}
1197
1198func (config ChatInviteLinkConfig) params() (Params, error) {
1199	params := make(Params)
1200
1201	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1202
1203	return params, nil
1204}
1205
1206// LeaveChatConfig allows you to leave a chat.
1207type LeaveChatConfig struct {
1208	ChatID          int64
1209	ChannelUsername string
1210}
1211
1212func (config LeaveChatConfig) method() string {
1213	return "leaveChat"
1214}
1215
1216func (config LeaveChatConfig) params() (Params, error) {
1217	params := make(Params)
1218
1219	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1220
1221	return params, nil
1222}
1223
1224// ChatConfigWithUser contains information about a chat and a user.
1225type ChatConfigWithUser struct {
1226	ChatID             int64
1227	SuperGroupUsername string
1228	UserID             int
1229}
1230
1231func (config ChatConfigWithUser) params() (Params, error) {
1232	params := make(Params)
1233
1234	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1235	params.AddNonZero("user_id", config.UserID)
1236
1237	return params, nil
1238}
1239
1240// GetChatMemberConfig is information about getting a specific member in a chat.
1241type GetChatMemberConfig struct {
1242	ChatConfigWithUser
1243}
1244
1245func (GetChatMemberConfig) method() string {
1246	return "getChatMember"
1247}
1248
1249// InvoiceConfig contains information for sendInvoice request.
1250type InvoiceConfig struct {
1251	BaseChat
1252	Title                     string         // required
1253	Description               string         // required
1254	Payload                   string         // required
1255	ProviderToken             string         // required
1256	StartParameter            string         // required
1257	Currency                  string         // required
1258	Prices                    []LabeledPrice // required
1259	ProviderData              string
1260	PhotoURL                  string
1261	PhotoSize                 int
1262	PhotoWidth                int
1263	PhotoHeight               int
1264	NeedName                  bool
1265	NeedPhoneNumber           bool
1266	NeedEmail                 bool
1267	NeedShippingAddress       bool
1268	SendPhoneNumberToProvider bool
1269	SendEmailToProvider       bool
1270	IsFlexible                bool
1271}
1272
1273func (config InvoiceConfig) params() (Params, error) {
1274	params, err := config.BaseChat.params()
1275	if err != nil {
1276		return params, err
1277	}
1278
1279	params["title"] = config.Title
1280	params["description"] = config.Description
1281	params["payload"] = config.Payload
1282	params["provider_token"] = config.ProviderToken
1283	params["start_parameter"] = config.StartParameter
1284	params["currency"] = config.Currency
1285
1286	if err = params.AddInterface("prices", config.Prices); err != nil {
1287		return params, err
1288	}
1289
1290	params.AddNonEmpty("provider_data", config.ProviderData)
1291	params.AddNonEmpty("photo_url", config.PhotoURL)
1292	params.AddNonZero("photo_size", config.PhotoSize)
1293	params.AddNonZero("photo_width", config.PhotoWidth)
1294	params.AddNonZero("photo_height", config.PhotoHeight)
1295	params.AddBool("need_name", config.NeedName)
1296	params.AddBool("need_phone_number", config.NeedPhoneNumber)
1297	params.AddBool("need_email", config.NeedEmail)
1298	params.AddBool("need_shipping_address", config.NeedShippingAddress)
1299	params.AddBool("is_flexible", config.IsFlexible)
1300	params.AddBool("send_phone_number_to_provider", config.SendPhoneNumberToProvider)
1301	params.AddBool("send_email_to_provider", config.SendEmailToProvider)
1302
1303	return params, nil
1304}
1305
1306func (config InvoiceConfig) method() string {
1307	return "sendInvoice"
1308}
1309
1310// ShippingConfig contains information for answerShippingQuery request.
1311type ShippingConfig struct {
1312	ShippingQueryID string // required
1313	OK              bool   // required
1314	ShippingOptions []ShippingOption
1315	ErrorMessage    string
1316}
1317
1318// PreCheckoutConfig conatins information for answerPreCheckoutQuery request.
1319type PreCheckoutConfig struct {
1320	PreCheckoutQueryID string // required
1321	OK                 bool   // required
1322	ErrorMessage       string
1323}
1324
1325// DeleteMessageConfig contains information of a message in a chat to delete.
1326type DeleteMessageConfig struct {
1327	ChannelUsername string
1328	ChatID          int64
1329	MessageID       int
1330}
1331
1332func (config DeleteMessageConfig) method() string {
1333	return "deleteMessage"
1334}
1335
1336func (config DeleteMessageConfig) params() (Params, error) {
1337	params := make(Params)
1338
1339	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1340	params.AddNonZero("message_id", config.MessageID)
1341
1342	return params, nil
1343}
1344
1345// PinChatMessageConfig contains information of a message in a chat to pin.
1346type PinChatMessageConfig struct {
1347	ChatID              int64
1348	ChannelUsername     string
1349	MessageID           int
1350	DisableNotification bool
1351}
1352
1353func (config PinChatMessageConfig) method() string {
1354	return "pinChatMessage"
1355}
1356
1357func (config PinChatMessageConfig) params() (Params, error) {
1358	params := make(Params)
1359
1360	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1361	params.AddNonZero("message_id", config.MessageID)
1362	params.AddBool("disable_notification", config.DisableNotification)
1363
1364	return params, nil
1365}
1366
1367// UnpinChatMessageConfig contains information of chat to unpin.
1368type UnpinChatMessageConfig struct {
1369	ChatID          int64
1370	ChannelUsername string
1371}
1372
1373func (config UnpinChatMessageConfig) method() string {
1374	return "unpinChatMessage"
1375}
1376
1377func (config UnpinChatMessageConfig) params() (Params, error) {
1378	params := make(Params)
1379
1380	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1381
1382	return params, nil
1383}
1384
1385// SetChatPhotoConfig allows you to set a group, supergroup, or channel's photo.
1386type SetChatPhotoConfig struct {
1387	BaseFile
1388}
1389
1390func (config SetChatPhotoConfig) method() string {
1391	return "setChatPhoto"
1392}
1393
1394func (config SetChatPhotoConfig) files() []RequestFile {
1395	return []RequestFile{{
1396		Name: "photo",
1397		File: config.File,
1398	}}
1399}
1400
1401// DeleteChatPhotoConfig allows you to delete a group, supergroup, or channel's photo.
1402type DeleteChatPhotoConfig struct {
1403	ChatID          int64
1404	ChannelUsername string
1405}
1406
1407func (config DeleteChatPhotoConfig) method() string {
1408	return "deleteChatPhoto"
1409}
1410
1411func (config DeleteChatPhotoConfig) params() (Params, error) {
1412	params := make(Params)
1413
1414	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1415
1416	return params, nil
1417}
1418
1419// SetChatTitleConfig allows you to set the title of something other than a private chat.
1420type SetChatTitleConfig struct {
1421	ChatID          int64
1422	ChannelUsername string
1423
1424	Title string
1425}
1426
1427func (config SetChatTitleConfig) method() string {
1428	return "setChatTitle"
1429}
1430
1431func (config SetChatTitleConfig) params() (Params, error) {
1432	params := make(Params)
1433
1434	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1435	params["title"] = config.Title
1436
1437	return params, nil
1438}
1439
1440// SetChatDescriptionConfig allows you to set the description of a supergroup or channel.
1441type SetChatDescriptionConfig struct {
1442	ChatID          int64
1443	ChannelUsername string
1444
1445	Description string
1446}
1447
1448func (config SetChatDescriptionConfig) method() string {
1449	return "setChatDescription"
1450}
1451
1452func (config SetChatDescriptionConfig) params() (Params, error) {
1453	params := make(Params)
1454
1455	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1456	params["description"] = config.Description
1457
1458	return params, nil
1459}
1460
1461// GetStickerSetConfig allows you to get the stickers in a set.
1462type GetStickerSetConfig struct {
1463	Name string
1464}
1465
1466func (config GetStickerSetConfig) method() string {
1467	return "getStickerSet"
1468}
1469
1470func (config GetStickerSetConfig) params() (Params, error) {
1471	params := make(Params)
1472
1473	params["name"] = config.Name
1474
1475	return params, nil
1476}
1477
1478// UploadStickerConfig allows you to upload a sticker for use in a set later.
1479type UploadStickerConfig struct {
1480	UserID     int64
1481	PNGSticker interface{}
1482}
1483
1484func (config UploadStickerConfig) method() string {
1485	return "uploadStickerFile"
1486}
1487
1488func (config UploadStickerConfig) params() (Params, error) {
1489	params := make(Params)
1490
1491	params.AddNonZero64("user_id", config.UserID)
1492
1493	return params, nil
1494}
1495
1496func (config UploadStickerConfig) files() []RequestFile {
1497	return []RequestFile{{
1498		Name: "png_sticker",
1499		File: config.PNGSticker,
1500	}}
1501}
1502
1503// NewStickerSetConfig allows creating a new sticker set.
1504//
1505// You must set either PNGSticker or TGSSticker.
1506type NewStickerSetConfig struct {
1507	UserID        int64
1508	Name          string
1509	Title         string
1510	PNGSticker    interface{}
1511	TGSSticker    interface{}
1512	Emojis        string
1513	ContainsMasks bool
1514	MaskPosition  *MaskPosition
1515}
1516
1517func (config NewStickerSetConfig) method() string {
1518	return "createNewStickerSet"
1519}
1520
1521func (config NewStickerSetConfig) params() (Params, error) {
1522	params := make(Params)
1523
1524	params.AddNonZero64("user_id", config.UserID)
1525	params["name"] = config.Name
1526	params["title"] = config.Title
1527
1528	params["emojis"] = config.Emojis
1529
1530	params.AddBool("contains_masks", config.ContainsMasks)
1531
1532	err := params.AddInterface("mask_position", config.MaskPosition)
1533
1534	return params, err
1535}
1536
1537func (config NewStickerSetConfig) files() []RequestFile {
1538	if config.PNGSticker != nil {
1539		return []RequestFile{{
1540			Name: "png_sticker",
1541			File: config.PNGSticker,
1542		}}
1543	}
1544
1545	return []RequestFile{{
1546		Name: "tgs_sticker",
1547		File: config.TGSSticker,
1548	}}
1549}
1550
1551// AddStickerConfig allows you to add a sticker to a set.
1552type AddStickerConfig struct {
1553	UserID       int64
1554	Name         string
1555	PNGSticker   interface{}
1556	TGSSticker   interface{}
1557	Emojis       string
1558	MaskPosition *MaskPosition
1559}
1560
1561func (config AddStickerConfig) method() string {
1562	return "addStickerToSet"
1563}
1564
1565func (config AddStickerConfig) params() (Params, error) {
1566	params := make(Params)
1567
1568	params.AddNonZero64("user_id", config.UserID)
1569	params["name"] = config.Name
1570	params["emojis"] = config.Emojis
1571
1572	err := params.AddInterface("mask_position", config.MaskPosition)
1573
1574	return params, err
1575}
1576
1577func (config AddStickerConfig) files() []RequestFile {
1578	if config.PNGSticker != nil {
1579		return []RequestFile{{
1580			Name: "png_sticker",
1581			File: config.PNGSticker,
1582		}}
1583	}
1584
1585	return []RequestFile{{
1586		Name: "tgs_sticker",
1587		File: config.TGSSticker,
1588	}}
1589
1590}
1591
1592// SetStickerPositionConfig allows you to change the position of a sticker in a set.
1593type SetStickerPositionConfig struct {
1594	Sticker  string
1595	Position int
1596}
1597
1598func (config SetStickerPositionConfig) method() string {
1599	return "setStickerPositionInSet"
1600}
1601
1602func (config SetStickerPositionConfig) params() (Params, error) {
1603	params := make(Params)
1604
1605	params["sticker"] = config.Sticker
1606	params.AddNonZero("position", config.Position)
1607
1608	return params, nil
1609}
1610
1611// DeleteStickerConfig allows you to delete a sticker from a set.
1612type DeleteStickerConfig struct {
1613	Sticker string
1614}
1615
1616func (config DeleteStickerConfig) method() string {
1617	return "deleteStickerFromSet"
1618}
1619
1620func (config DeleteStickerConfig) params() (Params, error) {
1621	params := make(Params)
1622
1623	params["sticker"] = config.Sticker
1624
1625	return params, nil
1626}
1627
1628// SetStickerSetThumbConfig allows you to set the thumbnail for a sticker set.
1629type SetStickerSetThumbConfig struct {
1630	Name   string
1631	UserID int
1632	Thumb  interface{}
1633}
1634
1635func (config SetStickerSetThumbConfig) method() string {
1636	return "setStickerSetThumb"
1637}
1638
1639func (config SetStickerSetThumbConfig) params() (Params, error) {
1640	params := make(Params)
1641
1642	params["name"] = config.Name
1643	params.AddNonZero("user_id", config.UserID)
1644
1645	return params, nil
1646}
1647
1648func (config SetStickerSetThumbConfig) files() []RequestFile {
1649	return []RequestFile{{
1650		Name: "thumb",
1651		File: config.Thumb,
1652	}}
1653}
1654
1655// SetChatStickerSetConfig allows you to set the sticker set for a supergroup.
1656type SetChatStickerSetConfig struct {
1657	ChatID             int64
1658	SuperGroupUsername string
1659
1660	StickerSetName string
1661}
1662
1663func (config SetChatStickerSetConfig) method() string {
1664	return "setChatStickerSet"
1665}
1666
1667func (config SetChatStickerSetConfig) params() (Params, error) {
1668	params := make(Params)
1669
1670	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1671	params["sticker_set_name"] = config.StickerSetName
1672
1673	return params, nil
1674}
1675
1676// DeleteChatStickerSetConfig allows you to remove a supergroup's sticker set.
1677type DeleteChatStickerSetConfig struct {
1678	ChatID             int64
1679	SuperGroupUsername string
1680}
1681
1682func (config DeleteChatStickerSetConfig) method() string {
1683	return "deleteChatStickerSet"
1684}
1685
1686func (config DeleteChatStickerSetConfig) params() (Params, error) {
1687	params := make(Params)
1688
1689	params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
1690
1691	return params, nil
1692}
1693
1694// MediaGroupConfig allows you to send a group of media.
1695//
1696// Media consist of InputMedia items (InputMediaPhoto, InputMediaVideo).
1697type MediaGroupConfig struct {
1698	ChatID          int64
1699	ChannelUsername string
1700
1701	Media               []interface{}
1702	DisableNotification bool
1703	ReplyToMessageID    int
1704}
1705
1706func (config MediaGroupConfig) method() string {
1707	return "sendMediaGroup"
1708}
1709
1710func (config MediaGroupConfig) params() (Params, error) {
1711	params := make(Params)
1712
1713	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
1714	params.AddBool("disable_notification", config.DisableNotification)
1715	params.AddNonZero("reply_to_message_id", config.ReplyToMessageID)
1716
1717	err := params.AddInterface("media", prepareInputMediaForParams(config.Media))
1718
1719	return params, err
1720}
1721
1722func (config MediaGroupConfig) files() []RequestFile {
1723	return prepareInputMediaForFiles(config.Media)
1724}
1725
1726// DiceConfig allows you to send a random dice roll to Telegram.
1727//
1728// Emoji may be one of the following: 🎲 (1-6), 🎯 (1-6), 🏀 (1-5).
1729type DiceConfig struct {
1730	BaseChat
1731
1732	Emoji string
1733}
1734
1735func (config DiceConfig) method() string {
1736	return "sendDice"
1737}
1738
1739func (config DiceConfig) params() (Params, error) {
1740	params, err := config.BaseChat.params()
1741	if err != nil {
1742		return params, err
1743	}
1744
1745	params.AddNonEmpty("emoji", config.Emoji)
1746
1747	return params, err
1748}
1749
1750// GetMyCommandsConfig gets a list of the currently registered commands.
1751type GetMyCommandsConfig struct{}
1752
1753func (config GetMyCommandsConfig) method() string {
1754	return "getMyCommands"
1755}
1756
1757func (config GetMyCommandsConfig) params() (Params, error) {
1758	return make(Params), nil
1759}
1760
1761// SetMyCommandsConfig sets a list of commands the bot understands.
1762type SetMyCommandsConfig struct {
1763	commands []BotCommand
1764}
1765
1766func (config SetMyCommandsConfig) method() string {
1767	return "setMyCommands"
1768}
1769
1770func (config SetMyCommandsConfig) params() (Params, error) {
1771	params := make(Params)
1772
1773	err := params.AddInterface("commands", config.commands)
1774
1775	return params, err
1776}
1777
1778// prepareInputMediaParam evaluates a single InputMedia and determines if it
1779// needs to be modified for a successful upload. If it returns nil, then the
1780// value does not need to be included in the params. Otherwise, it will return
1781// the same type as was originally provided.
1782//
1783// The idx is used to calculate the file field name. If you only have a single
1784// file, 0 may be used. It is formatted into "attach://file-%d" for the primary
1785// media and "attach://file-%d-thumb" for thumbnails.
1786//
1787// It is expected to be used in conjunction with prepareInputMediaFile.
1788func prepareInputMediaParam(inputMedia interface{}, idx int) interface{} {
1789	switch m := inputMedia.(type) {
1790	case InputMediaPhoto:
1791		switch m.Media.(type) {
1792		case string, FileBytes, FileReader:
1793			m.Media = fmt.Sprintf("attach://file-%d", idx)
1794		}
1795
1796		return m
1797	case InputMediaVideo:
1798		switch m.Media.(type) {
1799		case string, FileBytes, FileReader:
1800			m.Media = fmt.Sprintf("attach://file-%d", idx)
1801		}
1802
1803		switch m.Thumb.(type) {
1804		case string, FileBytes, FileReader:
1805			m.Thumb = fmt.Sprintf("attach://file-%d-thumb", idx)
1806		}
1807
1808		return m
1809	}
1810
1811	return nil
1812}
1813
1814// prepareInputMediaFile generates an array of RequestFile to provide for
1815// Fileable's files method. It returns an array as a single InputMedia may have
1816// multiple files, for the primary media and a thumbnail.
1817//
1818// The idx parameter is used to generate file field names. It uses the names
1819// "file-%d" for the main file and "file-%d-thumb" for the thumbnail.
1820//
1821// It is expected to be used in conjunction with prepareInputMediaParam.
1822func prepareInputMediaFile(inputMedia interface{}, idx int) []RequestFile {
1823	files := []RequestFile{}
1824
1825	switch m := inputMedia.(type) {
1826	case InputMediaPhoto:
1827		switch f := m.Media.(type) {
1828		case string, FileBytes, FileReader:
1829			files = append(files, RequestFile{
1830				Name: fmt.Sprintf("file-%d", idx),
1831				File: f,
1832			})
1833		}
1834	case InputMediaVideo:
1835		switch f := m.Media.(type) {
1836		case string, FileBytes, FileReader:
1837			files = append(files, RequestFile{
1838				Name: fmt.Sprintf("file-%d", idx),
1839				File: f,
1840			})
1841		}
1842
1843		switch f := m.Thumb.(type) {
1844		case string, FileBytes, FileReader:
1845			files = append(files, RequestFile{
1846				Name: fmt.Sprintf("file-%d-thumb", idx),
1847				File: f,
1848			})
1849		}
1850	}
1851
1852	return files
1853}
1854
1855// prepareInputMediaForParams calls prepareInputMediaParam for each item
1856// provided and returns a new array with the correct params for a request.
1857//
1858// It is expected that files will get data from the associated function,
1859// prepareInputMediaForFiles.
1860func prepareInputMediaForParams(inputMedia []interface{}) []interface{} {
1861	newMedia := make([]interface{}, len(inputMedia))
1862	copy(newMedia, inputMedia)
1863
1864	for idx, media := range inputMedia {
1865		if param := prepareInputMediaParam(media, idx); param != nil {
1866			newMedia[idx] = param
1867		}
1868	}
1869
1870	return newMedia
1871}
1872
1873// prepareInputMediaForFiles calls prepareInputMediaFile for each item
1874// provided and returns a new array with the correct files for a request.
1875//
1876// It is expected that params will get data from the associated function,
1877// prepareInputMediaForParams.
1878func prepareInputMediaForFiles(inputMedia []interface{}) []RequestFile {
1879	files := []RequestFile{}
1880
1881	for idx, media := range inputMedia {
1882		if file := prepareInputMediaFile(media, idx); file != nil {
1883			files = append(files, file...)
1884		}
1885	}
1886
1887	return files
1888}