events: Enforce MessageContent to not be empty
This commit is contained in:
parent
f9390c7c35
commit
685bd34fd4
@ -47,7 +47,7 @@
|
||||
//! [MSC3245]: https://github.com/matrix-org/matrix-spec-proposals/pull/3245
|
||||
//! [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
|
||||
//! [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
|
||||
use std::ops::Deref;
|
||||
use std::{convert::TryFrom, ops::Deref};
|
||||
|
||||
use ruma_macros::EventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -123,11 +123,25 @@ impl MessageEventContent {
|
||||
}
|
||||
|
||||
/// Text message content.
|
||||
///
|
||||
/// A `MessageContent` must contain at least one message to be used as a fallback text
|
||||
/// representation.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(try_from = "MessageContentSerDeHelper")]
|
||||
pub struct MessageContent(pub(crate) Vec<Text>);
|
||||
|
||||
impl MessageContent {
|
||||
/// Create a `MessageContent` from an array of messages.
|
||||
///
|
||||
/// Returns `None` if the array is empty.
|
||||
pub fn new(messages: Vec<Text>) -> Option<Self> {
|
||||
if messages.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Self(messages))
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenience constructor to create a plain text message.
|
||||
pub fn plain(body: impl Into<String>) -> Self {
|
||||
Self(vec![Text::plain(body)])
|
||||
@ -178,9 +192,17 @@ impl MessageContent {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Text>> for MessageContent {
|
||||
fn from(variants: Vec<Text>) -> Self {
|
||||
Self(variants)
|
||||
/// The error type returned when trying to construct an empty `MessageContent`.
|
||||
#[derive(Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
#[error("MessageContent cannot be empty")]
|
||||
pub struct EmptyMessageContentError;
|
||||
|
||||
impl TryFrom<Vec<Text>> for MessageContent {
|
||||
type Error = EmptyMessageContentError;
|
||||
|
||||
fn try_from(messages: Vec<Text>) -> Result<Self, Self::Error> {
|
||||
Self::new(messages).ok_or(EmptyMessageContentError)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ impl Serialize for MessageContent {
|
||||
}
|
||||
|
||||
pub(crate) mod as_vec {
|
||||
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serializer};
|
||||
use serde::{de, ser::SerializeSeq, Deserialize, Deserializer, Serializer};
|
||||
|
||||
use crate::events::message::{MessageContent, Text};
|
||||
|
||||
@ -87,7 +87,10 @@ pub(crate) mod as_vec {
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Option::<Vec<Text>>::deserialize(deserializer)
|
||||
.map(|content| content.filter(|content| !content.is_empty()).map(Into::into))
|
||||
Option::<Vec<Text>>::deserialize(deserializer).and_then(|content| {
|
||||
content.map(MessageContent::new).ok_or_else(|| {
|
||||
de::Error::invalid_value(de::Unexpected::Other("empty array"), &"a non-empty array")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![cfg(feature = "unstable-msc1767")]
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use assign::assign;
|
||||
use js_int::uint;
|
||||
use matches::assert_matches;
|
||||
@ -7,7 +9,7 @@ use ruma_common::{
|
||||
event_id,
|
||||
events::{
|
||||
emote::EmoteEventContent,
|
||||
message::MessageEventContent,
|
||||
message::{MessageContent, MessageEventContent, Text},
|
||||
notice::NoticeEventContent,
|
||||
room::message::{
|
||||
EmoteMessageEventContent, InReplyTo, MessageType, NoticeMessageEventContent, Relation,
|
||||
@ -19,6 +21,19 @@ use ruma_common::{
|
||||
};
|
||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||
|
||||
#[test]
|
||||
fn try_from_valid() {
|
||||
assert_matches!(
|
||||
MessageContent::try_from(vec![Text::plain("A message")]),
|
||||
Ok(message) if message.len() == 1
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_from_invalid() {
|
||||
assert_matches!(MessageContent::try_from(vec![]), Err(_));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn html_content_serialization() {
|
||||
let message_event_content =
|
||||
@ -712,13 +727,12 @@ fn room_message_emote_unstable_deserialization() {
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-msc3554")]
|
||||
fn lang_serialization() {
|
||||
use ruma_common::events::message::{MessageContent, Text};
|
||||
|
||||
let content = MessageContent::from(vec![
|
||||
let content = MessageContent::try_from(vec![
|
||||
assign!(Text::plain("Bonjour le monde !"), { lang: Some("fr".into()) }),
|
||||
assign!(Text::plain("Hallo Welt!"), { lang: Some("de".into()) }),
|
||||
assign!(Text::plain("Hello World!"), { lang: Some("en".into()) }),
|
||||
]);
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to_json_value(&content).unwrap(),
|
||||
@ -735,8 +749,6 @@ fn lang_serialization() {
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-msc3554")]
|
||||
fn lang_deserialization() {
|
||||
use ruma_common::events::message::MessageContent;
|
||||
|
||||
let json_data = json!({
|
||||
"org.matrix.msc1767.message": [
|
||||
{ "body": "Bonjour le monde !", "mimetype": "text/plain", "lang": "fr"},
|
||||
|
Loading…
x
Reference in New Issue
Block a user