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