events: Add support for redacts key into content of RoomRedactionEvent
According to MSC2174
This commit is contained in:
parent
cf70f74fb7
commit
7a5d9b6e8b
@ -24,6 +24,11 @@ Breaking changes:
|
|||||||
(MSC2746 / Matrix 1.7)
|
(MSC2746 / Matrix 1.7)
|
||||||
- The `Replacement` relation for `RoomMessageEventContent` now takes a
|
- The `Replacement` relation for `RoomMessageEventContent` now takes a
|
||||||
`RoomMessageEventContentWithoutRelation` instead of a `MessageType`
|
`RoomMessageEventContentWithoutRelation` instead of a `MessageType`
|
||||||
|
- Make the `redacts` field of `Original(Sync)RoomRedactionEvent` optional to handle the format
|
||||||
|
where the `redacts` key is moved inside the `content`, as introduced in room version 11,
|
||||||
|
according to MSC2174 / MSC3820
|
||||||
|
- `RoomRedactionEventContent::new()` was renamed to `new_v1()`, and `with_reason()` is no
|
||||||
|
longer a constructor but a builder-type method
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
|
||||||
|
@ -4,19 +4,21 @@
|
|||||||
|
|
||||||
use js_int::Int;
|
use js_int::Int;
|
||||||
use ruma_macros::{Event, EventContent};
|
use ruma_macros::{Event, EventContent};
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{
|
events::{
|
||||||
BundledMessageLikeRelations, EventContent, MessageLikeEventType, RedactedUnsigned,
|
BundledMessageLikeRelations, EventContent, MessageLikeEventType, RedactContent,
|
||||||
RedactionDeHelper,
|
RedactedMessageLikeEventContent, RedactedUnsigned, StaticEventContent,
|
||||||
},
|
},
|
||||||
serde::{from_raw_json_value, CanBeEmpty},
|
serde::CanBeEmpty,
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedTransactionId,
|
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedTransactionId,
|
||||||
OwnedUserId, RoomId, UserId,
|
OwnedUserId, RoomId, RoomVersionId, UserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod event_serde;
|
||||||
|
|
||||||
/// A possibly-redacted redaction event.
|
/// A possibly-redacted redaction event.
|
||||||
#[allow(clippy::exhaustive_enums)]
|
#[allow(clippy::exhaustive_enums)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -40,14 +42,16 @@ pub enum SyncRoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Redaction event.
|
/// Redaction event.
|
||||||
#[derive(Clone, Debug, Event)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::exhaustive_structs)]
|
#[allow(clippy::exhaustive_structs)]
|
||||||
pub struct OriginalRoomRedactionEvent {
|
pub struct OriginalRoomRedactionEvent {
|
||||||
/// Data specific to the event type.
|
/// Data specific to the event type.
|
||||||
pub content: RoomRedactionEventContent,
|
pub content: RoomRedactionEventContent,
|
||||||
|
|
||||||
/// The ID of the event that was redacted.
|
/// The ID of the event that was redacted.
|
||||||
pub redacts: OwnedEventId,
|
///
|
||||||
|
/// This field is required in room versions prior to 11.
|
||||||
|
pub redacts: Option<OwnedEventId>,
|
||||||
|
|
||||||
/// The globally unique event identifier for the user who sent the event.
|
/// The globally unique event identifier for the user who sent the event.
|
||||||
pub event_id: OwnedEventId,
|
pub event_id: OwnedEventId,
|
||||||
@ -65,6 +69,22 @@ pub struct OriginalRoomRedactionEvent {
|
|||||||
pub unsigned: RoomRedactionUnsigned,
|
pub unsigned: RoomRedactionUnsigned,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<OriginalRoomRedactionEvent> for OriginalSyncRoomRedactionEvent {
|
||||||
|
fn from(value: OriginalRoomRedactionEvent) -> Self {
|
||||||
|
let OriginalRoomRedactionEvent {
|
||||||
|
content,
|
||||||
|
redacts,
|
||||||
|
event_id,
|
||||||
|
sender,
|
||||||
|
origin_server_ts,
|
||||||
|
unsigned,
|
||||||
|
..
|
||||||
|
} = value;
|
||||||
|
|
||||||
|
Self { content, redacts, event_id, sender, origin_server_ts, unsigned }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Redacted redaction event.
|
/// Redacted redaction event.
|
||||||
#[derive(Clone, Debug, Event)]
|
#[derive(Clone, Debug, Event)]
|
||||||
#[allow(clippy::exhaustive_structs)]
|
#[allow(clippy::exhaustive_structs)]
|
||||||
@ -89,14 +109,16 @@ pub struct RedactedRoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Redaction event without a `room_id`.
|
/// Redaction event without a `room_id`.
|
||||||
#[derive(Clone, Debug, Event)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::exhaustive_structs)]
|
#[allow(clippy::exhaustive_structs)]
|
||||||
pub struct OriginalSyncRoomRedactionEvent {
|
pub struct OriginalSyncRoomRedactionEvent {
|
||||||
/// Data specific to the event type.
|
/// Data specific to the event type.
|
||||||
pub content: RoomRedactionEventContent,
|
pub content: RoomRedactionEventContent,
|
||||||
|
|
||||||
/// The ID of the event that was redacted.
|
/// The ID of the event that was redacted.
|
||||||
pub redacts: OwnedEventId,
|
///
|
||||||
|
/// This field is required in room versions prior to 11.
|
||||||
|
pub redacts: Option<OwnedEventId>,
|
||||||
|
|
||||||
/// The globally unique event identifier for the user who sent the event.
|
/// The globally unique event identifier for the user who sent the event.
|
||||||
pub event_id: OwnedEventId,
|
pub event_id: OwnedEventId,
|
||||||
@ -112,6 +134,21 @@ pub struct OriginalSyncRoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OriginalSyncRoomRedactionEvent {
|
impl OriginalSyncRoomRedactionEvent {
|
||||||
|
/// Convert this sync event into a full event, one with a `room_id` field.
|
||||||
|
pub fn into_full_event(self, room_id: OwnedRoomId) -> OriginalRoomRedactionEvent {
|
||||||
|
let Self { content, redacts, event_id, sender, origin_server_ts, unsigned } = self;
|
||||||
|
|
||||||
|
OriginalRoomRedactionEvent {
|
||||||
|
content,
|
||||||
|
redacts,
|
||||||
|
event_id,
|
||||||
|
sender,
|
||||||
|
origin_server_ts,
|
||||||
|
room_id,
|
||||||
|
unsigned,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn into_maybe_redacted(self) -> SyncRoomRedactionEvent {
|
pub(crate) fn into_maybe_redacted(self) -> SyncRoomRedactionEvent {
|
||||||
SyncRoomRedactionEvent::Original(self)
|
SyncRoomRedactionEvent::Original(self)
|
||||||
}
|
}
|
||||||
@ -140,25 +177,85 @@ pub struct RedactedSyncRoomRedactionEvent {
|
|||||||
/// A redaction of an event.
|
/// A redaction of an event.
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
|
||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
#[ruma_event(type = "m.room.redaction", kind = MessageLike)]
|
#[ruma_event(type = "m.room.redaction", kind = MessageLike, custom_redacted)]
|
||||||
pub struct RoomRedactionEventContent {
|
pub struct RoomRedactionEventContent {
|
||||||
|
/// The ID of the event that was redacted.
|
||||||
|
///
|
||||||
|
/// This field is required starting from room version 11.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub redacts: Option<OwnedEventId>,
|
||||||
|
|
||||||
/// The reason for the redaction, if any.
|
/// The reason for the redaction, if any.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub reason: Option<String>,
|
pub reason: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomRedactionEventContent {
|
impl RoomRedactionEventContent {
|
||||||
/// Creates an empty `RoomRedactionEventContent`.
|
/// Creates an empty `RoomRedactionEventContent` according to room versions 1 through 10.
|
||||||
pub fn new() -> Self {
|
pub fn new_v1() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `RoomRedactionEventContent` with the given reason.
|
/// Creates a `RoomRedactionEventContent` with the required `redacts` field introduced in room
|
||||||
pub fn with_reason(reason: String) -> Self {
|
/// version 11.
|
||||||
Self { reason: Some(reason) }
|
pub fn new_v11(redacts: OwnedEventId) -> Self {
|
||||||
|
Self { redacts: Some(redacts), ..Default::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add the given reason to this `RoomRedactionEventContent`.
|
||||||
|
pub fn with_reason(mut self, reason: String) -> Self {
|
||||||
|
self.reason = Some(reason);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RedactContent for RoomRedactionEventContent {
|
||||||
|
type Redacted = RedactedRoomRedactionEventContent;
|
||||||
|
|
||||||
|
fn redact(self, version: &RoomVersionId) -> Self::Redacted {
|
||||||
|
let redacts = match version {
|
||||||
|
RoomVersionId::V1
|
||||||
|
| RoomVersionId::V2
|
||||||
|
| RoomVersionId::V3
|
||||||
|
| RoomVersionId::V4
|
||||||
|
| RoomVersionId::V5
|
||||||
|
| RoomVersionId::V6
|
||||||
|
| RoomVersionId::V7
|
||||||
|
| RoomVersionId::V8
|
||||||
|
| RoomVersionId::V9
|
||||||
|
| RoomVersionId::V10 => None,
|
||||||
|
_ => self.redacts,
|
||||||
|
};
|
||||||
|
|
||||||
|
RedactedRoomRedactionEventContent { redacts }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A redacted redaction event.
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct RedactedRoomRedactionEventContent {
|
||||||
|
/// The ID of the event that was redacted.
|
||||||
|
///
|
||||||
|
/// This field is required starting from room version 11.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub redacts: Option<OwnedEventId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventContent for RedactedRoomRedactionEventContent {
|
||||||
|
type EventType = MessageLikeEventType;
|
||||||
|
|
||||||
|
fn event_type(&self) -> Self::EventType {
|
||||||
|
MessageLikeEventType::RoomRedaction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticEventContent for RedactedRoomRedactionEventContent {
|
||||||
|
const TYPE: &'static str = "m.room.redaction";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RedactedMessageLikeEventContent for RedactedRoomRedactionEventContent {}
|
||||||
|
|
||||||
impl RoomRedactionEvent {
|
impl RoomRedactionEvent {
|
||||||
/// Returns the `type` of this event.
|
/// Returns the `type` of this event.
|
||||||
pub fn event_type(&self) -> MessageLikeEventType {
|
pub fn event_type(&self) -> MessageLikeEventType {
|
||||||
@ -200,6 +297,19 @@ impl RoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the ID of the event that this event redacts, according to the given room version.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if this is a non-redacted event and both `redacts` field are `None`, which is only
|
||||||
|
/// possible if the event was modified after being deserialized.
|
||||||
|
pub fn redacts(&self, room_version: &RoomVersionId) -> Option<&EventId> {
|
||||||
|
match self {
|
||||||
|
Self::Original(ev) => Some(ev.redacts(room_version)),
|
||||||
|
Self::Redacted(ev) => ev.content.redacts.as_deref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the inner `RoomRedactionEvent` if this is an unredacted event.
|
/// Get the inner `RoomRedactionEvent` if this is an unredacted event.
|
||||||
pub fn as_original(&self) -> Option<&OriginalRoomRedactionEvent> {
|
pub fn as_original(&self) -> Option<&OriginalRoomRedactionEvent> {
|
||||||
match self {
|
match self {
|
||||||
@ -209,22 +319,6 @@ impl RoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for RoomRedactionEvent {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
|
||||||
let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
|
|
||||||
|
|
||||||
if unsigned.and_then(|u| u.redacted_because).is_some() {
|
|
||||||
Ok(Self::Redacted(from_raw_json_value(&json)?))
|
|
||||||
} else {
|
|
||||||
Ok(Self::Original(from_raw_json_value(&json)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyncRoomRedactionEvent {
|
impl SyncRoomRedactionEvent {
|
||||||
/// Returns the `type` of this event.
|
/// Returns the `type` of this event.
|
||||||
pub fn event_type(&self) -> MessageLikeEventType {
|
pub fn event_type(&self) -> MessageLikeEventType {
|
||||||
@ -258,6 +352,19 @@ impl SyncRoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the ID of the event that this event redacts, according to the given room version.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if this is a non-redacted event and both `redacts` field are `None`, which is only
|
||||||
|
/// possible if the event was modified after being deserialized.
|
||||||
|
pub fn redacts(&self, room_version: &RoomVersionId) -> Option<&EventId> {
|
||||||
|
match self {
|
||||||
|
Self::Original(ev) => Some(ev.redacts(room_version)),
|
||||||
|
Self::Redacted(ev) => ev.content.redacts.as_deref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the inner `SyncRoomRedactionEvent` if this is an unredacted event.
|
/// Get the inner `SyncRoomRedactionEvent` if this is an unredacted event.
|
||||||
pub fn as_original(&self) -> Option<&OriginalSyncRoomRedactionEvent> {
|
pub fn as_original(&self) -> Option<&OriginalSyncRoomRedactionEvent> {
|
||||||
match self {
|
match self {
|
||||||
@ -284,19 +391,35 @@ impl From<RoomRedactionEvent> for SyncRoomRedactionEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for SyncRoomRedactionEvent {
|
impl OriginalRoomRedactionEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
/// Returns the ID of the event that this event redacts, according to the proper `redacts` field
|
||||||
where
|
/// for the given room version.
|
||||||
D: Deserializer<'de>,
|
///
|
||||||
{
|
/// If the `redacts` field is not the proper one for the given room version, this falls back to
|
||||||
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
/// the one that is available.
|
||||||
let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if both `redacts` field are `None`, which is only possible if the event was modified
|
||||||
|
/// after being deserialized.
|
||||||
|
pub fn redacts(&self, room_version: &RoomVersionId) -> &EventId {
|
||||||
|
redacts(room_version, self.redacts.as_deref(), self.content.redacts.as_deref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if unsigned.and_then(|u| u.redacted_because).is_some() {
|
impl OriginalSyncRoomRedactionEvent {
|
||||||
Ok(Self::Redacted(from_raw_json_value(&json)?))
|
/// Returns the ID of the event that this event redacts, according to the proper `redacts` field
|
||||||
} else {
|
/// for the given room version.
|
||||||
Ok(Self::Original(from_raw_json_value(&json)?))
|
///
|
||||||
}
|
/// If the `redacts` field is not the proper one for the given room version, this falls back to
|
||||||
|
/// the one that is available.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if both `redacts` field are `None`, which is only possible if the event was modified
|
||||||
|
/// after being deserialized.
|
||||||
|
pub fn redacts(&self, room_version: &RoomVersionId) -> &EventId {
|
||||||
|
redacts(room_version, self.redacts.as_deref(), self.content.redacts.as_deref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,3 +468,41 @@ impl CanBeEmpty for RoomRedactionUnsigned {
|
|||||||
self.age.is_none() && self.transaction_id.is_none() && self.relations.is_empty()
|
self.age.is_none() && self.transaction_id.is_none() && self.relations.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the value of the proper `redacts` field for the given room version.
|
||||||
|
///
|
||||||
|
/// If the `redacts` field is not the proper one for the given room version, this falls back to
|
||||||
|
/// the one that is available.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if both `redacts` and `content_redacts` are `None`.
|
||||||
|
fn redacts<'a>(
|
||||||
|
room_version: &'_ RoomVersionId,
|
||||||
|
redacts: Option<&'a EventId>,
|
||||||
|
content_redacts: Option<&'a EventId>,
|
||||||
|
) -> &'a EventId {
|
||||||
|
match room_version {
|
||||||
|
RoomVersionId::V1
|
||||||
|
| RoomVersionId::V2
|
||||||
|
| RoomVersionId::V3
|
||||||
|
| RoomVersionId::V4
|
||||||
|
| RoomVersionId::V5
|
||||||
|
| RoomVersionId::V6
|
||||||
|
| RoomVersionId::V7
|
||||||
|
| RoomVersionId::V8
|
||||||
|
| RoomVersionId::V9
|
||||||
|
| RoomVersionId::V10 => redacts
|
||||||
|
.or_else(|| {
|
||||||
|
error!("Redacts field at event level not available, falling back to the one inside content");
|
||||||
|
content_redacts
|
||||||
|
})
|
||||||
|
.expect("At least one redacts field is set"),
|
||||||
|
_ => content_redacts
|
||||||
|
.or_else(|| {
|
||||||
|
error!("Redacts field inside content not available, falling back to the one at the event level");
|
||||||
|
redacts
|
||||||
|
})
|
||||||
|
.expect("At least one redacts field is set"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
105
crates/ruma-common/src/events/room/redaction/event_serde.rs
Normal file
105
crates/ruma-common/src/events/room/redaction/event_serde.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
use serde::{de, Deserialize, Deserializer};
|
||||||
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
OriginalRoomRedactionEvent, OriginalSyncRoomRedactionEvent, RoomRedactionEvent,
|
||||||
|
RoomRedactionEventContent, RoomRedactionUnsigned, SyncRoomRedactionEvent,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
events::RedactionDeHelper, serde::from_raw_json_value, MilliSecondsSinceUnixEpoch,
|
||||||
|
OwnedEventId, OwnedRoomId, OwnedUserId,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for RoomRedactionEvent {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||||
|
let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
|
||||||
|
|
||||||
|
if unsigned.and_then(|u| u.redacted_because).is_some() {
|
||||||
|
Ok(Self::Redacted(from_raw_json_value(&json)?))
|
||||||
|
} else {
|
||||||
|
Ok(Self::Original(from_raw_json_value(&json)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for SyncRoomRedactionEvent {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||||
|
let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
|
||||||
|
|
||||||
|
if unsigned.and_then(|u| u.redacted_because).is_some() {
|
||||||
|
Ok(Self::Redacted(from_raw_json_value(&json)?))
|
||||||
|
} else {
|
||||||
|
Ok(Self::Original(from_raw_json_value(&json)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct OriginalRoomRedactionEventDeHelper {
|
||||||
|
content: RoomRedactionEventContent,
|
||||||
|
redacts: Option<OwnedEventId>,
|
||||||
|
event_id: OwnedEventId,
|
||||||
|
sender: OwnedUserId,
|
||||||
|
origin_server_ts: MilliSecondsSinceUnixEpoch,
|
||||||
|
room_id: Option<OwnedRoomId>,
|
||||||
|
#[serde(default)]
|
||||||
|
unsigned: RoomRedactionUnsigned,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for OriginalRoomRedactionEvent {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||||
|
let OriginalRoomRedactionEventDeHelper {
|
||||||
|
content,
|
||||||
|
redacts,
|
||||||
|
event_id,
|
||||||
|
sender,
|
||||||
|
origin_server_ts,
|
||||||
|
room_id,
|
||||||
|
unsigned,
|
||||||
|
} = from_raw_json_value(&json)?;
|
||||||
|
|
||||||
|
let Some(room_id) = room_id else { return Err(de::Error::missing_field("room_id")) };
|
||||||
|
|
||||||
|
if redacts.is_none() && content.redacts.is_none() {
|
||||||
|
return Err(de::Error::missing_field("redacts"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { content, redacts, event_id, sender, origin_server_ts, room_id, unsigned })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for OriginalSyncRoomRedactionEvent {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||||
|
let OriginalRoomRedactionEventDeHelper {
|
||||||
|
content,
|
||||||
|
redacts,
|
||||||
|
event_id,
|
||||||
|
sender,
|
||||||
|
origin_server_ts,
|
||||||
|
unsigned,
|
||||||
|
..
|
||||||
|
} = from_raw_json_value(&json)?;
|
||||||
|
|
||||||
|
if redacts.is_none() && content.redacts.is_none() {
|
||||||
|
return Err(de::Error::missing_field("redacts"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { content, redacts, event_id, sender, origin_server_ts, unsigned })
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ fn unsigned() -> JsonValue {
|
|||||||
json!({
|
json!({
|
||||||
"redacted_because": {
|
"redacted_because": {
|
||||||
"type": "m.room.redaction",
|
"type": "m.room.redaction",
|
||||||
"content": RoomRedactionEventContent::with_reason("redacted because".into()),
|
"content": RoomRedactionEventContent::new_v1().with_reason("redacted because".into()),
|
||||||
"redacts": "$h29iv0s8:example.com",
|
"redacts": "$h29iv0s8:example.com",
|
||||||
"event_id": "$h29iv0s8:example.com",
|
"event_id": "$h29iv0s8:example.com",
|
||||||
"origin_server_ts": 1,
|
"origin_server_ts": 1,
|
||||||
|
@ -5,14 +5,15 @@ use ruma_common::{
|
|||||||
room::redaction::{RoomRedactionEvent, RoomRedactionEventContent},
|
room::redaction::{RoomRedactionEvent, RoomRedactionEventContent},
|
||||||
AnyMessageLikeEvent,
|
AnyMessageLikeEvent,
|
||||||
},
|
},
|
||||||
|
owned_event_id,
|
||||||
serde::CanBeEmpty,
|
serde::CanBeEmpty,
|
||||||
MilliSecondsSinceUnixEpoch,
|
MilliSecondsSinceUnixEpoch, RoomVersionId,
|
||||||
};
|
};
|
||||||
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};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_redaction_content() {
|
fn serialize_redaction_content() {
|
||||||
let content = RoomRedactionEventContent::with_reason("being very unfriendly".into());
|
let content = RoomRedactionEventContent::new_v1().with_reason("being very unfriendly".into());
|
||||||
|
|
||||||
let actual = to_json_value(content).unwrap();
|
let actual = to_json_value(content).unwrap();
|
||||||
let expected = json!({
|
let expected = json!({
|
||||||
@ -22,13 +23,29 @@ fn serialize_redaction_content() {
|
|||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_redaction_content_v11() {
|
||||||
|
let redacts = owned_event_id!("$abcdef");
|
||||||
|
let content = RoomRedactionEventContent::new_v11(redacts.clone())
|
||||||
|
.with_reason("being very unfriendly".into());
|
||||||
|
|
||||||
|
let actual = to_json_value(content).unwrap();
|
||||||
|
let expected = json!({
|
||||||
|
"redacts": redacts,
|
||||||
|
"reason": "being very unfriendly"
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_redaction() {
|
fn deserialize_redaction() {
|
||||||
let json_data = json!({
|
let json_data = json!({
|
||||||
"content": {
|
"content": {
|
||||||
|
"redacts": "$nomorev11:example.com",
|
||||||
"reason": "being very unfriendly"
|
"reason": "being very unfriendly"
|
||||||
},
|
},
|
||||||
"redacts": "$nomore:example.com",
|
"redacts": "$nomorev1:example.com",
|
||||||
"event_id": "$h29iv0s8:example.com",
|
"event_id": "$h29iv0s8:example.com",
|
||||||
"sender": "@carl:example.com",
|
"sender": "@carl:example.com",
|
||||||
"origin_server_ts": 1,
|
"origin_server_ts": 1,
|
||||||
@ -40,11 +57,32 @@ fn deserialize_redaction() {
|
|||||||
from_json_value::<AnyMessageLikeEvent>(json_data),
|
from_json_value::<AnyMessageLikeEvent>(json_data),
|
||||||
Ok(AnyMessageLikeEvent::RoomRedaction(RoomRedactionEvent::Original(ev)))
|
Ok(AnyMessageLikeEvent::RoomRedaction(RoomRedactionEvent::Original(ev)))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(ev.redacts(&RoomVersionId::V1), "$nomorev1:example.com");
|
||||||
|
assert_eq!(ev.redacts(&RoomVersionId::V11), "$nomorev11:example.com");
|
||||||
|
|
||||||
|
assert_eq!(ev.content.redacts.unwrap(), "$nomorev11:example.com");
|
||||||
assert_eq!(ev.content.reason.as_deref(), Some("being very unfriendly"));
|
assert_eq!(ev.content.reason.as_deref(), Some("being very unfriendly"));
|
||||||
assert_eq!(ev.event_id, "$h29iv0s8:example.com");
|
assert_eq!(ev.event_id, "$h29iv0s8:example.com");
|
||||||
assert_eq!(ev.redacts, "$nomore:example.com");
|
assert_eq!(ev.redacts.unwrap(), "$nomorev1:example.com");
|
||||||
assert_eq!(ev.origin_server_ts, MilliSecondsSinceUnixEpoch(uint!(1)));
|
assert_eq!(ev.origin_server_ts, MilliSecondsSinceUnixEpoch(uint!(1)));
|
||||||
assert_eq!(ev.room_id, "!roomid:room.com");
|
assert_eq!(ev.room_id, "!roomid:room.com");
|
||||||
assert_eq!(ev.sender, "@carl:example.com");
|
assert_eq!(ev.sender, "@carl:example.com");
|
||||||
assert!(ev.unsigned.is_empty());
|
assert!(ev.unsigned.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_redaction_missing_redacts() {
|
||||||
|
let json_data = json!({
|
||||||
|
"content": {
|
||||||
|
"reason": "being very unfriendly"
|
||||||
|
},
|
||||||
|
"event_id": "$h29iv0s8:example.com",
|
||||||
|
"sender": "@carl:example.com",
|
||||||
|
"origin_server_ts": 1,
|
||||||
|
"room_id": "!roomid:room.com",
|
||||||
|
"type": "m.room.redaction"
|
||||||
|
});
|
||||||
|
|
||||||
|
from_json_value::<AnyMessageLikeEvent>(json_data).unwrap_err();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user