methods.go (view raw)
1package tgbotapi
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "io/ioutil"
8 "log"
9 "net/http"
10 "net/url"
11 "os"
12 "strconv"
13
14 "github.com/technoweenie/multipartstreamer"
15)
16
17// Telegram constants
18const (
19 // APIEndpoint is the endpoint for all API methods, with formatting for Sprintf
20 APIEndpoint = "https://api.telegram.org/bot%s/%s"
21)
22
23// Constant values for ChatActions
24const (
25 ChatTyping = "typing"
26 ChatUploadPhoto = "upload_photo"
27 ChatRecordVideo = "record_video"
28 ChatUploadVideo = "upload_video"
29 ChatRecordAudio = "record_audio"
30 ChatUploadAudio = "upload_audio"
31 ChatUploadDocument = "upload_document"
32 ChatFindLocation = "find_location"
33)
34
35// API errors
36const (
37 // APIForbidden happens when a token is bad
38 APIForbidden = "forbidden"
39)
40
41// Constant values for ParseMode in MessageConfig
42const (
43 ModeMarkdown = "Markdown"
44)
45
46// MessageConfig contains information about a SendMessage request.
47type MessageConfig struct {
48 ChatID int
49 Text string
50 ParseMode string
51 DisableWebPagePreview bool
52 ReplyToMessageID int
53 ReplyMarkup interface{}
54}
55
56// ForwardConfig contains information about a ForwardMessage request.
57type ForwardConfig struct {
58 ChatID int
59 FromChatID int
60 MessageID int
61}
62
63// PhotoConfig contains information about a SendPhoto request.
64type PhotoConfig struct {
65 ChatID int
66 Caption string
67 ReplyToMessageID int
68 ReplyMarkup interface{}
69 UseExistingPhoto bool
70 FilePath string
71 FileID string
72}
73
74// AudioConfig contains information about a SendAudio request.
75type AudioConfig struct {
76 ChatID int
77 Duration int
78 Performer string
79 Title string
80 ReplyToMessageID int
81 ReplyMarkup interface{}
82 UseExistingAudio bool
83 FilePath string
84 FileID string
85}
86
87// DocumentConfig contains information about a SendDocument request.
88type DocumentConfig struct {
89 ChatID int
90 ReplyToMessageID int
91 ReplyMarkup interface{}
92 UseExistingDocument bool
93 FilePath string
94 FileID string
95}
96
97// StickerConfig contains information about a SendSticker request.
98type StickerConfig struct {
99 ChatID int
100 ReplyToMessageID int
101 ReplyMarkup interface{}
102 UseExistingSticker bool
103 FilePath string
104 FileID string
105}
106
107// VideoConfig contains information about a SendVideo request.
108type VideoConfig struct {
109 ChatID int
110 Duration int
111 Caption string
112 ReplyToMessageID int
113 ReplyMarkup interface{}
114 UseExistingVideo bool
115 FilePath string
116 FileID string
117}
118
119// VoiceConfig contains information about a SendVoice request.
120type VoiceConfig struct {
121 ChatID int
122 Duration int
123 ReplyToMessageID int
124 ReplyMarkup interface{}
125 UseExistingVoice bool
126 FilePath string
127 FileID string
128}
129
130// LocationConfig contains information about a SendLocation request.
131type LocationConfig struct {
132 ChatID int
133 Latitude float64
134 Longitude float64
135 ReplyToMessageID int
136 ReplyMarkup interface{}
137}
138
139// ChatActionConfig contains information about a SendChatAction request.
140type ChatActionConfig struct {
141 ChatID int
142 Action string
143}
144
145// UserProfilePhotosConfig contains information about a GetUserProfilePhotos request.
146type UserProfilePhotosConfig struct {
147 UserID int
148 Offset int
149 Limit int
150}
151
152// UpdateConfig contains information about a GetUpdates request.
153type UpdateConfig struct {
154 Offset int
155 Limit int
156 Timeout int
157}
158
159// WebhookConfig contains information about a SetWebhook request.
160type WebhookConfig struct {
161 Clear bool
162 URL *url.URL
163}
164
165// MakeRequest makes a request to a specific endpoint with our token.
166// All requests are POSTs because Telegram doesn't care, and it's easier.
167func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
168 resp, err := bot.Client.PostForm(fmt.Sprintf(APIEndpoint, bot.Token, endpoint), params)
169 if err != nil {
170 return APIResponse{}, err
171 }
172 defer resp.Body.Close()
173
174 if resp.StatusCode == http.StatusForbidden {
175 return APIResponse{}, errors.New(APIForbidden)
176 }
177
178 bytes, err := ioutil.ReadAll(resp.Body)
179 if err != nil {
180 return APIResponse{}, err
181 }
182
183 if bot.Debug {
184 log.Println(endpoint, string(bytes))
185 }
186
187 var apiResp APIResponse
188 json.Unmarshal(bytes, &apiResp)
189
190 if !apiResp.Ok {
191 return APIResponse{}, errors.New(apiResp.Description)
192 }
193
194 return apiResp, nil
195}
196
197// UploadFile makes a request to the API with a file.
198//
199// Requires the parameter to hold the file not be in the params.
200func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, filename string) (APIResponse, error) {
201 f, err := os.Open(filename)
202 if err != nil {
203 return APIResponse{}, err
204 }
205 defer f.Close()
206
207 fi, err := os.Stat(filename)
208 if err != nil {
209 return APIResponse{}, err
210 }
211
212 ms := multipartstreamer.New()
213 ms.WriteFields(params)
214 ms.WriteReader(fieldname, f.Name(), fi.Size(), f)
215
216 req, err := http.NewRequest("POST", fmt.Sprintf(APIEndpoint, bot.Token, endpoint), nil)
217 ms.SetupRequest(req)
218 if err != nil {
219 return APIResponse{}, err
220 }
221
222 res, err := bot.Client.Do(req)
223 if err != nil {
224 return APIResponse{}, err
225 }
226 defer res.Body.Close()
227
228 bytes, err := ioutil.ReadAll(res.Body)
229 if err != nil {
230 return APIResponse{}, err
231 }
232
233 if bot.Debug {
234 log.Println(string(bytes[:]))
235 }
236
237 var apiResp APIResponse
238 json.Unmarshal(bytes, &apiResp)
239
240 return apiResp, nil
241}
242
243// GetMe fetches the currently authenticated bot.
244//
245// There are no parameters for this method.
246func (bot *BotAPI) GetMe() (User, error) {
247 resp, err := bot.MakeRequest("getMe", nil)
248 if err != nil {
249 return User{}, err
250 }
251
252 var user User
253 json.Unmarshal(resp.Result, &user)
254
255 if bot.Debug {
256 log.Printf("getMe: %+v\n", user)
257 }
258
259 return user, nil
260}
261
262// SendMessage sends a Message to a chat.
263//
264// Requires ChatID and Text.
265// DisableWebPagePreview, ReplyToMessageID, and ReplyMarkup are optional.
266func (bot *BotAPI) SendMessage(config MessageConfig) (Message, error) {
267 v := url.Values{}
268 v.Add("chat_id", strconv.Itoa(config.ChatID))
269 v.Add("text", config.Text)
270 v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
271 if config.ParseMode != "" {
272 v.Add("parse_mode", config.ParseMode)
273 }
274 if config.ReplyToMessageID != 0 {
275 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
276 }
277 if config.ReplyMarkup != nil {
278 data, err := json.Marshal(config.ReplyMarkup)
279 if err != nil {
280 return Message{}, err
281 }
282
283 v.Add("reply_markup", string(data))
284 }
285
286 resp, err := bot.MakeRequest("SendMessage", v)
287 if err != nil {
288 return Message{}, err
289 }
290
291 var message Message
292 json.Unmarshal(resp.Result, &message)
293
294 if bot.Debug {
295 log.Printf("SendMessage req : %+v\n", v)
296 log.Printf("SendMessage resp: %+v\n", message)
297 }
298
299 return message, nil
300}
301
302// ForwardMessage forwards a message from one chat to another.
303//
304// Requires ChatID (destination), FromChatID (source), and MessageID.
305func (bot *BotAPI) ForwardMessage(config ForwardConfig) (Message, error) {
306 v := url.Values{}
307 v.Add("chat_id", strconv.Itoa(config.ChatID))
308 v.Add("from_chat_id", strconv.Itoa(config.FromChatID))
309 v.Add("message_id", strconv.Itoa(config.MessageID))
310
311 resp, err := bot.MakeRequest("forwardMessage", v)
312 if err != nil {
313 return Message{}, err
314 }
315
316 var message Message
317 json.Unmarshal(resp.Result, &message)
318
319 if bot.Debug {
320 log.Printf("forwardMessage req : %+v\n", v)
321 log.Printf("forwardMessage resp: %+v\n", message)
322 }
323
324 return message, nil
325}
326
327// SendPhoto sends or uploads a photo to a chat.
328//
329// Requires ChatID and FileID OR FilePath.
330// Caption, ReplyToMessageID, and ReplyMarkup are optional.
331func (bot *BotAPI) SendPhoto(config PhotoConfig) (Message, error) {
332 if config.UseExistingPhoto {
333 v := url.Values{}
334 v.Add("chat_id", strconv.Itoa(config.ChatID))
335 v.Add("photo", config.FileID)
336 if config.Caption != "" {
337 v.Add("caption", config.Caption)
338 }
339 if config.ReplyToMessageID != 0 {
340 v.Add("reply_to_message_id", strconv.Itoa(config.ChatID))
341 }
342 if config.ReplyMarkup != nil {
343 data, err := json.Marshal(config.ReplyMarkup)
344 if err != nil {
345 return Message{}, err
346 }
347
348 v.Add("reply_markup", string(data))
349 }
350
351 resp, err := bot.MakeRequest("SendPhoto", v)
352 if err != nil {
353 return Message{}, err
354 }
355
356 var message Message
357 json.Unmarshal(resp.Result, &message)
358
359 if bot.Debug {
360 log.Printf("SendPhoto req : %+v\n", v)
361 log.Printf("SendPhoto resp: %+v\n", message)
362 }
363
364 return message, nil
365 }
366
367 params := make(map[string]string)
368 params["chat_id"] = strconv.Itoa(config.ChatID)
369 if config.Caption != "" {
370 params["caption"] = config.Caption
371 }
372 if config.ReplyToMessageID != 0 {
373 params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
374 }
375 if config.ReplyMarkup != nil {
376 data, err := json.Marshal(config.ReplyMarkup)
377 if err != nil {
378 return Message{}, err
379 }
380
381 params["reply_markup"] = string(data)
382 }
383
384 resp, err := bot.UploadFile("SendPhoto", params, "photo", config.FilePath)
385 if err != nil {
386 return Message{}, err
387 }
388
389 var message Message
390 json.Unmarshal(resp.Result, &message)
391
392 if bot.Debug {
393 log.Printf("SendPhoto resp: %+v\n", message)
394 }
395
396 return message, nil
397}
398
399// SendAudio sends or uploads an audio clip to a chat.
400// If using a file, the file must be in the .mp3 format.
401//
402// when the fields title and performer are both empty
403// and the mime-type of the file to be sent is not audio/mpeg,
404// the file must be in an .ogg file encoded with OPUS.
405// You may use the tgutils.EncodeAudio func to assist you with this, if needed.
406//
407// Requires ChatID and FileID OR FilePath.
408// ReplyToMessageID and ReplyMarkup are optional.
409func (bot *BotAPI) SendAudio(config AudioConfig) (Message, error) {
410 if config.UseExistingAudio {
411 v := url.Values{}
412 v.Add("chat_id", strconv.Itoa(config.ChatID))
413 v.Add("audio", config.FileID)
414 if config.ReplyToMessageID != 0 {
415 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
416 }
417 if config.Duration != 0 {
418 v.Add("duration", strconv.Itoa(config.Duration))
419 }
420 if config.ReplyMarkup != nil {
421 data, err := json.Marshal(config.ReplyMarkup)
422 if err != nil {
423 return Message{}, err
424 }
425
426 v.Add("reply_markup", string(data))
427 }
428 if config.Performer != "" {
429 v.Add("performer", config.Performer)
430 }
431 if config.Title != "" {
432 v.Add("title", config.Title)
433 }
434
435 resp, err := bot.MakeRequest("sendAudio", v)
436 if err != nil {
437 return Message{}, err
438 }
439
440 var message Message
441 json.Unmarshal(resp.Result, &message)
442
443 if bot.Debug {
444 log.Printf("sendAudio req : %+v\n", v)
445 log.Printf("sendAudio resp: %+v\n", message)
446 }
447
448 return message, nil
449 }
450
451 params := make(map[string]string)
452
453 params["chat_id"] = strconv.Itoa(config.ChatID)
454 if config.ReplyToMessageID != 0 {
455 params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
456 }
457 if config.Duration != 0 {
458 params["duration"] = strconv.Itoa(config.Duration)
459 }
460 if config.ReplyMarkup != nil {
461 data, err := json.Marshal(config.ReplyMarkup)
462 if err != nil {
463 return Message{}, err
464 }
465
466 params["reply_markup"] = string(data)
467 }
468 if config.Performer != "" {
469 params["performer"] = config.Performer
470 }
471 if config.Title != "" {
472 params["title"] = config.Title
473 }
474
475 resp, err := bot.UploadFile("sendAudio", params, "audio", config.FilePath)
476 if err != nil {
477 return Message{}, err
478 }
479
480 var message Message
481 json.Unmarshal(resp.Result, &message)
482
483 if bot.Debug {
484 log.Printf("sendAudio resp: %+v\n", message)
485 }
486
487 return message, nil
488}
489
490// SendDocument sends or uploads a document to a chat.
491//
492// Requires ChatID and FileID OR FilePath.
493// ReplyToMessageID and ReplyMarkup are optional.
494func (bot *BotAPI) SendDocument(config DocumentConfig) (Message, error) {
495 if config.UseExistingDocument {
496 v := url.Values{}
497 v.Add("chat_id", strconv.Itoa(config.ChatID))
498 v.Add("document", config.FileID)
499 if config.ReplyToMessageID != 0 {
500 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
501 }
502 if config.ReplyMarkup != nil {
503 data, err := json.Marshal(config.ReplyMarkup)
504 if err != nil {
505 return Message{}, err
506 }
507
508 v.Add("reply_markup", string(data))
509 }
510
511 resp, err := bot.MakeRequest("sendDocument", v)
512 if err != nil {
513 return Message{}, err
514 }
515
516 var message Message
517 json.Unmarshal(resp.Result, &message)
518
519 if bot.Debug {
520 log.Printf("sendDocument req : %+v\n", v)
521 log.Printf("sendDocument resp: %+v\n", message)
522 }
523
524 return message, nil
525 }
526
527 params := make(map[string]string)
528
529 params["chat_id"] = strconv.Itoa(config.ChatID)
530 if config.ReplyToMessageID != 0 {
531 params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
532 }
533 if config.ReplyMarkup != nil {
534 data, err := json.Marshal(config.ReplyMarkup)
535 if err != nil {
536 return Message{}, err
537 }
538
539 params["reply_markup"] = string(data)
540 }
541
542 resp, err := bot.UploadFile("sendDocument", params, "document", config.FilePath)
543 if err != nil {
544 return Message{}, err
545 }
546
547 var message Message
548 json.Unmarshal(resp.Result, &message)
549
550 if bot.Debug {
551 log.Printf("sendDocument resp: %+v\n", message)
552 }
553
554 return message, nil
555}
556
557// SendVoice sends or uploads a playable voice to a chat.
558// If using a file, the file must be encoded as an .ogg with OPUS.
559// You may use the tgutils.EncodeAudio func to assist you with this, if needed.
560//
561// Requires ChatID and FileID OR FilePath.
562// ReplyToMessageID and ReplyMarkup are optional.
563func (bot *BotAPI) SendVoice(config VoiceConfig) (Message, error) {
564 if config.UseExistingVoice {
565 v := url.Values{}
566 v.Add("chat_id", strconv.Itoa(config.ChatID))
567 v.Add("voice", config.FileID)
568 if config.ReplyToMessageID != 0 {
569 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
570 }
571 if config.Duration != 0 {
572 v.Add("duration", strconv.Itoa(config.Duration))
573 }
574 if config.ReplyMarkup != nil {
575 data, err := json.Marshal(config.ReplyMarkup)
576 if err != nil {
577 return Message{}, err
578 }
579
580 v.Add("reply_markup", string(data))
581 }
582
583 resp, err := bot.MakeRequest("sendVoice", v)
584 if err != nil {
585 return Message{}, err
586 }
587
588 var message Message
589 json.Unmarshal(resp.Result, &message)
590
591 if bot.Debug {
592 log.Printf("SendVoice req : %+v\n", v)
593 log.Printf("SendVoice resp: %+v\n", message)
594 }
595
596 return message, nil
597 }
598
599 params := make(map[string]string)
600
601 params["chat_id"] = strconv.Itoa(config.ChatID)
602 if config.ReplyToMessageID != 0 {
603 params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
604 }
605 if config.Duration != 0 {
606 params["duration"] = strconv.Itoa(config.Duration)
607 }
608 if config.ReplyMarkup != nil {
609 data, err := json.Marshal(config.ReplyMarkup)
610 if err != nil {
611 return Message{}, err
612 }
613
614 params["reply_markup"] = string(data)
615 }
616
617 resp, err := bot.UploadFile("SendVoice", params, "voice", config.FilePath)
618 if err != nil {
619 return Message{}, err
620 }
621
622 var message Message
623 json.Unmarshal(resp.Result, &message)
624
625 if bot.Debug {
626 log.Printf("SendVoice resp: %+v\n", message)
627 }
628
629 return message, nil
630}
631
632// SendSticker sends or uploads a sticker to a chat.
633//
634// Requires ChatID and FileID OR FilePath.
635// ReplyToMessageID and ReplyMarkup are optional.
636func (bot *BotAPI) SendSticker(config StickerConfig) (Message, error) {
637 if config.UseExistingSticker {
638 v := url.Values{}
639 v.Add("chat_id", strconv.Itoa(config.ChatID))
640 v.Add("sticker", config.FileID)
641 if config.ReplyToMessageID != 0 {
642 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
643 }
644 if config.ReplyMarkup != nil {
645 data, err := json.Marshal(config.ReplyMarkup)
646 if err != nil {
647 return Message{}, err
648 }
649
650 v.Add("reply_markup", string(data))
651 }
652
653 resp, err := bot.MakeRequest("sendSticker", v)
654 if err != nil {
655 return Message{}, err
656 }
657
658 var message Message
659 json.Unmarshal(resp.Result, &message)
660
661 if bot.Debug {
662 log.Printf("sendSticker req : %+v\n", v)
663 log.Printf("sendSticker resp: %+v\n", message)
664 }
665
666 return message, nil
667 }
668
669 params := make(map[string]string)
670
671 params["chat_id"] = strconv.Itoa(config.ChatID)
672 if config.ReplyToMessageID != 0 {
673 params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
674 }
675 if config.ReplyMarkup != nil {
676 data, err := json.Marshal(config.ReplyMarkup)
677 if err != nil {
678 return Message{}, err
679 }
680
681 params["reply_markup"] = string(data)
682 }
683
684 resp, err := bot.UploadFile("sendSticker", params, "sticker", config.FilePath)
685 if err != nil {
686 return Message{}, err
687 }
688
689 var message Message
690 json.Unmarshal(resp.Result, &message)
691
692 if bot.Debug {
693 log.Printf("sendSticker resp: %+v\n", message)
694 }
695
696 return message, nil
697}
698
699// SendVideo sends or uploads a video to a chat.
700//
701// Requires ChatID and FileID OR FilePath.
702// ReplyToMessageID and ReplyMarkup are optional.
703func (bot *BotAPI) SendVideo(config VideoConfig) (Message, error) {
704 if config.UseExistingVideo {
705 v := url.Values{}
706 v.Add("chat_id", strconv.Itoa(config.ChatID))
707 v.Add("video", config.FileID)
708 if config.ReplyToMessageID != 0 {
709 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
710 }
711 if config.Duration != 0 {
712 v.Add("duration", strconv.Itoa(config.Duration))
713 }
714 if config.Caption != "" {
715 v.Add("caption", config.Caption)
716 }
717 if config.ReplyMarkup != nil {
718 data, err := json.Marshal(config.ReplyMarkup)
719 if err != nil {
720 return Message{}, err
721 }
722
723 v.Add("reply_markup", string(data))
724 }
725
726 resp, err := bot.MakeRequest("sendVideo", v)
727 if err != nil {
728 return Message{}, err
729 }
730
731 var message Message
732 json.Unmarshal(resp.Result, &message)
733
734 if bot.Debug {
735 log.Printf("sendVideo req : %+v\n", v)
736 log.Printf("sendVideo resp: %+v\n", message)
737 }
738
739 return message, nil
740 }
741
742 params := make(map[string]string)
743
744 params["chat_id"] = strconv.Itoa(config.ChatID)
745 if config.ReplyToMessageID != 0 {
746 params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
747 }
748 if config.ReplyMarkup != nil {
749 data, err := json.Marshal(config.ReplyMarkup)
750 if err != nil {
751 return Message{}, err
752 }
753
754 params["reply_markup"] = string(data)
755 }
756
757 resp, err := bot.UploadFile("sendVideo", params, "video", config.FilePath)
758 if err != nil {
759 return Message{}, err
760 }
761
762 var message Message
763 json.Unmarshal(resp.Result, &message)
764
765 if bot.Debug {
766 log.Printf("sendVideo resp: %+v\n", message)
767 }
768
769 return message, nil
770}
771
772// SendLocation sends a location to a chat.
773//
774// Requires ChatID, Latitude, and Longitude.
775// ReplyToMessageID and ReplyMarkup are optional.
776func (bot *BotAPI) SendLocation(config LocationConfig) (Message, error) {
777 v := url.Values{}
778 v.Add("chat_id", strconv.Itoa(config.ChatID))
779 v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
780 v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
781 if config.ReplyToMessageID != 0 {
782 v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
783 }
784 if config.ReplyMarkup != nil {
785 data, err := json.Marshal(config.ReplyMarkup)
786 if err != nil {
787 return Message{}, err
788 }
789
790 v.Add("reply_markup", string(data))
791 }
792
793 resp, err := bot.MakeRequest("sendLocation", v)
794 if err != nil {
795 return Message{}, err
796 }
797
798 var message Message
799 json.Unmarshal(resp.Result, &message)
800
801 if bot.Debug {
802 log.Printf("sendLocation req : %+v\n", v)
803 log.Printf("sendLocation resp: %+v\n", message)
804 }
805
806 return message, nil
807}
808
809// SendChatAction sets a current action in a chat.
810//
811// Requires ChatID and a valid Action (see Chat constants).
812func (bot *BotAPI) SendChatAction(config ChatActionConfig) error {
813 v := url.Values{}
814 v.Add("chat_id", strconv.Itoa(config.ChatID))
815 v.Add("action", config.Action)
816
817 _, err := bot.MakeRequest("sendChatAction", v)
818 if err != nil {
819 return err
820 }
821
822 return nil
823}
824
825// GetUserProfilePhotos gets a user's profile photos.
826//
827// Requires UserID.
828// Offset and Limit are optional.
829func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
830 v := url.Values{}
831 v.Add("user_id", strconv.Itoa(config.UserID))
832 if config.Offset != 0 {
833 v.Add("offset", strconv.Itoa(config.Offset))
834 }
835 if config.Limit != 0 {
836 v.Add("limit", strconv.Itoa(config.Limit))
837 }
838
839 resp, err := bot.MakeRequest("getUserProfilePhotos", v)
840 if err != nil {
841 return UserProfilePhotos{}, err
842 }
843
844 var profilePhotos UserProfilePhotos
845 json.Unmarshal(resp.Result, &profilePhotos)
846
847 if bot.Debug {
848 log.Printf("getUserProfilePhotos req : %+v\n", v)
849 log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos)
850 }
851
852 return profilePhotos, nil
853}
854
855// GetUpdates fetches updates.
856// If a WebHook is set, this will not return any data!
857//
858// Offset, Limit, and Timeout are optional.
859// To not get old items, set Offset to one higher than the previous item.
860// Set Timeout to a large number to reduce requests and get responses instantly.
861func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
862 v := url.Values{}
863 if config.Offset > 0 {
864 v.Add("offset", strconv.Itoa(config.Offset))
865 }
866 if config.Limit > 0 {
867 v.Add("limit", strconv.Itoa(config.Limit))
868 }
869 if config.Timeout > 0 {
870 v.Add("timeout", strconv.Itoa(config.Timeout))
871 }
872
873 resp, err := bot.MakeRequest("getUpdates", v)
874 if err != nil {
875 return []Update{}, err
876 }
877
878 var updates []Update
879 json.Unmarshal(resp.Result, &updates)
880
881 if bot.Debug {
882 log.Printf("getUpdates: %+v\n", updates)
883 }
884
885 return updates, nil
886}
887
888// SetWebhook sets a webhook.
889// If this is set, GetUpdates will not get any data!
890//
891// Requires Url OR to set Clear to true.
892func (bot *BotAPI) SetWebhook(config WebhookConfig) error {
893 v := url.Values{}
894 if !config.Clear {
895 v.Add("url", config.URL.String())
896 }
897
898 _, err := bot.MakeRequest("setWebhook", v)
899
900 return err
901}