bot.go (view raw)
1// Package tgbotapi has functions and types used for interacting with
2// the Telegram Bot API.
3package tgbotapi
4
5import (
6 "bytes"
7 "encoding/json"
8 "errors"
9 "fmt"
10 "io"
11 "io/ioutil"
12 "net/http"
13 "net/url"
14 "os"
15 "strconv"
16 "strings"
17 "time"
18
19 "github.com/technoweenie/multipartstreamer"
20)
21
22type HttpClient interface {
23 Do(req *http.Request) (*http.Response, error)
24}
25
26// BotAPI allows you to interact with the Telegram Bot API.
27type BotAPI struct {
28 Token string `json:"token"`
29 Debug bool `json:"debug"`
30 Buffer int `json:"buffer"`
31
32 Self User `json:"-"`
33 Client HttpClient `json:"-"`
34 shutdownChannel chan interface{}
35
36 apiEndpoint string
37}
38
39// NewBotAPI creates a new BotAPI instance.
40//
41// It requires a token, provided by @BotFather on Telegram.
42func NewBotAPI(token string) (*BotAPI, error) {
43 return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
44}
45
46// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
47// and allows you to pass API endpoint.
48//
49// It requires a token, provided by @BotFather on Telegram and API endpoint.
50func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
51 return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
52}
53
54// NewBotAPIWithClient creates a new BotAPI instance
55// and allows you to pass a http.Client.
56//
57// It requires a token, provided by @BotFather on Telegram and API endpoint.
58func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, error) {
59 bot := &BotAPI{
60 Token: token,
61 Client: client,
62 Buffer: 100,
63 shutdownChannel: make(chan interface{}),
64
65 apiEndpoint: apiEndpoint,
66 }
67
68 self, err := bot.GetMe()
69 if err != nil {
70 return nil, err
71 }
72
73 bot.Self = self
74
75 return bot, nil
76}
77
78// SetAPIEndpoint add telegram apiEndpont to Bot
79func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
80 bot.apiEndpoint = apiEndpoint
81}
82
83// MakeRequest makes a request to a specific endpoint with our token.
84func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
85 method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
86
87 req, err := http.NewRequest("POST", method, strings.NewReader(params.Encode()))
88 if err != nil {
89 return APIResponse{}, err
90 }
91 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
92
93 resp, err := bot.Client.Do(req)
94 if err != nil {
95 return APIResponse{}, err
96 }
97 defer resp.Body.Close()
98
99 var apiResp APIResponse
100 bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
101 if err != nil {
102 return apiResp, err
103 }
104
105 if bot.Debug {
106 log.Printf("%s resp: %s", endpoint, bytes)
107 }
108
109 if !apiResp.Ok {
110 parameters := ResponseParameters{}
111 if apiResp.Parameters != nil {
112 parameters = *apiResp.Parameters
113 }
114 return apiResp, &Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
115 }
116
117 return apiResp, nil
118}
119
120// decodeAPIResponse decode response and return slice of bytes if debug enabled.
121// If debug disabled, just decode http.Response.Body stream to APIResponse struct
122// for efficient memory usage
123func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) (_ []byte, err error) {
124 if !bot.Debug {
125 dec := json.NewDecoder(responseBody)
126 err = dec.Decode(resp)
127 return
128 }
129
130 // if debug, read reponse body
131 data, err := ioutil.ReadAll(responseBody)
132 if err != nil {
133 return
134 }
135
136 err = json.Unmarshal(data, resp)
137 if err != nil {
138 return
139 }
140
141 return data, nil
142}
143
144// makeMessageRequest makes a request to a method that returns a Message.
145func (bot *BotAPI) makeMessageRequest(endpoint string, params url.Values) (Message, error) {
146 resp, err := bot.MakeRequest(endpoint, params)
147 if err != nil {
148 return Message{}, err
149 }
150
151 var message Message
152 json.Unmarshal(resp.Result, &message)
153
154 bot.debugLog(endpoint, params, message)
155
156 return message, nil
157}
158
159// UploadFile makes a request to the API with a file.
160//
161// Requires the parameter to hold the file not be in the params.
162// File should be a string to a file path, a FileBytes struct,
163// a FileReader struct, or a url.URL.
164//
165// Note that if your FileReader has a size set to -1, it will read
166// the file into memory to calculate a size.
167func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, file interface{}) (APIResponse, error) {
168 ms := multipartstreamer.New()
169
170 switch f := file.(type) {
171 case string:
172 ms.WriteFields(params)
173
174 fileHandle, err := os.Open(f)
175 if err != nil {
176 return APIResponse{}, err
177 }
178 defer fileHandle.Close()
179
180 fi, err := os.Stat(f)
181 if err != nil {
182 return APIResponse{}, err
183 }
184
185 ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle)
186 case FileBytes:
187 ms.WriteFields(params)
188
189 buf := bytes.NewBuffer(f.Bytes)
190 ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf)
191 case FileReader:
192 ms.WriteFields(params)
193
194 if f.Size != -1 {
195 ms.WriteReader(fieldname, f.Name, f.Size, f.Reader)
196
197 break
198 }
199
200 data, err := ioutil.ReadAll(f.Reader)
201 if err != nil {
202 return APIResponse{}, err
203 }
204
205 buf := bytes.NewBuffer(data)
206
207 ms.WriteReader(fieldname, f.Name, int64(len(data)), buf)
208 case url.URL:
209 params[fieldname] = f.String()
210
211 ms.WriteFields(params)
212 default:
213 return APIResponse{}, errors.New(ErrBadFileType)
214 }
215
216 method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
217
218 req, err := http.NewRequest("POST", method, nil)
219 if err != nil {
220 return APIResponse{}, err
221 }
222
223 ms.SetupRequest(req)
224
225 res, err := bot.Client.Do(req)
226 if err != nil {
227 return APIResponse{}, err
228 }
229 defer res.Body.Close()
230
231 bytes, err := ioutil.ReadAll(res.Body)
232 if err != nil {
233 return APIResponse{}, err
234 }
235
236 if bot.Debug {
237 log.Println(string(bytes))
238 }
239
240 var apiResp APIResponse
241
242 err = json.Unmarshal(bytes, &apiResp)
243 if err != nil {
244 return APIResponse{}, err
245 }
246
247 if !apiResp.Ok {
248 parameters := ResponseParameters{}
249 if apiResp.Parameters != nil {
250 parameters = *apiResp.Parameters
251 }
252 return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
253 }
254
255 return apiResp, nil
256}
257
258// GetFileDirectURL returns direct URL to file
259//
260// It requires the FileID.
261func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) {
262 file, err := bot.GetFile(FileConfig{fileID})
263
264 if err != nil {
265 return "", err
266 }
267
268 return file.Link(bot.Token), nil
269}
270
271// GetMe fetches the currently authenticated bot.
272//
273// This method is called upon creation to validate the token,
274// and so you may get this data from BotAPI.Self without the need for
275// another request.
276func (bot *BotAPI) GetMe() (User, error) {
277 resp, err := bot.MakeRequest("getMe", nil)
278 if err != nil {
279 return User{}, err
280 }
281
282 var user User
283 json.Unmarshal(resp.Result, &user)
284
285 bot.debugLog("getMe", nil, user)
286
287 return user, nil
288}
289
290// IsMessageToMe returns true if message directed to this bot.
291//
292// It requires the Message.
293func (bot *BotAPI) IsMessageToMe(message Message) bool {
294 return strings.Contains(message.Text, "@"+bot.Self.UserName)
295}
296
297// Send will send a Chattable item to Telegram.
298//
299// It requires the Chattable to send.
300func (bot *BotAPI) Send(c Chattable) (Message, error) {
301 switch c.(type) {
302 case Fileable:
303 return bot.sendFile(c.(Fileable))
304 default:
305 return bot.sendChattable(c)
306 }
307}
308
309// debugLog checks if the bot is currently running in debug mode, and if
310// so will display information about the request and response in the
311// debug log.
312func (bot *BotAPI) debugLog(context string, v url.Values, message interface{}) {
313 if bot.Debug {
314 log.Printf("%s req : %+v\n", context, v)
315 log.Printf("%s resp: %+v\n", context, message)
316 }
317}
318
319// sendExisting will send a Message with an existing file to Telegram.
320func (bot *BotAPI) sendExisting(method string, config Fileable) (Message, error) {
321 v, err := config.values()
322
323 if err != nil {
324 return Message{}, err
325 }
326
327 message, err := bot.makeMessageRequest(method, v)
328 if err != nil {
329 return Message{}, err
330 }
331
332 return message, nil
333}
334
335// uploadAndSend will send a Message with a new file to Telegram.
336func (bot *BotAPI) uploadAndSend(method string, config Fileable) (Message, error) {
337 params, err := config.params()
338 if err != nil {
339 return Message{}, err
340 }
341
342 file := config.getFile()
343
344 resp, err := bot.UploadFile(method, params, config.name(), file)
345 if err != nil {
346 return Message{}, err
347 }
348
349 var message Message
350 json.Unmarshal(resp.Result, &message)
351
352 bot.debugLog(method, nil, message)
353
354 return message, nil
355}
356
357// sendFile determines if the file is using an existing file or uploading
358// a new file, then sends it as needed.
359func (bot *BotAPI) sendFile(config Fileable) (Message, error) {
360 if config.useExistingFile() {
361 return bot.sendExisting(config.method(), config)
362 }
363
364 return bot.uploadAndSend(config.method(), config)
365}
366
367// sendChattable sends a Chattable.
368func (bot *BotAPI) sendChattable(config Chattable) (Message, error) {
369 v, err := config.values()
370 if err != nil {
371 return Message{}, err
372 }
373
374 message, err := bot.makeMessageRequest(config.method(), v)
375
376 if err != nil {
377 return Message{}, err
378 }
379
380 return message, nil
381}
382
383// GetUserProfilePhotos gets a user's profile photos.
384//
385// It requires UserID.
386// Offset and Limit are optional.
387func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
388 v := url.Values{}
389 v.Add("user_id", strconv.Itoa(config.UserID))
390 if config.Offset != 0 {
391 v.Add("offset", strconv.Itoa(config.Offset))
392 }
393 if config.Limit != 0 {
394 v.Add("limit", strconv.Itoa(config.Limit))
395 }
396
397 resp, err := bot.MakeRequest("getUserProfilePhotos", v)
398 if err != nil {
399 return UserProfilePhotos{}, err
400 }
401
402 var profilePhotos UserProfilePhotos
403 json.Unmarshal(resp.Result, &profilePhotos)
404
405 bot.debugLog("GetUserProfilePhoto", v, profilePhotos)
406
407 return profilePhotos, nil
408}
409
410// GetFile returns a File which can download a file from Telegram.
411//
412// Requires FileID.
413func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
414 v := url.Values{}
415 v.Add("file_id", config.FileID)
416
417 resp, err := bot.MakeRequest("getFile", v)
418 if err != nil {
419 return File{}, err
420 }
421
422 var file File
423 json.Unmarshal(resp.Result, &file)
424
425 bot.debugLog("GetFile", v, file)
426
427 return file, nil
428}
429
430// GetUpdates fetches updates.
431// If a WebHook is set, this will not return any data!
432//
433// Offset, Limit, and Timeout are optional.
434// To avoid stale items, set Offset to one higher than the previous item.
435// Set Timeout to a large number to reduce requests so you can get updates
436// instantly instead of having to wait between requests.
437func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
438 v := url.Values{}
439 if config.Offset != 0 {
440 v.Add("offset", strconv.Itoa(config.Offset))
441 }
442 if config.Limit > 0 {
443 v.Add("limit", strconv.Itoa(config.Limit))
444 }
445 if config.Timeout > 0 {
446 v.Add("timeout", strconv.Itoa(config.Timeout))
447 }
448
449 resp, err := bot.MakeRequest("getUpdates", v)
450 if err != nil {
451 return []Update{}, err
452 }
453
454 var updates []Update
455 json.Unmarshal(resp.Result, &updates)
456
457 bot.debugLog("getUpdates", v, updates)
458
459 return updates, nil
460}
461
462// RemoveWebhook unsets the webhook.
463func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
464 return bot.MakeRequest("deleteWebhook", url.Values{})
465}
466
467// SetWebhook sets a webhook.
468//
469// If this is set, GetUpdates will not get any data!
470//
471// If you do not have a legitimate TLS certificate, you need to include
472// your self signed certificate with the config.
473func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) {
474
475 if config.Certificate == nil {
476 v := url.Values{}
477 v.Add("url", config.URL.String())
478 if config.MaxConnections != 0 {
479 v.Add("max_connections", strconv.Itoa(config.MaxConnections))
480 }
481
482 return bot.MakeRequest("setWebhook", v)
483 }
484
485 params := make(map[string]string)
486 params["url"] = config.URL.String()
487 if config.MaxConnections != 0 {
488 params["max_connections"] = strconv.Itoa(config.MaxConnections)
489 }
490
491 resp, err := bot.UploadFile("setWebhook", params, "certificate", config.Certificate)
492 if err != nil {
493 return APIResponse{}, err
494 }
495
496 return resp, nil
497}
498
499// GetWebhookInfo allows you to fetch information about a webhook and if
500// one currently is set, along with pending update count and error messages.
501func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
502 resp, err := bot.MakeRequest("getWebhookInfo", url.Values{})
503 if err != nil {
504 return WebhookInfo{}, err
505 }
506
507 var info WebhookInfo
508 err = json.Unmarshal(resp.Result, &info)
509
510 return info, err
511}
512
513// GetUpdatesChan starts and returns a channel for getting updates.
514func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
515 ch := make(chan Update, bot.Buffer)
516
517 go func() {
518 for {
519 select {
520 case <-bot.shutdownChannel:
521 close(ch)
522 return
523 default:
524 }
525
526 updates, err := bot.GetUpdates(config)
527 if err != nil {
528 log.Println(err)
529 log.Println("Failed to get updates, retrying in 3 seconds...")
530 time.Sleep(time.Second * 3)
531
532 continue
533 }
534
535 for _, update := range updates {
536 if update.UpdateID >= config.Offset {
537 config.Offset = update.UpdateID + 1
538 ch <- update
539 }
540 }
541 }
542 }()
543
544 return ch, nil
545}
546
547// StopReceivingUpdates stops the go routine which receives updates
548func (bot *BotAPI) StopReceivingUpdates() {
549 if bot.Debug {
550 log.Println("Stopping the update receiver routine...")
551 }
552 close(bot.shutdownChannel)
553}
554
555// ListenForWebhook registers a http handler for a webhook.
556func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
557 ch := make(chan Update, bot.Buffer)
558
559 http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
560 ch <- bot.HandleUpdate(w, r)
561 })
562
563 return ch
564}
565
566// HandleUpdate parses and returns update received via webhook
567func (bot *BotAPI) HandleUpdate(res http.ResponseWriter, req *http.Request) Update {
568 bytes, _ := ioutil.ReadAll(req.Body)
569 req.Body.Close()
570
571 var update Update
572 json.Unmarshal(bytes, &update)
573
574 return update
575}
576
577// AnswerInlineQuery sends a response to an inline query.
578//
579// Note that you must respond to an inline query within 30 seconds.
580func (bot *BotAPI) AnswerInlineQuery(config InlineConfig) (APIResponse, error) {
581 v := url.Values{}
582
583 v.Add("inline_query_id", config.InlineQueryID)
584 v.Add("cache_time", strconv.Itoa(config.CacheTime))
585 v.Add("is_personal", strconv.FormatBool(config.IsPersonal))
586 v.Add("next_offset", config.NextOffset)
587 data, err := json.Marshal(config.Results)
588 if err != nil {
589 return APIResponse{}, err
590 }
591 v.Add("results", string(data))
592 v.Add("switch_pm_text", config.SwitchPMText)
593 v.Add("switch_pm_parameter", config.SwitchPMParameter)
594
595 bot.debugLog("answerInlineQuery", v, nil)
596
597 return bot.MakeRequest("answerInlineQuery", v)
598}
599
600// AnswerCallbackQuery sends a response to an inline query callback.
601func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, error) {
602 v := url.Values{}
603
604 v.Add("callback_query_id", config.CallbackQueryID)
605 if config.Text != "" {
606 v.Add("text", config.Text)
607 }
608 v.Add("show_alert", strconv.FormatBool(config.ShowAlert))
609 if config.URL != "" {
610 v.Add("url", config.URL)
611 }
612 v.Add("cache_time", strconv.Itoa(config.CacheTime))
613
614 bot.debugLog("answerCallbackQuery", v, nil)
615
616 return bot.MakeRequest("answerCallbackQuery", v)
617}
618
619// KickChatMember kicks a user from a chat. Note that this only will work
620// in supergroups, and requires the bot to be an admin. Also note they
621// will be unable to rejoin until they are unbanned.
622func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) {
623 v := url.Values{}
624
625 if config.SuperGroupUsername == "" {
626 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
627 } else {
628 v.Add("chat_id", config.SuperGroupUsername)
629 }
630 v.Add("user_id", strconv.Itoa(config.UserID))
631
632 if config.UntilDate != 0 {
633 v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
634 }
635
636 bot.debugLog("kickChatMember", v, nil)
637
638 return bot.MakeRequest("kickChatMember", v)
639}
640
641// LeaveChat makes the bot leave the chat.
642func (bot *BotAPI) LeaveChat(config ChatConfig) (APIResponse, error) {
643 v := url.Values{}
644
645 if config.SuperGroupUsername == "" {
646 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
647 } else {
648 v.Add("chat_id", config.SuperGroupUsername)
649 }
650
651 bot.debugLog("leaveChat", v, nil)
652
653 return bot.MakeRequest("leaveChat", v)
654}
655
656// GetChat gets information about a chat.
657func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
658 v := url.Values{}
659
660 if config.SuperGroupUsername == "" {
661 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
662 } else {
663 v.Add("chat_id", config.SuperGroupUsername)
664 }
665
666 resp, err := bot.MakeRequest("getChat", v)
667 if err != nil {
668 return Chat{}, err
669 }
670
671 var chat Chat
672 err = json.Unmarshal(resp.Result, &chat)
673
674 bot.debugLog("getChat", v, chat)
675
676 return chat, err
677}
678
679// GetChatAdministrators gets a list of administrators in the chat.
680//
681// If none have been appointed, only the creator will be returned.
682// Bots are not shown, even if they are an administrator.
683func (bot *BotAPI) GetChatAdministrators(config ChatConfig) ([]ChatMember, error) {
684 v := url.Values{}
685
686 if config.SuperGroupUsername == "" {
687 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
688 } else {
689 v.Add("chat_id", config.SuperGroupUsername)
690 }
691
692 resp, err := bot.MakeRequest("getChatAdministrators", v)
693 if err != nil {
694 return []ChatMember{}, err
695 }
696
697 var members []ChatMember
698 err = json.Unmarshal(resp.Result, &members)
699
700 bot.debugLog("getChatAdministrators", v, members)
701
702 return members, err
703}
704
705// GetChatMembersCount gets the number of users in a chat.
706func (bot *BotAPI) GetChatMembersCount(config ChatConfig) (int, error) {
707 v := url.Values{}
708
709 if config.SuperGroupUsername == "" {
710 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
711 } else {
712 v.Add("chat_id", config.SuperGroupUsername)
713 }
714
715 resp, err := bot.MakeRequest("getChatMembersCount", v)
716 if err != nil {
717 return -1, err
718 }
719
720 var count int
721 err = json.Unmarshal(resp.Result, &count)
722
723 bot.debugLog("getChatMembersCount", v, count)
724
725 return count, err
726}
727
728// GetChatMember gets a specific chat member.
729func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error) {
730 v := url.Values{}
731
732 if config.SuperGroupUsername == "" {
733 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
734 } else {
735 v.Add("chat_id", config.SuperGroupUsername)
736 }
737 v.Add("user_id", strconv.Itoa(config.UserID))
738
739 resp, err := bot.MakeRequest("getChatMember", v)
740 if err != nil {
741 return ChatMember{}, err
742 }
743
744 var member ChatMember
745 err = json.Unmarshal(resp.Result, &member)
746
747 bot.debugLog("getChatMember", v, member)
748
749 return member, err
750}
751
752// UnbanChatMember unbans a user from a chat. Note that this only will work
753// in supergroups and channels, and requires the bot to be an admin.
754func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
755 v := url.Values{}
756
757 if config.SuperGroupUsername != "" {
758 v.Add("chat_id", config.SuperGroupUsername)
759 } else if config.ChannelUsername != "" {
760 v.Add("chat_id", config.ChannelUsername)
761 } else {
762 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
763 }
764 v.Add("user_id", strconv.Itoa(config.UserID))
765
766 bot.debugLog("unbanChatMember", v, nil)
767
768 return bot.MakeRequest("unbanChatMember", v)
769}
770
771// RestrictChatMember to restrict a user in a supergroup. The bot must be an
772// administrator in the supergroup for this to work and must have the
773// appropriate admin rights. Pass True for all boolean parameters to lift
774// restrictions from a user. Returns True on success.
775func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
776 v := url.Values{}
777
778 if config.SuperGroupUsername != "" {
779 v.Add("chat_id", config.SuperGroupUsername)
780 } else if config.ChannelUsername != "" {
781 v.Add("chat_id", config.ChannelUsername)
782 } else {
783 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
784 }
785 v.Add("user_id", strconv.Itoa(config.UserID))
786
787 if config.CanSendMessages != nil {
788 v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
789 }
790 if config.CanSendMediaMessages != nil {
791 v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
792 }
793 if config.CanSendOtherMessages != nil {
794 v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
795 }
796 if config.CanAddWebPagePreviews != nil {
797 v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
798 }
799 if config.UntilDate != 0 {
800 v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
801 }
802
803 bot.debugLog("restrictChatMember", v, nil)
804
805 return bot.MakeRequest("restrictChatMember", v)
806}
807
808// PromoteChatMember add admin rights to user
809func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
810 v := url.Values{}
811
812 if config.SuperGroupUsername != "" {
813 v.Add("chat_id", config.SuperGroupUsername)
814 } else if config.ChannelUsername != "" {
815 v.Add("chat_id", config.ChannelUsername)
816 } else {
817 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
818 }
819 v.Add("user_id", strconv.Itoa(config.UserID))
820
821 if config.CanChangeInfo != nil {
822 v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
823 }
824 if config.CanPostMessages != nil {
825 v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
826 }
827 if config.CanEditMessages != nil {
828 v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
829 }
830 if config.CanDeleteMessages != nil {
831 v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
832 }
833 if config.CanInviteUsers != nil {
834 v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
835 }
836 if config.CanRestrictMembers != nil {
837 v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
838 }
839 if config.CanPinMessages != nil {
840 v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
841 }
842 if config.CanPromoteMembers != nil {
843 v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
844 }
845
846 bot.debugLog("promoteChatMember", v, nil)
847
848 return bot.MakeRequest("promoteChatMember", v)
849}
850
851// GetGameHighScores allows you to get the high scores for a game.
852func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
853 v, _ := config.values()
854
855 resp, err := bot.MakeRequest(config.method(), v)
856 if err != nil {
857 return []GameHighScore{}, err
858 }
859
860 var highScores []GameHighScore
861 err = json.Unmarshal(resp.Result, &highScores)
862
863 return highScores, err
864}
865
866// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
867func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) {
868 v := url.Values{}
869
870 v.Add("shipping_query_id", config.ShippingQueryID)
871 v.Add("ok", strconv.FormatBool(config.OK))
872 if config.OK == true {
873 data, err := json.Marshal(config.ShippingOptions)
874 if err != nil {
875 return APIResponse{}, err
876 }
877 v.Add("shipping_options", string(data))
878 } else {
879 v.Add("error_message", config.ErrorMessage)
880 }
881
882 bot.debugLog("answerShippingQuery", v, nil)
883
884 return bot.MakeRequest("answerShippingQuery", v)
885}
886
887// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
888func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) {
889 v := url.Values{}
890
891 v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
892 v.Add("ok", strconv.FormatBool(config.OK))
893 if config.OK != true {
894 v.Add("error_message", config.ErrorMessage)
895 }
896
897 bot.debugLog("answerPreCheckoutQuery", v, nil)
898
899 return bot.MakeRequest("answerPreCheckoutQuery", v)
900}
901
902// DeleteMessage deletes a message in a chat
903func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) {
904 v, err := config.values()
905 if err != nil {
906 return APIResponse{}, err
907 }
908
909 bot.debugLog(config.method(), v, nil)
910
911 return bot.MakeRequest(config.method(), v)
912}
913
914// GetInviteLink get InviteLink for a chat
915func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
916 v := url.Values{}
917
918 if config.SuperGroupUsername == "" {
919 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
920 } else {
921 v.Add("chat_id", config.SuperGroupUsername)
922 }
923
924 resp, err := bot.MakeRequest("exportChatInviteLink", v)
925 if err != nil {
926 return "", err
927 }
928
929 var inviteLink string
930 err = json.Unmarshal(resp.Result, &inviteLink)
931
932 return inviteLink, err
933}
934
935// PinChatMessage pin message in supergroup
936func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) {
937 v, err := config.values()
938 if err != nil {
939 return APIResponse{}, err
940 }
941
942 bot.debugLog(config.method(), v, nil)
943
944 return bot.MakeRequest(config.method(), v)
945}
946
947// UnpinChatMessage unpin message in supergroup
948func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) {
949 v, err := config.values()
950 if err != nil {
951 return APIResponse{}, err
952 }
953
954 bot.debugLog(config.method(), v, nil)
955
956 return bot.MakeRequest(config.method(), v)
957}
958
959// SetChatTitle change title of chat.
960func (bot *BotAPI) SetChatTitle(config SetChatTitleConfig) (APIResponse, error) {
961 v, err := config.values()
962 if err != nil {
963 return APIResponse{}, err
964 }
965
966 bot.debugLog(config.method(), v, nil)
967
968 return bot.MakeRequest(config.method(), v)
969}
970
971// SetChatDescription change description of chat.
972func (bot *BotAPI) SetChatDescription(config SetChatDescriptionConfig) (APIResponse, error) {
973 v, err := config.values()
974 if err != nil {
975 return APIResponse{}, err
976 }
977
978 bot.debugLog(config.method(), v, nil)
979
980 return bot.MakeRequest(config.method(), v)
981}
982
983// SetChatPhoto change photo of chat.
984func (bot *BotAPI) SetChatPhoto(config SetChatPhotoConfig) (APIResponse, error) {
985 params, err := config.params()
986 if err != nil {
987 return APIResponse{}, err
988 }
989
990 file := config.getFile()
991
992 return bot.UploadFile(config.method(), params, config.name(), file)
993}
994
995// DeleteChatPhoto delete photo of chat.
996func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, error) {
997 v, err := config.values()
998 if err != nil {
999 return APIResponse{}, err
1000 }
1001
1002 bot.debugLog(config.method(), v, nil)
1003
1004 return bot.MakeRequest(config.method(), v)
1005}
1006
1007// GetStickerSet get a sticker set.
1008func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
1009 v, err := config.values()
1010 if err != nil {
1011 return StickerSet{}, err
1012 }
1013 bot.debugLog(config.method(), v, nil)
1014 res, err := bot.MakeRequest(config.method(), v)
1015 if err != nil {
1016 return StickerSet{}, err
1017 }
1018 stickerSet := StickerSet{}
1019 err = json.Unmarshal(res.Result, &stickerSet)
1020 if err != nil {
1021 return StickerSet{}, err
1022 }
1023 return stickerSet, nil
1024}