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