Fix redacted aliases event deserialization
This commit is contained in:
parent
3f951e931b
commit
6f69a6fe76
@ -151,11 +151,18 @@ fn expand_deserialize_event(
|
|||||||
if name == "content" {
|
if name == "content" {
|
||||||
if is_generic && ident.to_string().contains("Redacted") {
|
if is_generic && ident.to_string().contains("Redacted") {
|
||||||
quote! {
|
quote! {
|
||||||
let content = if !C::has_deserialize_fields() {
|
let content = match C::has_deserialize_fields() {
|
||||||
C::empty(&event_type).map_err(A::Error::custom)?
|
::ruma_events::HasDeserializeFields::False => {
|
||||||
} else {
|
C::empty(&event_type).map_err(A::Error::custom)?
|
||||||
let json = content.ok_or_else(|| ::serde::de::Error::missing_field("content"))?;
|
},
|
||||||
C::from_parts(&event_type, json).map_err(A::Error::custom)?
|
::ruma_events::HasDeserializeFields::True => {
|
||||||
|
let json = content.ok_or_else(|| ::serde::de::Error::missing_field("content"))?;
|
||||||
|
C::from_parts(&event_type, json).map_err(A::Error::custom)?
|
||||||
|
},
|
||||||
|
::ruma_events::HasDeserializeFields::Optional => {
|
||||||
|
let json = content.unwrap_or(::serde_json::value::RawValue::from_string("{}".to_string()).unwrap());
|
||||||
|
C::from_parts(&event_type, json).map_err(A::Error::custom)?
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if is_generic {
|
} else if is_generic {
|
||||||
|
@ -135,7 +135,13 @@ pub fn expand_event_content(input: &DeriveInput, emit_redacted: bool) -> syn::Re
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_fields = if kept_redacted_fields.is_empty() {
|
let has_deserialize_fields = if kept_redacted_fields.is_empty() {
|
||||||
|
quote! { ::ruma_events::HasDeserializeFields::False }
|
||||||
|
} else {
|
||||||
|
quote! { ::ruma_events::HasDeserializeFields::True }
|
||||||
|
};
|
||||||
|
|
||||||
|
let has_serialize_fields = if kept_redacted_fields.is_empty() {
|
||||||
quote! { false }
|
quote! { false }
|
||||||
} else {
|
} else {
|
||||||
quote! { true }
|
quote! { true }
|
||||||
@ -170,11 +176,11 @@ pub fn expand_event_content(input: &DeriveInput, emit_redacted: bool) -> syn::Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_serialize_fields(&self) -> bool {
|
fn has_serialize_fields(&self) -> bool {
|
||||||
#has_fields
|
#has_serialize_fields
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_deserialize_fields() -> bool {
|
fn has_deserialize_fields() -> ::ruma_events::HasDeserializeFields {
|
||||||
#has_fields
|
#has_deserialize_fields
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ use serde::Serialize;
|
|||||||
use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
|
use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BasicEventContent, EphemeralRoomEventContent, EventContent, MessageEventContent,
|
BasicEventContent, EphemeralRoomEventContent, EventContent, HasDeserializeFields,
|
||||||
RedactedEventContent, RedactedMessageEventContent, RedactedStateEventContent, RoomEventContent,
|
MessageEventContent, RedactedEventContent, RedactedMessageEventContent,
|
||||||
StateEventContent,
|
RedactedStateEventContent, RoomEventContent, StateEventContent,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A custom event's type and `content` JSON object.
|
/// A custom event's type and `content` JSON object.
|
||||||
@ -83,8 +83,8 @@ impl RedactedEventContent for RedactedCustomEventContent {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_deserialize_fields() -> bool {
|
fn has_deserialize_fields() -> HasDeserializeFields {
|
||||||
false
|
HasDeserializeFields::False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,20 +243,27 @@ pub trait StateEventContent: RoomEventContent {}
|
|||||||
|
|
||||||
/// The base trait that all redacted event content types implement.
|
/// The base trait that all redacted event content types implement.
|
||||||
///
|
///
|
||||||
/// Implementing this trait allows content types to be serialized as well as deserialized.
|
/// This trait's associated functions and methods should not be used to build
|
||||||
|
/// redacted events, prefer the `redact` method on `AnyStateEvent` and
|
||||||
|
/// `AnyMessageEvent` and their "sync" and "stripped" counterparts. The
|
||||||
|
/// `RedactedEventContent` trait is an implementation detail, ruma makes no
|
||||||
|
/// API guarantees.
|
||||||
pub trait RedactedEventContent: EventContent {
|
pub trait RedactedEventContent: EventContent {
|
||||||
/// Constructs the redacted event content.
|
/// Constructs the redacted event content.
|
||||||
///
|
///
|
||||||
/// If called for anything but "empty" redacted content this will error.
|
/// If called for anything but "empty" redacted content this will error.
|
||||||
|
#[doc(hidden)]
|
||||||
fn empty(_event_type: &str) -> Result<Self, serde_json::Error> {
|
fn empty(_event_type: &str) -> Result<Self, serde_json::Error> {
|
||||||
Err(serde::de::Error::custom("this event is not redacted"))
|
Err(serde::de::Error::custom("this event is not redacted"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if the redacted event content needs to serialize fields.
|
/// Determines if the redacted event content needs to serialize fields.
|
||||||
|
#[doc(hidden)]
|
||||||
fn has_serialize_fields(&self) -> bool;
|
fn has_serialize_fields(&self) -> bool;
|
||||||
|
|
||||||
/// Determines if the redacted event content needs to deserialize fields.
|
/// Determines if the redacted event content needs to deserialize fields.
|
||||||
fn has_deserialize_fields() -> bool;
|
#[doc(hidden)]
|
||||||
|
fn has_deserialize_fields() -> HasDeserializeFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marker trait for the content of a redacted message event.
|
/// Marker trait for the content of a redacted message event.
|
||||||
@ -265,6 +272,21 @@ pub trait RedactedMessageEventContent: RedactedEventContent {}
|
|||||||
/// Marker trait for the content of a redacted state event.
|
/// Marker trait for the content of a redacted state event.
|
||||||
pub trait RedactedStateEventContent: RedactedEventContent {}
|
pub trait RedactedStateEventContent: RedactedEventContent {}
|
||||||
|
|
||||||
|
/// `HasDeserializeFields` is used in the code generated by the `Event` derive
|
||||||
|
/// to aid in deserializing redacted events.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HasDeserializeFields {
|
||||||
|
/// Deserialize the event's content, failing if invalid.
|
||||||
|
True,
|
||||||
|
/// Return the redacted version of this event's content.
|
||||||
|
False,
|
||||||
|
/// `Optional` is used for `RedactedAliasesEventContent` since it has
|
||||||
|
/// an empty version and one with content left after redaction that
|
||||||
|
/// must be supported together.
|
||||||
|
Optional,
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper struct to determine if the event has been redacted.
|
/// Helper struct to determine if the event has been redacted.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -5,7 +5,9 @@ use ruma_identifiers::RoomAliasId;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
use crate::{EventContent, RedactedEventContent, RedactedStateEventContent, StateEvent};
|
use crate::{
|
||||||
|
EventContent, HasDeserializeFields, RedactedEventContent, RedactedStateEventContent, StateEvent,
|
||||||
|
};
|
||||||
|
|
||||||
/// Informs the room about what room aliases it has been given.
|
/// Informs the room about what room aliases it has been given.
|
||||||
pub type AliasesEvent = StateEvent<AliasesEventContent>;
|
pub type AliasesEvent = StateEvent<AliasesEventContent>;
|
||||||
@ -53,8 +55,8 @@ impl RedactedEventContent for RedactedAliasesEventContent {
|
|||||||
self.aliases.is_some()
|
self.aliases.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_deserialize_fields() -> bool {
|
fn has_deserialize_fields() -> HasDeserializeFields {
|
||||||
true
|
HasDeserializeFields::Optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,10 +19,6 @@ use ruma_events::{
|
|||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||||
|
|
||||||
fn is_zst<T>(_: &T) -> bool {
|
|
||||||
std::mem::size_of::<T>() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn full_unsigned() -> UnsignedData {
|
fn full_unsigned() -> UnsignedData {
|
||||||
let mut unsigned = UnsignedData::default();
|
let mut unsigned = UnsignedData::default();
|
||||||
// The presence of `redacted_because` triggers the event enum to return early
|
// The presence of `redacted_because` triggers the event enum to return early
|
||||||
@ -63,7 +59,7 @@ fn redacted_message_event_serialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn redacted_aliases_event_serialize() {
|
fn redacted_aliases_event_serialize_no_content() {
|
||||||
let redacted = RedactedSyncStateEvent {
|
let redacted = RedactedSyncStateEvent {
|
||||||
content: RedactedAliasesEventContent { aliases: None },
|
content: RedactedAliasesEventContent { aliases: None },
|
||||||
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
|
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
|
||||||
@ -85,6 +81,32 @@ fn redacted_aliases_event_serialize() {
|
|||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn redacted_aliases_event_serialize_with_content() {
|
||||||
|
let redacted = RedactedSyncStateEvent {
|
||||||
|
content: RedactedAliasesEventContent { aliases: Some(vec![]) },
|
||||||
|
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
|
||||||
|
state_key: "".to_string(),
|
||||||
|
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
|
||||||
|
sender: UserId::try_from("@carl:example.com").unwrap(),
|
||||||
|
unsigned: UnsignedData::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = json!({
|
||||||
|
"content": {
|
||||||
|
"aliases": []
|
||||||
|
},
|
||||||
|
"event_id": "$h29iv0s8:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"origin_server_ts": 1,
|
||||||
|
"sender": "@carl:example.com",
|
||||||
|
"type": "m.room.aliases"
|
||||||
|
});
|
||||||
|
|
||||||
|
let actual = to_json_value(&redacted).unwrap();
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn redacted_aliases_deserialize() {
|
fn redacted_aliases_deserialize() {
|
||||||
let unsigned = full_unsigned();
|
let unsigned = full_unsigned();
|
||||||
@ -101,14 +123,15 @@ fn redacted_aliases_deserialize() {
|
|||||||
let actual = to_json_value(&redacted).unwrap();
|
let actual = to_json_value(&redacted).unwrap();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
from_json_value::<EventJson<AnyRoomEventStub>>(actual)
|
from_json_value::<EventJson<AnySyncRoomEvent>>(actual)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.deserialize()
|
.deserialize()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
AnyRoomEventStub::RedactedState(AnyRedactedStateEventStub::RoomAliases(RedactedStateEventStub {
|
AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomAliases(RedactedSyncStateEvent {
|
||||||
event_id, content, ..
|
content: RedactedAliasesEventContent { aliases },
|
||||||
|
event_id, ..
|
||||||
})) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
})) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
||||||
&& is_zst(&content)
|
&& aliases.is_none()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,10 +156,10 @@ fn redacted_deserialize_any_room() {
|
|||||||
.deserialize()
|
.deserialize()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
AnyRoomEvent::RedactedMessage(AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
|
AnyRoomEvent::RedactedMessage(AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
|
||||||
event_id, room_id, content, ..
|
content: RedactedMessageEventContent,
|
||||||
|
event_id, room_id, ..
|
||||||
})) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
})) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
||||||
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
|
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
|
||||||
&& is_zst(&content)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +195,9 @@ fn redacted_deserialize_any_room_sync() {
|
|||||||
.deserialize()
|
.deserialize()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(RedactedSyncMessageEvent {
|
AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(RedactedSyncMessageEvent {
|
||||||
event_id, content, ..
|
content: RedactedMessageEventContent,
|
||||||
|
event_id, ..
|
||||||
})) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
})) if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
||||||
&& is_zst(&content)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user