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// NewBotCommandScopeDefault represents the default scope of bot commands.
992func NewBotCommandScopeDefault() BotCommandScope {
993 return BotCommandScope{Type: "default"}
994}
995
996// NewBotCommandScopeAllPrivateChats represents the scope of bot commands,
997// covering all private chats.
998func NewBotCommandScopeAllPrivateChats() BotCommandScope {
999 return BotCommandScope{Type: "all_private_chats"}
1000}
1001
1002// NewBotCommandScopeAllGroupChats represents the scope of bot commands,
1003// covering all group and supergroup chats.
1004func NewBotCommandScopeAllGroupChats() BotCommandScope {
1005 return BotCommandScope{Type: "all_group_chats"}
1006}
1007
1008// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands,
1009// covering all group and supergroup chat administrators.
1010func NewBotCommandScopeAllChatAdministrators() BotCommandScope {
1011 return BotCommandScope{Type: "all_chat_administrators"}
1012}
1013
1014// NewBotCommandScopeChat represents the scope of bot commands, covering a
1015// specific chat.
1016func NewBotCommandScopeChat(chatID int64) BotCommandScope {
1017 return BotCommandScope{
1018 Type: "chat",
1019 ChatID: chatID,
1020 }
1021}
1022
1023// NewBotCommandScopeChatAdministrators represents the scope of bot commands,
1024// covering all administrators of a specific group or supergroup chat.
1025func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope {
1026 return BotCommandScope{
1027 Type: "chat_administrators",
1028 ChatID: chatID,
1029 }
1030}
1031
1032// NewBotCommandScopeChatMember represents the scope of bot commands, covering a
1033// specific member of a group or supergroup chat.
1034func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope {
1035 return BotCommandScope{
1036 Type: "chat_member",
1037 ChatID: chatID,
1038 UserID: userID,
1039 }
1040}
1041
1042// NewSetMyDescription allows you to change the bot's description, which is shown in the chat with the bot if the chat is empty.
1043func NewSetMyDescription(description, languageCode string) SetMyDescriptionConfig {
1044 return SetMyDescriptionConfig{
1045 Description: description,
1046 LanguageCode: languageCode,
1047 }
1048}
1049
1050// NewGetMyDescription returns the current bot description for the given user language
1051func NewGetMyDescription(languageCode string) GetMyDescriptionConfig {
1052 return GetMyDescriptionConfig{
1053 LanguageCode: languageCode,
1054 }
1055}
1056
1057// 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.
1058func NewSetMyShortDescription(shortDescription, languageCode string) SetMyShortDescriptionConfig {
1059 return SetMyShortDescriptionConfig{
1060 ShortDescription: shortDescription,
1061 LanguageCode: languageCode,
1062 }
1063}
1064
1065// NewGetMyShortDescription returns the current bot short description for the given user language.
1066func NewGetMyShortDescription(languageCode string) GetMyShortDescriptionConfig {
1067 return GetMyShortDescriptionConfig{
1068 LanguageCode: languageCode,
1069 }
1070}
1071
1072// NewGetMyName get the current bot name for the given user language
1073func NewGetMyName(languageCode string) GetMyNameConfig {
1074 return GetMyNameConfig{
1075 LanguageCode: languageCode,
1076 }
1077}
1078
1079// NewSetMyName change the bot's name
1080func NewSetMyName(languageCode, name string) SetMyNameConfig {
1081 return SetMyNameConfig{
1082 Name: name,
1083 LanguageCode: languageCode,
1084 }
1085}
1086
1087// NewGetBusinessConnection gets business connection request struct
1088func NewGetBusinessConnection(id string) GetBusinessConnectionConfig {
1089 return GetBusinessConnectionConfig{
1090 BusinessConnectionID: BusinessConnectionID(id),
1091 }
1092}
1093
1094// NewGetMyCommandsWithScope allows you to set the registered commands for a
1095// given scope.
1096func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig {
1097 return GetMyCommandsConfig{Scope: &scope}
1098}
1099
1100// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered
1101// commands for a given scope and language code.
1102func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig {
1103 return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
1104}
1105
1106// NewSetMyCommands allows you to set the registered commands.
1107func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig {
1108 return SetMyCommandsConfig{Commands: commands}
1109}
1110
1111// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope.
1112func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig {
1113 return SetMyCommandsConfig{Commands: commands, Scope: &scope}
1114}
1115
1116// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope
1117// and language code.
1118func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig {
1119 return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode}
1120}
1121
1122// NewDeleteMyCommands allows you to delete the registered commands.
1123func NewDeleteMyCommands() DeleteMyCommandsConfig {
1124 return DeleteMyCommandsConfig{}
1125}
1126
1127// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given
1128// scope.
1129func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig {
1130 return DeleteMyCommandsConfig{Scope: &scope}
1131}
1132
1133// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given
1134// scope and language code.
1135func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig {
1136 return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
1137}
1138
1139// ValidateWebAppData validate data received via the Web App
1140// https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app
1141func ValidateWebAppData(token, telegramInitData string) (bool, error) {
1142 initData, err := url.ParseQuery(telegramInitData)
1143 if err != nil {
1144 return false, fmt.Errorf("error parsing data %w", err)
1145 }
1146
1147 dataCheckString := make([]string, 0, len(initData))
1148 for k, v := range initData {
1149 if k == "hash" {
1150 continue
1151 }
1152 if len(v) > 0 {
1153 dataCheckString = append(dataCheckString, fmt.Sprintf("%s=%s", k, v[0]))
1154 }
1155 }
1156
1157 sort.Strings(dataCheckString)
1158
1159 secret := hmac.New(sha256.New, []byte("WebAppData"))
1160 secret.Write([]byte(token))
1161
1162 hHash := hmac.New(sha256.New, secret.Sum(nil))
1163 hHash.Write([]byte(strings.Join(dataCheckString, "\n")))
1164
1165 hash := hex.EncodeToString(hHash.Sum(nil))
1166
1167 if initData.Get("hash") != hash {
1168 return false, errors.New("hash not equal")
1169 }
1170
1171 return true, nil
1172}