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