all repos — telegram-bot-api @ 4b372faeebe7df44f54a8495a6d3ca91b59fb6dd

Golang bindings for the Telegram Bot API

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}