From 49e5d45ac9b5ec95ae7702752ccf531e9590304b Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 18 Nov 2021 22:51:58 +0100 Subject: [PATCH] events: Improve usability and docs of `m.room.message` reply constructors --- crates/ruma-events/src/room/message.rs | 23 ++++-- crates/ruma-events/src/room/message/reply.rs | 76 ++++++++++++++++---- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/crates/ruma-events/src/room/message.rs b/crates/ruma-events/src/room/message.rs index 394f0862..b5f0633c 100644 --- a/crates/ruma-events/src/room/message.rs +++ b/crates/ruma-events/src/room/message.rs @@ -20,6 +20,8 @@ pub mod feedback; mod relation_serde; mod reply; +pub use reply::ReplyBaseEvent; + /// The content of an `m.room.message` event. /// /// This event is used when sending messages in a room. @@ -81,20 +83,28 @@ impl RoomMessageEventContent { } /// Creates a plain text reply to a message. - pub fn text_reply_plain(reply: impl fmt::Display, original_message: &RoomMessageEvent) -> Self { + pub fn text_reply_plain( + reply: impl fmt::Display, + original_message: &impl ReplyBaseEvent, + ) -> Self { let quoted = reply::get_plain_quote_fallback(original_message); let body = format!("{}\n\n{}", quoted, reply); Self { relates_to: Some(Relation::Reply { - in_reply_to: InReplyTo { event_id: original_message.event_id.clone() }, + in_reply_to: InReplyTo { event_id: original_message.event_id().clone() }, }), ..Self::text_plain(body) } } /// Creates a html text reply to a message. + /// + /// Different from `text_reply_plain`, this constructor requires specifically a + /// [`RoomMessageEvent`] since it creates a permalink to the previous message, for which the + /// room ID is required. If you want to reply to a [`SyncRoomMessageEvent`], you have to convert + /// it first by calling [`.into_full_event()`][crate::SyncMessageEvent::into_full_event]. pub fn text_reply_html( reply: impl fmt::Display, html_reply: impl fmt::Display, @@ -115,16 +125,21 @@ impl RoomMessageEventContent { } /// Creates a plain text notice reply to a message. + /// + /// Different from `notice_reply_plain`, this constructor requires specifically a + /// [`RoomMessageEvent`] since it creates a permalink to the previous message, for which the + /// room ID is required. If you want to reply to a [`SyncRoomMessageEvent`], you have to convert + /// it first by calling [`.into_full_event()`][crate::SyncMessageEvent::into_full_event]. pub fn notice_reply_plain( reply: impl fmt::Display, - original_message: &RoomMessageEvent, + original_message: &impl ReplyBaseEvent, ) -> Self { let quoted = reply::get_plain_quote_fallback(original_message); let body = format!("{}\n\n{}", quoted, reply); Self { relates_to: Some(Relation::Reply { - in_reply_to: InReplyTo { event_id: original_message.event_id.clone() }, + in_reply_to: InReplyTo { event_id: original_message.event_id().clone() }, }), ..Self::notice_plain(body) } diff --git a/crates/ruma-events/src/room/message/reply.rs b/crates/ruma-events/src/room/message/reply.rs index 44c19039..882311ef 100644 --- a/crates/ruma-events/src/room/message/reply.rs +++ b/crates/ruma-events/src/room/message/reply.rs @@ -1,42 +1,90 @@ use indoc::formatdoc; +use ruma_identifiers::{EventId, UserId}; -use super::{FormattedBody, MessageType, RoomMessageEvent}; +use super::{ + FormattedBody, MessageType, RoomMessageEvent, RoomMessageEventContent, SyncRoomMessageEvent, +}; -pub fn get_plain_quote_fallback(original_message: &RoomMessageEvent) -> String { - match &original_message.content.msgtype { +/// An event that can be replied to. +/// +/// This trait only exists to allow the plain-text `reply` constructors on `MessageEventContent` to +/// use either a [`RoomMessageEvent`] or a [`SyncRoomMessageEvent`] as the event being replied to. +pub trait ReplyBaseEvent { + #[doc(hidden)] + fn event_id(&self) -> &EventId; + + #[doc(hidden)] + fn sender(&self) -> &UserId; + + #[doc(hidden)] + fn content(&self) -> &RoomMessageEventContent; +} + +impl ReplyBaseEvent for RoomMessageEvent { + fn event_id(&self) -> &EventId { + &self.event_id + } + + fn sender(&self) -> &UserId { + &self.sender + } + + fn content(&self) -> &RoomMessageEventContent { + &self.content + } +} + +impl ReplyBaseEvent for SyncRoomMessageEvent { + fn event_id(&self) -> &EventId { + &self.event_id + } + + fn sender(&self) -> &UserId { + &self.sender + } + + fn content(&self) -> &RoomMessageEventContent { + &self.content + } +} + +pub fn get_plain_quote_fallback(original_message: &impl ReplyBaseEvent) -> String { + let sender = original_message.sender(); + + match &original_message.content().msgtype { MessageType::Audio(_) => { - format!("> <{}> sent an audio file.", original_message.sender) + format!("> <{}> sent an audio file.", sender) } MessageType::Emote(content) => { - format!("> * <{}> {}", original_message.sender, content.body) + format!("> * <{}> {}", sender, content.body) } MessageType::File(_) => { - format!("> <{}> sent a file.", original_message.sender) + format!("> <{}> sent a file.", sender) } MessageType::Image(_) => { - format!("> <{}> sent an image.", original_message.sender) + format!("> <{}> sent an image.", sender) } MessageType::Location(content) => { - format!("> <{}> {}", original_message.sender, content.body) + format!("> <{}> {}", sender, content.body) } MessageType::Notice(content) => { - format!("> <{}> {}", original_message.sender, content.body) + format!("> <{}> {}", sender, content.body) } MessageType::ServerNotice(content) => { - format!("> <{}> {}", original_message.sender, content.body) + format!("> <{}> {}", sender, content.body) } MessageType::Text(content) => { - format!("> <{}> {}", original_message.sender, content.body) + format!("> <{}> {}", sender, content.body) } MessageType::Video(_) => { - format!("> <{}> sent a video.", original_message.sender) + format!("> <{}> sent a video.", sender) } MessageType::_Custom(content) => { - format!("> <{}> {}", original_message.sender, content.body) + format!("> <{}> {}", sender, content.body) } #[cfg(feature = "unstable-pre-spec")] MessageType::VerificationRequest(content) => { - format!("> <{}> {}", original_message.sender, content.body) + format!("> <{}> {}", sender, content.body) } } .replace('\n', "\n> ")