events: Add method to construct a replacement
This commit is contained in:
parent
764e96a254
commit
a3675e61bf
@ -218,6 +218,81 @@ impl RoomMessageEventContent {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turns `self` into a [replacement] (or edit) for the message with the given event ID.
|
||||||
|
///
|
||||||
|
/// This takes the content and sets it in `m.new_content`, and modifies the `content` to include
|
||||||
|
/// a fallback.
|
||||||
|
///
|
||||||
|
/// If the message that is replaced is a reply to another message, the latter should also be
|
||||||
|
/// provided to be able to generate a rich reply fallback that takes the `body` /
|
||||||
|
/// `formatted_body` (if any) in `self` for the main text and prepends a quoted version of
|
||||||
|
/// `original_message`.
|
||||||
|
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/rich_reply.md"))]
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `self` has a `formatted_body` with a format other than HTML.
|
||||||
|
///
|
||||||
|
/// [replacement]: https://spec.matrix.org/v1.4/client-server-api/#event-replacements
|
||||||
|
#[track_caller]
|
||||||
|
pub fn make_replacement(
|
||||||
|
mut self,
|
||||||
|
original_message_id: OwnedEventId,
|
||||||
|
replied_to_message: Option<&OriginalRoomMessageEvent>,
|
||||||
|
) -> Self {
|
||||||
|
// Prepare relates_to with the untouched msgtype.
|
||||||
|
let relates_to = Relation::Replacement(Replacement {
|
||||||
|
event_id: original_message_id,
|
||||||
|
new_content: self.msgtype.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let empty_formatted_body = || FormattedBody::html(String::new());
|
||||||
|
|
||||||
|
let (body, formatted) = {
|
||||||
|
match &mut self.msgtype {
|
||||||
|
MessageType::Emote(m) => {
|
||||||
|
(&mut m.body, Some(m.formatted.get_or_insert_with(empty_formatted_body)))
|
||||||
|
}
|
||||||
|
MessageType::Notice(m) => {
|
||||||
|
(&mut m.body, Some(m.formatted.get_or_insert_with(empty_formatted_body)))
|
||||||
|
}
|
||||||
|
MessageType::Text(m) => {
|
||||||
|
(&mut m.body, Some(m.formatted.get_or_insert_with(empty_formatted_body)))
|
||||||
|
}
|
||||||
|
MessageType::Audio(m) => (&mut m.body, None),
|
||||||
|
MessageType::File(m) => (&mut m.body, None),
|
||||||
|
MessageType::Image(m) => (&mut m.body, None),
|
||||||
|
MessageType::Location(m) => (&mut m.body, None),
|
||||||
|
MessageType::ServerNotice(m) => (&mut m.body, None),
|
||||||
|
MessageType::Video(m) => (&mut m.body, None),
|
||||||
|
MessageType::VerificationRequest(m) => (&mut m.body, None),
|
||||||
|
MessageType::_Custom(m) => (&mut m.body, None),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add replacement fallback.
|
||||||
|
*body = format!("* {body}");
|
||||||
|
|
||||||
|
if let Some(f) = formatted {
|
||||||
|
assert_eq!(
|
||||||
|
f.format,
|
||||||
|
MessageFormat::Html,
|
||||||
|
"make_replacement can't handle non-HTML formatted messages"
|
||||||
|
);
|
||||||
|
|
||||||
|
f.body = format!("* {}", f.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add reply fallback if needed.
|
||||||
|
if let Some(original_message) = replied_to_message {
|
||||||
|
self = self.make_reply_to(original_message, ForwardThread::No);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.relates_to = Some(relates_to);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to the `msgtype` string.
|
/// Returns a reference to the `msgtype` string.
|
||||||
///
|
///
|
||||||
/// If you want to access the message type-specific data rather than the message type itself,
|
/// If you want to access the message type-specific data rather than the message type itself,
|
||||||
|
@ -9,7 +9,7 @@ use ruma_common::{
|
|||||||
room::{
|
room::{
|
||||||
message::{
|
message::{
|
||||||
AudioMessageEventContent, KeyVerificationRequestEventContent, MessageType,
|
AudioMessageEventContent, KeyVerificationRequestEventContent, MessageType,
|
||||||
OriginalRoomMessageEvent, RoomMessageEventContent,
|
OriginalRoomMessageEvent, RoomMessageEventContent, TextMessageEventContent,
|
||||||
},
|
},
|
||||||
MediaSource,
|
MediaSource,
|
||||||
},
|
},
|
||||||
@ -437,7 +437,7 @@ fn content_deserialization_failure() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "unstable-sanitize")]
|
#[cfg(feature = "unstable-sanitize")]
|
||||||
fn reply_sanitize() {
|
fn reply_sanitize() {
|
||||||
use ruma_common::events::room::message::{ForwardThread, TextMessageEventContent};
|
use ruma_common::events::room::message::ForwardThread;
|
||||||
|
|
||||||
let first_message = OriginalRoomMessageEvent {
|
let first_message = OriginalRoomMessageEvent {
|
||||||
content: RoomMessageEventContent::text_html(
|
content: RoomMessageEventContent::text_html(
|
||||||
@ -530,3 +530,72 @@ fn reply_sanitize() {
|
|||||||
"
|
"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn make_replacement_no_reply() {
|
||||||
|
let content = RoomMessageEventContent::text_html(
|
||||||
|
"This is _an edited_ message.",
|
||||||
|
"This is <em>an edited</em> message.",
|
||||||
|
);
|
||||||
|
let event_id = event_id!("$143273582443PhrSn:example.org").to_owned();
|
||||||
|
|
||||||
|
let content = content.make_replacement(event_id, None);
|
||||||
|
|
||||||
|
let (body, formatted) = assert_matches!(
|
||||||
|
content.msgtype,
|
||||||
|
MessageType::Text(TextMessageEventContent { body, formatted, .. }) => (body, formatted)
|
||||||
|
);
|
||||||
|
assert_eq!(body, "* This is _an edited_ message.");
|
||||||
|
let formatted = formatted.unwrap();
|
||||||
|
assert_eq!(formatted.body, "* This is <em>an edited</em> message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn make_replacement_with_reply() {
|
||||||
|
let replied_to_message = OriginalRoomMessageEvent {
|
||||||
|
content: RoomMessageEventContent::text_html(
|
||||||
|
"# This is the first message",
|
||||||
|
"<h1>This is the first message</h1>",
|
||||||
|
),
|
||||||
|
event_id: event_id!("$143273582443PhrSn:example.org").to_owned(),
|
||||||
|
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(10_000)),
|
||||||
|
room_id: room_id!("!testroomid:example.org").to_owned(),
|
||||||
|
sender: user_id!("@user:example.org").to_owned(),
|
||||||
|
unsigned: MessageLikeUnsigned::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let content = RoomMessageEventContent::text_html(
|
||||||
|
"This is _an edited_ reply.",
|
||||||
|
"This is <em>an edited</em> reply.",
|
||||||
|
);
|
||||||
|
let event_id = event_id!("$143273582443PhrSn:example.org").to_owned();
|
||||||
|
|
||||||
|
let content = content.make_replacement(event_id, Some(&replied_to_message));
|
||||||
|
|
||||||
|
let (body, formatted) = assert_matches!(
|
||||||
|
content.msgtype,
|
||||||
|
MessageType::Text(TextMessageEventContent { body, formatted, .. }) => (body, formatted)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
body,
|
||||||
|
"\
|
||||||
|
> <@user:example.org> # This is the first message\n\
|
||||||
|
* This is _an edited_ reply.\
|
||||||
|
"
|
||||||
|
);
|
||||||
|
let formatted = formatted.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
formatted.body,
|
||||||
|
"\
|
||||||
|
<mx-reply>\
|
||||||
|
<blockquote>\
|
||||||
|
<a href=\"https://matrix.to/#/!testroomid:example.org/$143273582443PhrSn:example.org\">In reply to</a> \
|
||||||
|
<a href=\"https://matrix.to/#/@user:example.org\">@user:example.org</a>\
|
||||||
|
<br>\
|
||||||
|
<h1>This is the first message</h1>\
|
||||||
|
</blockquote>\
|
||||||
|
</mx-reply>\
|
||||||
|
* This is <em>an edited</em> reply.\
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user