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) 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}
850
851// NewChatTitle allows you to update the title of a chat.
852func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
853 return SetChatTitleConfig{
854 ChatConfig: ChatConfig{
855 ChatID: chatID,
856 },
857 Title: title,
858 }
859}
860
861// NewChatDescription allows you to update the description of a chat.
862func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig {
863 return SetChatDescriptionConfig{
864 ChatConfig: ChatConfig{
865 ChatID: chatID,
866 },
867 Description: description,
868 }
869}
870
871func NewPinChatMessage(chatID int64, messageID int, disableNotification bool) PinChatMessageConfig {
872 return PinChatMessageConfig{
873 BaseChatMessage: BaseChatMessage{
874 ChatConfig: ChatConfig{
875 ChatID: chatID,
876 },
877 MessageID: messageID,
878 },
879 DisableNotification: disableNotification,
880 }
881}
882
883func NewUnpinChatMessage(chatID int64, messageID int) UnpinChatMessageConfig {
884 return UnpinChatMessageConfig{
885 BaseChatMessage: BaseChatMessage{
886 ChatConfig: ChatConfig{
887 ChatID: chatID,
888 },
889 MessageID: messageID,
890 },
891 }
892}
893
894func NewGetChatMember(chatID, userID int64) GetChatMemberConfig {
895 return GetChatMemberConfig{
896 ChatConfigWithUser: ChatConfigWithUser{
897 ChatConfig: ChatConfig{
898 ChatID: chatID,
899 },
900 UserID: userID,
901 },
902 }
903}
904
905func NewChatMember(chatID, userID int64) ChatMemberConfig {
906 return ChatMemberConfig{
907 ChatConfig: ChatConfig{
908 ChatID: chatID,
909 },
910 UserID: userID,
911 }
912}
913
914// NewChatPhoto allows you to update the photo for a chat.
915func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig {
916 return SetChatPhotoConfig{
917 BaseFile: BaseFile{
918 BaseChat: BaseChat{
919 ChatConfig: ChatConfig{ChatID: chatID},
920 },
921 File: photo,
922 },
923 }
924}
925
926// NewDeleteChatPhoto allows you to delete the photo for a chat.
927func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig {
928 return DeleteChatPhotoConfig{
929 ChatConfig: ChatConfig{
930 ChatID: chatID,
931 },
932 }
933}
934
935// NewPoll allows you to create a new poll.
936func NewPoll(chatID int64, question string, options ...string) SendPollConfig {
937 return SendPollConfig{
938 BaseChat: BaseChat{
939 ChatConfig: ChatConfig{ChatID: chatID},
940 },
941 Question: question,
942 Options: options,
943 IsAnonymous: true, // This is Telegram's default.
944 }
945}
946
947// NewStopPoll allows you to stop a poll.
948func NewStopPoll(chatID int64, messageID int) StopPollConfig {
949 return StopPollConfig{
950 BaseEdit{
951 BaseChatMessage: BaseChatMessage{
952 ChatConfig: ChatConfig{
953 ChatID: chatID,
954 },
955 MessageID: messageID,
956 },
957 },
958 }
959}
960
961// NewDice allows you to send a random dice roll.
962func NewDice(chatID int64) DiceConfig {
963 return DiceConfig{
964 BaseChat: BaseChat{
965 ChatConfig: ChatConfig{ChatID: chatID},
966 },
967 }
968}
969
970// NewDiceWithEmoji allows you to send a random roll of one of many types.
971//
972// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5).
973func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig {
974 return DiceConfig{
975 BaseChat: BaseChat{
976 ChatConfig: ChatConfig{ChatID: chatID},
977 },
978 Emoji: emoji,
979 }
980}
981
982// NewBotCommandScopeDefault represents the default scope of bot commands.
983func NewBotCommandScopeDefault() BotCommandScope {
984 return BotCommandScope{Type: "default"}
985}
986
987// NewBotCommandScopeAllPrivateChats represents the scope of bot commands,
988// covering all private chats.
989func NewBotCommandScopeAllPrivateChats() BotCommandScope {
990 return BotCommandScope{Type: "all_private_chats"}
991}
992
993// NewBotCommandScopeAllGroupChats represents the scope of bot commands,
994// covering all group and supergroup chats.
995func NewBotCommandScopeAllGroupChats() BotCommandScope {
996 return BotCommandScope{Type: "all_group_chats"}
997}
998
999// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands,
1000// covering all group and supergroup chat administrators.
1001func NewBotCommandScopeAllChatAdministrators() BotCommandScope {
1002 return BotCommandScope{Type: "all_chat_administrators"}
1003}
1004
1005// NewBotCommandScopeChat represents the scope of bot commands, covering a
1006// specific chat.
1007func NewBotCommandScopeChat(chatID int64) BotCommandScope {
1008 return BotCommandScope{
1009 Type: "chat",
1010 ChatID: chatID,
1011 }
1012}
1013
1014// NewBotCommandScopeChatAdministrators represents the scope of bot commands,
1015// covering all administrators of a specific group or supergroup chat.
1016func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope {
1017 return BotCommandScope{
1018 Type: "chat_administrators",
1019 ChatID: chatID,
1020 }
1021}
1022
1023// NewBotCommandScopeChatMember represents the scope of bot commands, covering a
1024// specific member of a group or supergroup chat.
1025func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope {
1026 return BotCommandScope{
1027 Type: "chat_member",
1028 ChatID: chatID,
1029 UserID: userID,
1030 }
1031}
1032
1033// NewSetMyDescription allows you to change the bot's description, which is shown in the chat with the bot if the chat is empty.
1034func NewSetMyDescription(description, languageCode string) SetMyDescriptionConfig {
1035 return SetMyDescriptionConfig{
1036 Description: description,
1037 LanguageCode: languageCode,
1038 }
1039}
1040
1041// NewGetMyDescription returns the current bot description for the given user language
1042func NewGetMyDescription(languageCode string) GetMyDescriptionConfig {
1043 return GetMyDescriptionConfig{
1044 LanguageCode: languageCode,
1045 }
1046}
1047
1048// 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.
1049func NewSetMyShortDescription(shortDescription, languageCode string) SetMyShortDescriptionConfig {
1050 return SetMyShortDescriptionConfig{
1051 ShortDescription: shortDescription,
1052 LanguageCode: languageCode,
1053 }
1054}
1055
1056// NewGetMyShortDescription returns the current bot short description for the given user language.
1057func NewGetMyShortDescription(languageCode string) GetMyShortDescriptionConfig {
1058 return GetMyShortDescriptionConfig{
1059 LanguageCode: languageCode,
1060 }
1061}
1062
1063// NewGetMyName get the current bot name for the given user language
1064func NewGetMyName(languageCode string) GetMyNameConfig {
1065 return GetMyNameConfig{
1066 LanguageCode: languageCode,
1067 }
1068}
1069
1070// NewSetMyName change the bot's name
1071func NewSetMyName(languageCode, name string) SetMyNameConfig {
1072 return SetMyNameConfig{
1073 Name: name,
1074 LanguageCode: languageCode,
1075 }
1076}
1077
1078// NewGetMyCommandsWithScope allows you to set the registered commands for a
1079// given scope.
1080func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig {
1081 return GetMyCommandsConfig{Scope: &scope}
1082}
1083
1084// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered
1085// commands for a given scope and language code.
1086func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig {
1087 return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
1088}
1089
1090// NewSetMyCommands allows you to set the registered commands.
1091func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig {
1092 return SetMyCommandsConfig{Commands: commands}
1093}
1094
1095// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope.
1096func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig {
1097 return SetMyCommandsConfig{Commands: commands, Scope: &scope}
1098}
1099
1100// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope
1101// and language code.
1102func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig {
1103 return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode}
1104}
1105
1106// NewDeleteMyCommands allows you to delete the registered commands.
1107func NewDeleteMyCommands() DeleteMyCommandsConfig {
1108 return DeleteMyCommandsConfig{}
1109}
1110
1111// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given
1112// scope.
1113func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig {
1114 return DeleteMyCommandsConfig{Scope: &scope}
1115}
1116
1117// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given
1118// scope and language code.
1119func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig {
1120 return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
1121}
1122
1123// ValidateWebAppData validate data received via the Web App
1124// https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app
1125func ValidateWebAppData(token, telegramInitData string) (bool, error) {
1126 initData, err := url.ParseQuery(telegramInitData)
1127 if err != nil {
1128 return false, fmt.Errorf("error parsing data %w", err)
1129 }
1130
1131 dataCheckString := make([]string, 0, len(initData))
1132 for k, v := range initData {
1133 if k == "hash" {
1134 continue
1135 }
1136 if len(v) > 0 {
1137 dataCheckString = append(dataCheckString, fmt.Sprintf("%s=%s", k, v[0]))
1138 }
1139 }
1140
1141 sort.Strings(dataCheckString)
1142
1143 secret := hmac.New(sha256.New, []byte("WebAppData"))
1144 secret.Write([]byte(token))
1145
1146 hHash := hmac.New(sha256.New, secret.Sum(nil))
1147 hHash.Write([]byte(strings.Join(dataCheckString, "\n")))
1148
1149 hash := hex.EncodeToString(hHash.Sum(nil))
1150
1151 if initData.Get("hash") != hash {
1152 return false, errors.New("hash not equal")
1153 }
1154
1155 return true, nil
1156}