Fix issue #945 (PR 946 originally)

This commit is contained in:
Сырцев Вадим Игоревич 2024-07-20 08:39:27 +03:00 committed by Andrey Brusnik
parent 664717e07d
commit b625e813cc
No known key found for this signature in database
GPG key ID: D33232F28CFF442C
5 changed files with 77 additions and 51 deletions

View file

@ -31,6 +31,15 @@ pub struct Message {
#[serde(rename = "message_thread_id")] #[serde(rename = "message_thread_id")]
pub thread_id: Option<ThreadId>, pub thread_id: Option<ThreadId>,
/// Sender, empty for messages sent to channels.
pub from: Option<User>,
/// Sender of the message, sent on behalf of a chat. The channel itself for
/// channel messages. The supergroup itself for messages from anonymous
/// group administrators. The linked channel for messages automatically
/// forwarded to the discussion group
pub sender_chat: Option<Chat>,
/// Date the message was sent in Unix time. /// Date the message was sent in Unix time.
#[serde(with = "crate::types::serde_date_from_unix_timestamp")] #[serde(with = "crate::types::serde_date_from_unix_timestamp")]
pub date: DateTime<Utc>, pub date: DateTime<Utc>,
@ -38,6 +47,10 @@ pub struct Message {
/// Conversation the message belongs to. /// Conversation the message belongs to.
pub chat: Chat, pub chat: Chat,
/// `true`, if the message is sent to a forum topic.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_topic_message: bool,
/// Bot through which the message was sent. /// Bot through which the message was sent.
pub via_bot: Option<User>, pub via_bot: Option<User>,
@ -94,15 +107,6 @@ pub enum MessageKind {
#[serde_with::skip_serializing_none] #[serde_with::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageCommon { pub struct MessageCommon {
/// Sender, empty for messages sent to channels.
pub from: Option<User>,
/// Sender of the message, sent on behalf of a chat. The channel itself for
/// channel messages. The supergroup itself for messages from anonymous
/// group administrators. The linked channel for messages automatically
/// forwarded to the discussion group
pub sender_chat: Option<Chat>,
/// Signature of the post author for messages in channels, or the custom /// Signature of the post author for messages in channels, or the custom
/// title of an anonymous group administrator. /// title of an anonymous group administrator.
pub author_signature: Option<String>, pub author_signature: Option<String>,
@ -130,12 +134,6 @@ pub struct MessageCommon {
/// represented as ordinary `url` buttons. /// represented as ordinary `url` buttons.
pub reply_markup: Option<InlineKeyboardMarkup>, pub reply_markup: Option<InlineKeyboardMarkup>,
/// `true`, if the message is sent to a forum topic.
// FIXME: `is_topic_message` is included even in service messages, like ForumTopicCreated.
// more this to `Message`
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_topic_message: bool,
/// `true`, if the message is a channel post that was automatically /// `true`, if the message is a channel post that was automatically
/// forwarded to the connected discussion group. /// forwarded to the connected discussion group.
#[serde(default, skip_serializing_if = "std::ops::Not::not")] #[serde(default, skip_serializing_if = "std::ops::Not::not")]
@ -708,12 +706,10 @@ mod getters {
/// [telegram docs]: https://core.telegram.org/bots/api#message /// [telegram docs]: https://core.telegram.org/bots/api#message
impl Message { impl Message {
/// Returns the user who sent the message. /// Returns the user who sent the message.
#[deprecated(since = "0.13.0", note = "use `.from` field instead")]
#[must_use] #[must_use]
pub fn from(&self) -> Option<&User> { pub fn from(&self) -> Option<&User> {
match &self.kind { self.from.as_ref()
Common(MessageCommon { from, .. }) => from.as_ref(),
_ => None,
}
} }
#[must_use] #[must_use]
@ -724,12 +720,10 @@ mod getters {
} }
} }
#[deprecated(since = "0.13.0", note = "use `.sender_chat` field instead")]
#[must_use] #[must_use]
pub fn sender_chat(&self) -> Option<&Chat> { pub fn sender_chat(&self) -> Option<&Chat> {
match &self.kind { self.sender_chat.as_ref()
Common(MessageCommon { sender_chat, .. }) => sender_chat.as_ref(),
_ => None,
}
} }
#[must_use] #[must_use]
@ -1746,8 +1740,8 @@ impl Message {
// Lets just hope we didn't forget something here... // Lets just hope we didn't forget something here...
self.from() self.from
.into_iter() .iter()
.chain(self.via_bot.as_ref()) .chain(self.via_bot.as_ref())
.chain(self.chat.mentioned_users_rec()) .chain(self.chat.mentioned_users_rec())
.chain(flatten(self.reply_to_message().map(Self::mentioned_users_rec))) .chain(flatten(self.reply_to_message().map(Self::mentioned_users_rec)))
@ -1844,7 +1838,10 @@ mod tests {
Message { Message {
id: MessageId(198283), id: MessageId(198283),
thread_id: None, thread_id: None,
from: None,
sender_chat: None,
date: chrono::DateTime::from_timestamp(1567927221, 0).unwrap(), date: chrono::DateTime::from_timestamp(1567927221, 0).unwrap(),
is_topic_message: false,
chat: Chat { chat: Chat {
id: ChatId(250918540), id: ChatId(250918540),
kind: ChatKind::Private(ChatPrivate { kind: ChatKind::Private(ChatPrivate {
@ -2101,9 +2098,9 @@ mod tests {
chat_full_info: ChatFullInfo::default(), chat_full_info: ChatFullInfo::default(),
}; };
assert!(message.from().unwrap().is_anonymous()); assert!(message.from.as_ref().unwrap().is_anonymous());
assert_eq!(message.author_signature().unwrap(), "TITLE2"); assert_eq!(message.author_signature().unwrap(), "TITLE2");
assert_eq!(message.sender_chat().unwrap(), &group); assert_eq!(message.sender_chat.as_ref().unwrap(), &group);
assert_eq!(&message.chat, &group); assert_eq!(&message.chat, &group);
assert_eq!(message.forward_from_chat().unwrap(), &group); assert_eq!(message.forward_from_chat().unwrap(), &group);
assert_eq!(message.forward_author_signature().unwrap(), "TITLE"); assert_eq!(message.forward_author_signature().unwrap(), "TITLE");
@ -2126,7 +2123,7 @@ mod tests {
assert_eq!(message.migrate_to_chat_id(), Some(&new)); assert_eq!(message.migrate_to_chat_id(), Some(&new));
// The user who initialized the migration // The user who initialized the migration
assert!(message.from().is_some()); assert!(message.from.is_some());
// Migration from a common group // Migration from a common group
let json = r#"{"chat":{"id":-1001555296434,"title":"test","type":"supergroup"},"date":1629404938,"from":{"first_name":"Group","id":1087968824,"is_bot":true,"username":"GroupAnonymousBot"},"message_id":1,"migrate_from_chat_id":-599075523,"sender_chat":{"id":-1001555296434,"title":"test","type":"supergroup"}}"#; let json = r#"{"chat":{"id":-1001555296434,"title":"test","type":"supergroup"},"date":1629404938,"from":{"first_name":"Group","id":1087968824,"is_bot":true,"username":"GroupAnonymousBot"},"message_id":1,"migrate_from_chat_id":-599075523,"sender_chat":{"id":-1001555296434,"title":"test","type":"supergroup"}}"#;
@ -2137,10 +2134,10 @@ mod tests {
assert_eq!(message.migrate_from_chat_id(), Some(&old)); assert_eq!(message.migrate_from_chat_id(), Some(&old));
// Anonymous bot // Anonymous bot
assert!(message.from().is_some()); assert!(message.from.is_some());
// The chat to which the group migrated // The chat to which the group migrated
assert!(message.sender_chat().is_some()); assert!(message.sender_chat.is_some());
} }
/// Regression test for <https://github.com/teloxide/teloxide/issues/481> /// Regression test for <https://github.com/teloxide/teloxide/issues/481>
@ -2296,7 +2293,9 @@ mod tests {
"message_thread_id":4 "message_thread_id":4
}"#; }"#;
let _: Message = serde_json::from_str(json).unwrap(); let message: Message = serde_json::from_str(json).unwrap();
// https://github.com/teloxide/teloxide/issues/945
assert!(message.from.is_some());
} }
#[test] #[test]
@ -2480,6 +2479,28 @@ mod tests {
giveaway_message: Some(Box::new(Message { giveaway_message: Some(Box::new(Message {
id: MessageId(24), id: MessageId(24),
thread_id: None, thread_id: None,
from: None,
sender_chat: Some(Chat {
id: ChatId(-1002236736395),
kind: ChatKind::Public(ChatPublic {
title: Some("Test".to_owned()),
kind: PublicChatKind::Channel(PublicChatChannel {
linked_chat_id: None,
username: None
}),
description: None,
invite_link: None,
has_protected_content: None
}),
chat_full_info: ChatFullInfo::default(),
available_reactions: None,
photo: None,
has_aggressive_anti_spam_enabled: false,
has_hidden_members: false,
message_auto_delete_time: None,
pinned_message: None
}),
is_topic_message: false,
date: DateTime::from_timestamp(1721161230, 0).unwrap(), date: DateTime::from_timestamp(1721161230, 0).unwrap(),
chat: Chat { chat: Chat {
id: ChatId(-1002236736395), id: ChatId(-1002236736395),

View file

@ -156,7 +156,9 @@ impl Update {
use UpdateKind::*; use UpdateKind::*;
let from = match &self.kind { let from = match &self.kind {
Message(m) | EditedMessage(m) | ChannelPost(m) | EditedChannelPost(m) => m.from()?, Message(m) | EditedMessage(m) | ChannelPost(m) | EditedChannelPost(m) => {
m.from.as_ref()?
}
CallbackQuery(query) => &query.from, CallbackQuery(query) => &query.from,
ChosenInlineResult(chosen) => &chosen.from, ChosenInlineResult(chosen) => &chosen.from,
@ -510,6 +512,18 @@ mod test {
via_bot: None, via_bot: None,
id: MessageId(6557), id: MessageId(6557),
thread_id: None, thread_id: None,
from: Some(User {
id: UserId(218_485_655),
is_bot: false,
first_name: String::from("Waffle"),
last_name: None,
username: Some(String::from("WaffleLapkin")),
language_code: Some(String::from("en")),
is_premium: false,
added_to_attachment_menu: false,
}),
sender_chat: None,
is_topic_message: false,
date, date,
chat: Chat { chat: Chat {
id: ChatId(218_485_655), id: ChatId(218_485_655),
@ -530,16 +544,6 @@ mod test {
chat_full_info: ChatFullInfo::default(), chat_full_info: ChatFullInfo::default(),
}, },
kind: MessageKind::Common(MessageCommon { kind: MessageKind::Common(MessageCommon {
from: Some(User {
id: UserId(218_485_655),
is_bot: false,
first_name: String::from("Waffle"),
last_name: None,
username: Some(String::from("WaffleLapkin")),
language_code: Some(String::from("en")),
is_premium: false,
added_to_attachment_menu: false,
}),
reply_to_message: None, reply_to_message: None,
forward_origin: None, forward_origin: None,
quote: None, quote: None,
@ -556,9 +560,7 @@ mod test {
}), }),
}), }),
reply_markup: None, reply_markup: None,
sender_chat: None,
author_signature: None, author_signature: None,
is_topic_message: false,
is_automatic_forward: false, is_automatic_forward: false,
has_protected_content: false, has_protected_content: false,
}), }),

View file

@ -79,7 +79,7 @@ async fn kick_user(bot: Bot, msg: Message) -> ResponseResult<()> {
match msg.reply_to_message() { match msg.reply_to_message() {
Some(replied) => { Some(replied) => {
// bot.unban_chat_member can also kicks a user from a group chat. // bot.unban_chat_member can also kicks a user from a group chat.
bot.unban_chat_member(msg.chat.id, replied.from().unwrap().id).await?; bot.unban_chat_member(msg.chat.id, replied.from.as_ref().unwrap().id).await?;
} }
None => { None => {
bot.send_message(msg.chat.id, "Use this command in reply to another message").await?; bot.send_message(msg.chat.id, "Use this command in reply to another message").await?;
@ -94,7 +94,7 @@ async fn ban_user(bot: Bot, msg: Message, time: Duration) -> ResponseResult<()>
Some(replied) => { Some(replied) => {
bot.kick_chat_member( bot.kick_chat_member(
msg.chat.id, msg.chat.id,
replied.from().expect("Must be MessageKind::Common").id, replied.from.as_ref().expect("Must be MessageKind::Common").id,
) )
.until_date(msg.date + time) .until_date(msg.date + time)
.await?; .await?;
@ -113,7 +113,7 @@ async fn mute_user(bot: Bot, msg: Message, time: Duration) -> ResponseResult<()>
Some(replied) => { Some(replied) => {
bot.restrict_chat_member( bot.restrict_chat_member(
msg.chat.id, msg.chat.id,
replied.from().expect("Must be MessageKind::Common").id, replied.from.as_ref().expect("Must be MessageKind::Common").id,
ChatPermissions::empty(), ChatPermissions::empty(),
) )
.until_date(msg.date + time) .until_date(msg.date + time)

View file

@ -34,7 +34,7 @@ async fn main() {
.branch( .branch(
// Filter a maintainer by a user ID. // Filter a maintainer by a user ID.
dptree::filter(|cfg: ConfigParameters, msg: Message| { dptree::filter(|cfg: ConfigParameters, msg: Message| {
msg.from().map(|user| user.id == cfg.bot_maintainer).unwrap_or_default() msg.from.map(|user| user.id == cfg.bot_maintainer).unwrap_or_default()
}) })
.filter_command::<MaintainerCommands>() .filter_command::<MaintainerCommands>()
.endpoint(|msg: Message, bot: Bot, cmd: MaintainerCommands| async move { .endpoint(|msg: Message, bot: Bot, cmd: MaintainerCommands| async move {
@ -125,7 +125,7 @@ async fn simple_commands_handler(
) -> Result<(), teloxide::RequestError> { ) -> Result<(), teloxide::RequestError> {
let text = match cmd { let text = match cmd {
SimpleCommand::Help => { SimpleCommand::Help => {
if msg.from().unwrap().id == cfg.bot_maintainer { if msg.from.unwrap().id == cfg.bot_maintainer {
format!( format!(
"{}\n\n{}", "{}\n\n{}",
SimpleCommand::descriptions(), SimpleCommand::descriptions(),
@ -138,7 +138,7 @@ async fn simple_commands_handler(
} }
} }
SimpleCommand::Maintainer => { SimpleCommand::Maintainer => {
if msg.from().unwrap().id == cfg.bot_maintainer { if msg.from.as_ref().unwrap().id == cfg.bot_maintainer {
"Maintainer is you!".into() "Maintainer is you!".into()
} else if let Some(username) = cfg.maintainer_username { } else if let Some(username) = cfg.maintainer_username {
format!("Maintainer is @{username}") format!("Maintainer is @{username}")
@ -147,7 +147,7 @@ async fn simple_commands_handler(
} }
} }
SimpleCommand::MyId => { SimpleCommand::MyId => {
format!("{}", msg.from().unwrap().id) format!("{}", msg.from.unwrap().id)
} }
}; };

View file

@ -1,4 +1,6 @@
#![allow(clippy::redundant_closure_call)] #![allow(clippy::redundant_closure_call)]
// Required for the `filter_from` currently
#![allow(deprecated)]
use dptree::{di::DependencyMap, Handler}; use dptree::{di::DependencyMap, Handler};
@ -68,6 +70,7 @@ macro_rules! define_message_ext {
} }
} }
// FIXME: change macro so that we can filter things without getters
// May be expanded in the future. // May be expanded in the future.
define_message_ext! { define_message_ext! {
// MessageCommon // MessageCommon