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