diff --git a/api.go b/api.go index 1167e7a..d9f3b4f 100644 --- a/api.go +++ b/api.go @@ -139,7 +139,7 @@ func (b *Bot) sendText(to Recipient, text string, opt *SendOptions) (*Message, e "chat_id": to.Recipient(), "text": text, } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) data, err := b.Raw("sendMessage", params) if err != nil { diff --git a/bot.go b/bot.go index 0ddad3e..17e114d 100644 --- a/bot.go +++ b/bot.go @@ -38,6 +38,7 @@ func NewBot(pref Settings) (*Bot, error) { handlers: make(map[string]interface{}), synchronous: pref.Synchronous, verbose: pref.Verbose, + parseMode: pref.ParseMode, stop: make(chan struct{}), reporter: pref.Reporter, client: client, @@ -67,6 +68,7 @@ type Bot struct { handlers map[string]interface{} synchronous bool verbose bool + parseMode ParseMode reporter func(error) stop chan struct{} client *http.Client @@ -95,6 +97,11 @@ type Settings struct { // Shows upcoming requests Verbose bool + // ParseMode used to set default parse mode of all sent messages. + // It attaches to every send, edit or whatever method. You also + // will be able to override the default mode by passing a new one. + ParseMode ParseMode + // Reporter is a callback function that will get called // on any panics recovered from endpoint handlers. Reporter func(error) @@ -524,7 +531,7 @@ func (b *Bot) Send(to Recipient, what interface{}, options ...interface{}) (*Mes // SendAlbum sends multiple instances of media as a single message. // -// From all existing options, it only supports tb.Silent option. +// From all existing options, it only supports tb.Silent. func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Message, error) { if to == nil { return nil, ErrBadRecipient @@ -596,7 +603,7 @@ func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Messag } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) data, err := b.sendFiles("sendMediaGroup", files, params) if err != nil { @@ -655,7 +662,7 @@ func (b *Bot) Forward(to Recipient, msg Editable, options ...interface{}) (*Mess } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) data, err := b.Raw("forwardMessage", params) if err != nil { @@ -667,11 +674,16 @@ func (b *Bot) Forward(to Recipient, msg Editable, options ...interface{}) (*Mess // Edit is magic, it lets you change already sent message. // +// If edited message is sent by the bot, returns it, +// otherwise returns nil and ErrTrueResult. +// // Use cases: // -// b.Edit(msg, msg.Text, newMarkup) -// b.Edit(msg, "new text", tb.ModeHTML) -// b.Edit(msg, tb.Location{42.1337, 69.4242}) +// b.Edit(m, m.Text, newMarkup) +// b.Edit(m, "new text", tb.ModeHTML) +// b.Edit(m, &tb.ReplyMarkup{...}) +// b.Edit(m, &tb.Photo{File: ...}) +// b.Edit(m, tb.Location{42.1337, 69.4242}) // // This function will panic upon nil Editable. func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Message, error) { @@ -681,6 +693,10 @@ func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Mes ) switch v := what.(type) { + case *ReplyMarkup: + return b.EditReplyMarkup(msg, v) + case InputMedia: + return b.EditMedia(msg, v, options...) case string: method = "editMessageText" params["text"] = v @@ -702,7 +718,7 @@ func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Mes } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) data, err := b.Raw(method, params) if err != nil { @@ -715,6 +731,9 @@ func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Mes // EditReplyMarkup edits reply markup of already sent message. // Pass nil or empty ReplyMarkup to delete it from the message. // +// If edited message is sent by the bot, returns it, +// otherwise returns nil and ErrTrueResult. +// // On success, returns edited message object. // This function will panic upon nil Editable. func (b *Bot) EditReplyMarkup(msg Editable, markup *ReplyMarkup) (*Message, error) { @@ -747,6 +766,9 @@ func (b *Bot) EditReplyMarkup(msg Editable, markup *ReplyMarkup) (*Message, erro // EditCaption edits already sent photo caption with known recipient and message id. // +// If edited message is sent by the bot, returns it, +// otherwise returns nil and ErrTrueResult. +// // On success, returns edited message object. // This function will panic upon nil Editable. func (b *Bot) EditCaption(msg Editable, caption string, options ...interface{}) (*Message, error) { @@ -764,7 +786,7 @@ func (b *Bot) EditCaption(msg Editable, caption string, options ...interface{}) } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) data, err := b.Raw("editMessageCaption", params) if err != nil { @@ -776,10 +798,13 @@ func (b *Bot) EditCaption(msg Editable, caption string, options ...interface{}) // EditMedia edits already sent media with known recipient and message id. // +// If edited message is sent by the bot, returns it, +// otherwise returns nil and ErrTrueResult. +// // Use cases: // -// bot.EditMedia(msg, &tb.Photo{File: tb.FromDisk("chicken.jpg")}) -// bot.EditMedia(msg, &tb.Video{File: tb.FromURL("http://video.mp4")}) +// b.EditMedia(m, &tb.Photo{File: tb.FromDisk("chicken.jpg")}) +// b.EditMedia(m, &tb.Video{File: tb.FromURL("http://video.mp4")}) // // This function will panic upon nil Editable. func (b *Bot) EditMedia(msg Editable, media InputMedia, options ...interface{}) (*Message, error) { @@ -875,7 +900,7 @@ func (b *Bot) EditMedia(msg Editable, media InputMedia, options ...interface{}) params := make(map[string]string) sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) if sendOpts != nil { result.ParseMode = sendOpts.ParseMode @@ -888,7 +913,7 @@ func (b *Bot) EditMedia(msg Editable, media InputMedia, options ...interface{}) data, _ := json.Marshal(result) params["media"] = string(data) - if chatID == 0 { // If inline message. + if chatID == 0 { // if inline message params["inline_message_id"] = msgID } else { params["chat_id"] = strconv.FormatInt(chatID, 10) @@ -1121,6 +1146,9 @@ func (b *Bot) GetFile(file *File) (io.ReadCloser, error) { // StopLiveLocation stops broadcasting live message location // before Location.LivePeriod expires. // +// If the message is sent by the bot, returns it, +// otherwise returns nil and ErrTrueResult. +// // It supports tb.ReplyMarkup. // This function will panic upon nil Editable. func (b *Bot) StopLiveLocation(msg Editable, options ...interface{}) (*Message, error) { @@ -1132,7 +1160,7 @@ func (b *Bot) StopLiveLocation(msg Editable, options ...interface{}) (*Message, } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) data, err := b.Raw("stopMessageLiveLocation", params) if err != nil { @@ -1156,7 +1184,7 @@ func (b *Bot) StopPoll(msg Editable, options ...interface{}) (*Poll, error) { } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) data, err := b.Raw("stopPoll", params) if err != nil { @@ -1289,7 +1317,7 @@ func (b *Bot) Pin(msg Editable, options ...interface{}) error { } sendOpts := extractOptions(options) - embedSendOptions(params, sendOpts) + b.embedSendOptions(params, sendOpts) _, err := b.Raw("pinChatMessage", params) return err diff --git a/bot_test.go b/bot_test.go index 7b21fae..73712ad 100644 --- a/bot_test.go +++ b/bot_test.go @@ -63,6 +63,7 @@ func TestNewBot(t *testing.T) { pref.Client = client pref.Poller = &LongPoller{Timeout: time.Second} pref.Updates = 50 + pref.ParseMode = ModeHTML pref.offline = true b, err = NewBot(pref) @@ -71,6 +72,7 @@ func TestNewBot(t *testing.T) { assert.Equal(t, pref.URL, b.URL) assert.Equal(t, pref.Poller, b.Poller) assert.Equal(t, 50, cap(b.Updates)) + assert.Equal(t, ModeHTML, b.parseMode) } func TestBotHandle(t *testing.T) { @@ -309,23 +311,36 @@ func TestBot(t *testing.T) { _, err = b.Forward(nil, nil) assert.Equal(t, ErrBadRecipient, err) - t.Run("Send(what=Sendable)", func(t *testing.T) { - photo := &Photo{ - File: File{FileID: photoID}, - Caption: t.Name(), - } + photo := &Photo{ + File: File{FileID: photoID}, + Caption: t.Name(), + } + var msg *Message - msg, err := b.Send(to, photo) + t.Run("Send(what=Sendable)", func(t *testing.T) { + msg, err = b.Send(to, photo) assert.NoError(t, err) assert.NotNil(t, msg.Photo) assert.Equal(t, photo.Caption, msg.Caption) + }) + + t.Run("EditCaption()+ParseMode", func(t *testing.T) { + b.parseMode = ModeHTML + edited, err := b.EditCaption(msg, "new caption with parse mode") + assert.NoError(t, err) + assert.Equal(t, "new caption with parse mode", edited.Caption) - msg, err = b.EditCaption(msg, "new caption") + b.parseMode = ModeDefault + edited, err = b.EditCaption(msg, "*new caption w/o parse mode*", ModeMarkdown) assert.NoError(t, err) - assert.Equal(t, "new caption", msg.Caption) + assert.Equal(t, "new caption w/o parse mode", edited.Caption) }) - var msg *Message + t.Run("Edit(what=InputMedia)", func(t *testing.T) { + edited, err := b.Edit(msg, photo) + assert.NoError(t, err) + assert.Equal(t, edited.Photo.FileID, photo.FileID) + }) t.Run("Send(what=string)", func(t *testing.T) { msg, err = b.Send(to, t.Name()) @@ -358,20 +373,8 @@ func TestBot(t *testing.T) { assert.Error(t, err) // message is not modified }) - t.Run("Edit(what=Location)", func(t *testing.T) { - loc := &Location{Lat: 42, Lng: 69, LivePeriod: 60} - msg, err := b.Send(to, loc) - assert.NoError(t, err) - assert.NotNil(t, msg.Location) - - loc = &Location{Lat: loc.Lng, Lng: loc.Lat} - msg, err = b.Edit(msg, *loc) - assert.NoError(t, err) - assert.NotNil(t, msg.Location) - }) - - t.Run("EditReplyMarkup()", func(t *testing.T) { - markup := &ReplyMarkup{ + t.Run("Edit(what=ReplyMarkup)", func(t *testing.T) { + good := &ReplyMarkup{ InlineKeyboard: [][]InlineButton{ {{ Data: "btn", @@ -379,7 +382,7 @@ func TestBot(t *testing.T) { }}, }, } - badMarkup := &ReplyMarkup{ + bad := &ReplyMarkup{ InlineKeyboard: [][]InlineButton{ {{ Data: strings.Repeat("*", 65), @@ -388,18 +391,30 @@ func TestBot(t *testing.T) { }, } - msg, err := b.EditReplyMarkup(msg, markup) + edited, err := b.Edit(msg, good) assert.NoError(t, err) - assert.Equal(t, msg.ReplyMarkup.InlineKeyboard, markup.InlineKeyboard) + assert.Equal(t, edited.ReplyMarkup.InlineKeyboard, good.InlineKeyboard) - msg, err = b.EditReplyMarkup(msg, nil) + edited, err = b.EditReplyMarkup(edited, nil) assert.NoError(t, err) - assert.Nil(t, msg.ReplyMarkup.InlineKeyboard) + assert.Nil(t, edited.ReplyMarkup.InlineKeyboard) - _, err = b.EditReplyMarkup(msg, badMarkup) + _, err = b.Edit(edited, bad) assert.Equal(t, ErrButtonDataInvalid, err) }) + t.Run("Edit(what=Location)", func(t *testing.T) { + loc := &Location{Lat: 42, Lng: 69, LivePeriod: 60} + edited, err := b.Send(to, loc) + assert.NoError(t, err) + assert.NotNil(t, edited.Location) + + loc = &Location{Lat: loc.Lng, Lng: loc.Lat} + edited, err = b.Edit(edited, *loc) + assert.NoError(t, err) + assert.NotNil(t, edited.Location) + }) + t.Run("Notify()", func(t *testing.T) { assert.Equal(t, ErrBadRecipient, b.Notify(nil, Typing)) assert.NoError(t, b.Notify(to, Typing)) diff --git a/filters.go b/filters.go deleted file mode 100644 index 7384fff..0000000 --- a/filters.go +++ /dev/null @@ -1,66 +0,0 @@ -package telebot - -// Filter is some thing that does filtering for -// incoming updates. -// -// Return false if you wish to sieve the update out. -type Filter interface { - Filter(*Update) bool -} - -// FilterFunc is basically a lightweight version of Filter. -type FilterFunc func(*Update) bool - -func NewChain(parent Poller) *Chain { - c := &Chain{} - c.Poller = parent - c.Filter = func(upd *Update) bool { - for _, filter := range c.Filters { - switch f := filter.(type) { - case Filter: - if !f.Filter(upd) { - return false - } - - case FilterFunc: - if !f(upd) { - return false - } - - case func(*Update) bool: - if !f(upd) { - return false - } - } - - } - - return true - } - - return c -} - -// Chain is a chain of middle -type Chain struct { - MiddlewarePoller - - // (Filter | FilterFunc | func(*Update) bool) - Filters []interface{} -} - -// Add accepts either Filter interface or FilterFunc -func (c *Chain) Add(filter interface{}) { - switch filter.(type) { - case Filter: - break - case FilterFunc: - break - case func(*Update) bool: - break - default: - panic("telebot: unsupported filter type") - } - - c.Filters = append(c.Filters, filter) -} diff --git a/games.go b/games.go index 96292d1..cceba14 100644 --- a/games.go +++ b/games.go @@ -70,11 +70,8 @@ func (b *Bot) GetGameScores(user Recipient, msg Editable) ([]GameHighScore, erro // SetGameScore sets the score of the specified user in a game. // -// NOTE: -// If the message was sent by the bot, returns the edited Message, -// otherwise returns nil Message and ErrNoGameMessage. -// If you expect successful True result, you must check -// for `telebot: no game message` error. +// If the message was sent by the bot, returns the edited Message, +// otherwise returns nil and ErrTrueResult. // func (b *Bot) SetGameScore(user Recipient, msg Editable, score GameHighScore) (*Message, error) { msgID, chatID := msg.MessageSig() @@ -97,13 +94,5 @@ func (b *Bot) SetGameScore(user Recipient, msg Editable, score GameHighScore) (* if err != nil { return nil, err } - - m, err := extractMessage(data) - if err != nil { - return nil, err - } - if m == nil { - return nil, ErrNoGameMessage - } - return m, nil + return extractMessage(data) } diff --git a/inline_types.go b/inline_types.go index 5d542af..cd745eb 100644 --- a/inline_types.go +++ b/inline_types.go @@ -182,6 +182,13 @@ type GifResult struct { // Optional. Duration of the GIF. Duration int `json:"gif_duration,omitempty"` + // URL of the static thumbnail for the result (jpeg or gif). + ThumbURL string `json:"thumb_url"` + + // Optional. MIME type of the thumbnail, must be one of + // “image/jpeg”, “image/gif”, or “video/mp4”. + ThumbMIME string `json:"thumb_mime_type,omitempty"` + // Optional. Title for the result. Title string `json:"title,omitempty"` @@ -192,9 +199,6 @@ type GifResult struct { // bold, italic, fixed-width text or inline URLs in the media caption. ParseMode ParseMode `json:"parse_mode,omitempty"` - // URL of the static thumbnail for the result (jpeg or gif). - ThumbURL string `json:"thumb_url"` - // If Cache != "", it'll be used instead Cache string `json:"gif_file_id,omitempty"` } @@ -234,6 +238,10 @@ type Mpeg4GifResult struct { // URL of the static thumbnail (jpeg or gif) for the result. ThumbURL string `json:"thumb_url,omitempty"` + // Optional. MIME type of the thumbnail, must be one of + // “image/jpeg”, “image/gif”, or “video/mp4”. + ThumbMIME string `json:"thumb_mime_type,omitempty"` + // Optional. Title for the result. Title string `json:"title,omitempty"` diff --git a/message.go b/message.go index 8877642..e314c1a 100644 --- a/message.go +++ b/message.go @@ -37,6 +37,9 @@ type Message struct { // itself is a reply. ReplyTo *Message `json:"reply_to_message"` + // Shows through which bot the message was sent. + Via *User `json:"via_bot"` + // (Optional) Time of last edit in Unix LastEdit int64 `json:"edit_date"` diff --git a/sendable.go b/sendable.go index 5816d72..0ec8150 100644 --- a/sendable.go +++ b/sendable.go @@ -30,7 +30,7 @@ func (p *Photo) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { "caption": p.Caption, } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&p.File, "photo", params, nil) if err != nil { @@ -58,7 +58,7 @@ func (a *Audio) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { params["duration"] = strconv.Itoa(a.Duration) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&a.File, "audio", params, thumbnailToFilemap(a.Thumbnail)) if err != nil { @@ -91,7 +91,7 @@ func (d *Document) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error params["file_size"] = strconv.Itoa(d.FileSize) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&d.File, "document", params, thumbnailToFilemap(d.Thumbnail)) if err != nil { @@ -110,7 +110,7 @@ func (s *Sticker) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) params := map[string]string{ "chat_id": to.Recipient(), } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&s.File, "sticker", params, nil) if err != nil { @@ -144,7 +144,7 @@ func (v *Video) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { params["supports_streaming"] = "true" } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&v.File, "video", params, thumbnailToFilemap(v.Thumbnail)) if err != nil { @@ -191,7 +191,7 @@ func (a *Animation) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, erro params["file_name"] = filepath.Base(a.File.FileLocal) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&a.File, "animation", params, nil) if err != nil { @@ -215,7 +215,7 @@ func (v *Voice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { params["duration"] = strconv.Itoa(v.Duration) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&v.File, "voice", params, nil) if err != nil { @@ -241,7 +241,7 @@ func (v *VideoNote) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, erro params["length"] = strconv.Itoa(v.Length) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) msg, err := b.sendObject(&v.File, "videoNote", params, thumbnailToFilemap(v.Thumbnail)) if err != nil { @@ -262,7 +262,7 @@ func (x *Location) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error "longitude": fmt.Sprintf("%f", x.Lng), "live_period": strconv.Itoa(x.LivePeriod), } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) data, err := b.Raw("sendLocation", params) if err != nil { @@ -283,7 +283,7 @@ func (v *Venue) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { "foursquare_id": v.FoursquareID, "foursquare_type": v.FoursquareType, } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) data, err := b.Raw("sendVenue", params) if err != nil { @@ -329,7 +329,7 @@ func (i *Invoice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) data, _ := json.Marshal(i.Prices) params["prices"] = string(data) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) data, err := b.Raw("sendInvoice", params) if err != nil { @@ -359,7 +359,7 @@ func (p *Poll) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { } else if p.CloseUnixdate != 0 { params["close_date"] = strconv.FormatInt(p.CloseUnixdate, 10) } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) var options []string for _, o := range p.Options { @@ -382,7 +382,7 @@ func (d *Dice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { "chat_id": to.Recipient(), "emoji": string(d.Type), } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) data, err := b.Raw("sendDice", params) if err != nil { @@ -398,7 +398,7 @@ func (g *Game) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { "chat_id": to.Recipient(), "game_short_name": g.Title, } - embedSendOptions(params, opt) + b.embedSendOptions(params, opt) data, err := b.Raw("sendGame", params) if err != nil { diff --git a/stickers.go b/stickers.go index d6c8cdc..2d878ba 100644 --- a/stickers.go +++ b/stickers.go @@ -13,11 +13,7 @@ type Sticker struct { Animated bool `json:"is_animated"` Thumbnail *Photo `json:"thumb"` Emoji string `json:"emoji"` - Name string `json:"name"` SetName string `json:"set_name"` - PNG *File `json:"png_sticker"` - TGS *File `json:"tgs_file"` - Emojis string `json:"emojis"` MaskPosition *MaskPosition `json:"mask_position"` } @@ -26,12 +22,12 @@ type StickerSet struct { Name string `json:"name"` Title string `json:"title"` Animated bool `json:"is_animated"` - ContainsMasks bool `json:"contains_masks"` Stickers []Sticker `json:"stickers"` Thumbnail *Photo `json:"thumb"` PNG *File `json:"png_sticker"` - TGS *File `json:"tgs_file"` + TGS *File `json:"tgs_sticker"` Emojis string `json:"emojis"` + ContainsMasks bool `json:"contains_masks"` MaskPosition *MaskPosition `json:"mask_position"` } @@ -44,15 +40,6 @@ type MaskPosition struct { Scale float32 `json:"scale"` } -// StickerSetParams describes the payload in creating new sticker set api-method. -type StickerSetParams struct { - UserID int - Name string - Title string - PngSticker *File - Emojis string -} - // UploadStickerFile uploads a .PNG file with a sticker for later use. func (b *Bot) UploadStickerFile(to Recipient, png *File) (*File, error) { files := map[string]File{ @@ -123,7 +110,7 @@ func (b *Bot) CreateNewStickerSet(to Recipient, s StickerSet) error { } // AddStickerToSet adds new sticker to existing sticker set. -func (b *Bot) AddStickerToSet(to Recipient, s Sticker) error { +func (b *Bot) AddStickerToSet(to Recipient, s StickerSet) error { files := make(map[string]File) if s.PNG != nil { files["png_sticker"] = *s.PNG @@ -176,7 +163,7 @@ func (b *Bot) DeleteStickerFromSet(sticker string) error { // // Animated sticker set thumbnail can't be uploaded via HTTP URL. // -func (b *Bot) SetStickerSetThumb(to Recipient, s Sticker) error { +func (b *Bot) SetStickerSetThumb(to Recipient, s StickerSet) error { files := map[string]File{} if s.PNG != nil { files["thumb"] = *s.PNG diff --git a/telebot.go b/telebot.go index be4c864..c5a1ceb 100644 --- a/telebot.go +++ b/telebot.go @@ -34,7 +34,7 @@ var ( ErrBadRecipient = errors.New("telebot: recipient is nil") ErrUnsupportedWhat = errors.New("telebot: unsupported what argument") ErrCouldNotUpdate = errors.New("telebot: could not fetch new updates") - ErrNoGameMessage = errors.New("telebot: no game message") + ErrTrueResult = errors.New("telebot: result is True") ) const DefaultApiURL = "https://api.telegram.org" @@ -218,4 +218,5 @@ type DiceType string var ( Cube = &Dice{Type: "🎲"} Dart = &Dice{Type: "🎯"} + Ball = &Dice{Type: "🏀"} ) diff --git a/util.go b/util.go index eae707c..ba81e1a 100644 --- a/util.go +++ b/util.go @@ -70,6 +70,15 @@ func extractMessage(data []byte) (*Message, error) { Result *Message } if err := json.Unmarshal(data, &resp); err != nil { + var resp struct { + Result bool + } + if err := json.Unmarshal(data, &resp); err != nil { + return nil, wrapError(err) + } + if resp.Result { + return nil, ErrTrueResult + } return nil, wrapError(err) } return resp.Result, nil @@ -123,7 +132,11 @@ func extractOptions(how []interface{}) *SendOptions { return opts } -func embedSendOptions(params map[string]string, opt *SendOptions) { +func (b *Bot) embedSendOptions(params map[string]string, opt *SendOptions) { + if b.parseMode != ModeDefault { + params["parse_mode"] = b.parseMode + } + if opt == nil { return } diff --git a/util_test.go b/util_test.go index 2272cdf..0837dec 100644 --- a/util_test.go +++ b/util_test.go @@ -13,6 +13,16 @@ func TestExtractOk(t *testing.T) { data = []byte(`{"ok":false,"error_code":429,"description":"Too Many Requests: retry after 8","parameters":{"retry_after":8}}`) assert.Error(t, extractOk(data)) - data = []byte(`{"ok":false,"error_code":400,"description":"Bad Request: reply message not found"}`) // Also check the old format + data = []byte(`{"ok":false,"error_code":400,"description":"Bad Request: reply message not found"}`) assert.EqualError(t, extractOk(data), ErrToReplyNotFound.Error()) } + +func TestExtractMessage(t *testing.T) { + data := []byte(`{"ok":true,"result":true}`) + _, err := extractMessage(data) + assert.Equal(t, ErrTrueResult, err) + + data = []byte(`{"ok":true,"result":{"foo":"bar"}}`) + _, err = extractMessage(data) + assert.NoError(t, err) +} diff --git a/webhook.go b/webhook.go index a17a1c0..e3f953a 100644 --- a/webhook.go +++ b/webhook.go @@ -17,9 +17,9 @@ type WebhookTLS struct { // A WebhookEndpoint describes the endpoint to which telegram will send its requests. // This must be a public URL and can be a loadbalancer or something similar. If the -// endpoint uses TLS and the certificate is selfsigned you have to add the certificate +// endpoint uses TLS and the certificate is self-signed you have to add the certificate // path of this certificate so telegram will trust it. This field can be ignored if you -// have a trusted certifcate (letsencrypt, ...). +// have a trusted certificate (letsencrypt, ...). type WebhookEndpoint struct { PublicURL string Cert string @@ -28,13 +28,16 @@ type WebhookEndpoint struct { // A Webhook configures the poller for webhooks. It opens a port on the given // listen address. If TLS is filled, the listener will use the key and cert to open // a secure port. Otherwise it will use plain HTTP. +// // If you have a loadbalancer ore other infrastructure in front of your service, you // must fill the Endpoint structure so this poller will send this data to telegram. If // you leave these values empty, your local address will be sent to telegram which is mostly // not what you want (at least while developing). If you have a single instance of your // bot you should consider to use the LongPoller instead of a WebHook. +// // You can also leave the Listen field empty. In this case it is up to the caller to // add the Webhook to a http-mux. +// type Webhook struct { Listen string `json:"url"` MaxConnections int `json:"max_connections"`