events: Support m.html shortcut for MessageContent

This commit is contained in:
Kévin Commaille 2022-07-02 11:17:46 +02:00 committed by Kévin Commaille
parent ed8990c3fd
commit 6f3d9fd327
8 changed files with 170 additions and 65 deletions

View File

@ -14,6 +14,14 @@ pub(crate) struct MessageContentSerDeHelper {
#[serde(rename = "org.matrix.msc1767.text")]
text_unstable: Option<String>,
/// HTML short form, stable name.
#[serde(rename = "m.html")]
html_stable: Option<String>,
/// HTML short form, unstable name.
#[serde(rename = "org.matrix.msc1767.html")]
html_unstable: Option<String>,
/// Long form, stable name.
#[serde(rename = "m.message")]
message_stable: Option<Vec<Text>>,
@ -30,16 +38,26 @@ impl TryFrom<MessageContentSerDeHelper> for MessageContent {
let MessageContentSerDeHelper {
text_stable,
text_unstable,
html_stable,
html_unstable,
message_stable,
message_unstable,
} = helper;
if let Some(message) = message_stable.or(message_unstable) {
Ok(Self(message))
} else if let Some(text) = text_stable.or(text_unstable) {
Ok(Self::plain(text))
} else {
Err(TryFromExtensibleError::MissingField("m.message or m.text".to_owned()))
let message: Vec<_> = html_stable
.or(html_unstable)
.map(Text::html)
.into_iter()
.chain(text_stable.or(text_unstable).map(Text::plain))
.collect();
if !message.is_empty() {
Ok(Self(message))
} else {
Err(TryFromExtensibleError::MissingField("m.message, m.text or m.html".to_owned()))
}
}
}
}
@ -49,13 +67,30 @@ impl Serialize for MessageContent {
where
S: serde::Serializer,
{
let mut st = serializer.serialize_struct("MessageContent", 1)?;
if self.len() == 1 && self[0].mimetype == "text/plain" {
st.serialize_field("org.matrix.msc1767.text", &self[0].body)?;
#[cfg(feature = "unstable-msc3554")]
let has_shortcut = |message: &Text| {
matches!(&*message.mimetype, "text/plain" | "text/html") && message.lang.is_none()
};
#[cfg(not(feature = "unstable-msc3554"))]
let has_shortcut =
|message: &Text| matches!(&*message.mimetype, "text/plain" | "text/html");
if self.iter().all(has_shortcut) {
let mut st = serializer.serialize_struct("MessageContent", self.len())?;
for message in self.iter() {
if message.mimetype == "text/plain" {
st.serialize_field("org.matrix.msc1767.text", &message.body)?;
} else if message.mimetype == "text/html" {
st.serialize_field("org.matrix.msc1767.html", &message.body)?;
}
}
st.end()
} else {
let mut st = serializer.serialize_struct("MessageContent", 1)?;
st.serialize_field("org.matrix.msc1767.message", &self.0)?;
st.end()
}
st.end()
}
}

View File

@ -172,10 +172,8 @@ fn event_serialization() {
to_json_value(&event).unwrap(),
json!({
"content": {
"org.matrix.msc1767.message": [
{ "body": "Upload: <strong>my_mix.mp3</strong>", "mimetype": "text/html"},
{ "body": "Upload: my_mix.mp3", "mimetype": "text/plain"},
],
"org.matrix.msc1767.html": "Upload: <strong>my_mix.mp3</strong>",
"org.matrix.msc1767.text": "Upload: my_mix.mp3",
"m.file": {
"url": "mxc://notareal.hs/abcdef",
"name": "my_mix.mp3",

View File

@ -126,10 +126,8 @@ fn file_event_serialization() {
to_json_value(&event).unwrap(),
json!({
"content": {
"org.matrix.msc1767.message": [
{ "body": "Upload: <strong>my_file.txt</strong>", "mimetype": "text/html"},
{ "body": "Upload: my_file.txt", "mimetype": "text/plain"},
],
"org.matrix.msc1767.html": "Upload: <strong>my_file.txt</strong>",
"org.matrix.msc1767.text": "Upload: my_file.txt",
"m.file": {
"url": "mxc://notareal.hs/abcdef",
"name": "my_file.txt",

View File

@ -147,10 +147,8 @@ fn image_event_serialization() {
to_json_value(&event).unwrap(),
json!({
"content": {
"org.matrix.msc1767.message": [
{ "body": "Upload: <strong>my_house.jpg</strong>", "mimetype": "text/html"},
{ "body": "Upload: my_house.jpg", "mimetype": "text/plain"},
],
"org.matrix.msc1767.html": "Upload: <strong>my_house.jpg</strong>",
"org.matrix.msc1767.text": "Upload: my_house.jpg",
"m.file": {
"url": "mxc://notareal.hs/abcdef",
"name": "my_house.jpg",

View File

@ -70,16 +70,8 @@ fn event_serialization() {
to_json_value(&event).unwrap(),
json!({
"content": {
"org.matrix.msc1767.message": [
{
"body": "Alice was at <strong>geo:51.5008,0.1247;u=35</strong> as of <em>Sat Nov 13 18:50:58 2021</em>",
"mimetype": "text/html",
},
{
"body": "Alice was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021",
"mimetype": "text/plain",
},
],
"org.matrix.msc1767.html": "Alice was at <strong>geo:51.5008,0.1247;u=35</strong> as of <em>Sat Nov 13 18:50:58 2021</em>",
"org.matrix.msc1767.text": "Alice was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021",
"m.location": {
"uri": "geo:51.5008,0.1247;u=35",
"description": "Alice's whereabouts",

View File

@ -37,10 +37,8 @@ fn html_content_serialization() {
assert_eq!(
to_json_value(&message_event_content).unwrap(),
json!({
"org.matrix.msc1767.message": [
{ "body": "Hello, <em>World</em>!", "mimetype": "text/html"},
{ "body": "Hello, World!", "mimetype": "text/plain"},
]
"org.matrix.msc1767.html": "Hello, <em>World</em>!",
"org.matrix.msc1767.text": "Hello, World!",
})
);
}
@ -96,10 +94,8 @@ fn markdown_content_serialization() {
assert_eq!(
to_json_value(&formatted_message).unwrap(),
json!({
"org.matrix.msc1767.message": [
{ "body": "<p>Testing <strong>bold</strong> and <em>italic</em>!</p>\n", "mimetype": "text/html"},
{ "body": "Testing **bold** and _italic_!", "mimetype": "text/plain"},
]
"org.matrix.msc1767.html": "<p>Testing <strong>bold</strong> and <em>italic</em>!</p>\n",
"org.matrix.msc1767.text": "Testing **bold** and _italic_!",
})
);
@ -118,10 +114,8 @@ fn markdown_content_serialization() {
assert_eq!(
to_json_value(&plain_message_paragraphs).unwrap(),
json!({
"org.matrix.msc1767.message": [
{ "body": "<p>Testing</p>\n<p>Several</p>\n<p>Paragraphs.</p>\n", "mimetype": "text/html"},
{ "body": "Testing\n\nSeveral\n\nParagraphs.", "mimetype": "text/plain"},
]
"org.matrix.msc1767.html": "<p>Testing</p>\n<p>Several</p>\n<p>Paragraphs.</p>\n",
"org.matrix.msc1767.text": "Testing\n\nSeveral\n\nParagraphs.",
})
);
}
@ -198,7 +192,53 @@ fn plain_text_content_stable_deserialization() {
}
#[test]
fn html_text_content_unstable_deserialization() {
fn html_content_unstable_deserialization() {
let json_data = json!({
"org.matrix.msc1767.html": "Hello, <em>New World</em>!",
});
let content = from_json_value::<MessageEventContent>(json_data).unwrap();
assert_eq!(content.message.find_plain(), None);
assert_eq!(content.message.find_html(), Some("Hello, <em>New World</em>!"));
}
#[test]
fn html_content_stable_deserialization() {
let json_data = json!({
"m.html": "Hello, <em>New World</em>!",
});
let content = from_json_value::<MessageEventContent>(json_data).unwrap();
assert_eq!(content.message.find_plain(), None);
assert_eq!(content.message.find_html(), Some("Hello, <em>New World</em>!"));
}
#[test]
fn html_and_text_content_unstable_deserialization() {
let json_data = json!({
"org.matrix.msc1767.html": "Hello, <em>New World</em>!",
"org.matrix.msc1767.text": "Hello, New World!",
});
let content = from_json_value::<MessageEventContent>(json_data).unwrap();
assert_eq!(content.message.find_plain(), Some("Hello, New World!"));
assert_eq!(content.message.find_html(), Some("Hello, <em>New World</em>!"));
}
#[test]
fn html_and_text_content_stable_deserialization() {
let json_data = json!({
"m.html": "Hello, <em>New World</em>!",
"m.text": "Hello, New World!",
});
let content = from_json_value::<MessageEventContent>(json_data).unwrap();
assert_eq!(content.message.find_plain(), Some("Hello, New World!"));
assert_eq!(content.message.find_html(), Some("Hello, <em>New World</em>!"));
}
#[test]
fn message_content_unstable_deserialization() {
let json_data = json!({
"org.matrix.msc1767.message": [
{ "body": "Hello, <em>New World</em>!", "mimetype": "text/html"},
@ -212,7 +252,7 @@ fn html_text_content_unstable_deserialization() {
}
#[test]
fn html_text_content_stable_deserialization() {
fn message_content_stable_deserialization() {
let json_data = json!({
"m.message": [
{ "body": "Hello, <em>New World</em>!", "mimetype": "text/html"},
@ -315,7 +355,61 @@ fn room_message_plain_text_unstable_deserialization() {
}
#[test]
fn room_message_html_text_stable_deserialization() {
fn room_message_html_and_text_stable_deserialization() {
let json_data = json!({
"body": "test",
"formatted_body": "<h1>test</h1>",
"format": "org.matrix.custom.html",
"msgtype": "m.text",
"m.html": "<h1>test</h1>",
"m.text": "test",
});
let content = assert_matches!(
from_json_value::<RoomMessageEventContent>(json_data),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(content),
..
}) => content
);
assert_eq!(content.body, "test");
let formatted = content.formatted.unwrap();
assert_eq!(formatted.body, "<h1>test</h1>");
let message = content.message.unwrap();
assert_eq!(message.len(), 2);
assert_eq!(message[0].body, "<h1>test</h1>");
assert_eq!(message[1].body, "test");
}
#[test]
fn room_message_html_and_text_unstable_deserialization() {
let json_data = json!({
"body": "test",
"formatted_body": "<h1>test</h1>",
"format": "org.matrix.custom.html",
"msgtype": "m.text",
"org.matrix.msc1767.html": "<h1>test</h1>",
"org.matrix.msc1767.text": "test",
});
let content = assert_matches!(
from_json_value::<RoomMessageEventContent>(json_data),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(content),
..
}) => content
);
assert_eq!(content.body, "test");
let formatted = content.formatted.unwrap();
assert_eq!(formatted.body, "<h1>test</h1>");
let message = content.message.unwrap();
assert_eq!(message.len(), 2);
assert_eq!(message[0].body, "<h1>test</h1>");
assert_eq!(message[1].body, "test");
}
#[test]
fn room_message_message_stable_deserialization() {
let json_data = json!({
"body": "test",
"formatted_body": "<h1>test</h1>",
@ -344,7 +438,7 @@ fn room_message_html_text_stable_deserialization() {
}
#[test]
fn room_message_html_text_unstable_deserialization() {
fn room_message_message_unstable_deserialization() {
let json_data = json!({
"body": "test",
"formatted_body": "<h1>test</h1>",
@ -537,10 +631,8 @@ fn emote_event_serialization() {
to_json_value(&event).unwrap(),
json!({
"content": {
"org.matrix.msc1767.message": [
{ "body": "is testing some <code>code</code>…", "mimetype": "text/html" },
{ "body": "is testing some code…", "mimetype": "text/plain" },
]
"org.matrix.msc1767.html": "is testing some <code>code</code>…",
"org.matrix.msc1767.text": "is testing some code…",
},
"event_id": "$event:notareal.hs",
"origin_server_ts": 134_829_848,

View File

@ -192,10 +192,8 @@ fn formatted_body_serialization() {
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"formatted_body": "Hello, <em>World</em>!",
"org.matrix.msc1767.message": [
{ "body": "Hello, <em>World</em>!", "mimetype": "text/html" },
{ "body": "Hello, World!", "mimetype": "text/plain" },
],
"org.matrix.msc1767.html": "Hello, <em>World</em>!",
"org.matrix.msc1767.text": "Hello, World!",
})
);
}
@ -253,10 +251,8 @@ fn markdown_content_serialization() {
"formatted_body": "<p>Testing <strong>bold</strong> and <em>italic</em>!</p>\n",
"format": "org.matrix.custom.html",
"msgtype": "m.text",
"org.matrix.msc1767.message": [
{ "body": "<p>Testing <strong>bold</strong> and <em>italic</em>!</p>\n", "mimetype": "text/html" },
{ "body": "Testing **bold** and _italic_!", "mimetype": "text/plain" },
],
"org.matrix.msc1767.html": "<p>Testing <strong>bold</strong> and <em>italic</em>!</p>\n",
"org.matrix.msc1767.text": "Testing **bold** and _italic_!",
})
);
@ -306,10 +302,8 @@ fn markdown_content_serialization() {
"formatted_body": "<p>Testing</p>\n<p>Several</p>\n<p>Paragraphs.</p>\n",
"format": "org.matrix.custom.html",
"msgtype": "m.text",
"org.matrix.msc1767.message": [
{ "body": "<p>Testing</p>\n<p>Several</p>\n<p>Paragraphs.</p>\n", "mimetype": "text/html" },
{ "body": "Testing\n\nSeveral\n\nParagraphs.", "mimetype": "text/plain" },
],
"org.matrix.msc1767.html": "<p>Testing</p>\n<p>Several</p>\n<p>Paragraphs.</p>\n",
"org.matrix.msc1767.text": "Testing\n\nSeveral\n\nParagraphs.",
})
);
}

View File

@ -154,10 +154,8 @@ fn event_serialization() {
to_json_value(&event).unwrap(),
json!({
"content": {
"org.matrix.msc1767.message": [
{ "body": "Upload: <strong>my_lava_lamp.webm</strong>", "mimetype": "text/html"},
{ "body": "Upload: my_lava_lamp.webm", "mimetype": "text/plain"},
],
"org.matrix.msc1767.html": "Upload: <strong>my_lava_lamp.webm</strong>",
"org.matrix.msc1767.text": "Upload: my_lava_lamp.webm",
"m.file": {
"url": "mxc://notareal.hs/abcdef",
"name": "my_lava_lamp.webm",