types.go (view raw)
1package tgbotapi
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "net/url"
8 "strings"
9 "time"
10)
11
12// APIResponse is a response from the Telegram API with the result
13// stored raw.
14type APIResponse struct {
15 Ok bool `json:"ok"`
16 Result json.RawMessage `json:"result"`
17 ErrorCode int `json:"error_code"`
18 Description string `json:"description"`
19 Parameters *ResponseParameters `json:"parameters"`
20}
21
22// ResponseParameters are various errors that can be returned in APIResponse.
23type ResponseParameters struct {
24 MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
25 RetryAfter int `json:"retry_after"` // optional
26}
27
28// Update is an update response, from GetUpdates.
29type Update struct {
30 UpdateID int `json:"update_id"`
31 Message *Message `json:"message"`
32 EditedMessage *Message `json:"edited_message"`
33 ChannelPost *Message `json:"channel_post"`
34 EditedChannelPost *Message `json:"edited_channel_post"`
35 InlineQuery *InlineQuery `json:"inline_query"`
36 ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
37 CallbackQuery *CallbackQuery `json:"callback_query"`
38}
39
40// User is a user on Telegram.
41type User struct {
42 ID int `json:"id"`
43 FirstName string `json:"first_name"`
44 LastName string `json:"last_name"` // optional
45 UserName string `json:"username"` // optional
46}
47
48// String displays a simple text version of a user.
49//
50// It is normally a user's username, but falls back to a first/last
51// name as available.
52func (u *User) String() string {
53 if u.UserName != "" {
54 return u.UserName
55 }
56
57 name := u.FirstName
58 if u.LastName != "" {
59 name += " " + u.LastName
60 }
61
62 return name
63}
64
65// GroupChat is a group chat.
66type GroupChat struct {
67 ID int `json:"id"`
68 Title string `json:"title"`
69}
70
71// Chat contains information about the place a message was sent.
72type Chat struct {
73 ID int64 `json:"id"`
74 Type string `json:"type"`
75 Title string `json:"title"` // optional
76 UserName string `json:"username"` // optional
77 FirstName string `json:"first_name"` // optional
78 LastName string `json:"last_name"` // optional
79 AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
80}
81
82// IsPrivate returns if the Chat is a private conversation.
83func (c Chat) IsPrivate() bool {
84 return c.Type == "private"
85}
86
87// IsGroup returns if the Chat is a group.
88func (c Chat) IsGroup() bool {
89 return c.Type == "group"
90}
91
92// IsSuperGroup returns if the Chat is a supergroup.
93func (c Chat) IsSuperGroup() bool {
94 return c.Type == "supergroup"
95}
96
97// IsChannel returns if the Chat is a channel.
98func (c Chat) IsChannel() bool {
99 return c.Type == "channel"
100}
101
102// ChatConfig returns a ChatConfig struct for chat related methods.
103func (c Chat) ChatConfig() ChatConfig {
104 return ChatConfig{ChatID: c.ID}
105}
106
107// Message is returned by almost every request, and contains data about
108// almost anything.
109type Message struct {
110 MessageID int `json:"message_id"`
111 From *User `json:"from"` // optional
112 Date int `json:"date"`
113 Chat *Chat `json:"chat"`
114 ForwardFrom *User `json:"forward_from"` // optional
115 ForwardFromChat *Chat `json:"forward_from_chat"` // optional
116 ForwardFromMessageID int `json:"forward_from_message_id"` // optional
117 ForwardDate int `json:"forward_date"` // optional
118 ReplyToMessage *Message `json:"reply_to_message"` // optional
119 EditDate int `json:"edit_date"` // optional
120 Text string `json:"text"` // optional
121 Entities *[]MessageEntity `json:"entities"` // optional
122 Audio *Audio `json:"audio"` // optional
123 Document *Document `json:"document"` // optional
124 Game *Game `json:"game"` // optional
125 Photo *[]PhotoSize `json:"photo"` // optional
126 Sticker *Sticker `json:"sticker"` // optional
127 Video *Video `json:"video"` // optional
128 Voice *Voice `json:"voice"` // optional
129 Caption string `json:"caption"` // optional
130 Contact *Contact `json:"contact"` // optional
131 Location *Location `json:"location"` // optional
132 Venue *Venue `json:"venue"` // optional
133 NewChatMember *User `json:"new_chat_member"` // optional
134 LeftChatMember *User `json:"left_chat_member"` // optional
135 NewChatTitle string `json:"new_chat_title"` // optional
136 NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
137 DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
138 GroupChatCreated bool `json:"group_chat_created"` // optional
139 SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
140 ChannelChatCreated bool `json:"channel_chat_created"` // optional
141 MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
142 MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
143 PinnedMessage *Message `json:"pinned_message"` // optional
144}
145
146// Time converts the message timestamp into a Time.
147func (m *Message) Time() time.Time {
148 return time.Unix(int64(m.Date), 0)
149}
150
151// IsCommand returns true if message starts with '/'.
152func (m *Message) IsCommand() bool {
153 return m.Text != "" && m.Text[0] == '/'
154}
155
156// Command checks if the message was a command and if it was, returns the
157// command. If the Message was not a command, it returns an empty string.
158//
159// If the command contains the at bot syntax, it removes the bot name.
160func (m *Message) Command() string {
161 if !m.IsCommand() {
162 return ""
163 }
164
165 command := strings.SplitN(m.Text, " ", 2)[0][1:]
166
167 if i := strings.Index(command, "@"); i != -1 {
168 command = command[:i]
169 }
170
171 return command
172}
173
174// CommandArguments checks if the message was a command and if it was,
175// returns all text after the command name. If the Message was not a
176// command, it returns an empty string.
177func (m *Message) CommandArguments() string {
178 if !m.IsCommand() {
179 return ""
180 }
181
182 split := strings.SplitN(m.Text, " ", 2)
183 if len(split) != 2 {
184 return ""
185 }
186
187 return strings.SplitN(m.Text, " ", 2)[1]
188}
189
190// MessageEntity contains information about data in a Message.
191type MessageEntity struct {
192 Type string `json:"type"`
193 Offset int `json:"offset"`
194 Length int `json:"length"`
195 URL string `json:"url"` // optional
196 User *User `json:"user"` // optional
197}
198
199// ParseURL attempts to parse a URL contained within a MessageEntity.
200func (entity MessageEntity) ParseURL() (*url.URL, error) {
201 if entity.URL == "" {
202 return nil, errors.New(ErrBadURL)
203 }
204
205 return url.Parse(entity.URL)
206}
207
208// PhotoSize contains information about photos.
209type PhotoSize struct {
210 FileID string `json:"file_id"`
211 Width int `json:"width"`
212 Height int `json:"height"`
213 FileSize int `json:"file_size"` // optional
214}
215
216// Audio contains information about audio.
217type Audio struct {
218 FileID string `json:"file_id"`
219 Duration int `json:"duration"`
220 Performer string `json:"performer"` // optional
221 Title string `json:"title"` // optional
222 MimeType string `json:"mime_type"` // optional
223 FileSize int `json:"file_size"` // optional
224}
225
226// Document contains information about a document.
227type Document struct {
228 FileID string `json:"file_id"`
229 Thumbnail *PhotoSize `json:"thumb"` // optional
230 FileName string `json:"file_name"` // optional
231 MimeType string `json:"mime_type"` // optional
232 FileSize int `json:"file_size"` // optional
233}
234
235// Sticker contains information about a sticker.
236type Sticker struct {
237 FileID string `json:"file_id"`
238 Width int `json:"width"`
239 Height int `json:"height"`
240 Thumbnail *PhotoSize `json:"thumb"` // optional
241 Emoji string `json:"emoji"` // optional
242 FileSize int `json:"file_size"` // optional
243}
244
245// Video contains information about a video.
246type Video struct {
247 FileID string `json:"file_id"`
248 Width int `json:"width"`
249 Height int `json:"height"`
250 Duration int `json:"duration"`
251 Thumbnail *PhotoSize `json:"thumb"` // optional
252 MimeType string `json:"mime_type"` // optional
253 FileSize int `json:"file_size"` // optional
254}
255
256// Voice contains information about a voice.
257type Voice struct {
258 FileID string `json:"file_id"`
259 Duration int `json:"duration"`
260 MimeType string `json:"mime_type"` // optional
261 FileSize int `json:"file_size"` // optional
262}
263
264// Contact contains information about a contact.
265//
266// Note that LastName and UserID may be empty.
267type Contact struct {
268 PhoneNumber string `json:"phone_number"`
269 FirstName string `json:"first_name"`
270 LastName string `json:"last_name"` // optional
271 UserID int `json:"user_id"` // optional
272}
273
274// Location contains information about a place.
275type Location struct {
276 Longitude float64 `json:"longitude"`
277 Latitude float64 `json:"latitude"`
278}
279
280// Venue contains information about a venue, including its Location.
281type Venue struct {
282 Location Location `json:"location"`
283 Title string `json:"title"`
284 Address string `json:"address"`
285 FoursquareID string `json:"foursquare_id"` // optional
286}
287
288// UserProfilePhotos contains a set of user profile photos.
289type UserProfilePhotos struct {
290 TotalCount int `json:"total_count"`
291 Photos [][]PhotoSize `json:"photos"`
292}
293
294// File contains information about a file to download from Telegram.
295type File struct {
296 FileID string `json:"file_id"`
297 FileSize int `json:"file_size"` // optional
298 FilePath string `json:"file_path"` // optional
299}
300
301// Link returns a full path to the download URL for a File.
302//
303// It requires the Bot Token to create the link.
304func (f *File) Link(token string) string {
305 return fmt.Sprintf(FileEndpoint, token, f.FilePath)
306}
307
308// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
309type ReplyKeyboardMarkup struct {
310 Keyboard [][]KeyboardButton `json:"keyboard"`
311 ResizeKeyboard bool `json:"resize_keyboard"` // optional
312 OneTimeKeyboard bool `json:"one_time_keyboard"` // optional
313 Selective bool `json:"selective"` // optional
314}
315
316// KeyboardButton is a button within a custom keyboard.
317type KeyboardButton struct {
318 Text string `json:"text"`
319 RequestContact bool `json:"request_contact"`
320 RequestLocation bool `json:"request_location"`
321}
322
323// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
324type ReplyKeyboardHide struct {
325 HideKeyboard bool `json:"hide_keyboard"`
326 Selective bool `json:"selective"` // optional
327}
328
329// ReplyKeyboardRemove allows the Bot to hide a custom keyboard.
330type ReplyKeyboardRemove struct {
331 RemoveKeyboard bool `json:"remove_keyboard"`
332 Selective bool `json:"selective"`
333}
334
335// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
336type InlineKeyboardMarkup struct {
337 InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
338}
339
340// InlineKeyboardButton is a button within a custom keyboard for
341// inline query responses.
342//
343// Note that some values are references as even an empty string
344// will change behavior.
345//
346// CallbackGame, if set, MUST be first button in first row.
347type InlineKeyboardButton struct {
348 Text string `json:"text"`
349 URL *string `json:"url,omitempty"` // optional
350 CallbackData *string `json:"callback_data,omitempty"` // optional
351 SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
352 SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat"` // optional
353 CallbackGame *CallbackGame `json:"callback_game"` // optional
354}
355
356// CallbackQuery is data sent when a keyboard button with callback data
357// is clicked.
358type CallbackQuery struct {
359 ID string `json:"id"`
360 From *User `json:"from"`
361 Message *Message `json:"message"` // optional
362 InlineMessageID string `json:"inline_message_id"` // optional
363 ChatInstance string `json:"chat_instance"`
364 Data string `json:"data"` // optional
365 GameShortName string `json:"game_short_name"` // optional
366}
367
368// ForceReply allows the Bot to have users directly reply to it without
369// additional interaction.
370type ForceReply struct {
371 ForceReply bool `json:"force_reply"`
372 Selective bool `json:"selective"` // optional
373}
374
375// ChatMember is information about a member in a chat.
376type ChatMember struct {
377 User *User `json:"user"`
378 Status string `json:"status"`
379}
380
381// IsCreator returns if the ChatMember was the creator of the chat.
382func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" }
383
384// IsAdministrator returns if the ChatMember is a chat administrator.
385func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" }
386
387// IsMember returns if the ChatMember is a current member of the chat.
388func (chat ChatMember) IsMember() bool { return chat.Status == "member" }
389
390// HasLeft returns if the ChatMember left the chat.
391func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
392
393// WasKicked returns if the ChatMember was kicked from the chat.
394func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
395
396// Game is a game within Telegram.
397type Game struct {
398 Title string `json:"title"`
399 Description string `json:"description"`
400 Photo []PhotoSize `json:"photo"`
401 Text string `json:"text"`
402 TextEntities []MessageEntity `json:"text_entities"`
403 Animation Animation `json:"animation"`
404}
405
406// Animation is a GIF animation demonstrating the game.
407type Animation struct {
408 FileID string `json:"file_id"`
409 Thumb PhotoSize `json:"thumb"`
410 FileName string `json:"file_name"`
411 MimeType string `json:"mime_type"`
412 FileSize int `json:"file_size"`
413}
414
415// GameHighScore is a user's score and position on the leaderboard.
416type GameHighScore struct {
417 Position int `json:"position"`
418 User User `json:"user"`
419 Score int `json:"score"`
420}
421
422// CallbackGame is for starting a game in an inline keyboard button.
423type CallbackGame struct{}
424
425// WebhookInfo is information about a currently set webhook.
426type WebhookInfo struct {
427 URL string `json:"url"`
428 HasCustomCertificate bool `json:"has_custom_certificate"`
429 PendingUpdateCount int `json:"pending_update_count"`
430 LastErrorDate int `json:"last_error_date"` // optional
431 LastErrorMessage string `json:"last_error_message"` // optional
432}
433
434// IsSet returns true if a webhook is currently set.
435func (info WebhookInfo) IsSet() bool {
436 return info.URL != ""
437}
438
439// InlineQuery is a Query from Telegram for an inline request.
440type InlineQuery struct {
441 ID string `json:"id"`
442 From *User `json:"from"`
443 Location *Location `json:"location"` // optional
444 Query string `json:"query"`
445 Offset string `json:"offset"`
446}
447
448// InlineQueryResultArticle is an inline query response article.
449type InlineQueryResultArticle struct {
450 Type string `json:"type"` // required
451 ID string `json:"id"` // required
452 Title string `json:"title"` // required
453 InputMessageContent interface{} `json:"input_message_content,omitempty"` // required
454 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
455 URL string `json:"url"`
456 HideURL bool `json:"hide_url"`
457 Description string `json:"description"`
458 ThumbURL string `json:"thumb_url"`
459 ThumbWidth int `json:"thumb_width"`
460 ThumbHeight int `json:"thumb_height"`
461}
462
463// InlineQueryResultPhoto is an inline query response photo.
464type InlineQueryResultPhoto struct {
465 Type string `json:"type"` // required
466 ID string `json:"id"` // required
467 URL string `json:"photo_url"` // required
468 MimeType string `json:"mime_type"`
469 Width int `json:"photo_width"`
470 Height int `json:"photo_height"`
471 ThumbURL string `json:"thumb_url"`
472 Title string `json:"title"`
473 Description string `json:"description"`
474 Caption string `json:"caption"`
475 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
476 InputMessageContent interface{} `json:"input_message_content,omitempty"`
477}
478
479// InlineQueryResultGIF is an inline query response GIF.
480type InlineQueryResultGIF struct {
481 Type string `json:"type"` // required
482 ID string `json:"id"` // required
483 URL string `json:"gif_url"` // required
484 Width int `json:"gif_width"`
485 Height int `json:"gif_height"`
486 ThumbURL string `json:"thumb_url"`
487 Title string `json:"title"`
488 Caption string `json:"caption"`
489 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
490 InputMessageContent interface{} `json:"input_message_content,omitempty"`
491}
492
493// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
494type InlineQueryResultMPEG4GIF struct {
495 Type string `json:"type"` // required
496 ID string `json:"id"` // required
497 URL string `json:"mpeg4_url"` // required
498 Width int `json:"mpeg4_width"`
499 Height int `json:"mpeg4_height"`
500 ThumbURL string `json:"thumb_url"`
501 Title string `json:"title"`
502 Caption string `json:"caption"`
503 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
504 InputMessageContent interface{} `json:"input_message_content,omitempty"`
505}
506
507// InlineQueryResultVideo is an inline query response video.
508type InlineQueryResultVideo struct {
509 Type string `json:"type"` // required
510 ID string `json:"id"` // required
511 URL string `json:"video_url"` // required
512 MimeType string `json:"mime_type"` // required
513 ThumbURL string `json:"thumb_url"`
514 Title string `json:"title"`
515 Caption string `json:"caption"`
516 Width int `json:"video_width"`
517 Height int `json:"video_height"`
518 Duration int `json:"video_duration"`
519 Description string `json:"description"`
520 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
521 InputMessageContent interface{} `json:"input_message_content,omitempty"`
522}
523
524// InlineQueryResultAudio is an inline query response audio.
525type InlineQueryResultAudio struct {
526 Type string `json:"type"` // required
527 ID string `json:"id"` // required
528 URL string `json:"audio_url"` // required
529 Title string `json:"title"` // required
530 Caption string `json:"caption"`
531 Performer string `json:"performer"`
532 Duration int `json:"audio_duration"`
533 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
534 InputMessageContent interface{} `json:"input_message_content,omitempty"`
535}
536
537// InlineQueryResultVoice is an inline query response voice.
538type InlineQueryResultVoice struct {
539 Type string `json:"type"` // required
540 ID string `json:"id"` // required
541 URL string `json:"voice_url"` // required
542 Title string `json:"title"` // required
543 Caption string `json:"caption"`
544 Duration int `json:"voice_duration"`
545 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
546 InputMessageContent interface{} `json:"input_message_content,omitempty"`
547}
548
549// InlineQueryResultDocument is an inline query response document.
550type InlineQueryResultDocument struct {
551 Type string `json:"type"` // required
552 ID string `json:"id"` // required
553 Title string `json:"title"` // required
554 Caption string `json:"caption"`
555 URL string `json:"document_url"` // required
556 MimeType string `json:"mime_type"` // required
557 Description string `json:"description"`
558 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
559 InputMessageContent interface{} `json:"input_message_content,omitempty"`
560 ThumbURL string `json:"thumb_url"`
561 ThumbWidth int `json:"thumb_width"`
562 ThumbHeight int `json:"thumb_height"`
563}
564
565// InlineQueryResultLocation is an inline query response location.
566type InlineQueryResultLocation struct {
567 Type string `json:"type"` // required
568 ID string `json:"id"` // required
569 Latitude float64 `json:"latitude"` // required
570 Longitude float64 `json:"longitude"` // required
571 Title string `json:"title"` // required
572 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
573 InputMessageContent interface{} `json:"input_message_content,omitempty"`
574 ThumbURL string `json:"thumb_url"`
575 ThumbWidth int `json:"thumb_width"`
576 ThumbHeight int `json:"thumb_height"`
577}
578
579// InlineQueryResultGame is an inline query response game.
580type InlineQueryResultGame struct {
581 Type string `json:"type"`
582 ID string `json:"id"`
583 GameShortName string `json:"game_short_name"`
584 ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup"`
585}
586
587// ChosenInlineResult is an inline query result chosen by a User
588type ChosenInlineResult struct {
589 ResultID string `json:"result_id"`
590 From *User `json:"from"`
591 Location *Location `json:"location"`
592 InlineMessageID string `json:"inline_message_id"`
593 Query string `json:"query"`
594}
595
596// InputTextMessageContent contains text for displaying
597// as an inline query result.
598type InputTextMessageContent struct {
599 Text string `json:"message_text"`
600 ParseMode string `json:"parse_mode"`
601 DisableWebPagePreview bool `json:"disable_web_page_preview"`
602}
603
604// InputLocationMessageContent contains a location for displaying
605// as an inline query result.
606type InputLocationMessageContent struct {
607 Latitude float64 `json:"latitude"`
608 Longitude float64 `json:"longitude"`
609}
610
611// InputVenueMessageContent contains a venue for displaying
612// as an inline query result.
613type InputVenueMessageContent struct {
614 Latitude float64 `json:"latitude"`
615 Longitude float64 `json:"longitude"`
616 Title string `json:"title"`
617 Address string `json:"address"`
618 FoursquareID string `json:"foursquare_id"`
619}
620
621// InputContactMessageContent contains a contact for displaying
622// as an inline query result.
623type InputContactMessageContent struct {
624 PhoneNumber string `json:"phone_number"`
625 FirstName string `json:"first_name"`
626 LastName string `json:"last_name"`
627}