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 update, err := bot.HandleUpdate(r)
561 if err != nil {
562 errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
563 w.WriteHeader(http.StatusBadRequest)
564 w.Header().Set("Content-Type", "application/json")
565 _, _ = w.Write(errMsg)
566 return
567 }
568
569 ch <- *update
570 })
571
572 return ch
573}
574
575// HandleUpdate parses and returns update received via webhook
576func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
577 if r.Method != http.MethodPost {
578 err := errors.New("wrong HTTP method required POST")
579 return nil, err
580 }
581
582 var update Update
583 err := json.NewDecoder(r.Body).Decode(&update)
584 if err != nil {
585 return nil, err
586 }
587
588 return &update, nil
589}
590
591// AnswerInlineQuery sends a response to an inline query.
592//
593// Note that you must respond to an inline query within 30 seconds.
594func (bot *BotAPI) AnswerInlineQuery(config InlineConfig) (APIResponse, error) {
595 v := url.Values{}
596
597 v.Add("inline_query_id", config.InlineQueryID)
598 v.Add("cache_time", strconv.Itoa(config.CacheTime))
599 v.Add("is_personal", strconv.FormatBool(config.IsPersonal))
600 v.Add("next_offset", config.NextOffset)
601 data, err := json.Marshal(config.Results)
602 if err != nil {
603 return APIResponse{}, err
604 }
605 v.Add("results", string(data))
606 v.Add("switch_pm_text", config.SwitchPMText)
607 v.Add("switch_pm_parameter", config.SwitchPMParameter)
608
609 bot.debugLog("answerInlineQuery", v, nil)
610
611 return bot.MakeRequest("answerInlineQuery", v)
612}
613
614// AnswerCallbackQuery sends a response to an inline query callback.
615func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, error) {
616 v := url.Values{}
617
618 v.Add("callback_query_id", config.CallbackQueryID)
619 if config.Text != "" {
620 v.Add("text", config.Text)
621 }
622 v.Add("show_alert", strconv.FormatBool(config.ShowAlert))
623 if config.URL != "" {
624 v.Add("url", config.URL)
625 }
626 v.Add("cache_time", strconv.Itoa(config.CacheTime))
627
628 bot.debugLog("answerCallbackQuery", v, nil)
629
630 return bot.MakeRequest("answerCallbackQuery", v)
631}
632
633// KickChatMember kicks a user from a chat. Note that this only will work
634// in supergroups, and requires the bot to be an admin. Also note they
635// will be unable to rejoin until they are unbanned.
636func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) {
637 v := url.Values{}
638
639 if config.SuperGroupUsername == "" {
640 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
641 } else {
642 v.Add("chat_id", config.SuperGroupUsername)
643 }
644 v.Add("user_id", strconv.Itoa(config.UserID))
645
646 if config.UntilDate != 0 {
647 v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
648 }
649
650 bot.debugLog("kickChatMember", v, nil)
651
652 return bot.MakeRequest("kickChatMember", v)
653}
654
655// LeaveChat makes the bot leave the chat.
656func (bot *BotAPI) LeaveChat(config ChatConfig) (APIResponse, error) {
657 v := url.Values{}
658
659 if config.SuperGroupUsername == "" {
660 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
661 } else {
662 v.Add("chat_id", config.SuperGroupUsername)
663 }
664
665 bot.debugLog("leaveChat", v, nil)
666
667 return bot.MakeRequest("leaveChat", v)
668}
669
670// GetChat gets information about a chat.
671func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
672 v := url.Values{}
673
674 if config.SuperGroupUsername == "" {
675 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
676 } else {
677 v.Add("chat_id", config.SuperGroupUsername)
678 }
679
680 resp, err := bot.MakeRequest("getChat", v)
681 if err != nil {
682 return Chat{}, err
683 }
684
685 var chat Chat
686 err = json.Unmarshal(resp.Result, &chat)
687
688 bot.debugLog("getChat", v, chat)
689
690 return chat, err
691}
692
693// GetChatAdministrators gets a list of administrators in the chat.
694//
695// If none have been appointed, only the creator will be returned.
696// Bots are not shown, even if they are an administrator.
697func (bot *BotAPI) GetChatAdministrators(config ChatConfig) ([]ChatMember, error) {
698 v := url.Values{}
699
700 if config.SuperGroupUsername == "" {
701 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
702 } else {
703 v.Add("chat_id", config.SuperGroupUsername)
704 }
705
706 resp, err := bot.MakeRequest("getChatAdministrators", v)
707 if err != nil {
708 return []ChatMember{}, err
709 }
710
711 var members []ChatMember
712 err = json.Unmarshal(resp.Result, &members)
713
714 bot.debugLog("getChatAdministrators", v, members)
715
716 return members, err
717}
718
719// GetChatMembersCount gets the number of users in a chat.
720func (bot *BotAPI) GetChatMembersCount(config ChatConfig) (int, error) {
721 v := url.Values{}
722
723 if config.SuperGroupUsername == "" {
724 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
725 } else {
726 v.Add("chat_id", config.SuperGroupUsername)
727 }
728
729 resp, err := bot.MakeRequest("getChatMembersCount", v)
730 if err != nil {
731 return -1, err
732 }
733
734 var count int
735 err = json.Unmarshal(resp.Result, &count)
736
737 bot.debugLog("getChatMembersCount", v, count)
738
739 return count, err
740}
741
742// GetChatMember gets a specific chat member.
743func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error) {
744 v := url.Values{}
745
746 if config.SuperGroupUsername == "" {
747 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
748 } else {
749 v.Add("chat_id", config.SuperGroupUsername)
750 }
751 v.Add("user_id", strconv.Itoa(config.UserID))
752
753 resp, err := bot.MakeRequest("getChatMember", v)
754 if err != nil {
755 return ChatMember{}, err
756 }
757
758 var member ChatMember
759 err = json.Unmarshal(resp.Result, &member)
760
761 bot.debugLog("getChatMember", v, member)
762
763 return member, err
764}
765
766// UnbanChatMember unbans a user from a chat. Note that this only will work
767// in supergroups and channels, and requires the bot to be an admin.
768func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
769 v := url.Values{}
770
771 if config.SuperGroupUsername != "" {
772 v.Add("chat_id", config.SuperGroupUsername)
773 } else if config.ChannelUsername != "" {
774 v.Add("chat_id", config.ChannelUsername)
775 } else {
776 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
777 }
778 v.Add("user_id", strconv.Itoa(config.UserID))
779
780 bot.debugLog("unbanChatMember", v, nil)
781
782 return bot.MakeRequest("unbanChatMember", v)
783}
784
785// RestrictChatMember to restrict a user in a supergroup. The bot must be an
786// administrator in the supergroup for this to work and must have the
787// appropriate admin rights. Pass True for all boolean parameters to lift
788// restrictions from a user. Returns True on success.
789func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
790 v := url.Values{}
791
792 if config.SuperGroupUsername != "" {
793 v.Add("chat_id", config.SuperGroupUsername)
794 } else if config.ChannelUsername != "" {
795 v.Add("chat_id", config.ChannelUsername)
796 } else {
797 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
798 }
799 v.Add("user_id", strconv.Itoa(config.UserID))
800
801 if config.CanSendMessages != nil {
802 v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
803 }
804 if config.CanSendMediaMessages != nil {
805 v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
806 }
807 if config.CanSendOtherMessages != nil {
808 v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
809 }
810 if config.CanAddWebPagePreviews != nil {
811 v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
812 }
813 if config.UntilDate != 0 {
814 v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
815 }
816
817 bot.debugLog("restrictChatMember", v, nil)
818
819 return bot.MakeRequest("restrictChatMember", v)
820}
821
822// PromoteChatMember add admin rights to user
823func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
824 v := url.Values{}
825
826 if config.SuperGroupUsername != "" {
827 v.Add("chat_id", config.SuperGroupUsername)
828 } else if config.ChannelUsername != "" {
829 v.Add("chat_id", config.ChannelUsername)
830 } else {
831 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
832 }
833 v.Add("user_id", strconv.Itoa(config.UserID))
834
835 if config.CanChangeInfo != nil {
836 v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
837 }
838 if config.CanPostMessages != nil {
839 v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
840 }
841 if config.CanEditMessages != nil {
842 v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
843 }
844 if config.CanDeleteMessages != nil {
845 v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
846 }
847 if config.CanInviteUsers != nil {
848 v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
849 }
850 if config.CanRestrictMembers != nil {
851 v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
852 }
853 if config.CanPinMessages != nil {
854 v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
855 }
856 if config.CanPromoteMembers != nil {
857 v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
858 }
859
860 bot.debugLog("promoteChatMember", v, nil)
861
862 return bot.MakeRequest("promoteChatMember", v)
863}
864
865// GetGameHighScores allows you to get the high scores for a game.
866func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
867 v, _ := config.values()
868
869 resp, err := bot.MakeRequest(config.method(), v)
870 if err != nil {
871 return []GameHighScore{}, err
872 }
873
874 var highScores []GameHighScore
875 err = json.Unmarshal(resp.Result, &highScores)
876
877 return highScores, err
878}
879
880// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
881func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) {
882 v := url.Values{}
883
884 v.Add("shipping_query_id", config.ShippingQueryID)
885 v.Add("ok", strconv.FormatBool(config.OK))
886 if config.OK == true {
887 data, err := json.Marshal(config.ShippingOptions)
888 if err != nil {
889 return APIResponse{}, err
890 }
891 v.Add("shipping_options", string(data))
892 } else {
893 v.Add("error_message", config.ErrorMessage)
894 }
895
896 bot.debugLog("answerShippingQuery", v, nil)
897
898 return bot.MakeRequest("answerShippingQuery", v)
899}
900
901// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
902func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) {
903 v := url.Values{}
904
905 v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
906 v.Add("ok", strconv.FormatBool(config.OK))
907 if config.OK != true {
908 v.Add("error_message", config.ErrorMessage)
909 }
910
911 bot.debugLog("answerPreCheckoutQuery", v, nil)
912
913 return bot.MakeRequest("answerPreCheckoutQuery", v)
914}
915
916// DeleteMessage deletes a message in a chat
917func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) {
918 v, err := config.values()
919 if err != nil {
920 return APIResponse{}, err
921 }
922
923 bot.debugLog(config.method(), v, nil)
924
925 return bot.MakeRequest(config.method(), v)
926}
927
928// GetInviteLink get InviteLink for a chat
929func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
930 v := url.Values{}
931
932 if config.SuperGroupUsername == "" {
933 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
934 } else {
935 v.Add("chat_id", config.SuperGroupUsername)
936 }
937
938 resp, err := bot.MakeRequest("exportChatInviteLink", v)
939 if err != nil {
940 return "", err
941 }
942
943 var inviteLink string
944 err = json.Unmarshal(resp.Result, &inviteLink)
945
946 return inviteLink, err
947}
948
949// PinChatMessage pin message in supergroup
950func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) {
951 v, err := config.values()
952 if err != nil {
953 return APIResponse{}, err
954 }
955
956 bot.debugLog(config.method(), v, nil)
957
958 return bot.MakeRequest(config.method(), v)
959}
960
961// UnpinChatMessage unpin message in supergroup
962func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) {
963 v, err := config.values()
964 if err != nil {
965 return APIResponse{}, err
966 }
967
968 bot.debugLog(config.method(), v, nil)
969
970 return bot.MakeRequest(config.method(), v)
971}
972
973// SetChatTitle change title of chat.
974func (bot *BotAPI) SetChatTitle(config SetChatTitleConfig) (APIResponse, error) {
975 v, err := config.values()
976 if err != nil {
977 return APIResponse{}, err
978 }
979
980 bot.debugLog(config.method(), v, nil)
981
982 return bot.MakeRequest(config.method(), v)
983}
984
985// SetChatDescription change description of chat.
986func (bot *BotAPI) SetChatDescription(config SetChatDescriptionConfig) (APIResponse, error) {
987 v, err := config.values()
988 if err != nil {
989 return APIResponse{}, err
990 }
991
992 bot.debugLog(config.method(), v, nil)
993
994 return bot.MakeRequest(config.method(), v)
995}
996
997// SetChatPhoto change photo of chat.
998func (bot *BotAPI) SetChatPhoto(config SetChatPhotoConfig) (APIResponse, error) {
999 params, err := config.params()
1000 if err != nil {
1001 return APIResponse{}, err
1002 }
1003
1004 file := config.getFile()
1005
1006 return bot.UploadFile(config.method(), params, config.name(), file)
1007}
1008
1009// DeleteChatPhoto delete photo of chat.
1010func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, error) {
1011 v, err := config.values()
1012 if err != nil {
1013 return APIResponse{}, err
1014 }
1015
1016 bot.debugLog(config.method(), v, nil)
1017
1018 return bot.MakeRequest(config.method(), v)
1019}
1020
1021// GetStickerSet get a sticker set.
1022func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
1023 v, err := config.values()
1024 if err != nil {
1025 return StickerSet{}, err
1026 }
1027 bot.debugLog(config.method(), v, nil)
1028 res, err := bot.MakeRequest(config.method(), v)
1029 if err != nil {
1030 return StickerSet{}, err
1031 }
1032 stickerSet := StickerSet{}
1033 err = json.Unmarshal(res.Result, &stickerSet)
1034 if err != nil {
1035 return StickerSet{}, err
1036 }
1037 return stickerSet, nil
1038}
1039
1040// GetMyCommands gets the current list of the bot's commands.
1041func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
1042 res, err := bot.MakeRequest("getMyCommands", nil)
1043 if err != nil {
1044 return nil, err
1045 }
1046 var commands []BotCommand
1047 err = json.Unmarshal(res.Result, &commands)
1048 if err != nil {
1049 return nil, err
1050 }
1051 return commands, nil
1052}
1053
1054// SetMyCommands changes the list of the bot's commands.
1055func (bot *BotAPI) SetMyCommands(commands []BotCommand) error {
1056 v := url.Values{}
1057 data, err := json.Marshal(commands)
1058 if err != nil {
1059 return err
1060 }
1061 v.Add("commands", string(data))
1062 _, err = bot.MakeRequest("setMyCommands", v)
1063 if err != nil {
1064 return err
1065 }
1066 return nil
1067}