events: Allow to add mentions automatically when generating reply

This commit is contained in:
Kévin Commaille 2023-08-21 17:13:07 +02:00 committed by Kévin Commaille
parent 3fe6ba7f52
commit b2b4c81645
3 changed files with 52 additions and 15 deletions

View File

@ -38,6 +38,8 @@ Breaking changes:
- `RedactedRoomRedactionEventContent`, - `RedactedRoomRedactionEventContent`,
- `RedactedRoomPowerLevelsEventContent`, - `RedactedRoomPowerLevelsEventContent`,
- `RedactedRoomMemberEventContent` - `RedactedRoomMemberEventContent`
- `RoomMessageEventContent::make_reply_to()` and `make_for_thread()` have an extra parameter to
support the recommended behavior for intentional mentions in replies according to Matrix 1.7
Improvements: Improvements:

View File

@ -150,6 +150,7 @@ impl RoomMessageEventContent {
mut self, mut self,
original_message: &OriginalRoomMessageEvent, original_message: &OriginalRoomMessageEvent,
forward_thread: ForwardThread, forward_thread: ForwardThread,
add_mentions: AddMentions,
) -> Self { ) -> Self {
let empty_formatted_body = || FormattedBody::html(String::new()); let empty_formatted_body = || FormattedBody::html(String::new());
@ -205,6 +206,17 @@ impl RoomMessageEventContent {
}; };
self.relates_to = Some(relates_to); self.relates_to = Some(relates_to);
if add_mentions == AddMentions::Yes {
// Copy the mentioned users.
let mut user_ids = match &original_message.content.mentions {
Some(m) => m.user_ids.clone(),
None => Default::default(),
};
// Add the sender.
user_ids.insert(original_message.sender.clone());
self.mentions = Some(Mentions { user_ids, ..Default::default() });
}
self self
} }
@ -227,9 +239,10 @@ impl RoomMessageEventContent {
mut self, mut self,
previous_message: &OriginalRoomMessageEvent, previous_message: &OriginalRoomMessageEvent,
is_reply: ReplyWithinThread, is_reply: ReplyWithinThread,
add_mentions: AddMentions,
) -> Self { ) -> Self {
if is_reply == ReplyWithinThread::Yes { if is_reply == ReplyWithinThread::Yes {
self = self.make_reply_to(previous_message, ForwardThread::No); self = self.make_reply_to(previous_message, ForwardThread::No, add_mentions);
} }
let thread_root = if let Some(Relation::Thread(Thread { event_id, .. })) = let thread_root = if let Some(Relation::Thread(Thread { event_id, .. })) =
@ -323,7 +336,7 @@ impl RoomMessageEventContent {
// Add reply fallback if needed. // Add reply fallback if needed.
if let Some(original_message) = replied_to_message { if let Some(original_message) = replied_to_message {
self = self.make_reply_to(original_message, ForwardThread::No); self = self.make_reply_to(original_message, ForwardThread::No, AddMentions::No);
} }
self.relates_to = Some(relates_to); self.relates_to = Some(relates_to);
@ -473,6 +486,24 @@ pub enum ForwardThread {
No, No,
} }
/// Whether or not to add intentional [`Mentions`] when sending a reply.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(clippy::exhaustive_enums)]
pub enum AddMentions {
/// Add automatic intentional mentions to the reply.
///
/// Set this if your client supports intentional mentions.
///
/// The sender of the original event will be added to the mentions of this message, along with
/// every user mentioned in the original event.
Yes,
/// Do not add intentional mentions to the reply.
///
/// Set this if your client does not support intentional mentions.
No,
}
/// Whether or not the message is a reply inside a thread. /// Whether or not the message is a reply inside a thread.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(clippy::exhaustive_enums)] #[allow(clippy::exhaustive_enums)]

View File

@ -7,10 +7,11 @@ use ruma_common::{
key::verification::VerificationMethod, key::verification::VerificationMethod,
room::{ room::{
message::{ message::{
AudioMessageEventContent, EmoteMessageEventContent, FileMessageEventContent, AddMentions, AudioMessageEventContent, EmoteMessageEventContent,
ForwardThread, ImageMessageEventContent, KeyVerificationRequestEventContent, FileMessageEventContent, ForwardThread, ImageMessageEventContent,
MessageType, OriginalRoomMessageEvent, OriginalSyncRoomMessageEvent, Relation, KeyVerificationRequestEventContent, MessageType, OriginalRoomMessageEvent,
RoomMessageEventContent, TextMessageEventContent, VideoMessageEventContent, OriginalSyncRoomMessageEvent, Relation, RoomMessageEventContent,
TextMessageEventContent, VideoMessageEventContent,
}, },
EncryptedFileInit, JsonWebKeyInit, MediaSource, EncryptedFileInit, JsonWebKeyInit, MediaSource,
}, },
@ -265,8 +266,11 @@ fn escape_tags_in_plain_reply_body() {
sender: owned_user_id!("@user:example.org"), sender: owned_user_id!("@user:example.org"),
unsigned: MessageLikeUnsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
let second_message = RoomMessageEventContent::text_plain("Usage: rm <path>") let second_message = RoomMessageEventContent::text_plain("Usage: rm <path>").make_reply_to(
.make_reply_to(&first_message, ForwardThread::Yes); &first_message,
ForwardThread::Yes,
AddMentions::No,
);
assert_matches!( assert_matches!(
first_message.content.msgtype, first_message.content.msgtype,
@ -324,7 +328,7 @@ fn reply_sanitize() {
"This is the _second_ message", "This is the _second_ message",
"This is the <em>second</em> message", "This is the <em>second</em> message",
) )
.make_reply_to(&first_message, ForwardThread::Yes), .make_reply_to(&first_message, ForwardThread::Yes, AddMentions::No),
event_id: owned_event_id!("$143273582443PhrSn:example.org"), event_id: owned_event_id!("$143273582443PhrSn:example.org"),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(10_000)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(10_000)),
room_id: owned_room_id!("!testroomid:example.org"), room_id: owned_room_id!("!testroomid:example.org"),
@ -335,7 +339,7 @@ fn reply_sanitize() {
"This is **my** reply", "This is **my** reply",
"This is <strong>my</strong> reply", "This is <strong>my</strong> reply",
) )
.make_reply_to(&second_message, ForwardThread::Yes); .make_reply_to(&second_message, ForwardThread::Yes, AddMentions::No);
assert_matches!( assert_matches!(
first_message.content.msgtype, first_message.content.msgtype,
@ -844,7 +848,7 @@ fn set_mentions() {
let user_id = owned_user_id!("@you:localhost"); let user_id = owned_user_id!("@you:localhost");
content = content.set_mentions(Mentions::with_user_ids(vec![user_id.clone()])); content = content.set_mentions(Mentions::with_user_ids(vec![user_id.clone()]));
let mentions = content.mentions.unwrap(); let mentions = content.mentions.unwrap();
assert_eq!(mentions.user_ids.as_slice(), &[user_id]); assert_eq!(mentions.user_ids, [user_id].into());
} }
#[test] #[test]
@ -878,14 +882,14 @@ fn make_replacement_set_mentions() {
assert_matches!(content.mentions, None); assert_matches!(content.mentions, None);
assert_matches!(content.relates_to, Some(Relation::Replacement(replacement))); assert_matches!(content.relates_to, Some(Relation::Replacement(replacement)));
let mentions = replacement.new_content.mentions.unwrap(); let mentions = replacement.new_content.mentions.unwrap();
assert_eq!(mentions.user_ids.as_slice(), &[alice.clone()]); assert_eq!(mentions.user_ids, [alice.clone()].into());
content = content_clone.set_mentions(Mentions::with_user_ids(vec![alice.clone(), bob.clone()])); content = content_clone.set_mentions(Mentions::with_user_ids(vec![alice.clone(), bob.clone()]));
let mentions = content.mentions.unwrap(); let mentions = content.mentions.unwrap();
assert_eq!(mentions.user_ids.as_slice(), &[bob.clone()]); assert_eq!(mentions.user_ids, [bob.clone()].into());
assert_matches!(content.relates_to, Some(Relation::Replacement(replacement))); assert_matches!(content.relates_to, Some(Relation::Replacement(replacement)));
let mentions = replacement.new_content.mentions.unwrap(); let mentions = replacement.new_content.mentions.unwrap();
assert_eq!(mentions.user_ids.as_slice(), &[alice, bob]); assert_eq!(mentions.user_ids, [alice, bob].into());
} }
#[test] #[test]