api: features 7.0, 7.1 (#658)

* api: feature 7.0 init

* message: remove blockquote

* api: partrly implement replies 2.0

* api: update comments

* message: add giveaway fields

* message,chat: other changes init

* boost: implement boost updates

* reactions: refactor

* api: implement multiple users request section

* api: provide preview customization

* api: implement 7.1 features

* message: fix story issue

* admin,context: refactor

* bot_test: type refactor

* api: partly fix review comments

* api: small tidy up

* react: reactions init

* telebot: added boost_updated,boost_removed constants

* message: fix InaccessibleMessage message struct parse

* message,reac: naming refactor

* context: add boost to the context of current events
v3.3
Nash-Well 2 months ago committed by GitHub
parent b67df6444e
commit 6fdf666a11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -327,6 +327,37 @@ func extractMessage(data []byte) (*Message, error) {
return resp.Result, nil
}
func (b *Bot) forwardCopyMessages(to Recipient, msgs []Editable, key string, opts ...*SendOptions) ([]Message, error) {
params := map[string]string{
"chat_id": to.Recipient(),
}
embedMessages(params, msgs)
if len(opts) > 0 {
b.embedSendOptions(params, opts[0])
}
data, err := b.Raw(key, params)
if err != nil {
return nil, err
}
var resp struct {
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)
}
return nil, wrapError(err)
}
return resp.Result, nil
}
func verbose(method string, payload interface{}, data []byte) {
body, _ := json.Marshal(payload)
body = bytes.ReplaceAll(body, []byte(`\"`), []byte(`"`))

@ -0,0 +1,111 @@
package telebot
import (
"encoding/json"
"time"
)
// Boost contains information about a chat boost.
type Boost struct {
// Unique identifier of the boost.
ID string `json:"boost_id"`
// Point in time (Unix timestamp) when the chat was boosted.
AddUnixtime int64 `json:"add_date"`
// Point in time (Unix timestamp) when the boost will automatically expire,
// unless the booster's Telegram Premium subscription is prolonged.
ExpirationUnixtime int64 `json:"expiration_date"`
// Source of the added boost.
Source *BoostSource `json:"source"`
}
// AddDate returns the moment of time when the chat has been boosted in local time.
func (c *Boost) AddDate() time.Time {
return time.Unix(c.AddUnixtime, 0)
}
// ExpirationDate returns the moment of time when the boost of the channel
// will expire in local time.
func (c *Boost) ExpirationDate() time.Time {
return time.Unix(c.ExpirationUnixtime, 0)
}
// BoostSourceType describes a type of boost.
type BoostSourceType = string
const (
BoostPremium = "premium"
BoostGiftCode = "gift_code"
BoostGiveaway = "giveaway"
)
// BoostSource describes the source of a chat boost.
type BoostSource struct {
// Source of the boost, always (“premium”, “gift_code”, “giveaway”).
Source BoostSourceType `json:"source"`
// User that boosted the chat.
Booster *User `json:"user"`
// Identifier of a message in the chat with the giveaway; the message
// could have been deleted already. May be 0 if the message isn't sent yet.
GiveawayMessageID int `json:"giveaway_message_id,omitempty"`
// (Optional) True, if the giveaway was completed, but there was
// no user to win the prize.
Unclaimed bool `json:"is_unclaimed,omitempty"`
}
// BoostAdded represents a service message about a user boosting a chat.
type BoostAdded struct {
// Number of boosts added by the user.
Count int `json:"boost_count"`
}
// BoostUpdated represents a boost added to a chat or changed.
type BoostUpdated struct {
// Chat which was boosted.
Chat *Chat `json:"chat"`
// Information about the chat boost.
Boost *Boost `json:"boost"`
}
// BoostRemoved represents a boost removed from a chat.
type BoostRemoved struct {
// Chat which was boosted.
Chat *Chat `json:"chat"`
// Unique identifier of the boost.
BoostID string `json:"boost_id"`
// Point in time (Unix timestamp) when the boost was removed.
RemoveUnixtime int64 `json:"remove_date"`
// Source of the removed boost.
Source *BoostSource `json:"source"`
}
// UserBoosts gets the list of boosts added to a chat by a user.
// Requires administrator rights in the chat.
func (b *Bot) UserBoosts(chat, user Recipient) ([]Boost, error) {
params := map[string]string{
"chat_id": chat.Recipient(),
"user_id": user.Recipient(),
}
data, err := b.Raw("getUserChatBoosts", params)
if err != nil {
return nil, err
}
var resp struct {
Result []Boost `json:"boosts"`
}
if err := json.Unmarshal(data, &resp); err != nil {
return nil, wrapError(err)
}
return resp.Result, nil
}

@ -400,6 +400,17 @@ func (b *Bot) Forward(to Recipient, msg Editable, opts ...interface{}) (*Message
return extractMessage(data)
}
// ForwardMessages method forwards multiple messages of any kind.
// If some of the specified messages can't be found or forwarded, they are skipped.
// Service messages and messages with protected content can't be forwarded.
// Album grouping is kept for forwarded messages.
func (b *Bot) ForwardMessages(to Recipient, msgs []Editable, opts ...*SendOptions) ([]Message, error) {
if to == nil {
return nil, ErrBadRecipient
}
return b.forwardCopyMessages(to, msgs, "forwardMessages", opts...)
}
// Copy behaves just like Forward() but the copied message doesn't have a link to the original message (see Bots API).
//
// This function will panic upon nil Editable.
@ -426,6 +437,20 @@ func (b *Bot) Copy(to Recipient, msg Editable, options ...interface{}) (*Message
return extractMessage(data)
}
// CopyMessages this method makes a copy of messages of any kind.
// If some of the specified messages can't be found or copied, they are skipped.
// Service messages, giveaway messages, giveaway winners messages, and
// invoice messages can't be copied. A quiz poll can be copied only if the value of the field
// correct_option_id is known to the bot. The method is analogous
// to the method forwardMessages, but the copied messages don't have a link to the original message.
// Album grouping is kept for copied messages.
func (b *Bot) CopyMessages(to Recipient, msgs []Editable, opts ...*SendOptions) ([]Message, error) {
if to == nil {
return nil, ErrBadRecipient
}
return b.forwardCopyMessages(to, msgs, "copyMessages", opts...)
}
// Edit is magic, it lets you change already sent message.
// This function will panic upon nil Editable.
//
@ -668,6 +693,17 @@ func (b *Bot) Delete(msg Editable) error {
return err
}
// DeleteMessages deletes multiple messages simultaneously.
// If some of the specified messages can't be found, they are skipped.
func (b *Bot) DeleteMessages(msgs []Editable) error {
params := make(map[string]string)
embedMessages(params, msgs)
_, err := b.Raw("deleteMessages", params)
return err
}
// Notify updates the chat action for recipient.
//
// Chat action is a status message that recipient would see where

@ -317,7 +317,7 @@ func TestBotProcessUpdate(t *testing.T) {
b.ProcessUpdate(Update{Message: &Message{Text: "/start@other_bot"}})
b.ProcessUpdate(Update{Message: &Message{Text: "hello"}})
b.ProcessUpdate(Update{Message: &Message{Text: "text"}})
b.ProcessUpdate(Update{Message: &Message{PinnedMessage: &Message{}}})
b.ProcessUpdate(Update{Message: &Message{PinnedMessage: &InaccessibleMessage{}}})
b.ProcessUpdate(Update{Message: &Message{Photo: &Photo{}}})
b.ProcessUpdate(Update{Message: &Message{Voice: &Voice{}}})
b.ProcessUpdate(Update{Message: &Message{Audio: &Audio{}}})
@ -342,7 +342,7 @@ func TestBotProcessUpdate(t *testing.T) {
b.ProcessUpdate(Update{Message: &Message{Chat: &Chat{ID: 1}, MigrateTo: 2}})
b.ProcessUpdate(Update{EditedMessage: &Message{Text: "edited"}})
b.ProcessUpdate(Update{ChannelPost: &Message{Text: "post"}})
b.ProcessUpdate(Update{ChannelPost: &Message{PinnedMessage: &Message{}}})
b.ProcessUpdate(Update{ChannelPost: &Message{PinnedMessage: &InaccessibleMessage{}}})
b.ProcessUpdate(Update{EditedChannelPost: &Message{Text: "edited post"}})
b.ProcessUpdate(Update{Callback: &Callback{MessageID: "inline", Data: "callback"}})
b.ProcessUpdate(Update{Callback: &Callback{Data: "callback"}})

@ -16,7 +16,7 @@ type Callback struct {
// Message will be set if the button that originated the query
// was attached to a message sent by a bot.
Message *Message `json:"message"`
Message *InaccessibleMessage `json:"message"`
// MessageID will be set if the button was attached to a message
// sent via the bot in inline mode.

@ -4,6 +4,8 @@ import (
"encoding/json"
"strconv"
"time"
"gopkg.in/telebot.v3/react"
)
// User object represents a Telegram user, bot.
@ -47,23 +49,32 @@ type Chat struct {
Username string `json:"username"`
// Returns only in getChat
Bio string `json:"bio,omitempty"`
Photo *ChatPhoto `json:"photo,omitempty"`
Description string `json:"description,omitempty"`
InviteLink string `json:"invite_link,omitempty"`
PinnedMessage *Message `json:"pinned_message,omitempty"`
Permissions *Rights `json:"permissions,omitempty"`
SlowMode int `json:"slow_mode_delay,omitempty"`
StickerSet string `json:"sticker_set_name,omitempty"`
CanSetStickerSet bool `json:"can_set_sticker_set,omitempty"`
LinkedChatID int64 `json:"linked_chat_id,omitempty"`
ChatLocation *ChatLocation `json:"location,omitempty"`
Private bool `json:"has_private_forwards,omitempty"`
Protected bool `json:"has_protected_content,omitempty"`
NoVoiceAndVideo bool `json:"has_restricted_voice_and_video_messages"`
HiddenMembers bool `json:"has_hidden_members,omitempty"`
AggressiveAntiSpam bool `json:"has_aggressive_anti_spam_enabled,omitempty"`
EmojiExpirationUnixtime int64 `json:"emoji_status_expiration_date"`
Bio string `json:"bio,omitempty"`
Photo *ChatPhoto `json:"photo,omitempty"`
Description string `json:"description,omitempty"`
InviteLink string `json:"invite_link,omitempty"`
PinnedMessage *Message `json:"pinned_message,omitempty"`
Permissions *Rights `json:"permissions,omitempty"`
Reactions []react.Reaction `json:"available_reactions"`
SlowMode int `json:"slow_mode_delay,omitempty"`
StickerSet string `json:"sticker_set_name,omitempty"`
CanSetStickerSet bool `json:"can_set_sticker_set,omitempty"`
CustomEmojiSetName string `json:"custom_emoji_sticker_set_name"`
LinkedChatID int64 `json:"linked_chat_id,omitempty"`
ChatLocation *ChatLocation `json:"location,omitempty"`
Private bool `json:"has_private_forwards,omitempty"`
Protected bool `json:"has_protected_content,omitempty"`
NoVoiceAndVideo bool `json:"has_restricted_voice_and_video_messages"`
HasHiddenMembers bool `json:"has_hidden_members,omitempty"`
AggressiveAntiSpam bool `json:"has_aggressive_anti_spam_enabled,omitempty"`
CustomEmojiID string `json:"emoji_status_custom_emoji_id"`
EmojiExpirationUnixtime int64 `json:"emoji_status_expiration_date"`
BackgroundEmojiID string `json:"background_custom_emoji_id"`
AccentColorID int `json:"accent_color_id"`
ProfileAccentColorID int `json:"profile_accent_color_id"`
ProfileBackgroundEmojiID string `json:"profile_background_custom_emoji_id"`
HasVisibleHistory bool `json:"has_visible_history"`
UnrestrictBoosts int `json:"unrestrict_boost_count"`
}
// Recipient returns chat ID (see Recipient interface).

@ -16,6 +16,12 @@ type Context interface {
// Bot returns the bot instance.
Bot() *Bot
// Boost returns the boost instance.
Boost() *BoostUpdated
// BoostRemoved returns the boost removed from a chat instance.
BoostRemoved() *BoostRemoved
// Update returns the original update.
Update() Update
@ -178,6 +184,14 @@ func (c *nativeContext) Bot() *Bot {
return c.b
}
func (c *nativeContext) Boost() *BoostUpdated {
return c.u.Boost
}
func (c *nativeContext) BoostRemoved() *BoostRemoved {
return c.u.BoostRemoved
}
func (c *nativeContext) Update() Update {
return c.u
}
@ -187,12 +201,12 @@ func (c *nativeContext) Message() *Message {
case c.u.Message != nil:
return c.u.Message
case c.u.Callback != nil:
return c.u.Callback.Message
return c.u.Callback.Message.Message
case c.u.EditedMessage != nil:
return c.u.EditedMessage
case c.u.ChannelPost != nil:
if c.u.ChannelPost.PinnedMessage != nil {
return c.u.ChannelPost.PinnedMessage
return c.u.ChannelPost.PinnedMessage.Message
}
return c.u.ChannelPost
case c.u.EditedChannelPost != nil:

@ -0,0 +1,103 @@
package telebot
import "time"
// Giveaway represents a message about a scheduled giveaway.
type Giveaway struct {
// The list of chats which the user must join to participate in the giveaway.
Chats []Chat `json:"chats"`
// Point in time (Unix timestamp) when winners of the giveaway will be selected.
SelectionUnixtime int64 `json:"winners_selection_date"`
// The number of users which are supposed to be selected as winners of the giveaway.
WinnerCount int `json:"winner_count"`
// (Optional) True, if only users who join the chats after the giveaway
// started should be eligible to win.
OnlyNewMembers bool `json:"only_new_members"`
// (Optional) True, if the list of giveaway winners will be visible to everyone.
HasPublicWinners bool `json:"has_public_winners"`
// (Optional) Description of additional giveaway prize.
PrizeDescription string `json:"prize_description"`
// (Optional) A list of two-letter ISO 3166-1 alpha-2 country codes indicating
// the countries from which eligible users for the giveaway must come.
// If empty, then all users can participate in the giveaway. Users with a phone number
// that was bought on Fragment can always participate in giveaways.
CountryCodes []string `json:"country_codes"`
// (Optional) The number of months the Telegram Premium subscription won from
// the giveaway will be active for.
PremiumMonthCount int `json:"premium_subscription_month_count"`
}
// SelectionDate returns the moment of when winners of the giveaway were selected in local time.
func (g *Giveaway) SelectionDate() time.Time {
return time.Unix(g.SelectionUnixtime, 0)
}
// GiveawayWinners object represents a message about the completion of a
// giveaway with public winners.
type GiveawayWinners struct {
// The chat that created the giveaway.
Chat *Chat `json:"chat"`
// Identifier of the message with the giveaway in the chat.
MessageID int `json:"message_id"`
// Point in time (Unix timestamp) when winners of the giveaway were selected.
SelectionUnixtime int64 `json:"winners_selection_date"`
// The number of users which are supposed to be selected as winners of the giveaway.
WinnerCount int `json:"winner_count"`
// List of up to 100 winners of the giveaway.
Winners []User `json:"winners"`
// (Optional) The number of other chats the user had to join in order
// to be eligible for the giveaway.
AdditionalChats int `json:"additional_chat_count"`
// (Optional) The number of months the Telegram Premium subscription won from
// the giveaway will be active for.
PremiumMonthCount int `json:"premium_subscription_month_count"`
// (Optional) Number of undistributed prizes.
UnclaimedPrizes int `json:"unclaimed_prize_count"`
// (Optional) True, if only users who had joined the chats after the giveaway started
// were eligible to win.
OnlyNewMembers bool `json:"only_new_members"`
// (Optional) True, if the giveaway was canceled because the payment for it was refunded.
Refunded bool `json:"was_refunded"`
// (Optional) Description of additional giveaway prize.
PrizeDescription string `json:"prize_description"`
}
// SelectionDate returns the moment of when winners of the giveaway
// were selected in local time.
func (g *GiveawayWinners) SelectionDate() time.Time {
return time.Unix(g.SelectionUnixtime, 0)
}
// GiveawayCreated represents a service message about the creation of a scheduled giveaway.
// Currently holds no information.
type GiveawayCreated struct{}
// GiveawayCompleted represents a service message about the completion of a
// giveaway without public winners.
type GiveawayCompleted struct {
// Number of winners in the giveaway.
WinnerCount int `json:"winner_count"`
// (Optional) Number of undistributed prizes.
UnclaimedPrizes int `json:"unclaimed_prize_count"`
// (Optional) Message with the giveaway that was completed, if it wasn't deleted.
Message *Message `json:"giveaway_message"`
}

@ -12,12 +12,12 @@ type InputTextMessageContent struct {
// Text of the message to be sent, 1-4096 characters.
Text string `json:"message_text"`
// Optional. Send Markdown or HTML, if you want Telegram apps to show
// (Optional) Send Markdown or HTML, if you want Telegram apps to show
// bold, italic, fixed-width text or inline URLs in your bot's message.
ParseMode string `json:"parse_mode,omitempty"`
// Optional. Disables link previews for links in the sent message.
DisablePreview bool `json:"disable_web_page_preview"`
// (Optional) Link preview generation options for the message.
PreviewOptions *PreviewOptions `json:"link_preview_options"`
}
func (input *InputTextMessageContent) IsInputMessageContent() bool {

@ -220,7 +220,7 @@ type ReplyButton struct {
Contact bool `json:"request_contact,omitempty"`
Location bool `json:"request_location,omitempty"`
Poll PollType `json:"request_poll,omitempty"`
User *ReplyRecipient `json:"request_user,omitempty"`
User *ReplyRecipient `json:"request_users,omitempty"`
Chat *ReplyRecipient `json:"request_chat,omitempty"`
WebApp *WebApp `json:"web_app,omitempty"`
}
@ -244,8 +244,9 @@ func (pt PollType) MarshalJSON() ([]byte, error) {
type ReplyRecipient struct {
ID int32 `json:"request_id"`
Bot *bool `json:"user_is_bot,omitempty"` // user only, optional
Premium *bool `json:"user_is_premium,omitempty"` // user only, optional
Bot *bool `json:"user_is_bot,omitempty"` // user only, optional
Premium *bool `json:"user_is_premium,omitempty"` // user only, optional
Quantity int `json:"max_quantity,omitempty"` // user only, optional
Channel bool `json:"chat_is_channel,omitempty"` // chat only, required
Forum *bool `json:"chat_is_forum,omitempty"` // chat only, optional

@ -1,9 +1,12 @@
package telebot
import (
"encoding/json"
"strconv"
"time"
"unicode/utf16"
"gopkg.in/telebot.v3/react"
)
// Message object represents a message.
@ -46,6 +49,9 @@ type Message struct {
// For forwarded messages, unixtime of the original message.
OriginalUnixtime int `json:"forward_date"`
// For information about the original message for forwarded messages.
Origin *MessageOrigin `json:"forward_origin"`
// Message is a channel post that was automatically forwarded to the connected discussion group.
AutomaticForward bool `json:"is_automatic_forward"`
@ -57,11 +63,22 @@ type Message struct {
ReplyTo *Message `json:"reply_to_message"`
// (Optional) For replies to a story, the original story
Story *Story `json:"reply_to_story"`
Story *Story `json:"story"`
// (Optional) Information about the message that is being replied to,
// which may come from another chat or forum topic.
ExternalReplyInfo *ExternalReplyInfo `json:"external_reply"`
// (Optional) For replies that quote part of the original message,
// the quoted part of the message.
Quote *TextQuote `json:"quote"`
// Shows through which bot the message was sent.
Via *User `json:"via_bot"`
// For replies to a story, the original story.
ReplyToStory *Story `json:"reply_to_story"`
// (Optional) Time of last edit in Unix.
LastEdit int64 `json:"edit_date"`
@ -90,6 +107,10 @@ type Message struct {
// etc. that appear in the text.
Entities Entities `json:"entities,omitempty"`
// (Optional) Options used for link preview generation for the message,
// if it is a text message and link preview options were changed
PreviewOptions PreviewOptions `json:"link_preview_options,omitempty"`
// Some messages containing media, may as well have a caption.
Caption string `json:"caption,omitempty"`
@ -139,6 +160,18 @@ type Message struct {
// For a dice, information about it.
Dice *Dice `json:"dice"`
// (Optional) The message is a scheduled giveaway message.
Giveaway *Giveaway `json:"giveaway"`
// (Optional) A giveaway with public winners was completed.
GiveawayWinners *GiveawayWinners `json:"giveaway_winners"`
// (Optional) Service message: a scheduled giveaway was created.
GiveawayCreated *GiveawayCreated `json:"giveaway_created"`
// (Optional) Service message: a giveaway without public winners was completed.
GiveawayCompleted *GiveawayCompleted `json:"giveaway_completed"`
// For a service message, represents a user,
// that just got added to chat, this message came from.
//
@ -224,7 +257,7 @@ type Message struct {
// Specified message was pinned. Note that the Message object
// in this field will not contain further ReplyTo fields even
// if it is itself a reply.
PinnedMessage *Message `json:"pinned_message"`
PinnedMessage *InaccessibleMessage `json:"pinned_message"`
// Message is an invoice for a payment.
Invoice *Invoice `json:"invoice"`
@ -233,7 +266,7 @@ type Message struct {
Payment *Payment `json:"successful_payment"`
// For a service message, a user was shared with the bot.
UserShared *RecipientShared `json:"user_shared,omitempty"`
UserShared *RecipientShared `json:"users_shared,omitempty"`
// For a service message, a chat was shared with the bot.
ChatShared *RecipientShared `json:"chat_shared,omitempty"`
@ -266,6 +299,13 @@ type Message struct {
// Inline keyboard attached to the message.
ReplyMarkup *ReplyMarkup `json:"reply_markup,omitempty"`
// Service message: user boosted the chat.
BoostAdded *BoostAdded `json:"boost_added"`
// If the sender of the message boosted the chat, the number of boosts
// added by the user.
SenderBoostCount int `json:"sender_boost_count"`
// Service message: forum topic created
TopicCreated *Topic `json:"forum_topic_created,omitempty"`
@ -465,3 +505,270 @@ func (m *Message) Media() Media {
return nil
}
}
// InaccessibleMessage describes a message that was deleted or is otherwise
// inaccessible to the bot. An instance of MaybeInaccessibleMessage object.
type InaccessibleMessage struct {
// A message that can be inaccessible to the bot.
*Message
// Chat the message belonged to.
Chat *Chat `json:"chat"`
// Unique message identifier inside the chat.
MessageID int `json:"message_id"`
// Always 0. The field can be used to differentiate regular and
// inaccessible messages.
DateUnixtime int64 `json:"date"`
}
func (im *InaccessibleMessage) MessageSig() (string, int64) {
return strconv.Itoa(im.MessageID), im.Chat.ID
}
func (im *InaccessibleMessage) Time() time.Time {
return time.Unix(im.DateUnixtime, 0)
}
// MessageReaction object represents a change of a reaction on a message performed by a user.
type MessageReaction struct {
// The chat containing the message the user reacted to.
Chat *Chat `json:"chat"`
// Unique identifier of the message inside the chat.
MessageID int `json:"message_id"`
// (Optional) The user that changed the reaction,
// if the user isn't anonymous
User *User `json:"user"`
// (Optional) The chat on behalf of which the reaction was changed,
// if the user is anonymous.
ActorChat *Chat `json:"actor_chat"`
// Date of the change in Unix time.
DateUnixtime int64 `json:"date"`
// Previous list of reaction types that were set by the user.
OldReaction []react.Reaction `json:"old_reaction"`
// New list of reaction types that have been set by the user.
NewReaction []react.Reaction `json:"new_reaction"`
}
func (mu *MessageReaction) Time() time.Time {
return time.Unix(mu.DateUnixtime, 0)
}
// MessageReactionCount represents reaction changes on a message with
// anonymous reactions.
type MessageReactionCount struct {
// The chat containing the message.
Chat *Chat `json:"chat"`
// Unique message identifier inside the chat.
MessageID int `json:"message_id"`
// Date of the change in Unix time.
DateUnixtime int64 `json:"date"`
// List of reactions that are present on the message.
Reactions *react.Count `json:"reactions"`
}
// Time returns the moment of change in local time.
func (mc *MessageReactionCount) Time() time.Time {
return time.Unix(mc.DateUnixtime, 0)
}
// TextQuote contains information about the quoted part of a message that is
// replied to by the given message.
type TextQuote struct {
// Text of the quoted part of a message that is replied to by the given message.
Text string `json:"text"`
// (Optional) Special entities that appear in the quote.
// Currently, only bold, italic, underline, strikethrough, spoiler,
// and custom_emoji entities are kept in quotes.
Entities []MessageEntity `json:"entities"`
// Approximate quote position in the original message in UTF-16 code units
// as specified by the sender.
Position int `json:"position"`
// (Optional) True, if the quote was chosen manually by the message sender.
// Otherwise, the quote was added automatically by the server.
Manual bool `json:"is_manual"`
}
// MessageOrigin a message reference that has been sent originally by a known user.
type MessageOrigin struct {
// Type of the message origin, always “channel”.
Type string `json:"type"`
// Date the message was sent originally in Unix time.
DateUnixtime int64 `json:"date"`
// User that sent the message originally.
Sender *User `json:"sender_user,omitempty"`
// Name of the user that sent the message originally.
SenderUsername string `json:"sender_user_name,omitempty"`
// Chat that sent the message originally.
SenderChat *Chat `json:"sender_chat,omitempty"`
// Channel chat to which the message was originally sent.
Chat *Chat `json:"chat,omitempty"`
// Unique message identifier inside the chat.
MessageID int `json:"message_id,omitempty"`
// (Optional) For messages originally sent by an anonymous chat administrator,
// original message author signature.
Signature string `json:"author_signature,omitempty"`
}
// Time returns the moment of message that was sent originally in local time.
func (mo *MessageOrigin) Time() time.Time {
return time.Unix(mo.DateUnixtime, 0)
}
// ExternalReplyInfo contains information about a message that is being replied to,
// which may come from another chat or forum topic.
type ExternalReplyInfo struct {
// Origin of the message replied to by the given message.
Origin *MessageOrigin `json:"origin"`
// (Optional) Chat the original message belongs to.
// Available only if the chat is a supergroup or a channel.
Chat *Chat `json:"chat"`
// (Optional) Unique message identifier inside the original chat.
// Available only if the original chat is a supergroup or a channel.
MessageID int `json:"message_id"`
// (Optional) Options used for link preview generation for the original message,
// if it is a text message.
PreviewOptions *PreviewOptions `json:"link_preview_options"`
// (Optional) Message is an animation, information about the animation.
Animation *Animation `json:"animation"`
// (Optional) Message is an audio file, information about the file.
Audio *Audio `json:"audio"`
// (Optional) Message is a general file, information about the file.
Document *Document `json:"document"`
// (Optional) Message is a photo, available sizes of the photo.
Photo []Photo `json:"photo"`
// (Optional) Message is a sticker, information about the sticker.
Sticker *Sticker `json:"sticker"`
// (Optional) Message is a forwarded story.
Story *Story `json:"story"`
// (Optional) Message is a video, information about the video.
Video *Video `json:"video"`
// (Optional) Message is a video note, information about the video message.
Note *VideoNote `json:"video_note"`
// (Optional) Message is a voice message, information about the file.
Voice *Voice `json:"voice"`
// (Optional) True, if the message media is covered by a spoiler animation.
HasMediaSpoiler bool `json:"has_media_spoiler"`
// (Optional) Message is a shared contact, information about the contact.
Contact *Contact `json:"contact"`
// (Optional) Message is a dice with random value.
Dice *Dice `json:"dice"`
//( Optional) Message is a game, information about the game.
Game *Game `json:"game"`
// (Optional) Message is a venue, information about the venue.
Venue *Venue `json:"venue"`
// (Optional) Message is a native poll, information about the poll.
Poll *Poll `json:"poll"`
// (Optional) Message is a shared location, information about the location.
Location *Location `json:"location"`
// (Optional) Message is an invoice for a payment, information about the invoice.
Invoice *Invoice `json:"invoice"`
// (Optional) Message is a scheduled giveaway, information about the giveaway.
Giveaway *Giveaway `json:"giveaway"`
// (Optional) A giveaway with public winners was completed.
GiveawayWinners *GiveawayWinners `json:"giveaway_winners"`
}
// ReplyParams describes reply parameters for the message that is being sent.
type ReplyParams struct {
// Identifier of the message that will be replied to in the current chat,
// or in the chat chat_id if it is specified.
MessageID int `json:"message_id"`
// (Optional) If the message to be replied to is from a different chat,
// unique identifier for the chat or username of the channel.
ChatID int64 `json:"chat_id"`
// Optional. Pass True if the message should be sent even if the specified message
// to be replied to is not found; can be used only for replies in the
// same chat and forum topic.
AllowWithoutReply bool `json:"allow_sending_without_reply"`
// (Optional) Quoted part of the message to be replied to; 0-1024 characters after
// entities parsing. The quote must be an exact substring of the message to be replied to,
// including bold, italic, underline, strikethrough, spoiler, and custom_emoji entities.
// The message will fail to send if the quote isn't found in the original message.
Quote string `json:"quote"`
// (Optional) Mode for parsing entities in the quote.
QuoteParseMode ParseMode `json:"quote_parse_mode"`
// (Optional) A JSON-serialized list of special entities that appear in the quote.
// It can be specified instead of quote_parse_mode.
QuoteEntities []MessageEntity `json:"quote_entities"`
// (Optional) Position of the quote in the original message in UTF-16 code units.
QuotePosition int `json:"quote_position"`
}
// React changes the chosen reactions on a message. Service messages can't be
// reacted to. Automatically forwarded messages from a channel to its discussion group have
// the same available reactions as messages in the channel.
func (b *Bot) React(to Recipient, msg Editable, opts ...react.Options) error {
if to == nil {
return ErrBadRecipient
}
msgID, _ := msg.MessageSig()
params := map[string]string{
"chat_id": to.Recipient(),
"message_id": msgID,
}
if len(opts) > 0 {
opt := opts[0]
if len(opt.Reactions) > 0 {
data, _ := json.Marshal(opt.Reactions)
params["reaction"] = string(data)
}
if opt.Big {
params["is_big"] = "true"
}
}
_, err := b.Raw("setMessageReaction", params)
return err
}

@ -84,6 +84,8 @@ type SendOptions struct {
// HasSpoiler marks the message as containing a spoiler.
HasSpoiler bool
// ReplyParams Describes the message to reply to
ReplyParams *ReplyParams
}
func (og *SendOptions) copy() *SendOptions {
@ -105,6 +107,8 @@ func extractOptions(how []interface{}) *SendOptions {
if opt != nil {
opts.ReplyMarkup = opt.copy()
}
case *ReplyParams:
opts.ReplyParams = opt
case Option:
switch opt {
case NoPreview:
@ -198,7 +202,7 @@ func (b *Bot) embedSendOptions(params map[string]string, opt *SendOptions) {
if opt.ThreadID != 0 {
params["message_thread_id"] = strconv.Itoa(opt.ThreadID)
}
if opt.HasSpoiler {
params["spoiler"] = "true"
}
@ -224,3 +228,45 @@ func processButtons(keys [][]InlineButton) {
}
}
}
// PreviewOptions describes the options used for link preview generation.
type PreviewOptions struct {
// (Optional) True, if the link preview is disabled.
Disabled bool `json:"is_disabled"`
// (Optional) URL to use for the link preview. If empty, then the first URL
// found in the message text will be used.
URL string `json:"url"`
// (Optional) True, if the media in the link preview is supposed to be shrunk;
// ignored if the URL isn't explicitly specified or media size change.
// isn't supported for the preview.
SmallMedia bool `json:"prefer_small_media"`
// (Optional) True, if the media in the link preview is supposed to be enlarged;
// ignored if the URL isn't explicitly specified or media size change.
// isn't supported for the preview.
LargeMedia bool `json:"prefer_large_media"`
// (Optional) True, if the link preview must be shown above the message text;
// otherwise, the link preview will be shown below the message text.
AboveText bool `json:"show_above_text"`
}
func embedMessages(params map[string]string, msgs []Editable) {
ids := make([]string, 0, len(msgs))
_, chatID := msgs[0].MessageSig()
for _, msg := range msgs {
msgID, _ := msg.MessageSig()
ids = append(ids, msgID)
}
data, err := json.Marshal(ids)
if err != nil {
return
}
params["message_ids"] = string(data)
params["chat_id"] = strconv.FormatInt(chatID, 10)
}

@ -0,0 +1,112 @@
package react
// EmojiType defines emoji types.
type EmojiType = string
// Currently available emojis.
var (
ThumbUp = Reaction{Emoji: "👍"}
ThumbDown = Reaction{Emoji: "👎"}
Heart = Reaction{Emoji: "❤"}
Fire = Reaction{Emoji: "🔥"}
HeartEyes = Reaction{Emoji: "😍"}
ClappingHands = Reaction{Emoji: "👏"}
GrinningFace = Reaction{Emoji: "😁"}
ThinkingFace = Reaction{Emoji: "🤔"}
ExplodingHead = Reaction{Emoji: "🤯"}
ScreamingFace = Reaction{Emoji: "😱"}
SwearingFace = Reaction{Emoji: "🤬"}
CryingFace = Reaction{Emoji: "😢"}
PartyPopper = Reaction{Emoji: "🎉"}
StarStruck = Reaction{Emoji: "🤩"}
VomitingFace = Reaction{Emoji: "🤮"}
PileOfPoo = Reaction{Emoji: "💩"}
PrayingHands = Reaction{Emoji: "🙏"}
OkHand = Reaction{Emoji: "👌"}
DoveOfPeace = Reaction{Emoji: "🕊"}
ClownFace = Reaction{Emoji: "🤡"}
YawningFace = Reaction{Emoji: "🥱"}
WoozyFace = Reaction{Emoji: "🥴"}
Whale = Reaction{Emoji: "🐳"}
HeartOnFire = Reaction{Emoji: "❤‍🔥"}
MoonFace = Reaction{Emoji: "🌚"}
HotDog = Reaction{Emoji: "🌭"}
HundredPoints = Reaction{Emoji: "💯"}
RollingOnTheFloorLaughing = Reaction{Emoji: "🤣"}
Lightning = Reaction{Emoji: "⚡"}
Banana = Reaction{Emoji: "🍌"}
Trophy = Reaction{Emoji: "🏆"}
BrokenHeart = Reaction{Emoji: "💔"}
FaceWithRaisedEyebrow = Reaction{Emoji: "🤨"}
NeutralFace = Reaction{Emoji: "😐"}
Strawberry = Reaction{Emoji: "🍓"}
Champagne = Reaction{Emoji: "🍾"}
KissMark = Reaction{Emoji: "💋"}
MiddleFinger = Reaction{Emoji: "🖕"}
EvilFace = Reaction{Emoji: "😈"}
SleepingFace = Reaction{Emoji: "😴"}
LoudlyCryingFace = Reaction{Emoji: "😭"}
NerdFace = Reaction{Emoji: "🤓"}
Ghost = Reaction{Emoji: "👻"}
Engineer = Reaction{Emoji: "👨‍💻"}
Eyes = Reaction{Emoji: "👀"}
JackOLantern = Reaction{Emoji: "🎃"}
NoMonkey = Reaction{Emoji: "🙈"}
SmilingFaceWithHalo = Reaction{Emoji: "😇"}
FearfulFace = Reaction{Emoji: "😨"}
Handshake = Reaction{Emoji: "🤝"}
WritingHand = Reaction{Emoji: "✍"}
HuggingFace = Reaction{Emoji: "🤗"}
Brain = Reaction{Emoji: "🫡"}
SantaClaus = Reaction{Emoji: "🎅"}
ChristmasTree = Reaction{Emoji: "🎄"}
Snowman = Reaction{Emoji: "☃"}
NailPolish = Reaction{Emoji: "💅"}
ZanyFace = Reaction{Emoji: "🤪"}
Moai = Reaction{Emoji: "🗿"}
Cool = Reaction{Emoji: "🆒"}
HeartWithArrow = Reaction{Emoji: "💘"}
HearMonkey = Reaction{Emoji: "🙉"}
Unicorn = Reaction{Emoji: "🦄"}
FaceBlowingKiss = Reaction{Emoji: "😘"}
Pill = Reaction{Emoji: "💊"}
SpeaklessMonkey = Reaction{Emoji: "🙊"}
Sunglasses = Reaction{Emoji: "😎"}
AlienMonster = Reaction{Emoji: "👾"}
ManShrugging = Reaction{Emoji: "🤷‍♂️"}
PersonShrugging = Reaction{Emoji: "🤷"}
WomanShrugging = Reaction{Emoji: "🤷‍♀️"}
PoutingFace = Reaction{Emoji: "😡"}
)
// Reaction describes the type of reaction.
// Describes an instance of ReactionTypeCustomEmoji and ReactionTypeEmoji.
type Reaction struct {
// Type of the reaction, always “emoji”
Type string `json:"type"`
// Reaction emoji.
Emoji EmojiType `json:"emoji,omitempty"`
// Custom emoji identifier.
CustomEmoji string `json:"custom_emoji_id,omitempty"`
}
// Count represents a reaction added to a message along
// with the number of times it was added.
type Count struct {
// Type of the reaction.
Type Reaction `json:"type"`
// Number of times the reaction was added.
Count int `json:"total_count"`
}
// Options represents an object of reaction options.
type Options struct {
// List of reaction types to set on the message.
Reactions []Reaction `json:"reaction"`
// Pass True to set the reaction with a big animation.
Big bool `json:"is_big"`
}

@ -109,6 +109,9 @@ const (
OnVideoChatEnded = "\avideo_chat_ended"
OnVideoChatParticipants = "\avideo_chat_participants_invited"
OnVideoChatScheduled = "\avideo_chat_scheduled"
OnBoost = "\aboost_updated"
onBoostRemoved = "\aboost_removed"
)
// ChatAction is a client-side status indicating bot activity.

@ -6,20 +6,24 @@ import "strings"
type Update struct {
ID int `json:"update_id"`
Message *Message `json:"message,omitempty"`
EditedMessage *Message `json:"edited_message,omitempty"`
ChannelPost *Message `json:"channel_post,omitempty"`
EditedChannelPost *Message `json:"edited_channel_post,omitempty"`
Callback *Callback `json:"callback_query,omitempty"`
Query *Query `json:"inline_query,omitempty"`
InlineResult *InlineResult `json:"chosen_inline_result,omitempty"`
ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"`
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"`
Poll *Poll `json:"poll,omitempty"`
PollAnswer *PollAnswer `json:"poll_answer,omitempty"`
MyChatMember *ChatMemberUpdate `json:"my_chat_member,omitempty"`
ChatMember *ChatMemberUpdate `json:"chat_member,omitempty"`
ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"`
Message *Message `json:"message,omitempty"`
EditedMessage *Message `json:"edited_message,omitempty"`
ChannelPost *Message `json:"channel_post,omitempty"`
EditedChannelPost *Message `json:"edited_channel_post,omitempty"`
MessageReaction *MessageReaction `json:"message_reaction"`
MessageReactionCount *MessageReactionCount `json:"message_reaction_count"`
Callback *Callback `json:"callback_query,omitempty"`
Query *Query `json:"inline_query,omitempty"`
InlineResult *InlineResult `json:"chosen_inline_result,omitempty"`
ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"`
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"`
Poll *Poll `json:"poll,omitempty"`
PollAnswer *PollAnswer `json:"poll_answer,omitempty"`
MyChatMember *ChatMemberUpdate `json:"my_chat_member,omitempty"`
ChatMember *ChatMemberUpdate `json:"chat_member,omitempty"`
ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"`
Boost *BoostUpdated `json:"chat_boost"`
BoostRemoved *BoostRemoved `json:"removed_chat_boost"`
}
// ProcessUpdate processes a single incoming update.
@ -308,6 +312,16 @@ func (b *Bot) ProcessUpdate(u Update) {
b.handle(OnChatJoinRequest, c)
return
}
if u.Boost != nil {
b.handle(OnBoost, c)
return
}
if u.BoostRemoved != nil {
b.handle(onBoostRemoved, c)
return
}
}
func (b *Bot) handle(end string, c Context) bool {

Loading…
Cancel
Save