mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 06:25:10 +01:00
Add MessageReactionUpdated
and MessageReactionCountUpdated
structs
This commit is contained in:
parent
77882d97f7
commit
50768a1af0
7 changed files with 390 additions and 15 deletions
|
@ -92,6 +92,8 @@ pub use message_auto_delete_timer_changed::*;
|
|||
pub use message_entity::*;
|
||||
pub use message_id::*;
|
||||
pub use message_origin::*;
|
||||
pub use message_reaction_count_updated::*;
|
||||
pub use message_reaction_updated::*;
|
||||
pub use order_info::*;
|
||||
pub use parse_mode::*;
|
||||
pub use passport_data::*;
|
||||
|
@ -208,6 +210,8 @@ mod message_auto_delete_timer_changed;
|
|||
mod message_entity;
|
||||
mod message_id;
|
||||
mod message_origin;
|
||||
mod message_reaction_count_updated;
|
||||
mod message_reaction_updated;
|
||||
mod order_info;
|
||||
mod parse_mode;
|
||||
mod photo_size;
|
||||
|
|
|
@ -7,6 +7,8 @@ pub enum AllowedUpdate {
|
|||
EditedMessage,
|
||||
ChannelPost,
|
||||
EditedChannelPost,
|
||||
MessageReaction,
|
||||
MessageReactionCount,
|
||||
InlineQuery,
|
||||
ChosenInlineResult,
|
||||
CallbackQuery,
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{Chat, MessageId, ReactionType};
|
||||
|
||||
/// This object represents reaction changes on a message with anonymous
|
||||
/// reactions.
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MessageReactionCountUpdated {
|
||||
/// The chat containing the message
|
||||
pub chat: Chat,
|
||||
|
||||
/// Unique message identifier inside the chat
|
||||
#[serde(flatten)]
|
||||
pub message_id: MessageId,
|
||||
|
||||
/// Date of the change in Unix time
|
||||
#[serde(with = "crate::types::serde_date_from_unix_timestamp")]
|
||||
pub date: DateTime<Utc>,
|
||||
|
||||
/// List of reactions that are present on the message
|
||||
pub reactions: Vec<ReactionCount>,
|
||||
}
|
||||
|
||||
/// Represents a reaction added to a message along with the number of times it
|
||||
/// was added.
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ReactionCount {
|
||||
/// Type of the reaction
|
||||
pub r#type: ReactionType,
|
||||
|
||||
/// Number of times the reaction was added
|
||||
pub total_count: u64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deserialize() {
|
||||
let data = r#"
|
||||
{
|
||||
"chat": {
|
||||
"id": -1002236736395,
|
||||
"title": "Test",
|
||||
"type": "channel"
|
||||
},
|
||||
"message_id": 36,
|
||||
"date": 1721306391,
|
||||
"reactions": [
|
||||
{
|
||||
"type": {
|
||||
"type": "emoji",
|
||||
"emoji": "🗿"
|
||||
},
|
||||
"total_count": 2
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"type": "emoji",
|
||||
"emoji": "🌭"
|
||||
},
|
||||
"total_count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
"#;
|
||||
serde_json::from_str::<MessageReactionCountUpdated>(data).unwrap();
|
||||
}
|
||||
}
|
82
crates/teloxide-core/src/types/message_reaction_updated.rs
Normal file
82
crates/teloxide-core/src/types/message_reaction_updated.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{Chat, MessageId, ReactionType, User};
|
||||
|
||||
/// This object represents a change of a reaction on a message performed by a
|
||||
/// user.
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MessageReactionUpdated {
|
||||
/// The chat containing the message the user reacted to
|
||||
pub chat: Chat,
|
||||
|
||||
/// Unique identifier of the message inside the chat
|
||||
#[serde(flatten)]
|
||||
pub message_id: MessageId,
|
||||
|
||||
/// The user that changed the reaction, if the user isn't anonymous
|
||||
pub user: Option<User>,
|
||||
|
||||
/// The chat on behalf of which the reaction was changed, if the user is
|
||||
/// anonymous
|
||||
pub actor_chat: Option<Chat>,
|
||||
|
||||
/// Date of the change in Unix time
|
||||
#[serde(with = "crate::types::serde_date_from_unix_timestamp")]
|
||||
pub date: DateTime<Utc>,
|
||||
|
||||
/// Previous list of reaction types that were set by the user
|
||||
pub old_reaction: Vec<ReactionType>,
|
||||
|
||||
/// New list of reaction types that have been set by the user
|
||||
pub new_reaction: Vec<ReactionType>,
|
||||
}
|
||||
|
||||
impl MessageReactionUpdated {
|
||||
#[must_use]
|
||||
pub fn actor_chat(&self) -> Option<&Chat> {
|
||||
self.actor_chat.as_ref()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user(&self) -> Option<&User> {
|
||||
self.user.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deserialize() {
|
||||
let data = r#"
|
||||
{
|
||||
"chat": {
|
||||
"id": -1002184233434,
|
||||
"title": "Test",
|
||||
"type": "supergroup"
|
||||
},
|
||||
"message_id": 35,
|
||||
"user": {
|
||||
"id": 1459074222,
|
||||
"is_bot": false,
|
||||
"first_name": "shadowchain",
|
||||
"username": "shdwchn10",
|
||||
"language_code": "en",
|
||||
"is_premium": true
|
||||
},
|
||||
"date": 1721306082,
|
||||
"old_reaction": [],
|
||||
"new_reaction": [
|
||||
{
|
||||
"type": "emoji",
|
||||
"emoji": "🌭"
|
||||
}
|
||||
]
|
||||
}
|
||||
"#;
|
||||
serde_json::from_str::<MessageReactionUpdated>(data).unwrap();
|
||||
}
|
||||
}
|
|
@ -4,7 +4,8 @@ use serde_json::Value;
|
|||
|
||||
use crate::types::{
|
||||
CallbackQuery, Chat, ChatJoinRequest, ChatMemberUpdated, ChosenInlineResult, InlineQuery,
|
||||
Message, Poll, PollAnswer, PreCheckoutQuery, ShippingQuery, User,
|
||||
Message, MessageReactionCountUpdated, MessageReactionUpdated, Poll, PollAnswer,
|
||||
PreCheckoutQuery, ShippingQuery, User,
|
||||
};
|
||||
|
||||
/// This [object] represents an incoming update.
|
||||
|
@ -59,6 +60,24 @@ pub enum UpdateKind {
|
|||
/// New version of a channel post that is known to the bot and was edited.
|
||||
EditedChannelPost(Message),
|
||||
|
||||
/// A reaction to a message was changed by a user. The bot must be an
|
||||
/// administrator in the chat and must explicitly specify
|
||||
/// [`AllowedUpdate::MessageReaction`] in the list of `allowed_updates`
|
||||
/// to receive these updates. The update isn't received for reactions
|
||||
/// set by bots.
|
||||
///
|
||||
/// [`AllowedUpdate::MessageReaction`]: crate::types::AllowedUpdate::MessageReaction
|
||||
MessageReaction(MessageReactionUpdated),
|
||||
|
||||
/// Reactions to a message with anonymous reactions were changed. The bot
|
||||
/// must be an administrator in the chat and must explicitly specify
|
||||
/// [`AllowedUpdate::MessageReactionCount`] in the list of `allowed_updates`
|
||||
/// to receive these updates. The updates are grouped and can be sent
|
||||
/// with delay up to a few minutes.
|
||||
///
|
||||
/// [`AllowedUpdate::MessageReactionCount`]: crate::types::AllowedUpdate::MessageReactionCount
|
||||
MessageReactionCount(MessageReactionCountUpdated),
|
||||
|
||||
/// New incoming [inline] query.
|
||||
///
|
||||
/// [inline]: https://core.telegram.org/bots/api#inline-mode
|
||||
|
@ -133,6 +152,7 @@ impl Update {
|
|||
|
||||
CallbackQuery(query) => &query.from,
|
||||
ChosenInlineResult(chosen) => &chosen.from,
|
||||
MessageReaction(reaction) => return reaction.user(),
|
||||
InlineQuery(query) => &query.from,
|
||||
ShippingQuery(query) => &query.from,
|
||||
PreCheckoutQuery(query) => &query.from,
|
||||
|
@ -141,7 +161,7 @@ impl Update {
|
|||
MyChatMember(m) | ChatMember(m) => &m.from,
|
||||
ChatJoinRequest(r) => &r.from,
|
||||
|
||||
Poll(_) | Error(_) => return None,
|
||||
MessageReactionCount(_) | Poll(_) | Error(_) => return None,
|
||||
};
|
||||
|
||||
Some(from)
|
||||
|
@ -191,6 +211,13 @@ impl Update {
|
|||
| UpdateKind::ChannelPost(message)
|
||||
| UpdateKind::EditedChannelPost(message) => i0(message.mentioned_users()),
|
||||
|
||||
UpdateKind::MessageReaction(answer) => {
|
||||
if let Some(user) = answer.user() {
|
||||
return i1(once(user));
|
||||
}
|
||||
i6(empty())
|
||||
}
|
||||
|
||||
UpdateKind::InlineQuery(query) => i1(once(&query.from)),
|
||||
UpdateKind::ChosenInlineResult(query) => i1(once(&query.from)),
|
||||
UpdateKind::CallbackQuery(query) => i2(query.mentioned_users()),
|
||||
|
@ -209,7 +236,7 @@ impl Update {
|
|||
i4(member.mentioned_users())
|
||||
}
|
||||
UpdateKind::ChatJoinRequest(request) => i5(request.mentioned_users()),
|
||||
UpdateKind::Error(_) => i6(empty()),
|
||||
UpdateKind::MessageReactionCount(_) | UpdateKind::Error(_) => i6(empty()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +251,8 @@ impl Update {
|
|||
ChatMember(m) => &m.chat,
|
||||
MyChatMember(m) => &m.chat,
|
||||
ChatJoinRequest(c) => &c.chat,
|
||||
MessageReaction(r) => &r.chat,
|
||||
MessageReactionCount(r) => &r.chat,
|
||||
|
||||
InlineQuery(_)
|
||||
| ChosenInlineResult(_)
|
||||
|
@ -293,6 +322,14 @@ impl<'de> Deserialize<'de> for UpdateKind {
|
|||
"edited_channel_post" => {
|
||||
map.next_value::<Message>().ok().map(UpdateKind::EditedChannelPost)
|
||||
}
|
||||
"message_reaction" => map
|
||||
.next_value::<MessageReactionUpdated>()
|
||||
.ok()
|
||||
.map(UpdateKind::MessageReaction),
|
||||
"message_reaction_count" => map
|
||||
.next_value::<MessageReactionCountUpdated>()
|
||||
.ok()
|
||||
.map(UpdateKind::MessageReactionCount),
|
||||
"inline_query" => {
|
||||
map.next_value::<InlineQuery>().ok().map(UpdateKind::InlineQuery)
|
||||
}
|
||||
|
@ -351,27 +388,33 @@ impl Serialize for UpdateKind {
|
|||
UpdateKind::EditedChannelPost(v) => {
|
||||
s.serialize_newtype_variant(name, 3, "edited_channel_post", v)
|
||||
}
|
||||
UpdateKind::InlineQuery(v) => s.serialize_newtype_variant(name, 4, "inline_query", v),
|
||||
UpdateKind::MessageReaction(v) => {
|
||||
s.serialize_newtype_variant(name, 4, "message_reaction", v)
|
||||
}
|
||||
UpdateKind::MessageReactionCount(v) => {
|
||||
s.serialize_newtype_variant(name, 5, "message_reaction_count", v)
|
||||
}
|
||||
UpdateKind::InlineQuery(v) => s.serialize_newtype_variant(name, 6, "inline_query", v),
|
||||
UpdateKind::ChosenInlineResult(v) => {
|
||||
s.serialize_newtype_variant(name, 5, "chosen_inline_result", v)
|
||||
s.serialize_newtype_variant(name, 7, "chosen_inline_result", v)
|
||||
}
|
||||
UpdateKind::CallbackQuery(v) => {
|
||||
s.serialize_newtype_variant(name, 6, "callback_query", v)
|
||||
s.serialize_newtype_variant(name, 8, "callback_query", v)
|
||||
}
|
||||
UpdateKind::ShippingQuery(v) => {
|
||||
s.serialize_newtype_variant(name, 7, "shipping_query", v)
|
||||
s.serialize_newtype_variant(name, 9, "shipping_query", v)
|
||||
}
|
||||
UpdateKind::PreCheckoutQuery(v) => {
|
||||
s.serialize_newtype_variant(name, 8, "pre_checkout_query", v)
|
||||
s.serialize_newtype_variant(name, 10, "pre_checkout_query", v)
|
||||
}
|
||||
UpdateKind::Poll(v) => s.serialize_newtype_variant(name, 9, "poll", v),
|
||||
UpdateKind::PollAnswer(v) => s.serialize_newtype_variant(name, 10, "poll_answer", v),
|
||||
UpdateKind::Poll(v) => s.serialize_newtype_variant(name, 11, "poll", v),
|
||||
UpdateKind::PollAnswer(v) => s.serialize_newtype_variant(name, 12, "poll_answer", v),
|
||||
UpdateKind::MyChatMember(v) => {
|
||||
s.serialize_newtype_variant(name, 11, "my_chat_member", v)
|
||||
s.serialize_newtype_variant(name, 13, "my_chat_member", v)
|
||||
}
|
||||
UpdateKind::ChatMember(v) => s.serialize_newtype_variant(name, 12, "chat_member", v),
|
||||
UpdateKind::ChatMember(v) => s.serialize_newtype_variant(name, 14, "chat_member", v),
|
||||
UpdateKind::ChatJoinRequest(v) => {
|
||||
s.serialize_newtype_variant(name, 13, "chat_join_request", v)
|
||||
s.serialize_newtype_variant(name, 15, "chat_join_request", v)
|
||||
}
|
||||
UpdateKind::Error(v) => v.serialize(s),
|
||||
}
|
||||
|
@ -385,8 +428,10 @@ fn empty_error() -> UpdateKind {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::types::{
|
||||
Chat, ChatFullInfo, ChatId, ChatKind, ChatPrivate, MediaKind, MediaText, Message,
|
||||
MessageCommon, MessageId, MessageKind, Update, UpdateId, UpdateKind, User, UserId,
|
||||
Chat, ChatFullInfo, ChatId, ChatKind, ChatPrivate, ChatPublic, MediaKind, MediaText,
|
||||
Message, MessageCommon, MessageId, MessageKind, MessageReactionCountUpdated,
|
||||
MessageReactionUpdated, PublicChatChannel, PublicChatKind, PublicChatSupergroup,
|
||||
ReactionCount, ReactionType, ReactionTypeKind, Update, UpdateId, UpdateKind, User, UserId,
|
||||
};
|
||||
|
||||
use chrono::DateTime;
|
||||
|
@ -726,4 +771,169 @@ mod test {
|
|||
_ => panic!("Expected `MyChatMember`"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_reaction_updated() {
|
||||
let json = r#"
|
||||
{
|
||||
"update_id": 71651249,
|
||||
"message_reaction": {
|
||||
"chat": {
|
||||
"id": -1002184233434,
|
||||
"title": "Test",
|
||||
"type": "supergroup"
|
||||
},
|
||||
"message_id": 35,
|
||||
"user": {
|
||||
"id": 1459074222,
|
||||
"is_bot": false,
|
||||
"first_name": "shadowchain",
|
||||
"username": "shdwchn10",
|
||||
"language_code": "en",
|
||||
"is_premium": true
|
||||
},
|
||||
"date": 1721306082,
|
||||
"old_reaction": [],
|
||||
"new_reaction": [
|
||||
{
|
||||
"type": "emoji",
|
||||
"emoji": "🌭"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let expected = Update {
|
||||
id: UpdateId(71651249),
|
||||
kind: UpdateKind::MessageReaction(MessageReactionUpdated {
|
||||
chat: Chat {
|
||||
id: ChatId(-1002184233434),
|
||||
kind: ChatKind::Public(ChatPublic {
|
||||
title: Some("Test".to_owned()),
|
||||
kind: PublicChatKind::Supergroup(PublicChatSupergroup {
|
||||
username: None,
|
||||
active_usernames: None,
|
||||
is_forum: false,
|
||||
sticker_set_name: None,
|
||||
can_set_sticker_set: None,
|
||||
permissions: None,
|
||||
slow_mode_delay: None,
|
||||
linked_chat_id: None,
|
||||
location: None,
|
||||
join_to_send_messages: None,
|
||||
join_by_request: None,
|
||||
}),
|
||||
description: None,
|
||||
invite_link: None,
|
||||
has_protected_content: None,
|
||||
}),
|
||||
photo: None,
|
||||
pinned_message: None,
|
||||
message_auto_delete_time: None,
|
||||
has_hidden_members: false,
|
||||
has_aggressive_anti_spam_enabled: false,
|
||||
chat_full_info: ChatFullInfo { emoji_status_expiration_date: None },
|
||||
},
|
||||
message_id: MessageId(35),
|
||||
user: Some(User {
|
||||
id: UserId(1459074222),
|
||||
is_bot: false,
|
||||
first_name: "shadowchain".to_owned(),
|
||||
last_name: None,
|
||||
username: Some("shdwchn10".to_owned()),
|
||||
language_code: Some("en".to_owned()),
|
||||
is_premium: true,
|
||||
added_to_attachment_menu: false,
|
||||
}),
|
||||
actor_chat: None,
|
||||
date: DateTime::from_timestamp(1721306082, 0).unwrap(),
|
||||
old_reaction: vec![],
|
||||
new_reaction: vec![ReactionType {
|
||||
kind: ReactionTypeKind::Emoji { emoji: "🌭".to_owned() },
|
||||
}],
|
||||
}),
|
||||
};
|
||||
|
||||
let actual = serde_json::from_str::<Update>(json).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_reaction_count_updated() {
|
||||
let json = r#"
|
||||
{
|
||||
"update_id": 71651251,
|
||||
"message_reaction_count": {
|
||||
"chat": {
|
||||
"id": -1002236736395,
|
||||
"title": "Test",
|
||||
"type": "channel"
|
||||
},
|
||||
"message_id": 36,
|
||||
"date": 1721306391,
|
||||
"reactions": [
|
||||
{
|
||||
"type": {
|
||||
"type": "emoji",
|
||||
"emoji": "🗿"
|
||||
},
|
||||
"total_count": 2
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"type": "emoji",
|
||||
"emoji": "🌭"
|
||||
},
|
||||
"total_count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let expected = Update {
|
||||
id: UpdateId(71651251),
|
||||
kind: UpdateKind::MessageReactionCount(MessageReactionCountUpdated {
|
||||
chat: Chat {
|
||||
id: ChatId(-1002236736395),
|
||||
kind: ChatKind::Public(ChatPublic {
|
||||
title: Some("Test".to_owned()),
|
||||
kind: PublicChatKind::Channel(PublicChatChannel {
|
||||
username: None,
|
||||
linked_chat_id: None,
|
||||
}),
|
||||
description: None,
|
||||
invite_link: None,
|
||||
has_protected_content: None,
|
||||
}),
|
||||
photo: None,
|
||||
pinned_message: None,
|
||||
message_auto_delete_time: None,
|
||||
has_hidden_members: false,
|
||||
has_aggressive_anti_spam_enabled: false,
|
||||
chat_full_info: ChatFullInfo { emoji_status_expiration_date: None },
|
||||
},
|
||||
message_id: MessageId(36),
|
||||
date: DateTime::from_timestamp(1721306391, 0).unwrap(),
|
||||
reactions: vec![
|
||||
ReactionCount {
|
||||
r#type: ReactionType {
|
||||
kind: ReactionTypeKind::Emoji { emoji: "🗿".to_owned() },
|
||||
},
|
||||
total_count: 2,
|
||||
},
|
||||
ReactionCount {
|
||||
r#type: ReactionType {
|
||||
kind: ReactionTypeKind::Emoji { emoji: "🌭".to_owned() },
|
||||
},
|
||||
total_count: 1,
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
|
||||
let actual = serde_json::from_str::<Update>(json).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,6 +149,8 @@ define_update_ext! {
|
|||
(filter_edited_message, UpdateKind::EditedMessage, EditedMessage),
|
||||
(filter_channel_post, UpdateKind::ChannelPost, ChannelPost),
|
||||
(filter_edited_channel_post, UpdateKind::EditedChannelPost, EditedChannelPost),
|
||||
(filter_message_reaction_updated, UpdateKind::MessageReaction, MessageReaction),
|
||||
(filter_message_reaction_count_updated, UpdateKind::MessageReactionCount, MessageReactionCount),
|
||||
(filter_inline_query, UpdateKind::InlineQuery, InlineQuery),
|
||||
(filter_chosen_inline_result, UpdateKind::ChosenInlineResult, ChosenInlineResult),
|
||||
(filter_callback_query, UpdateKind::CallbackQuery, CallbackQuery),
|
||||
|
|
|
@ -65,6 +65,8 @@ impl EventKind for Kind {
|
|||
EditedMessage,
|
||||
ChannelPost,
|
||||
EditedChannelPost,
|
||||
MessageReaction,
|
||||
MessageReactionCount,
|
||||
InlineQuery,
|
||||
ChosenInlineResult,
|
||||
CallbackQuery,
|
||||
|
|
Loading…
Reference in a new issue