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 return APIResponse{}, errors.New(apiResp.Description)
249 }
250
251 return apiResp, nil
252}
253
254// GetFileDirectURL returns direct URL to file
255//
256// It requires the FileID.
257func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) {
258 file, err := bot.GetFile(FileConfig{fileID})
259
260 if err != nil {
261 return "", err
262 }
263
264 return file.Link(bot.Token), nil
265}
266
267// GetMe fetches the currently authenticated bot.
268//
269// This method is called upon creation to validate the token,
270// and so you may get this data from BotAPI.Self without the need for
271// another request.
272func (bot *BotAPI) GetMe() (User, error) {
273 resp, err := bot.MakeRequest("getMe", nil)
274 if err != nil {
275 return User{}, err
276 }
277
278 var user User
279 json.Unmarshal(resp.Result, &user)
280
281 bot.debugLog("getMe", nil, user)
282
283 return user, nil
284}
285
286// IsMessageToMe returns true if message directed to this bot.
287//
288// It requires the Message.
289func (bot *BotAPI) IsMessageToMe(message Message) bool {
290 return strings.Contains(message.Text, "@"+bot.Self.UserName)
291}
292
293// Send will send a Chattable item to Telegram.
294//
295// It requires the Chattable to send.
296func (bot *BotAPI) Send(c Chattable) (Message, error) {
297 switch c.(type) {
298 case Fileable:
299 return bot.sendFile(c.(Fileable))
300 default:
301 return bot.sendChattable(c)
302 }
303}
304
305// debugLog checks if the bot is currently running in debug mode, and if
306// so will display information about the request and response in the
307// debug log.
308func (bot *BotAPI) debugLog(context string, v url.Values, message interface{}) {
309 if bot.Debug {
310 log.Printf("%s req : %+v\n", context, v)
311 log.Printf("%s resp: %+v\n", context, message)
312 }
313}
314
315// sendExisting will send a Message with an existing file to Telegram.
316func (bot *BotAPI) sendExisting(method string, config Fileable) (Message, error) {
317 v, err := config.values()
318
319 if err != nil {
320 return Message{}, err
321 }
322
323 message, err := bot.makeMessageRequest(method, v)
324 if err != nil {
325 return Message{}, err
326 }
327
328 return message, nil
329}
330
331// uploadAndSend will send a Message with a new file to Telegram.
332func (bot *BotAPI) uploadAndSend(method string, config Fileable) (Message, error) {
333 params, err := config.params()
334 if err != nil {
335 return Message{}, err
336 }
337
338 file := config.getFile()
339
340 resp, err := bot.UploadFile(method, params, config.name(), file)
341 if err != nil {
342 return Message{}, err
343 }
344
345 var message Message
346 json.Unmarshal(resp.Result, &message)
347
348 bot.debugLog(method, nil, message)
349
350 return message, nil
351}
352
353// sendFile determines if the file is using an existing file or uploading
354// a new file, then sends it as needed.
355func (bot *BotAPI) sendFile(config Fileable) (Message, error) {
356 if config.useExistingFile() {
357 return bot.sendExisting(config.method(), config)
358 }
359
360 return bot.uploadAndSend(config.method(), config)
361}
362
363// sendChattable sends a Chattable.
364func (bot *BotAPI) sendChattable(config Chattable) (Message, error) {
365 v, err := config.values()
366 if err != nil {
367 return Message{}, err
368 }
369
370 message, err := bot.makeMessageRequest(config.method(), v)
371
372 if err != nil {
373 return Message{}, err
374 }
375
376 return message, nil
377}
378
379// GetUserProfilePhotos gets a user's profile photos.
380//
381// It requires UserID.
382// Offset and Limit are optional.
383func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
384 v := url.Values{}
385 v.Add("user_id", strconv.Itoa(config.UserID))
386 if config.Offset != 0 {
387 v.Add("offset", strconv.Itoa(config.Offset))
388 }
389 if config.Limit != 0 {
390 v.Add("limit", strconv.Itoa(config.Limit))
391 }
392
393 resp, err := bot.MakeRequest("getUserProfilePhotos", v)
394 if err != nil {
395 return UserProfilePhotos{}, err
396 }
397
398 var profilePhotos UserProfilePhotos
399 json.Unmarshal(resp.Result, &profilePhotos)
400
401 bot.debugLog("GetUserProfilePhoto", v, profilePhotos)
402
403 return profilePhotos, nil
404}
405
406// GetFile returns a File which can download a file from Telegram.
407//
408// Requires FileID.
409func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
410 v := url.Values{}
411 v.Add("file_id", config.FileID)
412
413 resp, err := bot.MakeRequest("getFile", v)
414 if err != nil {
415 return File{}, err
416 }
417
418 var file File
419 json.Unmarshal(resp.Result, &file)
420
421 bot.debugLog("GetFile", v, file)
422
423 return file, nil
424}
425
426// GetUpdates fetches updates.
427// If a WebHook is set, this will not return any data!
428//
429// Offset, Limit, and Timeout are optional.
430// To avoid stale items, set Offset to one higher than the previous item.
431// Set Timeout to a large number to reduce requests so you can get updates
432// instantly instead of having to wait between requests.
433func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
434 v := url.Values{}
435 if config.Offset != 0 {
436 v.Add("offset", strconv.Itoa(config.Offset))
437 }
438 if config.Limit > 0 {
439 v.Add("limit", strconv.Itoa(config.Limit))
440 }
441 if config.Timeout > 0 {
442 v.Add("timeout", strconv.Itoa(config.Timeout))
443 }
444
445 resp, err := bot.MakeRequest("getUpdates", v)
446 if err != nil {
447 return []Update{}, err
448 }
449
450 var updates []Update
451 json.Unmarshal(resp.Result, &updates)
452
453 bot.debugLog("getUpdates", v, updates)
454
455 return updates, nil
456}
457
458// RemoveWebhook unsets the webhook.
459func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
460 return bot.MakeRequest("deleteWebhook", url.Values{})
461}
462
463// SetWebhook sets a webhook.
464//
465// If this is set, GetUpdates will not get any data!
466//
467// If you do not have a legitimate TLS certificate, you need to include
468// your self signed certificate with the config.
469func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) {
470
471 if config.Certificate == nil {
472 v := url.Values{}
473 v.Add("url", config.URL.String())
474 if config.MaxConnections != 0 {
475 v.Add("max_connections", strconv.Itoa(config.MaxConnections))
476 }
477
478 return bot.MakeRequest("setWebhook", v)
479 }
480
481 params := make(map[string]string)
482 params["url"] = config.URL.String()
483 if config.MaxConnections != 0 {
484 params["max_connections"] = strconv.Itoa(config.MaxConnections)
485 }
486
487 resp, err := bot.UploadFile("setWebhook", params, "certificate", config.Certificate)
488 if err != nil {
489 return APIResponse{}, err
490 }
491
492 return resp, nil
493}
494
495// GetWebhookInfo allows you to fetch information about a webhook and if
496// one currently is set, along with pending update count and error messages.
497func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
498 resp, err := bot.MakeRequest("getWebhookInfo", url.Values{})
499 if err != nil {
500 return WebhookInfo{}, err
501 }
502
503 var info WebhookInfo
504 err = json.Unmarshal(resp.Result, &info)
505
506 return info, err
507}
508
509// GetUpdatesChan starts and returns a channel for getting updates.
510func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
511 ch := make(chan Update, bot.Buffer)
512
513 go func() {
514 for {
515 select {
516 case <-bot.shutdownChannel:
517 close(ch)
518 return
519 default:
520 }
521
522 updates, err := bot.GetUpdates(config)
523 if err != nil {
524 log.Println(err)
525 log.Println("Failed to get updates, retrying in 3 seconds...")
526 time.Sleep(time.Second * 3)
527
528 continue
529 }
530
531 for _, update := range updates {
532 if update.UpdateID >= config.Offset {
533 config.Offset = update.UpdateID + 1
534 ch <- update
535 }
536 }
537 }
538 }()
539
540 return ch, nil
541}
542
543// StopReceivingUpdates stops the go routine which receives updates
544func (bot *BotAPI) StopReceivingUpdates() {
545 if bot.Debug {
546 log.Println("Stopping the update receiver routine...")
547 }
548 close(bot.shutdownChannel)
549}
550
551// ListenForWebhook registers a http handler for a webhook.
552func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
553 ch := make(chan Update, bot.Buffer)
554
555 http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
556 ch <- bot.HandleUpdate(w, r)
557 })
558
559 return ch
560}
561
562// HandleUpdate parses and returns update received via webhook
563func (bot *BotAPI) HandleUpdate(res http.ResponseWriter, req *http.Request) Update {
564 bytes, _ := ioutil.ReadAll(req.Body)
565 req.Body.Close()
566
567 var update Update
568 json.Unmarshal(bytes, &update)
569
570 return update
571}
572
573// AnswerInlineQuery sends a response to an inline query.
574//
575// Note that you must respond to an inline query within 30 seconds.
576func (bot *BotAPI) AnswerInlineQuery(config InlineConfig) (APIResponse, error) {
577 v := url.Values{}
578
579 v.Add("inline_query_id", config.InlineQueryID)
580 v.Add("cache_time", strconv.Itoa(config.CacheTime))
581 v.Add("is_personal", strconv.FormatBool(config.IsPersonal))
582 v.Add("next_offset", config.NextOffset)
583 data, err := json.Marshal(config.Results)
584 if err != nil {
585 return APIResponse{}, err
586 }
587 v.Add("results", string(data))
588 v.Add("switch_pm_text", config.SwitchPMText)
589 v.Add("switch_pm_parameter", config.SwitchPMParameter)
590
591 bot.debugLog("answerInlineQuery", v, nil)
592
593 return bot.MakeRequest("answerInlineQuery", v)
594}
595
596// AnswerCallbackQuery sends a response to an inline query callback.
597func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, error) {
598 v := url.Values{}
599
600 v.Add("callback_query_id", config.CallbackQueryID)
601 if config.Text != "" {
602 v.Add("text", config.Text)
603 }
604 v.Add("show_alert", strconv.FormatBool(config.ShowAlert))
605 if config.URL != "" {
606 v.Add("url", config.URL)
607 }
608 v.Add("cache_time", strconv.Itoa(config.CacheTime))
609
610 bot.debugLog("answerCallbackQuery", v, nil)
611
612 return bot.MakeRequest("answerCallbackQuery", v)
613}
614
615// KickChatMember kicks a user from a chat. Note that this only will work
616// in supergroups, and requires the bot to be an admin. Also note they
617// will be unable to rejoin until they are unbanned.
618func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) {
619 v := url.Values{}
620
621 if config.SuperGroupUsername == "" {
622 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
623 } else {
624 v.Add("chat_id", config.SuperGroupUsername)
625 }
626 v.Add("user_id", strconv.Itoa(config.UserID))
627
628 if config.UntilDate != 0 {
629 v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
630 }
631
632 bot.debugLog("kickChatMember", v, nil)
633
634 return bot.MakeRequest("kickChatMember", v)
635}
636
637// LeaveChat makes the bot leave the chat.
638func (bot *BotAPI) LeaveChat(config ChatConfig) (APIResponse, error) {
639 v := url.Values{}
640
641 if config.SuperGroupUsername == "" {
642 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
643 } else {
644 v.Add("chat_id", config.SuperGroupUsername)
645 }
646
647 bot.debugLog("leaveChat", v, nil)
648
649 return bot.MakeRequest("leaveChat", v)
650}
651
652// GetChat gets information about a chat.
653func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
654 v := url.Values{}
655
656 if config.SuperGroupUsername == "" {
657 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
658 } else {
659 v.Add("chat_id", config.SuperGroupUsername)
660 }
661
662 resp, err := bot.MakeRequest("getChat", v)
663 if err != nil {
664 return Chat{}, err
665 }
666
667 var chat Chat
668 err = json.Unmarshal(resp.Result, &chat)
669
670 bot.debugLog("getChat", v, chat)
671
672 return chat, err
673}
674
675// GetChatAdministrators gets a list of administrators in the chat.
676//
677// If none have been appointed, only the creator will be returned.
678// Bots are not shown, even if they are an administrator.
679func (bot *BotAPI) GetChatAdministrators(config ChatConfig) ([]ChatMember, error) {
680 v := url.Values{}
681
682 if config.SuperGroupUsername == "" {
683 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
684 } else {
685 v.Add("chat_id", config.SuperGroupUsername)
686 }
687
688 resp, err := bot.MakeRequest("getChatAdministrators", v)
689 if err != nil {
690 return []ChatMember{}, err
691 }
692
693 var members []ChatMember
694 err = json.Unmarshal(resp.Result, &members)
695
696 bot.debugLog("getChatAdministrators", v, members)
697
698 return members, err
699}
700
701// GetChatMembersCount gets the number of users in a chat.
702func (bot *BotAPI) GetChatMembersCount(config ChatConfig) (int, error) {
703 v := url.Values{}
704
705 if config.SuperGroupUsername == "" {
706 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
707 } else {
708 v.Add("chat_id", config.SuperGroupUsername)
709 }
710
711 resp, err := bot.MakeRequest("getChatMembersCount", v)
712 if err != nil {
713 return -1, err
714 }
715
716 var count int
717 err = json.Unmarshal(resp.Result, &count)
718
719 bot.debugLog("getChatMembersCount", v, count)
720
721 return count, err
722}
723
724// GetChatMember gets a specific chat member.
725func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error) {
726 v := url.Values{}
727
728 if config.SuperGroupUsername == "" {
729 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
730 } else {
731 v.Add("chat_id", config.SuperGroupUsername)
732 }
733 v.Add("user_id", strconv.Itoa(config.UserID))
734
735 resp, err := bot.MakeRequest("getChatMember", v)
736 if err != nil {
737 return ChatMember{}, err
738 }
739
740 var member ChatMember
741 err = json.Unmarshal(resp.Result, &member)
742
743 bot.debugLog("getChatMember", v, member)
744
745 return member, err
746}
747
748// UnbanChatMember unbans a user from a chat. Note that this only will work
749// in supergroups and channels, and requires the bot to be an admin.
750func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
751 v := url.Values{}
752
753 if config.SuperGroupUsername != "" {
754 v.Add("chat_id", config.SuperGroupUsername)
755 } else if config.ChannelUsername != "" {
756 v.Add("chat_id", config.ChannelUsername)
757 } else {
758 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
759 }
760 v.Add("user_id", strconv.Itoa(config.UserID))
761
762 bot.debugLog("unbanChatMember", v, nil)
763
764 return bot.MakeRequest("unbanChatMember", v)
765}
766
767// RestrictChatMember to restrict a user in a supergroup. The bot must be an
768//administrator in the supergroup for this to work and must have the
769//appropriate admin rights. Pass True for all boolean parameters to lift
770//restrictions from a user. Returns True on success.
771func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
772 v := url.Values{}
773
774 if config.SuperGroupUsername != "" {
775 v.Add("chat_id", config.SuperGroupUsername)
776 } else if config.ChannelUsername != "" {
777 v.Add("chat_id", config.ChannelUsername)
778 } else {
779 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
780 }
781 v.Add("user_id", strconv.Itoa(config.UserID))
782
783 if config.CanSendMessages != nil {
784 v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
785 }
786 if config.CanSendMediaMessages != nil {
787 v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
788 }
789 if config.CanSendOtherMessages != nil {
790 v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
791 }
792 if config.CanAddWebPagePreviews != nil {
793 v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
794 }
795 if config.UntilDate != 0 {
796 v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
797 }
798
799 bot.debugLog("restrictChatMember", v, nil)
800
801 return bot.MakeRequest("restrictChatMember", v)
802}
803
804// PromoteChatMember add admin rights to user
805func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
806 v := url.Values{}
807
808 if config.SuperGroupUsername != "" {
809 v.Add("chat_id", config.SuperGroupUsername)
810 } else if config.ChannelUsername != "" {
811 v.Add("chat_id", config.ChannelUsername)
812 } else {
813 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
814 }
815 v.Add("user_id", strconv.Itoa(config.UserID))
816
817 if config.CanChangeInfo != nil {
818 v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
819 }
820 if config.CanPostMessages != nil {
821 v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
822 }
823 if config.CanEditMessages != nil {
824 v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
825 }
826 if config.CanDeleteMessages != nil {
827 v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
828 }
829 if config.CanInviteUsers != nil {
830 v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
831 }
832 if config.CanRestrictMembers != nil {
833 v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
834 }
835 if config.CanPinMessages != nil {
836 v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
837 }
838 if config.CanPromoteMembers != nil {
839 v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
840 }
841
842 bot.debugLog("promoteChatMember", v, nil)
843
844 return bot.MakeRequest("promoteChatMember", v)
845}
846
847// GetGameHighScores allows you to get the high scores for a game.
848func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
849 v, _ := config.values()
850
851 resp, err := bot.MakeRequest(config.method(), v)
852 if err != nil {
853 return []GameHighScore{}, err
854 }
855
856 var highScores []GameHighScore
857 err = json.Unmarshal(resp.Result, &highScores)
858
859 return highScores, err
860}
861
862// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
863func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) {
864 v := url.Values{}
865
866 v.Add("shipping_query_id", config.ShippingQueryID)
867 v.Add("ok", strconv.FormatBool(config.OK))
868 if config.OK == true {
869 data, err := json.Marshal(config.ShippingOptions)
870 if err != nil {
871 return APIResponse{}, err
872 }
873 v.Add("shipping_options", string(data))
874 } else {
875 v.Add("error_message", config.ErrorMessage)
876 }
877
878 bot.debugLog("answerShippingQuery", v, nil)
879
880 return bot.MakeRequest("answerShippingQuery", v)
881}
882
883// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
884func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) {
885 v := url.Values{}
886
887 v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
888 v.Add("ok", strconv.FormatBool(config.OK))
889 if config.OK != true {
890 v.Add("error_message", config.ErrorMessage)
891 }
892
893 bot.debugLog("answerPreCheckoutQuery", v, nil)
894
895 return bot.MakeRequest("answerPreCheckoutQuery", v)
896}
897
898// DeleteMessage deletes a message in a chat
899func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) {
900 v, err := config.values()
901 if err != nil {
902 return APIResponse{}, err
903 }
904
905 bot.debugLog(config.method(), v, nil)
906
907 return bot.MakeRequest(config.method(), v)
908}
909
910// GetInviteLink get InviteLink for a chat
911func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
912 v := url.Values{}
913
914 if config.SuperGroupUsername == "" {
915 v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
916 } else {
917 v.Add("chat_id", config.SuperGroupUsername)
918 }
919
920 resp, err := bot.MakeRequest("exportChatInviteLink", v)
921 if err != nil {
922 return "", err
923 }
924
925 var inviteLink string
926 err = json.Unmarshal(resp.Result, &inviteLink)
927
928 return inviteLink, err
929}
930
931// PinChatMessage pin message in supergroup
932func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) {
933 v, err := config.values()
934 if err != nil {
935 return APIResponse{}, err
936 }
937
938 bot.debugLog(config.method(), v, nil)
939
940 return bot.MakeRequest(config.method(), v)
941}
942
943// UnpinChatMessage unpin message in supergroup
944func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) {
945 v, err := config.values()
946 if err != nil {
947 return APIResponse{}, err
948 }
949
950 bot.debugLog(config.method(), v, nil)
951
952 return bot.MakeRequest(config.method(), v)
953}
954
955// SetChatTitle change title of chat.
956func (bot *BotAPI) SetChatTitle(config SetChatTitleConfig) (APIResponse, error) {
957 v, err := config.values()
958 if err != nil {
959 return APIResponse{}, err
960 }
961
962 bot.debugLog(config.method(), v, nil)
963
964 return bot.MakeRequest(config.method(), v)
965}
966
967// SetChatDescription change description of chat.
968func (bot *BotAPI) SetChatDescription(config SetChatDescriptionConfig) (APIResponse, error) {
969 v, err := config.values()
970 if err != nil {
971 return APIResponse{}, err
972 }
973
974 bot.debugLog(config.method(), v, nil)
975
976 return bot.MakeRequest(config.method(), v)
977}
978
979// SetChatPhoto change photo of chat.
980func (bot *BotAPI) SetChatPhoto(config SetChatPhotoConfig) (APIResponse, error) {
981 params, err := config.params()
982 if err != nil {
983 return APIResponse{}, err
984 }
985
986 file := config.getFile()
987
988 return bot.UploadFile(config.method(), params, config.name(), file)
989}
990
991// DeleteChatPhoto delete photo of chat.
992func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, error) {
993 v, err := config.values()
994 if err != nil {
995 return APIResponse{}, err
996 }
997
998 bot.debugLog(config.method(), v, nil)
999
1000 return bot.MakeRequest(config.method(), v)
1001}
1002
1003// GetStickerSet get a sticker set.
1004func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
1005 v, err := config.values()
1006 if err != nil {
1007 return StickerSet{}, err
1008 }
1009 bot.debugLog(config.method(), v, nil)
1010 res, err := bot.MakeRequest(config.method(), v)
1011 if err != nil {
1012 return StickerSet{}, err
1013 }
1014 stickerSet := StickerSet{}
1015 err = json.Unmarshal(res.Result, &stickerSet)
1016 if err != nil {
1017 return StickerSet{}, err
1018 }
1019 return stickerSet, nil
1020}