events: Require MessageType to always contain a body

This commit is contained in:
Jonas Platte 2021-09-17 19:08:57 +02:00
parent aa2388fe86
commit 4ec9f1aa03
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
3 changed files with 60 additions and 22 deletions

View File

@ -5,6 +5,12 @@ Breaking changes:
* Remove `RedactedStrippedStateEvent`
* It was not used anywhere since stripped state events are never actually redacted.
* Use `Box<RawJsonValue>` instead of `JsonValue` for PDU `content` field
* Require `room::message::MessageType` to always contain a body
* The `new` constructor now also has a body parameter
Improvements:
* Add `room::message::MessageType::body` accessor method
# 0.24.5

View File

@ -187,24 +187,35 @@ impl MessageType {
/// Prefer to use the public variants of `MessageType` where possible; this constructor is meant
/// be used for unsupported message types only and does not allow setting arbitrary data for
/// supported ones.
pub fn new(msgtype: &str, data: JsonObject) -> serde_json::Result<Self> {
fn from_json_object<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
///
/// # Errors
///
/// Returns an error if the `msgtype` is known and serialization of `data` to the corresponding
/// `MessageType` variant fails.
pub fn new(msgtype: &str, body: String, data: JsonObject) -> serde_json::Result<Self> {
fn deserialize_variant<T: DeserializeOwned>(
body: String,
mut obj: JsonObject,
) -> serde_json::Result<T> {
obj.insert("body".into(), body.into());
serde_json::from_value(JsonValue::Object(obj))
}
Ok(match msgtype {
"m.audio" => Self::Audio(from_json_object(data)?),
"m.emote" => Self::Emote(from_json_object(data)?),
"m.file" => Self::File(from_json_object(data)?),
"m.image" => Self::Image(from_json_object(data)?),
"m.location" => Self::Location(from_json_object(data)?),
"m.notice" => Self::Notice(from_json_object(data)?),
"m.server_notice" => Self::ServerNotice(from_json_object(data)?),
"m.text" => Self::Text(from_json_object(data)?),
"m.video" => Self::Video(from_json_object(data)?),
"m.audio" => Self::Audio(deserialize_variant(body, data)?),
"m.emote" => Self::Emote(deserialize_variant(body, data)?),
"m.file" => Self::File(deserialize_variant(body, data)?),
"m.image" => Self::Image(deserialize_variant(body, data)?),
"m.location" => Self::Location(deserialize_variant(body, data)?),
"m.notice" => Self::Notice(deserialize_variant(body, data)?),
"m.server_notice" => Self::ServerNotice(deserialize_variant(body, data)?),
"m.text" => Self::Text(deserialize_variant(body, data)?),
"m.video" => Self::Video(deserialize_variant(body, data)?),
#[cfg(feature = "unstable-pre-spec")]
"m.key.verification.request" => Self::VerificationRequest(from_json_object(data)?),
_ => Self::_Custom(CustomEventContent { msgtype: msgtype.to_owned(), data }),
"m.key.verification.request" => {
Self::VerificationRequest(deserialize_variant(body, data)?)
}
_ => Self::_Custom(CustomEventContent { msgtype: msgtype.to_owned(), body, data }),
})
}
@ -226,6 +237,24 @@ impl MessageType {
}
}
/// Return a reference to the message body.
pub fn body(&self) -> &str {
match self {
MessageType::Audio(m) => &m.body,
MessageType::Emote(m) => &m.body,
MessageType::File(m) => &m.body,
MessageType::Image(m) => &m.body,
MessageType::Location(m) => &m.body,
MessageType::Notice(m) => &m.body,
MessageType::ServerNotice(m) => &m.body,
MessageType::Text(m) => &m.body,
MessageType::Video(m) => &m.body,
#[cfg(feature = "unstable-pre-spec")]
MessageType::VerificationRequest(m) => &m.body,
MessageType::_Custom(m) => &m.body,
}
}
/// Returns the associated data.
///
/// Prefer to use the public variants of `MessageType` where possible; this method is meant to
@ -929,10 +958,13 @@ impl KeyVerificationRequestEventContent {
#[doc(hidden)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CustomEventContent {
/// A custom msgtype
/// A custom msgtype.
msgtype: String,
/// Remaining event content
/// The message body.
body: String,
/// Remaining event content.
#[serde(flatten)]
data: JsonObject,
}
@ -967,11 +999,7 @@ fn get_plain_quote_fallback(original_message: &MessageEvent) -> String {
format!("> <{:?}> sent a video.", original_message.sender)
}
MessageType::_Custom(content) => {
format!(
"> <{:?}> {}",
original_message.sender,
content.data["body"].as_str().unwrap_or(""),
)
format!("> <{:?}> {}", original_message.sender, content.body)
}
#[cfg(feature = "unstable-pre-spec")]
MessageType::VerificationRequest(content) => {
@ -1156,7 +1184,7 @@ fn get_html_quote_fallback(original_message: &MessageEvent) -> String {
room_id = original_message.room_id,
event_id = original_message.event_id,
sender = original_message.sender,
body = content.data["body"].as_str().unwrap_or(""),
body = content.body,
)
}
#[cfg(feature = "unstable-pre-spec")]

View File

@ -90,12 +90,14 @@ fn custom_msgtype_serialization() {
"custom_field".into() => json!("baba"),
"another_one".into() => json!("abab"),
};
let custom_msgtype = MessageType::new("my_custom_msgtype", json_data).unwrap();
let custom_msgtype =
MessageType::new("my_custom_msgtype", "my message body".into(), json_data).unwrap();
assert_eq!(
to_json_value(&custom_msgtype).unwrap(),
json!({
"msgtype": "my_custom_msgtype",
"body": "my message body",
"custom_field": "baba",
"another_one": "abab",
})
@ -106,6 +108,7 @@ fn custom_msgtype_serialization() {
fn custom_content_deserialization() {
let json_data = json!({
"msgtype": "my_custom_msgtype",
"body": "my custom message",
"custom_field": "baba",
"another_one": "abab",
});
@ -119,6 +122,7 @@ fn custom_content_deserialization() {
from_json_value::<Raw<MessageType>>(json_data).unwrap().deserialize().unwrap();
assert_eq!(custom_event.msgtype(), "my_custom_msgtype");
assert_eq!(custom_event.body(), "my custom message");
assert_eq!(custom_event.data(), Cow::Owned(expected_json_data));
}