all repos — telegram-bot-api @ f9ab9c0a4df305dcfc111e96a8b92c6fda442a39

Golang bindings for the Telegram Bot API

helper_methods.go (view raw)

   1package tgbotapi
   2
   3import (
   4	"crypto/hmac"
   5	"crypto/sha256"
   6	"encoding/hex"
   7	"errors"
   8	"fmt"
   9	"net/url"
  10	"sort"
  11	"strings"
  12)
  13
  14// NewMessage creates a new Message.
  15//
  16// chatID is where to send it, text is the message text.
  17func NewMessage(chatID int64, text string) MessageConfig {
  18	return MessageConfig{
  19		BaseChat: BaseChat{
  20			ChatConfig: ChatConfig{
  21				ChatID: chatID,
  22			},
  23		},
  24		Text: text,
  25		LinkPreviewOptions: LinkPreviewOptions{
  26			IsDisabled: false,
  27		},
  28	}
  29}
  30
  31// NewDeleteMessage creates a request to delete a message.
  32func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
  33	return DeleteMessageConfig{
  34		BaseChatMessage: BaseChatMessage{
  35			ChatConfig: ChatConfig{
  36				ChatID: chatID,
  37			},
  38			MessageID: messageID,
  39		},
  40	}
  41}
  42
  43// NewDeleteMessages creates a request to delete multiple messages. The messages have to be
  44// in the same chat. Provide the message ids as an array of integers
  45func NewDeleteMessages(chatID int64, messageIDs []int) DeleteMessagesConfig {
  46	return DeleteMessagesConfig{
  47		BaseChatMessages: BaseChatMessages{
  48			ChatConfig: ChatConfig{
  49				ChatID: chatID,
  50			},
  51			MessageIDs: messageIDs,
  52		},
  53	}
  54}
  55
  56// NewMessageToChannel creates a new Message that is sent to a channel
  57// by username.
  58//
  59// username is the username of the channel, text is the message text,
  60// and the username should be in the form of `@username`.
  61func NewMessageToChannel(username string, text string) MessageConfig {
  62	return MessageConfig{
  63		BaseChat: BaseChat{
  64			ChatConfig: ChatConfig{
  65				ChannelUsername: username,
  66			}},
  67		Text: text,
  68	}
  69}
  70
  71// NewForward creates a new forward.
  72//
  73// chatID is where to send it, fromChatID is the source chat,
  74// and messageID is the ID of the original message.
  75func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
  76	return ForwardConfig{
  77		BaseChat:  BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
  78		FromChat:  ChatConfig{ChatID: fromChatID},
  79		MessageID: messageID,
  80	}
  81}
  82
  83// NewCopyMessage creates a new copy message.
  84//
  85// chatID is where to send it, fromChatID is the source chat,
  86// and messageID is the ID of the original message.
  87func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig {
  88	return CopyMessageConfig{
  89		BaseChat:  BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
  90		FromChat:  ChatConfig{ChatID: fromChatID},
  91		MessageID: messageID,
  92	}
  93}
  94
  95// NewPhoto creates a new sendPhoto request.
  96//
  97// chatID is where to send it, file is a string path to the file,
  98// FileReader, or FileBytes.
  99//
 100// Note that you must send animated GIFs as a document.
 101func NewPhoto(chatID int64, file RequestFileData) PhotoConfig {
 102	return PhotoConfig{
 103		BaseFile: BaseFile{
 104			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 105			File:     file,
 106		},
 107	}
 108}
 109
 110// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
 111//
 112// Note that you must send animated GIFs as a document.
 113func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig {
 114	return PhotoConfig{
 115		BaseFile: BaseFile{
 116			BaseChat: BaseChat{ChatConfig: ChatConfig{ChannelUsername: username}},
 117			File:     file,
 118		},
 119	}
 120}
 121
 122// NewAudio creates a new sendAudio request.
 123func NewAudio(chatID int64, file RequestFileData) AudioConfig {
 124	return AudioConfig{
 125		BaseFile: BaseFile{
 126			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 127			File:     file,
 128		},
 129	}
 130}
 131
 132// NewDocument creates a new sendDocument request.
 133func NewDocument(chatID int64, file RequestFileData) DocumentConfig {
 134	return DocumentConfig{
 135		BaseFile: BaseFile{
 136			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 137			File:     file,
 138		},
 139	}
 140}
 141
 142// NewSticker creates a new sendSticker request.
 143func NewSticker(chatID int64, file RequestFileData) StickerConfig {
 144	return StickerConfig{
 145		BaseFile: BaseFile{
 146			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 147			File:     file,
 148		},
 149	}
 150}
 151
 152// NewCustomEmojiStickerSetThumbnal creates a new setCustomEmojiStickerSetThumbnal request
 153func NewCustomEmojiStickerSetThumbnal(name, customEmojiID string) SetCustomEmojiStickerSetThumbnailConfig {
 154	return SetCustomEmojiStickerSetThumbnailConfig{
 155		Name:          name,
 156		CustomEmojiID: customEmojiID,
 157	}
 158}
 159
 160// NewStickerSetTitle creates a new setStickerSetTitle request
 161func NewStickerSetTitle(name, title string) SetStickerSetTitleConfig {
 162	return SetStickerSetTitleConfig{
 163		Name:  name,
 164		Title: title,
 165	}
 166}
 167
 168// NewDeleteStickerSet creates a new deleteStickerSet request
 169func NewDeleteStickerSet(name, title string) DeleteStickerSetConfig {
 170	return DeleteStickerSetConfig{
 171		Name: name,
 172	}
 173}
 174
 175// NewVideo creates a new sendVideo request.
 176func NewVideo(chatID int64, file RequestFileData) VideoConfig {
 177	return VideoConfig{
 178		BaseFile: BaseFile{
 179			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 180			File:     file,
 181		},
 182	}
 183}
 184
 185// NewAnimation creates a new sendAnimation request.
 186func NewAnimation(chatID int64, file RequestFileData) AnimationConfig {
 187	return AnimationConfig{
 188		BaseFile: BaseFile{
 189			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 190			File:     file,
 191		},
 192	}
 193}
 194
 195// NewVideoNote creates a new sendVideoNote request.
 196//
 197// chatID is where to send it, file is a string path to the file,
 198// FileReader, or FileBytes.
 199func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig {
 200	return VideoNoteConfig{
 201		BaseFile: BaseFile{
 202			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 203			File:     file,
 204		},
 205		Length: length,
 206	}
 207}
 208
 209// NewVoice creates a new sendVoice request.
 210func NewVoice(chatID int64, file RequestFileData) VoiceConfig {
 211	return VoiceConfig{
 212		BaseFile: BaseFile{
 213			BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 214			File:     file,
 215		},
 216	}
 217}
 218
 219// NewMediaGroup creates a new media group. Files should be an array of
 220// two to ten InputMediaPhoto or InputMediaVideo.
 221func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
 222	return MediaGroupConfig{
 223		BaseChat: BaseChat{
 224			ChatConfig: ChatConfig{ChatID: chatID},
 225		},
 226		Media: files,
 227	}
 228}
 229
 230// NewInputMediaPhoto creates a new InputMediaPhoto.
 231func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto {
 232	return InputMediaPhoto{
 233		BaseInputMedia{
 234			Type:  "photo",
 235			Media: media,
 236		},
 237	}
 238}
 239
 240// NewInputMediaVideo creates a new InputMediaVideo.
 241func NewInputMediaVideo(media RequestFileData) InputMediaVideo {
 242	return InputMediaVideo{
 243		BaseInputMedia: BaseInputMedia{
 244			Type:  "video",
 245			Media: media,
 246		},
 247	}
 248}
 249
 250// NewInputMediaAnimation creates a new InputMediaAnimation.
 251func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation {
 252	return InputMediaAnimation{
 253		BaseInputMedia: BaseInputMedia{
 254			Type:  "animation",
 255			Media: media,
 256		},
 257	}
 258}
 259
 260// NewInputMediaAudio creates a new InputMediaAudio.
 261func NewInputMediaAudio(media RequestFileData) InputMediaAudio {
 262	return InputMediaAudio{
 263		BaseInputMedia: BaseInputMedia{
 264			Type:  "audio",
 265			Media: media,
 266		},
 267	}
 268}
 269
 270// NewInputMediaDocument creates a new InputMediaDocument.
 271func NewInputMediaDocument(media RequestFileData) InputMediaDocument {
 272	return InputMediaDocument{
 273		BaseInputMedia: BaseInputMedia{
 274			Type:  "document",
 275			Media: media,
 276		},
 277	}
 278}
 279
 280// NewContact allows you to send a shared contact.
 281func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig {
 282	return ContactConfig{
 283		BaseChat: BaseChat{
 284			ChatConfig: ChatConfig{ChatID: chatID},
 285		},
 286		PhoneNumber: phoneNumber,
 287		FirstName:   firstName,
 288	}
 289}
 290
 291// NewLocation shares your location.
 292//
 293// chatID is where to send it, latitude and longitude are coordinates.
 294func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig {
 295	return LocationConfig{
 296		BaseChat: BaseChat{
 297			ChatConfig: ChatConfig{ChatID: chatID},
 298		},
 299		Latitude:  latitude,
 300		Longitude: longitude,
 301	}
 302}
 303
 304// NewVenue allows you to send a venue and its location.
 305func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig {
 306	return VenueConfig{
 307		BaseChat: BaseChat{
 308			ChatConfig: ChatConfig{ChatID: chatID},
 309		},
 310		Title:     title,
 311		Address:   address,
 312		Latitude:  latitude,
 313		Longitude: longitude,
 314	}
 315}
 316
 317// NewChatAction sets a chat action.
 318// Actions last for 5 seconds, or until your next action.
 319//
 320// chatID is where to send it, action should be set via Chat constants.
 321func NewChatAction(chatID int64, action string) ChatActionConfig {
 322	return ChatActionConfig{
 323		BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}},
 324		Action:   action,
 325	}
 326}
 327
 328// NewUserProfilePhotos gets user profile photos.
 329//
 330// userID is the ID of the user you wish to get profile photos from.
 331func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig {
 332	return UserProfilePhotosConfig{
 333		UserID: userID,
 334		Offset: 0,
 335		Limit:  0,
 336	}
 337}
 338
 339// NewUpdate gets updates since the last Offset.
 340//
 341// offset is the last Update ID to include.
 342// You likely want to set this to the last Update ID plus 1.
 343func NewUpdate(offset int) UpdateConfig {
 344	return UpdateConfig{
 345		Offset:  offset,
 346		Limit:   0,
 347		Timeout: 0,
 348	}
 349}
 350
 351// NewWebhook creates a new webhook.
 352//
 353// link is the url parsable link you wish to get the updates.
 354func NewWebhook(link string) (WebhookConfig, error) {
 355	u, err := url.Parse(link)
 356
 357	if err != nil {
 358		return WebhookConfig{}, err
 359	}
 360
 361	return WebhookConfig{
 362		URL: u,
 363	}, nil
 364}
 365
 366// NewWebhookWithCert creates a new webhook with a certificate.
 367//
 368// link is the url you wish to get webhooks,
 369// file contains a string to a file, FileReader, or FileBytes.
 370func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) {
 371	u, err := url.Parse(link)
 372
 373	if err != nil {
 374		return WebhookConfig{}, err
 375	}
 376
 377	return WebhookConfig{
 378		URL:         u,
 379		Certificate: file,
 380	}, nil
 381}
 382
 383// NewInlineQueryResultArticle creates a new inline query article.
 384func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle {
 385	return InlineQueryResultArticle{
 386		Type:  "article",
 387		ID:    id,
 388		Title: title,
 389		InputMessageContent: InputTextMessageContent{
 390			Text: messageText,
 391		},
 392	}
 393}
 394
 395// NewInlineQueryResultArticleMarkdown creates a new inline query article with Markdown parsing.
 396func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQueryResultArticle {
 397	return InlineQueryResultArticle{
 398		Type:  "article",
 399		ID:    id,
 400		Title: title,
 401		InputMessageContent: InputTextMessageContent{
 402			Text:      messageText,
 403			ParseMode: "Markdown",
 404		},
 405	}
 406}
 407
 408// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing.
 409func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle {
 410	return InlineQueryResultArticle{
 411		Type:  "article",
 412		ID:    id,
 413		Title: title,
 414		InputMessageContent: InputTextMessageContent{
 415			Text:      messageText,
 416			ParseMode: "MarkdownV2",
 417		},
 418	}
 419}
 420
 421// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
 422func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
 423	return InlineQueryResultArticle{
 424		Type:  "article",
 425		ID:    id,
 426		Title: title,
 427		InputMessageContent: InputTextMessageContent{
 428			Text:      messageText,
 429			ParseMode: "HTML",
 430		},
 431	}
 432}
 433
 434// NewInlineQueryResultGIF creates a new inline query GIF.
 435func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF {
 436	return InlineQueryResultGIF{
 437		Type: "gif",
 438		ID:   id,
 439		URL:  url,
 440	}
 441}
 442
 443// NewInlineQueryResultCachedGIF create a new inline query with cached photo.
 444func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF {
 445	return InlineQueryResultCachedGIF{
 446		Type:  "gif",
 447		ID:    id,
 448		GIFID: gifID,
 449	}
 450}
 451
 452// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF.
 453func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
 454	return InlineQueryResultMPEG4GIF{
 455		Type: "mpeg4_gif",
 456		ID:   id,
 457		URL:  url,
 458	}
 459}
 460
 461// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
 462func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF {
 463	return InlineQueryResultCachedMPEG4GIF{
 464		Type:        "mpeg4_gif",
 465		ID:          id,
 466		MPEG4FileID: MPEG4GIFID,
 467	}
 468}
 469
 470// NewInlineQueryResultPhoto creates a new inline query photo.
 471func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto {
 472	return InlineQueryResultPhoto{
 473		Type: "photo",
 474		ID:   id,
 475		URL:  url,
 476	}
 477}
 478
 479// NewInlineQueryResultPhotoWithThumb creates a new inline query photo.
 480func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResultPhoto {
 481	return InlineQueryResultPhoto{
 482		Type:     "photo",
 483		ID:       id,
 484		URL:      url,
 485		ThumbURL: thumb,
 486	}
 487}
 488
 489// NewInlineQueryResultCachedPhoto create a new inline query with cached photo.
 490func NewInlineQueryResultCachedPhoto(id, photoID string) InlineQueryResultCachedPhoto {
 491	return InlineQueryResultCachedPhoto{
 492		Type:    "photo",
 493		ID:      id,
 494		PhotoID: photoID,
 495	}
 496}
 497
 498// NewInlineQueryResultVideo creates a new inline query video.
 499func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo {
 500	return InlineQueryResultVideo{
 501		Type: "video",
 502		ID:   id,
 503		URL:  url,
 504	}
 505}
 506
 507// NewInlineQueryResultCachedVideo create a new inline query with cached video.
 508func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResultCachedVideo {
 509	return InlineQueryResultCachedVideo{
 510		Type:    "video",
 511		ID:      id,
 512		VideoID: videoID,
 513		Title:   title,
 514	}
 515}
 516
 517// NewInlineQueryResultCachedSticker create a new inline query with cached sticker.
 518func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker {
 519	return InlineQueryResultCachedSticker{
 520		Type:      "sticker",
 521		ID:        id,
 522		StickerID: stickerID,
 523		Title:     title,
 524	}
 525}
 526
 527// NewInlineQueryResultAudio creates a new inline query audio.
 528func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
 529	return InlineQueryResultAudio{
 530		Type:  "audio",
 531		ID:    id,
 532		URL:   url,
 533		Title: title,
 534	}
 535}
 536
 537// NewInlineQueryResultCachedAudio create a new inline query with cached photo.
 538func NewInlineQueryResultCachedAudio(id, audioID string) InlineQueryResultCachedAudio {
 539	return InlineQueryResultCachedAudio{
 540		Type:    "audio",
 541		ID:      id,
 542		AudioID: audioID,
 543	}
 544}
 545
 546// NewInlineQueryResultVoice creates a new inline query voice.
 547func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice {
 548	return InlineQueryResultVoice{
 549		Type:  "voice",
 550		ID:    id,
 551		URL:   url,
 552		Title: title,
 553	}
 554}
 555
 556// NewInlineQueryResultCachedVoice create a new inline query with cached photo.
 557func NewInlineQueryResultCachedVoice(id, voiceID, title string) InlineQueryResultCachedVoice {
 558	return InlineQueryResultCachedVoice{
 559		Type:    "voice",
 560		ID:      id,
 561		VoiceID: voiceID,
 562		Title:   title,
 563	}
 564}
 565
 566// NewInlineQueryResultDocument creates a new inline query document.
 567func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument {
 568	return InlineQueryResultDocument{
 569		Type:     "document",
 570		ID:       id,
 571		URL:      url,
 572		Title:    title,
 573		MimeType: mimeType,
 574	}
 575}
 576
 577// NewInlineQueryResultCachedDocument create a new inline query with cached photo.
 578func NewInlineQueryResultCachedDocument(id, documentID, title string) InlineQueryResultCachedDocument {
 579	return InlineQueryResultCachedDocument{
 580		Type:       "document",
 581		ID:         id,
 582		DocumentID: documentID,
 583		Title:      title,
 584	}
 585}
 586
 587// NewInlineQueryResultLocation creates a new inline query location.
 588func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation {
 589	return InlineQueryResultLocation{
 590		Type:      "location",
 591		ID:        id,
 592		Title:     title,
 593		Latitude:  latitude,
 594		Longitude: longitude,
 595	}
 596}
 597
 598// NewInlineQueryResultVenue creates a new inline query venue.
 599func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue {
 600	return InlineQueryResultVenue{
 601		Type:      "venue",
 602		ID:        id,
 603		Title:     title,
 604		Address:   address,
 605		Latitude:  latitude,
 606		Longitude: longitude,
 607	}
 608}
 609
 610// NewEditMessageText allows you to edit the text of a message.
 611func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
 612	return EditMessageTextConfig{
 613		BaseEdit: BaseEdit{
 614			BaseChatMessage: BaseChatMessage{
 615				ChatConfig: ChatConfig{
 616					ChatID: chatID,
 617				},
 618				MessageID: messageID,
 619			},
 620		},
 621		Text: text,
 622	}
 623}
 624
 625// NewEditMessageTextAndMarkup allows you to edit the text and reply markup of a message.
 626func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig {
 627	return EditMessageTextConfig{
 628		BaseEdit: BaseEdit{
 629			BaseChatMessage: BaseChatMessage{
 630				ChatConfig: ChatConfig{
 631					ChatID: chatID,
 632				},
 633				MessageID: messageID,
 634			},
 635			ReplyMarkup: &replyMarkup,
 636		},
 637		Text: text,
 638	}
 639}
 640
 641// NewEditMessageCaption allows you to edit the caption of a message.
 642func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
 643	return EditMessageCaptionConfig{
 644		BaseEdit: BaseEdit{
 645			BaseChatMessage: BaseChatMessage{
 646				ChatConfig: ChatConfig{
 647					ChatID: chatID,
 648				},
 649				MessageID: messageID,
 650			},
 651		},
 652		Caption: caption,
 653	}
 654}
 655
 656// NewEditMessageReplyMarkup allows you to edit the inline
 657// keyboard markup.
 658func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig {
 659	return EditMessageReplyMarkupConfig{
 660		BaseEdit: BaseEdit{
 661			BaseChatMessage: BaseChatMessage{
 662				ChatConfig: ChatConfig{
 663					ChatID: chatID,
 664				},
 665				MessageID: messageID,
 666			},
 667			ReplyMarkup: &replyMarkup,
 668		},
 669	}
 670}
 671
 672// NewRemoveKeyboard hides the keyboard, with the option for being selective
 673// or hiding for everyone.
 674func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
 675	return ReplyKeyboardRemove{
 676		RemoveKeyboard: true,
 677		Selective:      selective,
 678	}
 679}
 680
 681// NewKeyboardButton creates a regular keyboard button.
 682func NewKeyboardButton(text string) KeyboardButton {
 683	return KeyboardButton{
 684		Text: text,
 685	}
 686}
 687
 688// NewKeyboardButtonWebApp creates a keyboard button with text
 689// which goes to a WebApp.
 690func NewKeyboardButtonWebApp(text string, webapp WebAppInfo) KeyboardButton {
 691	return KeyboardButton{
 692		Text:   text,
 693		WebApp: &webapp,
 694	}
 695}
 696
 697// NewKeyboardButtonContact creates a keyboard button that requests
 698// user contact information upon click.
 699func NewKeyboardButtonContact(text string) KeyboardButton {
 700	return KeyboardButton{
 701		Text:           text,
 702		RequestContact: true,
 703	}
 704}
 705
 706// NewKeyboardButtonLocation creates a keyboard button that requests
 707// user location information upon click.
 708func NewKeyboardButtonLocation(text string) KeyboardButton {
 709	return KeyboardButton{
 710		Text:            text,
 711		RequestLocation: true,
 712	}
 713}
 714
 715// NewKeyboardButtonRow creates a row of keyboard buttons.
 716func NewKeyboardButtonRow(buttons ...KeyboardButton) []KeyboardButton {
 717	var row []KeyboardButton
 718
 719	row = append(row, buttons...)
 720
 721	return row
 722}
 723
 724// NewReplyKeyboard creates a new regular keyboard with sane defaults.
 725func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
 726	var keyboard [][]KeyboardButton
 727
 728	keyboard = append(keyboard, rows...)
 729
 730	return ReplyKeyboardMarkup{
 731		ResizeKeyboard: true,
 732		Keyboard:       keyboard,
 733	}
 734}
 735
 736// NewOneTimeReplyKeyboard creates a new one time keyboard.
 737func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
 738	markup := NewReplyKeyboard(rows...)
 739	markup.OneTimeKeyboard = true
 740	return markup
 741}
 742
 743// NewInlineKeyboardButtonData creates an inline keyboard button with text
 744// and data for a callback.
 745func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
 746	return InlineKeyboardButton{
 747		Text:         text,
 748		CallbackData: &data,
 749	}
 750}
 751
 752// NewInlineKeyboardButtonWebApp creates an inline keyboard button with text
 753// which goes to a WebApp.
 754func NewInlineKeyboardButtonWebApp(text string, webapp WebAppInfo) InlineKeyboardButton {
 755	return InlineKeyboardButton{
 756		Text:   text,
 757		WebApp: &webapp,
 758	}
 759}
 760
 761// NewInlineKeyboardButtonSwitchInlineQueryChoosenChat creates an inline keyboard button with text
 762// which goes to a SwitchInlineQueryChosenChat.
 763func NewInlineKeyboardButtonSwitchInlineQueryChoosenChat(text string, switchInlineQueryChosenChat SwitchInlineQueryChosenChat) InlineKeyboardButton {
 764	return InlineKeyboardButton{
 765		Text:                        text,
 766		SwitchInlineQueryChosenChat: &switchInlineQueryChosenChat,
 767	}
 768}
 769
 770// NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text
 771// which goes to a LoginURL.
 772func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton {
 773	return InlineKeyboardButton{
 774		Text:     text,
 775		LoginURL: &loginURL,
 776	}
 777}
 778
 779// NewInlineKeyboardButtonURL creates an inline keyboard button with text
 780// which goes to a URL.
 781func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton {
 782	return InlineKeyboardButton{
 783		Text: text,
 784		URL:  &url,
 785	}
 786}
 787
 788// NewInlineKeyboardButtonSwitch creates an inline keyboard button with
 789// text which allows the user to switch to a chat or return to a chat.
 790func NewInlineKeyboardButtonSwitch(text, sw string) InlineKeyboardButton {
 791	return InlineKeyboardButton{
 792		Text:              text,
 793		SwitchInlineQuery: &sw,
 794	}
 795}
 796
 797// NewInlineKeyboardRow creates an inline keyboard row with buttons.
 798func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton {
 799	var row []InlineKeyboardButton
 800
 801	row = append(row, buttons...)
 802
 803	return row
 804}
 805
 806// NewInlineKeyboardMarkup creates a new inline keyboard.
 807func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup {
 808	var keyboard [][]InlineKeyboardButton
 809
 810	keyboard = append(keyboard, rows...)
 811
 812	return InlineKeyboardMarkup{
 813		InlineKeyboard: keyboard,
 814	}
 815}
 816
 817// NewCallback creates a new callback message.
 818func NewCallback(id, text string) CallbackConfig {
 819	return CallbackConfig{
 820		CallbackQueryID: id,
 821		Text:            text,
 822		ShowAlert:       false,
 823	}
 824}
 825
 826// NewCallbackWithAlert creates a new callback message that alerts
 827// the user.
 828func NewCallbackWithAlert(id, text string) CallbackConfig {
 829	return CallbackConfig{
 830		CallbackQueryID: id,
 831		Text:            text,
 832		ShowAlert:       true,
 833	}
 834}
 835
 836// NewInvoice creates a new Invoice request to the user.
 837func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice, suggestedTipAmounts []int) InvoiceConfig {
 838	return InvoiceConfig{
 839		BaseChat: BaseChat{
 840			ChatConfig: ChatConfig{ChatID: chatID},
 841		},
 842		Title:               title,
 843		Description:         description,
 844		Payload:             payload,
 845		ProviderToken:       providerToken,
 846		StartParameter:      startParameter,
 847		Currency:            currency,
 848		Prices:              prices,
 849		SuggestedTipAmounts: suggestedTipAmounts,
 850	}
 851}
 852
 853// NewChatTitle allows you to update the title of a chat.
 854func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
 855	return SetChatTitleConfig{
 856		ChatConfig: ChatConfig{
 857			ChatID: chatID,
 858		},
 859		Title: title,
 860	}
 861}
 862
 863// NewChatDescription allows you to update the description of a chat.
 864func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig {
 865	return SetChatDescriptionConfig{
 866		ChatConfig: ChatConfig{
 867			ChatID: chatID,
 868		},
 869		Description: description,
 870	}
 871}
 872
 873func NewPinChatMessage(chatID int64, messageID int, disableNotification bool) PinChatMessageConfig {
 874	return PinChatMessageConfig{
 875		BaseChatMessage: BaseChatMessage{
 876			ChatConfig: ChatConfig{
 877				ChatID: chatID,
 878			},
 879			MessageID: messageID,
 880		},
 881		DisableNotification: disableNotification,
 882	}
 883}
 884
 885func NewUnpinChatMessage(chatID int64, messageID int) UnpinChatMessageConfig {
 886	return UnpinChatMessageConfig{
 887		BaseChatMessage: BaseChatMessage{
 888			ChatConfig: ChatConfig{
 889				ChatID: chatID,
 890			},
 891			MessageID: messageID,
 892		},
 893	}
 894}
 895
 896func NewGetChatMember(chatID, userID int64) GetChatMemberConfig {
 897	return GetChatMemberConfig{
 898		ChatConfigWithUser: ChatConfigWithUser{
 899			ChatConfig: ChatConfig{
 900				ChatID: chatID,
 901			},
 902			UserID: userID,
 903		},
 904	}
 905}
 906
 907func NewChatMember(chatID, userID int64) ChatMemberConfig {
 908	return ChatMemberConfig{
 909		ChatConfig: ChatConfig{
 910			ChatID: chatID,
 911		},
 912		UserID: userID,
 913	}
 914}
 915
 916// NewChatPhoto allows you to update the photo for a chat.
 917func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig {
 918	return SetChatPhotoConfig{
 919		BaseFile: BaseFile{
 920			BaseChat: BaseChat{
 921				ChatConfig: ChatConfig{ChatID: chatID},
 922			},
 923			File: photo,
 924		},
 925	}
 926}
 927
 928// NewDeleteChatPhoto allows you to delete the photo for a chat.
 929func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig {
 930	return DeleteChatPhotoConfig{
 931		ChatConfig: ChatConfig{
 932			ChatID: chatID,
 933		},
 934	}
 935}
 936
 937// NewPoll allows you to create a new poll.
 938func NewPoll(chatID int64, question string, options ...InputPollOption) SendPollConfig {
 939	return SendPollConfig{
 940		BaseChat: BaseChat{
 941			ChatConfig: ChatConfig{ChatID: chatID},
 942		},
 943		Question:    question,
 944		Options:     options,
 945		IsAnonymous: true, // This is Telegram's default.
 946	}
 947}
 948
 949// NewPollOption allows you to create poll option
 950func NewPollOption(text string) InputPollOption {
 951	return InputPollOption{
 952		Text: text,
 953	}
 954}
 955
 956// NewStopPoll allows you to stop a poll.
 957func NewStopPoll(chatID int64, messageID int) StopPollConfig {
 958	return StopPollConfig{
 959		BaseEdit{
 960			BaseChatMessage: BaseChatMessage{
 961				ChatConfig: ChatConfig{
 962					ChatID: chatID,
 963				},
 964				MessageID: messageID,
 965			},
 966		},
 967	}
 968}
 969
 970// NewDice allows you to send a random dice roll.
 971func NewDice(chatID int64) DiceConfig {
 972	return DiceConfig{
 973		BaseChat: BaseChat{
 974			ChatConfig: ChatConfig{ChatID: chatID},
 975		},
 976	}
 977}
 978
 979// NewDiceWithEmoji allows you to send a random roll of one of many types.
 980//
 981// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5).
 982func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig {
 983	return DiceConfig{
 984		BaseChat: BaseChat{
 985			ChatConfig: ChatConfig{ChatID: chatID},
 986		},
 987		Emoji: emoji,
 988	}
 989}
 990
 991// NewSetMessageReaction allows you to set a message's reactions.
 992func NewSetMessageReaction(chatID int64, messageID int, reaction []ReactionType, isBig bool) SetMessageReactionConfig {
 993	return SetMessageReactionConfig{
 994		BaseChatMessage: BaseChatMessage{
 995			ChatConfig: ChatConfig{
 996				ChatID: chatID,
 997			},
 998			MessageID: messageID,
 999		},
1000		Reaction: reaction,
1001		IsBig:    isBig,
1002	}
1003}
1004
1005// NewBotCommandScopeDefault represents the default scope of bot commands.
1006func NewBotCommandScopeDefault() BotCommandScope {
1007	return BotCommandScope{Type: "default"}
1008}
1009
1010// NewBotCommandScopeAllPrivateChats represents the scope of bot commands,
1011// covering all private chats.
1012func NewBotCommandScopeAllPrivateChats() BotCommandScope {
1013	return BotCommandScope{Type: "all_private_chats"}
1014}
1015
1016// NewBotCommandScopeAllGroupChats represents the scope of bot commands,
1017// covering all group and supergroup chats.
1018func NewBotCommandScopeAllGroupChats() BotCommandScope {
1019	return BotCommandScope{Type: "all_group_chats"}
1020}
1021
1022// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands,
1023// covering all group and supergroup chat administrators.
1024func NewBotCommandScopeAllChatAdministrators() BotCommandScope {
1025	return BotCommandScope{Type: "all_chat_administrators"}
1026}
1027
1028// NewBotCommandScopeChat represents the scope of bot commands, covering a
1029// specific chat.
1030func NewBotCommandScopeChat(chatID int64) BotCommandScope {
1031	return BotCommandScope{
1032		Type:   "chat",
1033		ChatID: chatID,
1034	}
1035}
1036
1037// NewBotCommandScopeChatAdministrators represents the scope of bot commands,
1038// covering all administrators of a specific group or supergroup chat.
1039func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope {
1040	return BotCommandScope{
1041		Type:   "chat_administrators",
1042		ChatID: chatID,
1043	}
1044}
1045
1046// NewBotCommandScopeChatMember represents the scope of bot commands, covering a
1047// specific member of a group or supergroup chat.
1048func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope {
1049	return BotCommandScope{
1050		Type:   "chat_member",
1051		ChatID: chatID,
1052		UserID: userID,
1053	}
1054}
1055
1056// NewSetMyDescription allows you to change the bot's description, which is shown in the chat with the bot if the chat is empty.
1057func NewSetMyDescription(description, languageCode string) SetMyDescriptionConfig {
1058	return SetMyDescriptionConfig{
1059		Description:  description,
1060		LanguageCode: languageCode,
1061	}
1062}
1063
1064// NewGetMyDescription returns the current bot description for the given user language
1065func NewGetMyDescription(languageCode string) GetMyDescriptionConfig {
1066	return GetMyDescriptionConfig{
1067		LanguageCode: languageCode,
1068	}
1069}
1070
1071// NewSetMyShortDescription allows you change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot.
1072func NewSetMyShortDescription(shortDescription, languageCode string) SetMyShortDescriptionConfig {
1073	return SetMyShortDescriptionConfig{
1074		ShortDescription: shortDescription,
1075		LanguageCode:     languageCode,
1076	}
1077}
1078
1079// NewGetMyShortDescription returns the current bot short description for the given user language.
1080func NewGetMyShortDescription(languageCode string) GetMyShortDescriptionConfig {
1081	return GetMyShortDescriptionConfig{
1082		LanguageCode: languageCode,
1083	}
1084}
1085
1086// NewGetMyName get the current bot name for the given user language
1087func NewGetMyName(languageCode string) GetMyNameConfig {
1088	return GetMyNameConfig{
1089		LanguageCode: languageCode,
1090	}
1091}
1092
1093// NewSetMyName change the bot's name
1094func NewSetMyName(languageCode, name string) SetMyNameConfig {
1095	return SetMyNameConfig{
1096		Name:         name,
1097		LanguageCode: languageCode,
1098	}
1099}
1100
1101// NewGetBusinessConnection gets business connection request struct
1102func NewGetBusinessConnection(id string) GetBusinessConnectionConfig {
1103	return GetBusinessConnectionConfig{
1104		BusinessConnectionID: BusinessConnectionID(id),
1105	}
1106}
1107
1108// NewGetMyCommandsWithScope allows you to set the registered commands for a
1109// given scope.
1110func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig {
1111	return GetMyCommandsConfig{Scope: &scope}
1112}
1113
1114// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered
1115// commands for a given scope and language code.
1116func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig {
1117	return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
1118}
1119
1120// NewSetMyCommands allows you to set the registered commands.
1121func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig {
1122	return SetMyCommandsConfig{Commands: commands}
1123}
1124
1125// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope.
1126func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig {
1127	return SetMyCommandsConfig{Commands: commands, Scope: &scope}
1128}
1129
1130// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope
1131// and language code.
1132func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig {
1133	return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode}
1134}
1135
1136// NewDeleteMyCommands allows you to delete the registered commands.
1137func NewDeleteMyCommands() DeleteMyCommandsConfig {
1138	return DeleteMyCommandsConfig{}
1139}
1140
1141// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given
1142// scope.
1143func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig {
1144	return DeleteMyCommandsConfig{Scope: &scope}
1145}
1146
1147// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given
1148// scope and language code.
1149func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig {
1150	return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
1151}
1152
1153// ValidateWebAppData validate data received via the Web App
1154// https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app
1155func ValidateWebAppData(token, telegramInitData string) (bool, error) {
1156	initData, err := url.ParseQuery(telegramInitData)
1157	if err != nil {
1158		return false, fmt.Errorf("error parsing data %w", err)
1159	}
1160
1161	dataCheckString := make([]string, 0, len(initData))
1162	for k, v := range initData {
1163		if k == "hash" {
1164			continue
1165		}
1166		if len(v) > 0 {
1167			dataCheckString = append(dataCheckString, fmt.Sprintf("%s=%s", k, v[0]))
1168		}
1169	}
1170
1171	sort.Strings(dataCheckString)
1172
1173	secret := hmac.New(sha256.New, []byte("WebAppData"))
1174	secret.Write([]byte(token))
1175
1176	hHash := hmac.New(sha256.New, secret.Sum(nil))
1177	hHash.Write([]byte(strings.Join(dataCheckString, "\n")))
1178
1179	hash := hex.EncodeToString(hHash.Sum(nil))
1180
1181	if initData.Get("hash") != hash {
1182		return false, errors.New("hash not equal")
1183	}
1184
1185	return true, nil
1186}