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