events: Allow replacement unstable poll start events to have no fallback
This commit is contained in:
parent
a70f99a233
commit
18195e0a6e
@ -6,10 +6,11 @@ use js_int::UInt;
|
||||
use ruma_macros::EventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod content_serde;
|
||||
mod unstable_poll_answers_serde;
|
||||
mod unstable_poll_kind_serde;
|
||||
|
||||
use ruma_common::MilliSecondsSinceUnixEpoch;
|
||||
use ruma_common::{MilliSecondsSinceUnixEpoch, OwnedEventId};
|
||||
|
||||
use self::unstable_poll_answers_serde::UnstablePollAnswersDeHelper;
|
||||
use super::{
|
||||
@ -18,7 +19,11 @@ use super::{
|
||||
unstable_end::UnstablePollEndEventContent,
|
||||
PollResponseData,
|
||||
};
|
||||
use crate::room::message::Relation;
|
||||
use crate::{
|
||||
relation::Replacement, room::message::RelationWithoutReplacement, EventContent,
|
||||
MessageLikeEventContent, MessageLikeEventType, RedactContent, RedactedMessageLikeEventContent,
|
||||
StaticEventContent,
|
||||
};
|
||||
|
||||
/// The payload for an unstable poll start event.
|
||||
///
|
||||
@ -30,37 +35,46 @@ use crate::room::message::Relation;
|
||||
/// [`PollStartEventContent`].
|
||||
///
|
||||
/// [`PollStartEventContent`]: super::start::PollStartEventContent
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
|
||||
#[derive(Clone, Debug, Serialize, EventContent)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
#[ruma_event(type = "org.matrix.msc3381.poll.start", kind = MessageLike, without_relation)]
|
||||
pub struct UnstablePollStartEventContent {
|
||||
/// The poll content of the message.
|
||||
#[serde(rename = "org.matrix.msc3381.poll.start")]
|
||||
pub poll_start: UnstablePollStartContentBlock,
|
||||
#[ruma_event(type = "org.matrix.msc3381.poll.start", kind = MessageLike, custom_redacted)]
|
||||
#[serde(untagged)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum UnstablePollStartEventContent {
|
||||
/// A new poll start event.
|
||||
New(NewUnstablePollStartEventContent),
|
||||
|
||||
/// Text representation of the message, for clients that don't support polls.
|
||||
#[serde(rename = "org.matrix.msc1767.text")]
|
||||
pub text: Option<String>,
|
||||
|
||||
/// Information about related messages.
|
||||
#[serde(
|
||||
flatten,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "crate::room::message::relation_serde::deserialize_relation"
|
||||
)]
|
||||
pub relates_to: Option<Relation<UnstablePollStartEventContentWithoutRelation>>,
|
||||
/// A replacement poll start event.
|
||||
Replacement(ReplacementUnstablePollStartEventContent),
|
||||
}
|
||||
|
||||
impl UnstablePollStartEventContent {
|
||||
/// Creates a new `PollStartEventContent` with the given poll content.
|
||||
pub fn new(poll_start: UnstablePollStartContentBlock) -> Self {
|
||||
Self { poll_start, text: None, relates_to: None }
|
||||
/// Get the poll start content of this event content.
|
||||
pub fn poll_start(&self) -> &UnstablePollStartContentBlock {
|
||||
match self {
|
||||
Self::New(c) => &c.poll_start,
|
||||
Self::Replacement(c) => &c.relates_to.new_content.poll_start,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `PollStartEventContent` with the given plain text fallback
|
||||
/// representation and poll content.
|
||||
pub fn plain_text(text: impl Into<String>, poll_start: UnstablePollStartContentBlock) -> Self {
|
||||
Self { poll_start, text: Some(text.into()), relates_to: None }
|
||||
impl RedactContent for UnstablePollStartEventContent {
|
||||
type Redacted = RedactedUnstablePollStartEventContent;
|
||||
|
||||
fn redact(self, _version: &crate::RoomVersionId) -> Self::Redacted {
|
||||
RedactedUnstablePollStartEventContent::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NewUnstablePollStartEventContent> for UnstablePollStartEventContent {
|
||||
fn from(value: NewUnstablePollStartEventContent) -> Self {
|
||||
Self::New(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReplacementUnstablePollStartEventContent> for UnstablePollStartEventContent {
|
||||
fn from(value: ReplacementUnstablePollStartEventContent) -> Self {
|
||||
Self::Replacement(value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,8 +89,10 @@ impl OriginalSyncUnstablePollStartEvent {
|
||||
&'a self,
|
||||
responses: impl IntoIterator<Item = PollResponseData<'a>>,
|
||||
) -> UnstablePollEndEventContent {
|
||||
let poll_start = self.content.poll_start();
|
||||
|
||||
let full_results = compile_unstable_poll_results(
|
||||
&self.content.poll_start,
|
||||
poll_start,
|
||||
responses,
|
||||
Some(MilliSecondsSinceUnixEpoch::now()),
|
||||
);
|
||||
@ -84,19 +100,171 @@ impl OriginalSyncUnstablePollStartEvent {
|
||||
full_results.into_iter().map(|(id, users)| (id, users.len())).collect::<Vec<_>>();
|
||||
|
||||
// Get the text representation of the best answers.
|
||||
let answers = self
|
||||
.content
|
||||
.poll_start
|
||||
.answers
|
||||
.iter()
|
||||
.map(|a| (a.id.as_str(), a.text.as_str()))
|
||||
.collect::<Vec<_>>();
|
||||
let answers =
|
||||
poll_start.answers.iter().map(|a| (a.id.as_str(), a.text.as_str())).collect::<Vec<_>>();
|
||||
let plain_text = generate_poll_end_fallback_text(&answers, results.into_iter());
|
||||
|
||||
UnstablePollEndEventContent::new(plain_text, self.event_id.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// A new unstable poll start event.
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub struct NewUnstablePollStartEventContent {
|
||||
/// The poll content of the message.
|
||||
#[serde(rename = "org.matrix.msc3381.poll.start")]
|
||||
pub poll_start: UnstablePollStartContentBlock,
|
||||
|
||||
/// Text representation of the message, for clients that don't support polls.
|
||||
#[serde(rename = "org.matrix.msc1767.text")]
|
||||
pub text: Option<String>,
|
||||
|
||||
/// Information about related messages.
|
||||
#[serde(rename = "m.relates_to", skip_serializing_if = "Option::is_none")]
|
||||
pub relates_to: Option<RelationWithoutReplacement>,
|
||||
}
|
||||
|
||||
impl NewUnstablePollStartEventContent {
|
||||
/// Creates a `NewUnstablePollStartEventContent` with the given poll content.
|
||||
pub fn new(poll_start: UnstablePollStartContentBlock) -> Self {
|
||||
Self { poll_start, text: None, relates_to: None }
|
||||
}
|
||||
|
||||
/// Creates a `NewUnstablePollStartEventContent` with the given plain text fallback
|
||||
/// representation and poll content.
|
||||
pub fn plain_text(text: impl Into<String>, poll_start: UnstablePollStartContentBlock) -> Self {
|
||||
Self { poll_start, text: Some(text.into()), relates_to: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl EventContent for NewUnstablePollStartEventContent {
|
||||
type EventType = MessageLikeEventType;
|
||||
|
||||
fn event_type(&self) -> Self::EventType {
|
||||
MessageLikeEventType::UnstablePollStart
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticEventContent for NewUnstablePollStartEventContent {
|
||||
const TYPE: &'static str = "org.matrix.msc3381.poll.start";
|
||||
}
|
||||
|
||||
impl MessageLikeEventContent for NewUnstablePollStartEventContent {}
|
||||
|
||||
/// Form of [`NewUnstablePollStartEventContent`] without relation.
|
||||
///
|
||||
/// To construct this type, construct a [`NewUnstablePollStartEventContent`] and then use one of its
|
||||
/// `::from()` / `.into()` methods.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub struct NewUnstablePollStartEventContentWithoutRelation {
|
||||
/// The poll content of the message.
|
||||
#[serde(rename = "org.matrix.msc3381.poll.start")]
|
||||
pub poll_start: UnstablePollStartContentBlock,
|
||||
|
||||
/// Text representation of the message, for clients that don't support polls.
|
||||
#[serde(rename = "org.matrix.msc1767.text")]
|
||||
pub text: Option<String>,
|
||||
}
|
||||
|
||||
impl From<NewUnstablePollStartEventContent> for NewUnstablePollStartEventContentWithoutRelation {
|
||||
fn from(value: NewUnstablePollStartEventContent) -> Self {
|
||||
let NewUnstablePollStartEventContent { poll_start, text, .. } = value;
|
||||
Self { poll_start, text }
|
||||
}
|
||||
}
|
||||
|
||||
/// A replacement unstable poll start event.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub struct ReplacementUnstablePollStartEventContent {
|
||||
/// The poll content of the message.
|
||||
pub poll_start: Option<UnstablePollStartContentBlock>,
|
||||
|
||||
/// Text representation of the message, for clients that don't support polls.
|
||||
pub text: Option<String>,
|
||||
|
||||
/// Information about related messages.
|
||||
pub relates_to: Replacement<NewUnstablePollStartEventContentWithoutRelation>,
|
||||
}
|
||||
|
||||
impl ReplacementUnstablePollStartEventContent {
|
||||
/// Creates a `ReplacementUnstablePollStartEventContent` with the given poll content that
|
||||
/// replaces the event with the given ID.
|
||||
///
|
||||
/// The constructed content does not have a fallback by default.
|
||||
pub fn new(poll_start: UnstablePollStartContentBlock, replaces: OwnedEventId) -> Self {
|
||||
Self {
|
||||
poll_start: None,
|
||||
text: None,
|
||||
relates_to: Replacement {
|
||||
event_id: replaces,
|
||||
new_content: NewUnstablePollStartEventContent::new(poll_start).into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a `ReplacementUnstablePollStartEventContent` with the given plain text fallback
|
||||
/// representation and poll content that replaces the event with the given ID.
|
||||
///
|
||||
/// The constructed content does not have a fallback by default.
|
||||
pub fn plain_text(
|
||||
text: impl Into<String>,
|
||||
poll_start: UnstablePollStartContentBlock,
|
||||
replaces: OwnedEventId,
|
||||
) -> Self {
|
||||
Self {
|
||||
poll_start: None,
|
||||
text: None,
|
||||
relates_to: Replacement {
|
||||
event_id: replaces,
|
||||
new_content: NewUnstablePollStartEventContent::plain_text(text, poll_start).into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventContent for ReplacementUnstablePollStartEventContent {
|
||||
type EventType = MessageLikeEventType;
|
||||
|
||||
fn event_type(&self) -> Self::EventType {
|
||||
MessageLikeEventType::UnstablePollStart
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticEventContent for ReplacementUnstablePollStartEventContent {
|
||||
const TYPE: &'static str = "org.matrix.msc3381.poll.start";
|
||||
}
|
||||
|
||||
impl MessageLikeEventContent for ReplacementUnstablePollStartEventContent {}
|
||||
|
||||
/// Redacted form of UnstablePollStartEventContent
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub struct RedactedUnstablePollStartEventContent {}
|
||||
|
||||
impl RedactedUnstablePollStartEventContent {
|
||||
/// Creates an empty RedactedUnstablePollStartEventContent.
|
||||
pub fn new() -> RedactedUnstablePollStartEventContent {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl EventContent for RedactedUnstablePollStartEventContent {
|
||||
type EventType = MessageLikeEventType;
|
||||
|
||||
fn event_type(&self) -> Self::EventType {
|
||||
MessageLikeEventType::UnstablePollStart
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticEventContent for RedactedUnstablePollStartEventContent {
|
||||
const TYPE: &'static str = "org.matrix.msc3381.poll.start";
|
||||
}
|
||||
|
||||
impl RedactedMessageLikeEventContent for RedactedUnstablePollStartEventContent {}
|
||||
|
||||
/// An unstable block for poll start content.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
|
82
crates/ruma-events/src/poll/unstable_start/content_serde.rs
Normal file
82
crates/ruma-events/src/poll/unstable_start/content_serde.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use ruma_common::{serde::from_raw_json_value, EventId};
|
||||
use serde::{de, ser::SerializeStruct, Deserialize, Deserializer, Serialize};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use super::{
|
||||
NewUnstablePollStartEventContent, NewUnstablePollStartEventContentWithoutRelation,
|
||||
ReplacementUnstablePollStartEventContent, UnstablePollStartContentBlock,
|
||||
UnstablePollStartEventContent,
|
||||
};
|
||||
use crate::room::message::{deserialize_relation, Relation};
|
||||
|
||||
impl<'de> Deserialize<'de> for UnstablePollStartEventContent {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||
|
||||
let mut deserializer = serde_json::Deserializer::from_str(json.get());
|
||||
let relates_to: Option<Relation<NewUnstablePollStartEventContentWithoutRelation>> =
|
||||
deserialize_relation(&mut deserializer).map_err(de::Error::custom)?;
|
||||
let UnstablePollStartEventContentDeHelper { poll_start, text } =
|
||||
from_raw_json_value(&json)?;
|
||||
|
||||
let c = match relates_to {
|
||||
Some(Relation::Replacement(relates_to)) => {
|
||||
ReplacementUnstablePollStartEventContent { poll_start, text, relates_to }.into()
|
||||
}
|
||||
rel => {
|
||||
let poll_start = poll_start
|
||||
.ok_or_else(|| de::Error::missing_field("org.matrix.msc3381.poll.start"))?;
|
||||
let relates_to = rel
|
||||
.map(|r| r.try_into().expect("Relation::Replacement has already been handled"));
|
||||
NewUnstablePollStartEventContent { poll_start, text, relates_to }.into()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(c)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct UnstablePollStartEventContentDeHelper {
|
||||
#[serde(rename = "org.matrix.msc3381.poll.start")]
|
||||
poll_start: Option<UnstablePollStartContentBlock>,
|
||||
|
||||
#[serde(rename = "org.matrix.msc1767.text")]
|
||||
text: Option<String>,
|
||||
}
|
||||
|
||||
impl Serialize for ReplacementUnstablePollStartEventContent {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let len = 2 + self.poll_start.is_some() as usize + self.text.is_some() as usize;
|
||||
|
||||
let mut state =
|
||||
serializer.serialize_struct("ReplacementUnstablePollStartEventContent", len)?;
|
||||
|
||||
if let Some(poll_start) = &self.poll_start {
|
||||
state.serialize_field("org.matrix.msc3381.poll.start", poll_start)?;
|
||||
}
|
||||
if let Some(text) = &self.text {
|
||||
state.serialize_field("org.matrix.msc1767.text", text)?;
|
||||
}
|
||||
|
||||
state.serialize_field("m.new_content", &self.relates_to.new_content)?;
|
||||
state.serialize_field(
|
||||
"m.relates_to",
|
||||
&ReplacementRelatesTo { event_id: &self.relates_to.event_id },
|
||||
)?;
|
||||
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(tag = "rel_type", rename = "m.replace")]
|
||||
struct ReplacementRelatesTo<'a> {
|
||||
event_id: &'a EventId,
|
||||
}
|
@ -866,6 +866,79 @@ impl<C> Relation<C> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Message event relationship, except a replacement.
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::manual_non_exhaustive)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub enum RelationWithoutReplacement {
|
||||
/// An `m.in_reply_to` relation indicating that the event is a reply to another event.
|
||||
Reply {
|
||||
/// Information about another message being replied to.
|
||||
in_reply_to: InReplyTo,
|
||||
},
|
||||
|
||||
/// An event that belongs to a thread.
|
||||
Thread(Thread),
|
||||
|
||||
#[doc(hidden)]
|
||||
_Custom(CustomRelation),
|
||||
}
|
||||
|
||||
impl RelationWithoutReplacement {
|
||||
/// The type of this `Relation`.
|
||||
///
|
||||
/// Returns an `Option` because the `Reply` relation does not have a`rel_type` field.
|
||||
pub fn rel_type(&self) -> Option<RelationType> {
|
||||
match self {
|
||||
Self::Reply { .. } => None,
|
||||
Self::Thread(_) => Some(RelationType::Thread),
|
||||
Self::_Custom(c) => Some(c.rel_type.as_str().into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// The ID of the event this relates to.
|
||||
///
|
||||
/// This is the `event_id` field at the root of an `m.relates_to` object, except in the case of
|
||||
/// a reply relation where it's the `event_id` field in the `m.in_reply_to` object.
|
||||
pub fn event_id(&self) -> &EventId {
|
||||
match self {
|
||||
Self::Reply { in_reply_to } => &in_reply_to.event_id,
|
||||
Self::Thread(t) => &t.event_id,
|
||||
Self::_Custom(c) => &c.event_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// The associated data.
|
||||
///
|
||||
/// The returned JSON object won't contain the `rel_type` field, use
|
||||
/// [`.rel_type()`][Self::rel_type] to access it.
|
||||
///
|
||||
/// Prefer to use the public variants of `Relation` where possible; this method is meant to
|
||||
/// be used for custom relations only.
|
||||
pub fn data(&self) -> Cow<'_, JsonObject> {
|
||||
if let Self::_Custom(c) = self {
|
||||
Cow::Borrowed(&c.data)
|
||||
} else {
|
||||
Cow::Owned(self.serialize_data())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> TryFrom<Relation<C>> for RelationWithoutReplacement {
|
||||
type Error = Replacement<C>;
|
||||
|
||||
fn try_from(value: Relation<C>) -> Result<Self, Self::Error> {
|
||||
let rel = match value {
|
||||
Relation::Reply { in_reply_to } => Self::Reply { in_reply_to },
|
||||
Relation::Replacement(r) => return Err(r),
|
||||
Relation::Thread(t) => Self::Thread(t),
|
||||
Relation::_Custom(c) => Self::_Custom(c),
|
||||
};
|
||||
|
||||
Ok(rel)
|
||||
}
|
||||
}
|
||||
|
||||
/// The format for the formatted representation of a message body.
|
||||
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
|
||||
#[derive(Clone, PartialEq, Eq, StringEnum)]
|
||||
|
@ -2,7 +2,7 @@ use ruma_common::{serde::JsonObject, OwnedEventId};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use super::{InReplyTo, Relation, Replacement, Thread};
|
||||
use super::{InReplyTo, Relation, RelationWithoutReplacement, Replacement, Thread};
|
||||
use crate::relation::CustomRelation;
|
||||
|
||||
/// Deserialize an event's `relates_to` field.
|
||||
@ -77,7 +77,7 @@ where
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct EventWithRelatesToDeHelper<C> {
|
||||
pub(crate) struct EventWithRelatesToDeHelper<C> {
|
||||
#[serde(rename = "m.relates_to")]
|
||||
relates_to: Option<RelatesToDeHelper>,
|
||||
|
||||
@ -86,7 +86,7 @@ struct EventWithRelatesToDeHelper<C> {
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RelatesToDeHelper {
|
||||
pub(crate) struct RelatesToDeHelper {
|
||||
#[serde(rename = "m.in_reply_to")]
|
||||
in_reply_to: Option<InReplyTo>,
|
||||
|
||||
@ -96,14 +96,14 @@ struct RelatesToDeHelper {
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum RelationDeHelper {
|
||||
pub(crate) enum RelationDeHelper {
|
||||
Known(KnownRelationDeHelper),
|
||||
Unknown(CustomRelation),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "rel_type")]
|
||||
enum KnownRelationDeHelper {
|
||||
pub(crate) enum KnownRelationDeHelper {
|
||||
#[serde(rename = "m.replace")]
|
||||
Replacement(ReplacementJsonRepr),
|
||||
|
||||
@ -116,13 +116,13 @@ enum KnownRelationDeHelper {
|
||||
|
||||
/// A replacement relation without `m.new_content`.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub(super) struct ReplacementJsonRepr {
|
||||
pub(crate) struct ReplacementJsonRepr {
|
||||
event_id: OwnedEventId,
|
||||
}
|
||||
|
||||
/// A thread relation without the reply fallback, with stable names.
|
||||
#[derive(Deserialize)]
|
||||
struct ThreadDeHelper {
|
||||
pub(crate) struct ThreadDeHelper {
|
||||
event_id: OwnedEventId,
|
||||
|
||||
#[serde(default)]
|
||||
@ -131,7 +131,7 @@ struct ThreadDeHelper {
|
||||
|
||||
/// A thread relation without the reply fallback, with unstable names.
|
||||
#[derive(Deserialize)]
|
||||
struct ThreadUnstableDeHelper {
|
||||
pub(crate) struct ThreadUnstableDeHelper {
|
||||
event_id: OwnedEventId,
|
||||
|
||||
#[serde(rename = "io.element.show_reply", default)]
|
||||
@ -222,3 +222,38 @@ impl From<CustomRelation> for CustomSerHelper {
|
||||
Self { rel_type: Some(rel_type), event_id: Some(event_id), data, ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RelationWithoutReplacement> for RelationSerHelper {
|
||||
fn from(value: &RelationWithoutReplacement) -> Self {
|
||||
match value.clone() {
|
||||
RelationWithoutReplacement::Reply { in_reply_to } => {
|
||||
RelationSerHelper::Custom(in_reply_to.into())
|
||||
}
|
||||
RelationWithoutReplacement::Thread(t) => RelationSerHelper::Thread(t),
|
||||
RelationWithoutReplacement::_Custom(c) => RelationSerHelper::Custom(c.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for RelationWithoutReplacement {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
RelationSerHelper::from(self).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationWithoutReplacement {
|
||||
pub(super) fn serialize_data(&self) -> JsonObject {
|
||||
let helper = RelationSerHelper::from(self);
|
||||
|
||||
match serde_json::to_value(helper).expect("relation serialization to succeed") {
|
||||
JsonValue::Object(mut obj) => {
|
||||
obj.remove("rel_type");
|
||||
obj
|
||||
}
|
||||
_ => panic!("all relations must serialize to objects"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,13 @@ use ruma_events::{
|
||||
OriginalSyncUnstablePollResponseEvent, UnstablePollResponseEventContent,
|
||||
},
|
||||
unstable_start::{
|
||||
OriginalSyncUnstablePollStartEvent, UnstablePollAnswer, UnstablePollStartContentBlock,
|
||||
UnstablePollStartEventContent,
|
||||
NewUnstablePollStartEventContent, OriginalSyncUnstablePollStartEvent,
|
||||
ReplacementUnstablePollStartEventContent, UnstablePollAnswer,
|
||||
UnstablePollStartContentBlock, UnstablePollStartEventContent,
|
||||
},
|
||||
},
|
||||
relation::Reference,
|
||||
room::message::Relation,
|
||||
room::message::{Relation, RelationWithoutReplacement},
|
||||
AnyMessageLikeEvent, MessageLikeEvent,
|
||||
};
|
||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||
@ -384,8 +385,8 @@ fn end_event_deserialization() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unstable_start_content_serialization() {
|
||||
let event_content = UnstablePollStartEventContent::plain_text(
|
||||
fn new_unstable_start_content_serialization() {
|
||||
let event_content = NewUnstablePollStartEventContent::plain_text(
|
||||
"How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!",
|
||||
UnstablePollStartContentBlock::new(
|
||||
"How's the weather?",
|
||||
@ -418,7 +419,58 @@ fn unstable_start_content_serialization() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unstable_start_event_deserialization() {
|
||||
fn replacement_unstable_start_content_serialization() {
|
||||
let replaces = owned_event_id!("$replacedevent");
|
||||
let event_content = ReplacementUnstablePollStartEventContent::plain_text(
|
||||
"How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!",
|
||||
UnstablePollStartContentBlock::new(
|
||||
"How's the weather?",
|
||||
vec![
|
||||
UnstablePollAnswer::new("not-bad", "Not bad…"),
|
||||
UnstablePollAnswer::new("fine", "Fine."),
|
||||
UnstablePollAnswer::new("amazing", "Amazing!"),
|
||||
]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
replaces.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
to_json_value(&event_content).unwrap(),
|
||||
json!({
|
||||
"m.new_content": {
|
||||
"org.matrix.msc1767.text": "How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!",
|
||||
"org.matrix.msc3381.poll.start": {
|
||||
"kind": "org.matrix.msc3381.poll.undisclosed",
|
||||
"max_selections": 1,
|
||||
"question": { "org.matrix.msc1767.text": "How's the weather?" },
|
||||
"answers": [
|
||||
{ "id": "not-bad", "org.matrix.msc1767.text": "Not bad…" },
|
||||
{ "id": "fine", "org.matrix.msc1767.text": "Fine." },
|
||||
{ "id": "amazing", "org.matrix.msc1767.text": "Amazing!" },
|
||||
],
|
||||
},
|
||||
},
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.replace",
|
||||
"event_id": replaces,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unstable_start_event_content_deserialization_missing_poll_start() {
|
||||
let json_data = json!({
|
||||
"org.matrix.msc1767.text": "How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!",
|
||||
});
|
||||
|
||||
from_json_value::<UnstablePollStartEventContent>(json_data).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_unstable_start_event_deserialization() {
|
||||
let json_data = json!({
|
||||
"content": {
|
||||
"org.matrix.msc1767.text": "How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!",
|
||||
@ -440,6 +492,45 @@ fn unstable_start_event_deserialization() {
|
||||
},
|
||||
]
|
||||
},
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.thread",
|
||||
"event_id": "$previous_event_id",
|
||||
},
|
||||
},
|
||||
"event_id": "$event:notareal.hs",
|
||||
"origin_server_ts": 134_829_848,
|
||||
"room_id": "!roomid:notareal.hs",
|
||||
"sender": "@user:notareal.hs",
|
||||
"type": "org.matrix.msc3381.poll.start",
|
||||
});
|
||||
|
||||
let event = from_json_value::<AnyMessageLikeEvent>(json_data).unwrap();
|
||||
assert_matches!(
|
||||
event,
|
||||
AnyMessageLikeEvent::UnstablePollStart(MessageLikeEvent::Original(message_event))
|
||||
);
|
||||
assert_matches!(message_event.content, UnstablePollStartEventContent::New(content));
|
||||
|
||||
assert_eq!(content.text.unwrap(), "How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!");
|
||||
let poll = content.poll_start;
|
||||
assert_eq!(poll.question.text, "How's the weather?");
|
||||
assert_eq!(poll.kind, PollKind::Undisclosed);
|
||||
assert_eq!(poll.max_selections, uint!(2));
|
||||
let answers = poll.answers;
|
||||
assert_eq!(answers.len(), 3);
|
||||
assert_eq!(answers[0].id, "not-bad");
|
||||
assert_eq!(answers[0].text, "Not bad…");
|
||||
assert_eq!(answers[1].id, "fine");
|
||||
assert_eq!(answers[1].text, "Fine.");
|
||||
assert_eq!(answers[2].id, "amazing");
|
||||
assert_eq!(answers[2].text, "Amazing!");
|
||||
assert_matches!(content.relates_to, Some(RelationWithoutReplacement::Thread(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replacement_unstable_start_event_deserialization() {
|
||||
let json_data = json!({
|
||||
"content": {
|
||||
"m.new_content": {
|
||||
"org.matrix.msc1767.text": "How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!",
|
||||
"org.matrix.msc3381.poll.start": {
|
||||
@ -478,11 +569,13 @@ fn unstable_start_event_deserialization() {
|
||||
event,
|
||||
AnyMessageLikeEvent::UnstablePollStart(MessageLikeEvent::Original(message_event))
|
||||
);
|
||||
assert_eq!(
|
||||
message_event.content.text.unwrap(),
|
||||
"How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!"
|
||||
);
|
||||
let poll = message_event.content.poll_start;
|
||||
assert_matches!(message_event.content, UnstablePollStartEventContent::Replacement(content));
|
||||
assert!(content.text.is_none());
|
||||
assert!(content.poll_start.is_none());
|
||||
|
||||
let new_content = content.relates_to.new_content;
|
||||
assert_eq!(new_content.text.unwrap(), "How's the weather?\n1. Not bad…\n2. Fine.\n3. Amazing!");
|
||||
let poll = new_content.poll_start;
|
||||
assert_eq!(poll.question.text, "How's the weather?");
|
||||
assert_eq!(poll.kind, PollKind::Undisclosed);
|
||||
assert_eq!(poll.max_selections, uint!(2));
|
||||
@ -494,7 +587,6 @@ fn unstable_start_event_deserialization() {
|
||||
assert_eq!(answers[1].text, "Fine.");
|
||||
assert_eq!(answers[2].id, "amazing");
|
||||
assert_eq!(answers[2].text, "Amazing!");
|
||||
assert_matches!(message_event.content.relates_to, Some(Relation::Replacement(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -985,7 +1077,7 @@ fn compute_unstable_results() {
|
||||
responses.extend(generate_unstable_poll_responses(8..11, &["wings"]));
|
||||
|
||||
let counted = compile_unstable_poll_results(
|
||||
&poll.content.poll_start,
|
||||
poll.content.poll_start(),
|
||||
responses.iter().map(|r| r.data()),
|
||||
None,
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user