events: Add helpers to construct the fallback for rich replies

This commit is contained in:
Adam 2021-05-10 09:06:40 +01:00 committed by GitHub
parent aca64eccea
commit 8adc9a0eb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 319 additions and 0 deletions

View File

@ -13,6 +13,7 @@ edition = "2018"
[dependencies] [dependencies]
criterion = { version = "0.3.3", optional = true } criterion = { version = "0.3.3", optional = true }
indoc = "1.0"
js_int = { version = "0.2.0", features = ["serde"] } js_int = { version = "0.2.0", features = ["serde"] }
ruma-common = { version = "0.5.0", path = "../ruma-common" } ruma-common = { version = "0.5.0", path = "../ruma-common" }
ruma-events-macros = { version = "=0.22.0-alpha.3", path = "../ruma-events-macros" } ruma-events-macros = { version = "=0.22.0-alpha.3", path = "../ruma-events-macros" }

View File

@ -2,6 +2,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use indoc::formatdoc;
use js_int::UInt; use js_int::UInt;
use ruma_events_macros::MessageEventContent; use ruma_events_macros::MessageEventContent;
use ruma_identifiers::MxcUri; use ruma_identifiers::MxcUri;
@ -85,6 +86,73 @@ impl MessageEventContent {
pub fn notice_html(body: impl Into<String>, html_body: impl Into<String>) -> Self { pub fn notice_html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
Self::new(MessageType::Notice(NoticeMessageEventContent::html(body, html_body))) Self::new(MessageType::Notice(NoticeMessageEventContent::html(body, html_body)))
} }
/// Creates a plain text reply to a message.
pub fn text_reply_plain(reply: impl Into<String>, original_message: &MessageEvent) -> Self {
let quoted = get_plain_quote_fallback(original_message);
let body = format!("{}\n\n{}", quoted, reply.into());
Self {
relates_to: Some(Relation::Reply {
in_reply_to: InReplyTo { event_id: original_message.event_id.clone() },
}),
..Self::text_plain(body)
}
}
/// Creates a html text reply to a message.
pub fn text_reply_html(
reply: impl Into<String>,
html_reply: impl Into<String>,
original_message: &MessageEvent,
) -> Self {
let quoted = get_plain_quote_fallback(original_message);
let quoted_html = get_html_quote_fallback(original_message);
let body = format!("{}\n\n{}", quoted, reply.into());
let html_body = format!("{}\n\n{}", quoted_html, html_reply.into());
Self {
relates_to: Some(Relation::Reply {
in_reply_to: InReplyTo { event_id: original_message.event_id.clone() },
}),
..Self::text_html(body, html_body)
}
}
/// Creates a plain text notice reply to a message.
pub fn notice_reply_plain(reply: impl Into<String>, original_message: &MessageEvent) -> Self {
let quoted = get_plain_quote_fallback(original_message);
let body = format!("{}\n\n{}", quoted, reply.into());
Self {
relates_to: Some(Relation::Reply {
in_reply_to: InReplyTo { event_id: original_message.event_id.clone() },
}),
..Self::notice_plain(body)
}
}
/// Creates a html text notice reply to a message.
pub fn notice_reply_html(
reply: impl Into<String>,
html_reply: impl Into<String>,
original_message: &MessageEvent,
) -> Self {
let quoted = get_plain_quote_fallback(original_message);
let quoted_html = get_html_quote_fallback(original_message);
let body = format!("{}\n\n{}", quoted, reply.into());
let html_body = format!("{}\n\n{}", quoted_html, html_reply.into());
Self {
relates_to: Some(Relation::Reply {
in_reply_to: InReplyTo { event_id: original_message.event_id.clone() },
}),
..Self::notice_html(body, html_body)
}
}
} }
/// The content that is specific to each message type variant. /// The content that is specific to each message type variant.
@ -690,3 +758,253 @@ pub struct CustomEventContent {
#[serde(flatten)] #[serde(flatten)]
pub data: JsonObject, pub data: JsonObject,
} }
fn get_plain_quote_fallback(original_message: &MessageEvent) -> String {
match &original_message.content.msgtype {
MessageType::Audio(_) => {
format!("> <{:?}> sent an audio file.", original_message.sender)
}
MessageType::Emote(content) => {
format!("> * <{:?}> {}", original_message.sender, content.body)
}
MessageType::File(_) => {
format!("> <{:?}> sent a file.", original_message.sender)
}
MessageType::Image(_) => {
format!("> <{:?}> sent an image.", original_message.sender)
}
MessageType::Location(content) => {
format!("> <{:?}> {}", original_message.sender, content.body)
}
MessageType::Notice(content) => {
format!("> <{:?}> {}", original_message.sender, content.body)
}
MessageType::ServerNotice(content) => {
format!("> <{:?}> {}", original_message.sender, content.body)
}
MessageType::Text(content) => {
format!("> <{:?}> {}", original_message.sender, content.body)
}
MessageType::Video(_) => {
format!("> <{:?}> sent a video.", original_message.sender)
}
MessageType::_Custom(content) => {
format!(
"> <{:?}> {}",
original_message.sender,
content.data["body"].as_str().unwrap_or(""),
)
}
#[cfg(feature = "unstable-pre-spec")]
MessageType::VerificationRequest(content) => {
format!("> <{:?}> {}", original_message.sender, content.body)
}
}
}
fn get_html_quote_fallback(original_message: &MessageEvent) -> String {
match &original_message.content.msgtype {
MessageType::Audio(_) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
sent an audio file.
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
)
}
MessageType::Emote(content) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
* <a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
{body}
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = formatted_or_plain_body(&content.formatted, &content.body),
)
}
MessageType::File(_) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
sent a file.
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
)
}
MessageType::Image(_) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
sent an image.
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
)
}
MessageType::Location(_) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
sent a location.
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
)
}
MessageType::Notice(content) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
{body}
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = formatted_or_plain_body(&content.formatted, &content.body),
)
}
MessageType::ServerNotice(content) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
{body}
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = content.body,
)
}
MessageType::Text(content) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
{body}
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = formatted_or_plain_body(&content.formatted, &content.body),
)
}
MessageType::Video(_) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
sent a video.
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
)
}
MessageType::_Custom(content) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{room_id}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
{body}
</blockquote>
</mx-reply>
",
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = content.data["body"].as_str().unwrap_or(""),
)
}
#[cfg(feature = "unstable-pre-spec")]
MessageType::VerificationRequest(content) => {
formatdoc!(
"
<mx-reply>
<blockquote>
<a href=\"https://matrix.to/#/{server_name}/{event_id}\">In reply to</a>
<a href=\"https://matrix.to/#/{sender}\">{sender}</a>
<br />
{body}
</blockquote>
</mx-reply>
",
server_name = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = content.body,
)
}
}
}
fn formatted_or_plain_body<'a>(formatted: &'a Option<FormattedBody>, body: &'a str) -> &'a str {
if let Some(formatted_body) = formatted {
&formatted_body.body
} else {
body
}
}