mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 14:35:36 +01:00
Add MaybeInaccessibleMessage
to the Message
and CallbackQuery
This commit is contained in:
parent
6c967231ef
commit
c8f7bd745c
8 changed files with 145 additions and 23 deletions
|
@ -41,6 +41,7 @@ pub use game::*;
|
||||||
pub use game_high_score::*;
|
pub use game_high_score::*;
|
||||||
pub use general_forum_topic_hidden::*;
|
pub use general_forum_topic_hidden::*;
|
||||||
pub use general_forum_topic_unhidden::*;
|
pub use general_forum_topic_unhidden::*;
|
||||||
|
pub use inaccessible_message::*;
|
||||||
pub use inline_keyboard_button::*;
|
pub use inline_keyboard_button::*;
|
||||||
pub use inline_keyboard_markup::*;
|
pub use inline_keyboard_markup::*;
|
||||||
pub use inline_query::*;
|
pub use inline_query::*;
|
||||||
|
@ -79,6 +80,7 @@ pub use label_price::*;
|
||||||
pub use location::*;
|
pub use location::*;
|
||||||
pub use login_url::*;
|
pub use login_url::*;
|
||||||
pub use mask_position::*;
|
pub use mask_position::*;
|
||||||
|
pub use maybe_inaccessible_message::*;
|
||||||
pub use me::*;
|
pub use me::*;
|
||||||
pub use menu_button::*;
|
pub use menu_button::*;
|
||||||
pub use message::*;
|
pub use message::*;
|
||||||
|
@ -170,6 +172,7 @@ mod game;
|
||||||
mod game_high_score;
|
mod game_high_score;
|
||||||
mod general_forum_topic_hidden;
|
mod general_forum_topic_hidden;
|
||||||
mod general_forum_topic_unhidden;
|
mod general_forum_topic_unhidden;
|
||||||
|
mod inaccessible_message;
|
||||||
mod inline_keyboard_button;
|
mod inline_keyboard_button;
|
||||||
mod inline_keyboard_markup;
|
mod inline_keyboard_markup;
|
||||||
mod inline_query_results_button;
|
mod inline_query_results_button;
|
||||||
|
@ -186,6 +189,7 @@ mod label_price;
|
||||||
mod location;
|
mod location;
|
||||||
mod login_url;
|
mod login_url;
|
||||||
mod mask_position;
|
mod mask_position;
|
||||||
|
mod maybe_inaccessible_message;
|
||||||
mod me;
|
mod me;
|
||||||
mod menu_button;
|
mod menu_button;
|
||||||
mod message;
|
mod message;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{Message, User};
|
use crate::types::{MaybeInaccessibleMessage, Message, User};
|
||||||
|
|
||||||
/// This object represents an incoming callback query from a callback button in
|
/// This object represents an incoming callback query from a callback button in
|
||||||
/// an [inline keyboard].
|
/// an [inline keyboard].
|
||||||
|
@ -24,10 +24,9 @@ pub struct CallbackQuery {
|
||||||
/// A sender.
|
/// A sender.
|
||||||
pub from: User,
|
pub from: User,
|
||||||
|
|
||||||
/// A message with the callback button that originated the query. Note that
|
/// Message sent by the bot with the callback button that originated the
|
||||||
/// message content and message date will not be available if the message
|
/// query
|
||||||
/// is too old.
|
pub message: Option<MaybeInaccessibleMessage>,
|
||||||
pub message: Option<Message>,
|
|
||||||
|
|
||||||
/// An identifier of the message sent via the bot in inline mode, that
|
/// An identifier of the message sent via the bot in inline mode, that
|
||||||
/// originated the query.
|
/// originated the query.
|
||||||
|
@ -58,7 +57,13 @@ impl CallbackQuery {
|
||||||
use crate::util::flatten;
|
use crate::util::flatten;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
once(&self.from).chain(flatten(self.message.as_ref().map(Message::mentioned_users)))
|
once(&self.from).chain(flatten(
|
||||||
|
self.message
|
||||||
|
.as_ref()
|
||||||
|
// If we can access the message
|
||||||
|
.and_then(|maybe| maybe.message())
|
||||||
|
.map(Message::mentioned_users),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
crates/teloxide-core/src/types/inaccessible_message.rs
Normal file
13
crates/teloxide-core/src/types/inaccessible_message.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::types::{Chat, MessageId};
|
||||||
|
|
||||||
|
/// This object describes a message that was deleted or is otherwise
|
||||||
|
/// inaccessible to the bot.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct InaccessibleMessage {
|
||||||
|
/// Chat the message belonged to
|
||||||
|
pub chat: Chat,
|
||||||
|
/// Unique message identifier inside the chat
|
||||||
|
pub message_id: MessageId,
|
||||||
|
}
|
98
crates/teloxide-core/src/types/maybe_inaccessible_message.rs
Normal file
98
crates/teloxide-core/src/types/maybe_inaccessible_message.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::types::{Chat, InaccessibleMessage, Message, MessageId};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MaybeInaccessibleMessage {
|
||||||
|
Inaccessible(InaccessibleMessage),
|
||||||
|
Regular(Message),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaybeInaccessibleMessage {
|
||||||
|
pub fn id(&self) -> MessageId {
|
||||||
|
match self {
|
||||||
|
Self::Inaccessible(i_message) => i_message.message_id,
|
||||||
|
Self::Regular(message) => message.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message(&self) -> Option<&Message> {
|
||||||
|
match self {
|
||||||
|
Self::Regular(message) => Some(message),
|
||||||
|
Self::Inaccessible(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chat_and_id(&self) -> (&Chat, MessageId) {
|
||||||
|
(self.chat(), self.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chat(&self) -> &Chat {
|
||||||
|
match self {
|
||||||
|
Self::Regular(message) => &message.chat,
|
||||||
|
Self::Inaccessible(i_message) => &i_message.chat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for MaybeInaccessibleMessage {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let message: Message = Message::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
// Thank you, TBA 7.0 authors!
|
||||||
|
if message.date.timestamp() == 0 {
|
||||||
|
return Ok(MaybeInaccessibleMessage::Inaccessible(InaccessibleMessage {
|
||||||
|
chat: message.chat,
|
||||||
|
message_id: message.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Ok(MaybeInaccessibleMessage::Regular(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inaccessible_message() {
|
||||||
|
let json = r#"{
|
||||||
|
"chat": {
|
||||||
|
"id": 42,
|
||||||
|
"first_name": "Вадим Игоревич",
|
||||||
|
"last_name": "Сырцев",
|
||||||
|
"username": "syrtcevvi",
|
||||||
|
"type": "private"
|
||||||
|
},
|
||||||
|
"message_id": 4,
|
||||||
|
"date": 0
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let inaccessible_message = serde_json::from_str::<MaybeInaccessibleMessage>(json);
|
||||||
|
assert!(inaccessible_message.is_ok());
|
||||||
|
assert!(matches!(inaccessible_message.unwrap(), MaybeInaccessibleMessage::Inaccessible(_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_regular_message() {
|
||||||
|
let json = r#"{
|
||||||
|
"chat": {
|
||||||
|
"id": 42,
|
||||||
|
"first_name": "Вадим Игоревич",
|
||||||
|
"last_name": "Сырцев",
|
||||||
|
"username": "syrtcevvi",
|
||||||
|
"type": "private"
|
||||||
|
},
|
||||||
|
"message_id": 4,
|
||||||
|
"date": 1
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let regular_message = serde_json::from_str::<MaybeInaccessibleMessage>(json);
|
||||||
|
assert!(regular_message.is_ok());
|
||||||
|
assert!(matches!(regular_message.unwrap(), MaybeInaccessibleMessage::Regular(_)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,10 +8,11 @@ use crate::types::{
|
||||||
Animation, Audio, BareChatId, Chat, ChatId, ChatShared, Contact, Dice, Document,
|
Animation, Audio, BareChatId, Chat, ChatId, ChatShared, Contact, Dice, Document,
|
||||||
ForumTopicClosed, ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game,
|
ForumTopicClosed, ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game,
|
||||||
GeneralForumTopicHidden, GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location,
|
GeneralForumTopicHidden, GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location,
|
||||||
MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef, MessageId, MessageOrigin,
|
MaybeInaccessibleMessage, MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef,
|
||||||
PassportData, PhotoSize, Poll, ProximityAlertTriggered, Sticker, Story, SuccessfulPayment,
|
MessageId, MessageOrigin, PassportData, PhotoSize, Poll, ProximityAlertTriggered, Sticker,
|
||||||
ThreadId, True, User, UsersShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited,
|
Story, SuccessfulPayment, ThreadId, True, User, UsersShared, Venue, Video, VideoChatEnded,
|
||||||
VideoChatScheduled, VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed,
|
VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted, VideoNote, Voice,
|
||||||
|
WebAppData, WriteAccessAllowed,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This object represents a message.
|
/// This object represents a message.
|
||||||
|
@ -245,7 +246,7 @@ pub struct MessagePinned {
|
||||||
/// field will not contain further `reply_to_message` fields even if it
|
/// field will not contain further `reply_to_message` fields even if it
|
||||||
/// is itself a reply.
|
/// is itself a reply.
|
||||||
#[serde(rename = "pinned_message")]
|
#[serde(rename = "pinned_message")]
|
||||||
pub pinned: Box<Message>,
|
pub pinned: Box<MaybeInaccessibleMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -627,14 +628,14 @@ mod getters {
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
self, message::MessageKind::*, Chat, ChatId, ChatMigration, MediaAnimation, MediaAudio,
|
self, message::MessageKind::*, Chat, ChatId, ChatMigration, MaybeInaccessibleMessage,
|
||||||
MediaContact, MediaDocument, MediaGame, MediaKind, MediaLocation, MediaPhoto, MediaPoll,
|
MediaAnimation, MediaAudio, MediaContact, MediaDocument, MediaGame, MediaKind,
|
||||||
MediaSticker, MediaStory, MediaText, MediaVenue, MediaVideo, MediaVideoNote, MediaVoice,
|
MediaLocation, MediaPhoto, MediaPoll, MediaSticker, MediaStory, MediaText, MediaVenue,
|
||||||
Message, MessageChannelChatCreated, MessageChatShared, MessageCommon,
|
MediaVideo, MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated,
|
||||||
MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity,
|
MessageChatShared, MessageCommon, MessageConnectedWebsite, MessageDeleteChatPhoto,
|
||||||
MessageGroupChatCreated, MessageId, MessageInvoice, MessageLeftChatMember,
|
MessageDice, MessageEntity, MessageGroupChatCreated, MessageId, MessageInvoice,
|
||||||
MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle, MessageOrigin,
|
MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle,
|
||||||
MessagePassportData, MessagePinned, MessageProximityAlertTriggered,
|
MessageOrigin, MessagePassportData, MessagePinned, MessageProximityAlertTriggered,
|
||||||
MessageSuccessfulPayment, MessageSupergroupChatCreated, MessageUsersShared,
|
MessageSuccessfulPayment, MessageSupergroupChatCreated, MessageUsersShared,
|
||||||
MessageVideoChatParticipantsInvited, PhotoSize, User,
|
MessageVideoChatParticipantsInvited, PhotoSize, User,
|
||||||
};
|
};
|
||||||
|
@ -1208,7 +1209,7 @@ mod getters {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn pinned_message(&self) -> Option<&Message> {
|
pub fn pinned_message(&self) -> Option<&MaybeInaccessibleMessage> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
Pinned(MessagePinned { pinned }) => Some(pinned),
|
Pinned(MessagePinned { pinned }) => Some(pinned),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -220,7 +220,7 @@ impl Update {
|
||||||
|
|
||||||
let chat = match &self.kind {
|
let chat = match &self.kind {
|
||||||
Message(m) | EditedMessage(m) | ChannelPost(m) | EditedChannelPost(m) => &m.chat,
|
Message(m) | EditedMessage(m) | ChannelPost(m) | EditedChannelPost(m) => &m.chat,
|
||||||
CallbackQuery(q) => &q.message.as_ref()?.chat,
|
CallbackQuery(q) => q.message.as_ref()?.chat(),
|
||||||
ChatMember(m) => &m.chat,
|
ChatMember(m) => &m.chat,
|
||||||
MyChatMember(m) => &m.chat,
|
MyChatMember(m) => &m.chat,
|
||||||
ChatJoinRequest(c) => &c.chat,
|
ChatJoinRequest(c) => &c.chat,
|
||||||
|
|
|
@ -116,7 +116,8 @@ async fn callback_handler(bot: Bot, q: CallbackQuery) -> Result<(), Box<dyn Erro
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
|
|
||||||
// Edit text of the message to which the buttons were attached
|
// Edit text of the message to which the buttons were attached
|
||||||
if let Some(Message { id, chat, .. }) = q.message {
|
if let Some(maybe_message) = q.message {
|
||||||
|
let (chat, id) = maybe_message.chat_and_id();
|
||||||
bot.edit_message_text(chat.id, id, text).await?;
|
bot.edit_message_text(chat.id, id, text).await?;
|
||||||
} else if let Some(id) = q.inline_message_id {
|
} else if let Some(id) = q.inline_message_id {
|
||||||
bot.edit_message_text_inline(id, text).await?;
|
bot.edit_message_text_inline(id, text).await?;
|
||||||
|
|
|
@ -16,7 +16,7 @@ impl GetChatId for Message {
|
||||||
|
|
||||||
impl GetChatId for CallbackQuery {
|
impl GetChatId for CallbackQuery {
|
||||||
fn chat_id(&self) -> Option<ChatId> {
|
fn chat_id(&self) -> Option<ChatId> {
|
||||||
self.message.as_ref().map(|mes| mes.chat.id)
|
self.message.as_ref().map(|mes| mes.chat().id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue