diff --git a/answer_callback_query.go b/answer_callback_query.go index 5679eb9..06f6b27 100644 --- a/answer_callback_query.go +++ b/answer_callback_query.go @@ -29,6 +29,12 @@ type AnswerCallbackQueryParameters struct { CacheTime int `json:"cache_time,omitempty"` } +func NewAnswerCallbackQuery(callbackQueryID string) *AnswerCallbackQueryParameters { + return &AnswerCallbackQueryParameters{ + CallbackQueryID: callbackQueryID, + } +} + // AnswerCallbackQuery send answers to callback queries sent from inline // keyboards. The answer will be displayed to the user as a notification at the // top of the chat screen or as an alert. On success, True is returned. diff --git a/answer_inline_query.go b/answer_inline_query.go index 38db9c4..95c0f04 100644 --- a/answer_inline_query.go +++ b/answer_inline_query.go @@ -35,6 +35,13 @@ type AnswerInlineQueryParameters struct { SwitchPrivateMessageParameter string `json:"switch_pm_parameter,omitempty"` } +func NewAnswerInlineQuery(inlineQueryID string, results ...InlineQueryResult) *AnswerInlineQueryParameters { + return &AnswerInlineQueryParameters{ + InlineQueryID: inlineQueryID, + Results: results, + } +} + // AnswerInlineQuery send answers to an inline query. On success, True is returned. // // No more than 50 results per query are allowed. diff --git a/answer_pre_checkout_query.go b/answer_pre_checkout_query.go index 41b2dca..6f34d11 100644 --- a/answer_pre_checkout_query.go +++ b/answer_pre_checkout_query.go @@ -19,6 +19,13 @@ type AnswerPreCheckoutQueryParameters struct { ErrorMessage string `json:"error_message,omitempty"` } +func NewAnswerPreCheckoutQuery(preCheckoutQueryID string, ok bool) *AnswerPreCheckoutQueryParameters { + return &AnswerPreCheckoutQueryParameters{ + PreCheckoutQueryID: preCheckoutQueryID, + Ok: ok, + } +} + // AnswerPreCheckoutQuery respond to such pre-checkout queries. // // Once the user has confirmed their payment and shipping details, the Bot API diff --git a/answer_shipping_query.go b/answer_shipping_query.go index 9338d89..58cd5ae 100644 --- a/answer_shipping_query.go +++ b/answer_shipping_query.go @@ -22,6 +22,13 @@ type AnswerShippingQueryParameters struct { ErrorMessage string `json:"error_message,omitempty"` } +func NewAnswerShippingQuery(shippingQueryID string, ok bool) *AnswerShippingQueryParameters { + return &AnswerShippingQueryParameters{ + ShippingQueryID: shippingQueryID, + Ok: ok, + } +} + // AnswerShippingQuery reply to shipping queries. // // If you sent an invoice requesting a shipping address and the parameter diff --git a/chat_helpers.go b/chat_helpers.go new file mode 100644 index 0000000..7a24982 --- /dev/null +++ b/chat_helpers.go @@ -0,0 +1,17 @@ +package telegram + +func (chat *Chat) IsPrivate() bool { + return chat.Type == ChatPrivate +} + +func (chat *Chat) IsGroup() bool { + return chat.Type == ChatGroup +} + +func (chat *Chat) IsSuperGroup() bool { + return chat.Type == ChatSuperGroup +} + +func (chat *Chat) IsChannel() bool { + return chat.Type == ChatChannel +} diff --git a/entities_helpers.go b/entities_helpers.go new file mode 100644 index 0000000..f0fbab1 --- /dev/null +++ b/entities_helpers.go @@ -0,0 +1,11 @@ +package telegram + +import "net/url" + +func (entity *MessageEntity) ParseURL() (*url.URL, error) { + if entity.Type == EntityTextLink { + return url.Parse(entity.URL) + } + + return nil, nil +} diff --git a/forward_message.go b/forward_message.go index ee2e446..19e282c 100644 --- a/forward_message.go +++ b/forward_message.go @@ -16,6 +16,14 @@ type ForwardMessageParameters struct { MessageID int `json:"message_id"` } +func NewForwardMessage(from, to int64, messageID int) *ForwardMessageParameters { + return &ForwardMessageParameters{ + FromChatID: from, + ChatID: to, + MessageID: messageID, + } +} + // ForwardMessage forward messages of any kind. On success, the sent Message is returned. func (bot *Bot) ForwardMessage(params *ForwardMessageParameters) (*Message, error) { dst, err := json.Marshal(params) diff --git a/helpers.go b/helpers.go deleted file mode 100644 index 7564e35..0000000 --- a/helpers.go +++ /dev/null @@ -1,300 +0,0 @@ -package telegram - -import ( - "fmt" - "log" - "net/url" - "strings" - "time" - - json "github.com/pquerna/ffjson/ffjson" - http "github.com/valyala/fasthttp" -) - -type UpdatesChannel <-chan Update - -func NewAnswerCallback(id string) *AnswerCallbackQueryParameters { - return &AnswerCallbackQueryParameters{ - CallbackQueryID: id} -} - -func NewAnswerInline(id string, results ...InlineQueryResult) *AnswerInlineQueryParameters { - return &AnswerInlineQueryParameters{ - InlineQueryID: id, - Results: results, - } -} - -func NewAnswerPreCheckout(id string, ok bool) *AnswerPreCheckoutQueryParameters { - return &AnswerPreCheckoutQueryParameters{ - PreCheckoutQueryID: id, - Ok: ok, - } -} - -func NewAnswerShipping(id string, ok bool) *AnswerShippingQueryParameters { - return &AnswerShippingQueryParameters{ - ShippingQueryID: id, - Ok: ok, - } -} - -func NewMessage(chatID int64, text string) *SendMessageParameters { - return &SendMessageParameters{ - ChatID: chatID, - Text: text, - } -} - -func NewMessageForward(from, to int64, messageID int) *ForwardMessageParameters { - return &ForwardMessageParameters{ - FromChatID: from, - ChatID: to, - MessageID: messageID, - } -} - -func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices ...LabeledPrice) *SendInvoiceParameters { - return &SendInvoiceParameters{ - ChatID: chatID, - Title: title, - Description: description, - Payload: payload, - ProviderToken: providerToken, - StartParameter: startParameter, - Currency: currency, - Prices: prices, - } -} - -func NewReplyKeyboard(rows ...[]KeyboardButton) *ReplyKeyboardMarkup { - var keyboard [][]KeyboardButton - keyboard = append(keyboard, rows...) - return &ReplyKeyboardMarkup{ - Keyboard: keyboard, - ResizeKeyboard: true, - } -} - -func NewReplyKeyboardRow(buttons ...KeyboardButton) []KeyboardButton { - var row []KeyboardButton - row = append(row, buttons...) - return row -} - -func NewReplyKeyboardButton(text string) KeyboardButton { - return KeyboardButton{ - Text: text, - } -} - -func NewReplyKeyboardButtonContact(text string) KeyboardButton { - return KeyboardButton{ - Text: text, - RequestContact: true, - } -} - -func NewReplyKeyboardButtonLocation(text string) KeyboardButton { - return KeyboardButton{ - Text: text, - RequestLocation: true, - } -} - -func NewInlineKeyboard(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup { - var keyboard [][]InlineKeyboardButton - keyboard = append(keyboard, rows...) - return InlineKeyboardMarkup{InlineKeyboard: keyboard} -} - -func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { - var row []InlineKeyboardButton - row = append(row, buttons...) - return row -} - -func NewInlineKeyboardButton(text, data string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - CallbackData: data, - } -} - -func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - URL: url, - } -} - -func NewInlineKeyboardButtonSwitch(text, query string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - SwitchInlineQuery: query, - } -} - -func NewInlineKeyboardButtonSwitchSelf(text, query string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - SwitchInlineQueryCurrentChat: query, - } -} - -func NewInlineKeyboardButtonGame(text string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - CallbackGame: &CallbackGame{}, - } -} - -func NewInlineKeyboardButtonPay(text string) InlineKeyboardButton { - return InlineKeyboardButton{ - Text: text, - Pay: true, - } -} - -func NewWebhook(url string, file interface{}) *SetWebhookParameters { - params := &SetWebhookParameters{URL: url} - - if file != nil { - var input InputFile = file - params.Certificate = &input - } - - return params -} - -func (bot *Bot) NewLongPollingChannel(params *GetUpdatesParameters) UpdatesChannel { - if params == nil { - params = &GetUpdatesParameters{ - Offset: 0, - Limit: 100, - Timeout: 60, - } - } - - channel := make(chan Update, params.Limit) - - go func() { - for { - updates, err := bot.GetUpdates(params) - if err != nil { - log.Println(err.Error()) - log.Println("failed to get updates, retrying in 3 seconds...") - time.Sleep(time.Second * 3) - - continue - } - - for _, update := range updates { - if update.ID >= params.Offset { - params.Offset = update.ID + 1 - channel <- update - } - } - } - }() - - return channel -} - -func NewWebhookChannel(serve, listen string, params *GetUpdatesParameters) UpdatesChannel { - if params == nil { - params = &GetUpdatesParameters{ - Offset: 0, - Limit: 100, - Timeout: 60, - } - } - - channel := make(chan Update, params.Limit) - - go func() { - if err := http.ListenAndServe(serve, func(ctx *http.RequestCtx) { - log.Println("PATH:", string(ctx.Path())) - if strings.HasPrefix(string(ctx.Path()), listen) { - log.Println("rawBody:", string(ctx.Request.Body())) - var update Update - json.Unmarshal(ctx.Request.Body(), &update) - channel <- update - } - }); err != nil { - panic(err.Error()) - } - }() - - return channel -} - -func (msg *Message) IsCommand() bool { - if len(msg.Entities) <= 0 { - return false - } - - if msg.Entities[0].Type == EntityBotCommand && - msg.Entities[0].Offset == 0 { - return true - } - - return false -} - -func (msg *Message) Command() string { - if !msg.IsCommand() { - return "" - } - - return string([]rune(msg.Text)[1:msg.Entities[0].Length]) -} - -func (msg *Message) CommandArgument() string { - if !msg.IsCommand() { - return "" - } - - arg := strings.TrimPrefix( - msg.Text, - fmt.Sprint("/", msg.Command()), - ) - - return strings.TrimPrefix(arg, " ") -} - -func (msg *Message) HasArgument() bool { - if !msg.IsCommand() { - return false - } - - if msg.CommandArgument() != "" { - return true - } - - return false -} - -func (chat *Chat) IsPrivate() bool { - return chat.Type == ChatPrivate -} - -func (chat *Chat) IsGroup() bool { - return chat.Type == ChatGroup -} - -func (chat *Chat) IsSuperGroup() bool { - return chat.Type == ChatSuperGroup -} - -func (chat *Chat) IsChannel() bool { - return chat.Type == ChatChannel -} - -func (entity *MessageEntity) ParseURL() (*url.URL, error) { - if entity.Type != EntityTextLink { - return nil, nil - } - - return url.Parse(entity.URL) -} diff --git a/messages_helpers.go b/messages_helpers.go new file mode 100644 index 0000000..b39ab11 --- /dev/null +++ b/messages_helpers.go @@ -0,0 +1,52 @@ +package telegram + +import "time" + +func (msg *Message) IsCommand() bool { + if len(msg.Entities) <= 0 { + return false + } + + if msg.Entities[0].Type == EntityBotCommand && + msg.Entities[0].Offset == 0 { + return true + } + + return false +} + +func (msg *Message) Command() string { + if !msg.IsCommand() { + return "" + } + + return string([]rune(msg.Text)[1:msg.Entities[0].Length]) +} + +func (msg *Message) CommandArgument() string { + if !msg.IsCommand() { + return "" + } + + if !msg.HasArgument() { + return "" + } + + return string([]rune(msg.Text)[(msg.Entities[0].Length + 1):]) +} + +func (msg *Message) HasArgument() bool { + if !msg.IsCommand() { + return false + } + + if msg.CommandArgument() != "" { + return true + } + + return false +} + +func (msg *Message) Time() time.Time { + return time.Unix(msg.Date, 0) +} diff --git a/new_helpers.go b/new_helpers.go new file mode 100644 index 0000000..2c701fe --- /dev/null +++ b/new_helpers.go @@ -0,0 +1,385 @@ +package telegram + +import ( + "log" + "strings" + "time" + + json "github.com/pquerna/ffjson/ffjson" + http "github.com/valyala/fasthttp" +) + +type UpdatesChannel <-chan Update + +func NewForceReply(selective bool) *ForceReply { + return &ForceReply{ + ForceReply: true, + Selective: selective, + } +} + +func NewReplyKeyboardMarkup(rows ...[]KeyboardButton) *ReplyKeyboardMarkup { + var keyboard [][]KeyboardButton + keyboard = append(keyboard, rows...) + return &ReplyKeyboardMarkup{ + Keyboard: keyboard, + ResizeKeyboard: true, + } +} + +func NewReplyKeyboardRow(buttons ...KeyboardButton) []KeyboardButton { + var row []KeyboardButton + row = append(row, buttons...) + return row +} + +func NewReplyKeyboardButton(text string) KeyboardButton { + return KeyboardButton{ + Text: text, + } +} + +func NewReplyKeyboardButtonContact(text string) KeyboardButton { + return KeyboardButton{ + Text: text, + RequestContact: true, + } +} + +func NewReplyKeyboardButtonLocation(text string) KeyboardButton { + return KeyboardButton{ + Text: text, + RequestLocation: true, + } +} + +func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) *InlineKeyboardMarkup { + var keyboard [][]InlineKeyboardButton + keyboard = append(keyboard, rows...) + return &InlineKeyboardMarkup{ + InlineKeyboard: keyboard, + } +} + +func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { + var row []InlineKeyboardButton + row = append(row, buttons...) + return row +} + +func NewInlineKeyboardButton(text, data string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + CallbackData: data, + } +} + +func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + URL: url, + } +} + +func NewInlineKeyboardButtonSwitch(text, query string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + SwitchInlineQuery: query, + } +} + +func NewInlineKeyboardButtonSwitchSelf(text, query string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + SwitchInlineQueryCurrentChat: query, + } +} + +func NewInlineKeyboardButtonGame(text string) InlineKeyboardButton { + var game CallbackGame + return InlineKeyboardButton{ + Text: text, + CallbackGame: &game, + } +} + +func NewInlineKeyboardButtonPay(text string) InlineKeyboardButton { + return InlineKeyboardButton{ + Text: text, + Pay: true, + } +} + +func NewReplyKeyboardRemove(selective bool) *ReplyKeyboardRemove { + return &ReplyKeyboardRemove{ + RemoveKeyboard: true, + Selective: selective, + } +} + +func NewInlineQueryResultCachedAudio(resultID, fileID string) *InlineQueryResultCachedAudio { + return &InlineQueryResultCachedAudio{ + Type: TypeAudio, + ID: resultID, + AudioFileID: fileID, + } +} + +func NewInlineQueryResultCachedDocument(resultID, fileID, title string) *InlineQueryResultCachedDocument { + return &InlineQueryResultCachedDocument{ + Type: TypeDocument, + ID: resultID, + Title: title, + DocumentFileID: fileID, + } +} + +func NewInlineQueryResultCachedGif(resultID, fileID string) *InlineQueryResultCachedGif { + return &InlineQueryResultCachedGif{ + Type: TypeGIF, + ID: resultID, + GifFileID: fileID, + } +} + +func NewInlineQueryResultCachedMpeg4Gif(resultID, fileID string) *InlineQueryResultCachedMpeg4Gif { + return &InlineQueryResultCachedMpeg4Gif{ + Type: TypeMpeg4Gif, + ID: resultID, + Mpeg4FileID: fileID, + } +} + +func NewInlineQueryResultCachedPhoto(resultID, fileID string) *InlineQueryResultCachedPhoto { + return &InlineQueryResultCachedPhoto{ + Type: TypePhoto, + ID: resultID, + PhotoFileID: fileID, + } +} + +func NewInlineQueryResultCachedSticker(resultID, fileID string) *InlineQueryResultCachedSticker { + return &InlineQueryResultCachedSticker{ + Type: TypeSticker, + ID: resultID, + StickerFileID: fileID, + } +} + +func NewInlineQueryResultCachedVideo(resultID, fileID, title string) *InlineQueryResultCachedVideo { + return &InlineQueryResultCachedVideo{ + Type: TypeVideo, + ID: resultID, + VideoFileID: fileID, + Title: title, + } +} + +func NewInlineQueryResultCachedVoice(resultID, fileID, title string) *InlineQueryResultCachedVoice { + return &InlineQueryResultCachedVoice{ + Type: TypeVoice, + ID: resultID, + VoiceFileID: fileID, + Title: title, + } +} + +func NewInlineQueryResultArticle(resultID, title string, content *InputMessageContent) *InlineQueryResultArticle { + return &InlineQueryResultArticle{ + Type: TypeArticle, + ID: resultID, + Title: title, + InputMessageContent: content, + } +} + +func NewInlineQueryResultAudio(resultID, audioURL, title string) *InlineQueryResultAudio { + return &InlineQueryResultAudio{ + Type: TypeAudio, + ID: resultID, + AudioURL: audioURL, + Title: title, + } +} + +func NewInlineQueryResultContact(resultID, phoneNumber, firstName string) *InlineQueryResultContact { + return &InlineQueryResultContact{ + Type: TypeContact, + ID: resultID, + PhoneNumber: phoneNumber, + FirstName: firstName, + } +} + +func NewInlineQueryResultGame(resultID, gameShortName string) *InlineQueryResultGame { + return &InlineQueryResultGame{ + Type: TypeGame, + ID: resultID, + GameShortName: gameShortName, + } +} + +func NewInlineQueryResultDocument(resultID, title, documentURL, mimeType string) *InlineQueryResultDocument { + return &InlineQueryResultDocument{ + Type: TypeDocument, + ID: resultID, + Title: title, + DocumentURL: documentURL, + MimeType: mimeType, + } +} + +func NewInlineQueryResultGif(resultID, gifURL, thumbURL string) *InlineQueryResultGif { + return &InlineQueryResultGif{ + Type: TypeGIF, + ID: resultID, + GifURL: gifURL, + ThumbURL: thumbURL, + } +} + +func NewInlineQueryResultLocation(resultID, title string, latitude, longitude float32) *InlineQueryResultLocation { + return &InlineQueryResultLocation{ + Type: TypeLocation, + ID: resultID, + Latitude: latitude, + Longitude: longitude, + Title: title, + } +} + +func NewInlineQueryResultMpeg4Gif(resultID, mpeg4URL, thumbURL string) *InlineQueryResultMpeg4Gif { + return &InlineQueryResultMpeg4Gif{ + Type: TypeMpeg4Gif, + ID: resultID, + Mpeg4URL: mpeg4URL, + ThumbURL: thumbURL, + } +} + +func NewInlineQueryResultPhoto(resultID, photoURL, thumbURL string) *InlineQueryResultPhoto { + return &InlineQueryResultPhoto{ + Type: TypePhoto, + PhotoURL: photoURL, + ThumbURL: thumbURL, + } +} + +func NewInlineQueryResultVenue(resultID, title, address string, latitude, longitude float32) *InlineQueryResultVenue { + return &InlineQueryResultVenue{ + Type: TypeVenue, + ID: resultID, + Latitude: latitude, + Longitude: longitude, + Title: title, + Address: address, + } +} + +func NewInlineQueryResultVideo(resultID, videoURL, mimeType, thumbURL, title string) *InlineQueryResultVideo { + return &InlineQueryResultVideo{ + Type: TypeVideo, + ID: resultID, + MimeType: mimeType, + ThumbURL: thumbURL, + Title: title, + } +} + +func NewInlineQueryResultVoice(resultID, voiceURL, title string) *InlineQueryResultVoice { + return &InlineQueryResultVoice{ + Type: TypeVoice, + ID: resultID, + VoiceURL: voiceURL, + Title: title, + } +} + +func NewInputTextMessageContent(messageText string) *InputTextMessageContent { + return &InputTextMessageContent{ + MessageText: messageText, + } +} + +func NewInputLocationMessageContent(latitude, longitude float32) *InputLocationMessageContent { + return &InputLocationMessageContent{ + Latitude: latitude, + Longitude: longitude, + } +} + +func NewInputVenueMessageContent(latitude, longitude float32, title, address string) *InputVenueMessageContent { + return &InputVenueMessageContent{ + Latitude: latitude, + Longitude: longitude, + Title: title, + Address: address, + } +} + +func NewInputContactMessageContent(phoneNumber, firstName string) *InputContactMessageContent { + return &InputContactMessageContent{ + PhoneNumber: phoneNumber, + FirstName: firstName, + } +} + +func (bot *Bot) NewLongPollingChannel(params *GetUpdatesParameters) UpdatesChannel { + if params == nil { + params = &GetUpdatesParameters{ + Offset: 0, + Limit: 100, + Timeout: 60, + } + } + + channel := make(chan Update, params.Limit) + + go func() { + for { + updates, err := bot.GetUpdates(params) + if err != nil { + log.Println(err.Error()) + log.Println("failed to get updates, retrying in 3 seconds...") + time.Sleep(time.Second * 3) + + continue + } + + for _, update := range updates { + if update.ID >= params.Offset { + params.Offset = update.ID + 1 + channel <- update + } + } + } + }() + + return channel +} + +func NewWebhookChannel(set, listen, serve string, params *GetUpdatesParameters) UpdatesChannel { + if params == nil { + params = &GetUpdatesParameters{ + Offset: 0, + Limit: 100, + Timeout: 60, + } + } + + channel := make(chan Update, params.Limit) + + go func() { + if err := http.ListenAndServe(serve, func(ctx *http.RequestCtx) { + if strings.HasPrefix(string(ctx.Path()), listen) { + var update Update + json.Unmarshal(ctx.Request.Body(), &update) + channel <- update + } + }); err != nil { + log.Fatalln(err.Error()) + } + }() + + return channel +} diff --git a/send_invoice.go b/send_invoice.go index 587d466..79f0242 100644 --- a/send_invoice.go +++ b/send_invoice.go @@ -73,6 +73,19 @@ type SendInvoiceParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices ...LabeledPrice) *SendInvoiceParameters { + return &SendInvoiceParameters{ + ChatID: chatID, + Title: title, + Description: description, + Payload: payload, + ProviderToken: providerToken, + StartParameter: startParameter, + Currency: currency, + Prices: prices, + } +} + // SendInvoice send invoices. On success, the sent Message is returned. func (bot *Bot) SendInvoice(params *SendInvoiceParameters) (*Message, error) { dst, err := json.Marshal(*params) diff --git a/send_message.go b/send_message.go index 91675a0..d0eb555 100644 --- a/send_message.go +++ b/send_message.go @@ -30,6 +30,13 @@ type SendMessageParameters struct { ReplyMarkup interface{} `json:"reply_markup,omitempty"` } +func NewMessage(chatID int64, text string) *SendMessageParameters { + return &SendMessageParameters{ + ChatID: chatID, + Text: text, + } +} + // SendMessage send text messages. On success, the sent Message is returned. func (bot *Bot) SendMessage(params *SendMessageParameters) (*Message, error) { dst, err := json.Marshal(*params) diff --git a/set_webhook.go b/set_webhook.go index e0a75b2..15ca722 100644 --- a/set_webhook.go +++ b/set_webhook.go @@ -35,6 +35,17 @@ type SetWebhookParameters struct { AllowedUpdates []string `json:"allowed_updates,omitempty"` } +func NewWebhook(url string, file interface{}) *SetWebhookParameters { + params := &SetWebhookParameters{URL: url} + + if file != nil { + var input InputFile = file + params.Certificate = &input + } + + return params +} + // SetWebhook specify a url and receive incoming updates via an outgoing webhook. // Whenever there is an update for the bot, we will send an HTTPS POST request to // the specified url, containing a JSON-serialized Update. In case of an