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