From 2d17e0e12c0fa124879f76256ea17d930817afcb Mon Sep 17 00:00:00 2001 From: demget <30910794+demget@users.noreply.github.com> Date: Sun, 23 May 2021 19:55:49 +0300 Subject: [PATCH] Merge pull request #405 from DiscoreMe/develop api: support 5.0 --- admin.go | 12 +++++++--- bot.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-- chat.go | 31 +++++++++++++++--------- file.go | 1 + media.go | 27 +++++++++++++++------ message.go | 7 ++++++ options.go | 6 +++++ sendable.go | 25 ++++++++++++++------ telebot.go | 5 ++++ util.go | 12 ++++++++-- webhook.go | 22 +++++++++++++---- 11 files changed, 180 insertions(+), 36 deletions(-) diff --git a/admin.go b/admin.go index 507804d..ae110ff 100644 --- a/admin.go +++ b/admin.go @@ -148,12 +148,17 @@ func (b *Bot) Ban(chat *Chat, member *ChatMember) error { } // Unban will unban user from chat, who would have thought eh? -func (b *Bot) Unban(chat *Chat, user *User) error { +// forBanned does nothing if the user is not banned. +func (b *Bot) Unban(chat *Chat, user *User, forBanned ...bool) error { params := map[string]string{ "chat_id": chat.Recipient(), "user_id": user.Recipient(), } + if len(forBanned) > 0 { + params["only_if_banned"] = strconv.FormatBool(forBanned[0]) + } + _, err := b.Raw("unbanChatMember", params) return err } @@ -195,8 +200,9 @@ func (b *Bot) Promote(chat *Chat, member *ChatMember) error { prv := member.Rights params := map[string]interface{}{ - "chat_id": chat.Recipient(), - "user_id": member.User.Recipient(), + "chat_id": chat.Recipient(), + "user_id": member.User.Recipient(), + "is_anonymous": member.Anonymous, } embedRights(params, prv) diff --git a/bot.go b/bot.go index 55642fc..55566a4 100644 --- a/bot.go +++ b/bot.go @@ -366,6 +366,11 @@ func (b *Bot) ProcessUpdate(upd Update) { b.handle(OnVoiceChatParticipants, c) return } + + if m.ProximityAlert != nil { + b.handle(OnProximityAlert, c) + return + } } if upd.EditedMessage != nil { @@ -710,6 +715,16 @@ func (b *Bot) Edit(msg Editable, what interface{}, opts ...interface{}) (*Messag method = "editMessageLiveLocation" params["latitude"] = fmt.Sprintf("%f", v.Lat) params["longitude"] = fmt.Sprintf("%f", v.Lng) + + if v.HorizontalAccuracy != nil { + params["horizontal_accuracy"] = fmt.Sprintf("%f", *v.HorizontalAccuracy) + } + if v.Heading != 0 { + params["heading"] = strconv.Itoa(v.Heading) + } + if v.AlertRadius != 0 { + params["proximity_alert_radius"] = strconv.Itoa(v.AlertRadius) + } default: return nil, ErrUnsupportedWhat } @@ -1332,16 +1347,31 @@ func (b *Bot) Pin(msg Editable, opts ...interface{}) error { } // Unpin unpins a message in a supergroup or a channel. -// It supports Silent option. -func (b *Bot) Unpin(chat *Chat) error { +// It supports tb.Silent option. +func (b *Bot) Unpin(chat *Chat, messageID ...int) error { params := map[string]string{ "chat_id": chat.Recipient(), } + if len(messageID) > 0 { + params["message_id"] = strconv.Itoa(messageID[0]) + } _, err := b.Raw("unpinChatMessage", params) return err } +// UnpinAll unpins all messages in a supergroup or a channel. +// +// It supports tb.Silent option. +func (b *Bot) UnpinAll(chat *Chat) error { + params := map[string]string{ + "chat_id": chat.Recipient(), + } + + _, err := b.Raw("unpinAllChatMessages", params) + return err +} + // ChatByID fetches chat info of its ID. // // Including current name of the user for one-on-one conversations, @@ -1440,3 +1470,37 @@ func (b *Bot) SetCommands(cmds []Command) error { _, err := b.Raw("setMyCommands", params) return err } + +// Logout logs out from the cloud Bot API server before launching the bot locally. +func (b *Bot) Logout() (bool, error) { + data, err := b.Raw("logOut", nil) + if err != nil { + return false, err + } + + var resp struct { + Result bool `json:"result"` + } + if err := json.Unmarshal(data, &resp); err != nil { + return false, wrapError(err) + } + + return resp.Result, nil +} + +// Close closes the bot instance before moving it from one local server to another. +func (b *Bot) Close() (bool, error) { + data, err := b.Raw("close", nil) + if err != nil { + return false, err + } + + var resp struct { + Result bool `json:"result"` + } + if err := json.Unmarshal(data, &resp); err != nil { + return false, wrapError(err) + } + + return resp.Result, nil +} diff --git a/chat.go b/chat.go index ceaff42..18bef77 100644 --- a/chat.go +++ b/chat.go @@ -42,14 +42,22 @@ type Chat struct { Still bool `json:"is_member,omitempty"` // Returns only in getChat - 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"` + 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"` +} + +type ChatLocation struct { + Location Location `json:"location,omitempty"` + Address string `json:"address,omitempty"` } // ChatPhoto object represents a chat photo. @@ -75,9 +83,10 @@ func (c *Chat) Recipient() string { type ChatMember struct { Rights - User *User `json:"user"` - Role MemberStatus `json:"status"` - Title string `json:"custom_title"` + User *User `json:"user"` + Role MemberStatus `json:"status"` + Title string `json:"custom_title"` + Anonymous bool `json:"is_anonymous"` // Date when restrictions will be lifted for the user, unix time. // diff --git a/file.go b/file.go index ee730f7..ea97ba5 100644 --- a/file.go +++ b/file.go @@ -9,6 +9,7 @@ import ( type File struct { FileID string `json:"file_id"` UniqueID string `json:"file_unique_id"` + FileName string `json:"file_name"` FileSize int `json:"file_size"` // file on telegram server https://core.telegram.org/bots/api#file diff --git a/media.go b/media.go index eeb1aa8..0632ca5 100644 --- a/media.go +++ b/media.go @@ -182,14 +182,25 @@ type Contact struct { // Location object represents geographic position. type Location struct { - Lat float32 `json:"latitude"` - Lng float32 `json:"longitude"` - - // Period in seconds for which the location will be updated, - // should be between 60 and 86400. + Lat float32 `json:"latitude"` + Lng float32 `json:"longitude"` + HorizontalAccuracy *float32 `json:"horizontal_accuracy,omitempty"` + Heading int `json:"heading,omitempty"` + AlertRadius int `json:"proximity_alert_radius,omitempty"` + + // Period in seconds for which the location will be updated + // (see Live Locations, should be between 60 and 86400.) LivePeriod int `json:"live_period,omitempty"` } +// ProximityAlert sent whenever +// a user in the chat triggers a proximity alert set by another user. +type ProximityAlert struct { + Traveler *User `json:"traveler,omitempty"` + Watcher *User `json:"watcher,omitempty"` + Distance int `json:"distance"` +} + // Venue object represents a venue location with name, address and // optional foursquare ID. type Venue struct { @@ -198,8 +209,10 @@ type Venue struct { Address string `json:"address"` // (Optional) - FoursquareID string `json:"foursquare_id,omitempty"` - FoursquareType string `json:"foursquare_type,omitempty"` + FoursquareID string `json:"foursquare_id,omitempty"` + FoursquareType string `json:"foursquare_type,omitempty"` + GooglePlaceID string `json:"google_place_id,omitempty"` + GooglePlaceType string `json:"google_place_type,omitempty"` } // Dice object represents a dice with a random value diff --git a/message.go b/message.go index 76afc3f..697f97f 100644 --- a/message.go +++ b/message.go @@ -20,6 +20,9 @@ type Message struct { // Conversation the message belongs to. Chat *Chat `json:"chat"` + // Sender of the message, sent on behalf of a chat. + SenderChat *Chat `json:"sender_chat"` + // For forwarded messages, sender of the original message. OriginalSender *User `json:"forward_from"` @@ -226,6 +229,10 @@ type Message struct { // For a service message, some users were invited in the voice chat. VoiceChatParticipants *VoiceChatParticipants `json:"voice_chat_participants_invited,omitempty"` + + // For a service message, represents the content of a service message, + // sent whenever a user in the chat triggers a proximity alert set by another user. + ProximityAlert *ProximityAlert `json:"proximity_alert_triggered,omitempty"` } // MessageEntity object represents "special" parts of text messages, diff --git a/options.go b/options.go index a4207c2..70b6917 100644 --- a/options.go +++ b/options.go @@ -65,6 +65,12 @@ type SendOptions struct { // ParseMode controls how client apps render your message. ParseMode ParseMode + + // DisableContentDetection abilities to disable server-side file content type detection. + DisableContentDetection bool + + // AllowWithoutReply allows sending messages not a as reply if the replied-to message has already been deleted. + AllowWithoutReply bool } func (og *SendOptions) copy() *SendOptions { diff --git a/sendable.go b/sendable.go index a8765cb..75d83e8 100644 --- a/sendable.go +++ b/sendable.go @@ -265,6 +265,15 @@ func (x *Location) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error "longitude": fmt.Sprintf("%f", x.Lng), "live_period": strconv.Itoa(x.LivePeriod), } + if x.HorizontalAccuracy != nil { + params["horizontal_accuracy"] = fmt.Sprintf("%f", *x.HorizontalAccuracy) + } + if x.Heading != 0 { + params["heading"] = strconv.Itoa(x.Heading) + } + if x.AlertRadius != 0 { + params["proximity_alert_radius"] = strconv.Itoa(x.Heading) + } b.embedSendOptions(params, opt) data, err := b.Raw("sendLocation", params) @@ -278,13 +287,15 @@ func (x *Location) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error // Send delivers media through bot b to recipient. func (v *Venue) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) { params := map[string]string{ - "chat_id": to.Recipient(), - "latitude": fmt.Sprintf("%f", v.Location.Lat), - "longitude": fmt.Sprintf("%f", v.Location.Lng), - "title": v.Title, - "address": v.Address, - "foursquare_id": v.FoursquareID, - "foursquare_type": v.FoursquareType, + "chat_id": to.Recipient(), + "latitude": fmt.Sprintf("%f", v.Location.Lat), + "longitude": fmt.Sprintf("%f", v.Location.Lng), + "title": v.Title, + "address": v.Address, + "foursquare_id": v.FoursquareID, + "foursquare_type": v.FoursquareType, + "google_place_id": v.GooglePlaceID, + "google_place_type": v.GooglePlaceType, } b.embedSendOptions(params, opt) diff --git a/telebot.go b/telebot.go index be36b17..07f2690 100644 --- a/telebot.go +++ b/telebot.go @@ -146,6 +146,11 @@ const ( // // Handler: func(*Message) OnVoiceChatParticipants = "\avoice_chat_participants_invited" + + // Will fire on ProximityAlert + // + // Handler: func(*Message) + OnProximityAlert = "\aproximity_alert_triggered" ) // ChatAction is a client-side status indicating bot activity. diff --git a/util.go b/util.go index 7e13586..670c369 100644 --- a/util.go +++ b/util.go @@ -1,13 +1,13 @@ package telebot import ( + "bytes" "encoding/json" "fmt" + "github.com/pkg/errors" "log" "net/http" "strconv" - "bytes" - "github.com/pkg/errors" ) func (b *Bot) debug(err error) { @@ -211,6 +211,14 @@ func (b *Bot) embedSendOptions(params map[string]string, opt *SendOptions) { params["parse_mode"] = opt.ParseMode } + if opt.DisableContentDetection { + params["disable_content_type_detection"] = "true" + } + + if opt.AllowWithoutReply { + params["allow_sending_without_reply"] = "true" + } + if opt.ReplyMarkup != nil { processButtons(opt.ReplyMarkup.InlineKeyboard) replyMarkup, _ := json.Marshal(opt.ReplyMarkup) diff --git a/webhook.go b/webhook.go index 8faae7e..64e7414 100644 --- a/webhook.go +++ b/webhook.go @@ -42,6 +42,8 @@ type Webhook struct { Listen string `json:"url"` MaxConnections int `json:"max_connections"` AllowedUpdates []string `json:"allowed_updates"` + IP string `json:"ip_address"` + DropUpdates bool `json:"drop_pending_updates"` // (WebhookInfo) HasCustomCert bool `json:"has_custom_certificate"` @@ -49,8 +51,8 @@ type Webhook struct { ErrorUnixtime int64 `json:"last_error_date"` ErrorMessage string `json:"last_error_message"` - TLS *WebhookTLS `json:"tls,omitempty"` - Endpoint *WebhookEndpoint `json:"endpoint,omitempty"` + TLS *WebhookTLS + Endpoint *WebhookEndpoint dest chan<- Update bot *Bot @@ -88,6 +90,12 @@ func (h *Webhook) getParams() map[string]string { data, _ := json.Marshal(h.AllowedUpdates) params["allowed_updates"] = string(data) } + if h.IP != "" { + params["ip_address"] = h.IP + } + if h.DropUpdates { + params["drop_pending_updates"] = strconv.FormatBool(h.DropUpdates) + } if h.TLS != nil { params["url"] = "https://" + h.Listen @@ -177,7 +185,13 @@ func (b *Bot) SetWebhook(w *Webhook) error { } // RemoveWebhook removes webhook integration. -func (b *Bot) RemoveWebhook() error { - _, err := b.Raw("deleteWebhook", nil) +func (b *Bot) RemoveWebhook(dropPending ...bool) error { + drop := false + if len(dropPending) > 0 { + drop = dropPending[0] + } + _, err := b.Raw("deleteWebhook", map[string]bool{ + "drop_pending_updates": drop, + }) return err }