events: Generate redact method for content enums
… and remove redacted content structs non-room events
This commit is contained in:
parent
4aec2d5ff0
commit
34134267c6
@ -129,7 +129,8 @@ pub fn expand_event_content(
|
|||||||
let content_derives =
|
let content_derives =
|
||||||
content_attr.iter().flat_map(|args| args.get_event_kinds()).collect::<Vec<_>>();
|
content_attr.iter().flat_map(|args| args.get_event_kinds()).collect::<Vec<_>>();
|
||||||
|
|
||||||
let redacted = if needs_redacted(&content_attr) {
|
// We only generate redacted content structs for state and message events
|
||||||
|
let redacted = if needs_redacted(&content_attr, &content_derives) {
|
||||||
let doc = format!("The payload for a redacted `{}`", ident);
|
let doc = format!("The payload for a redacted `{}`", ident);
|
||||||
let redacted_ident = format_ident!("Redacted{}", ident);
|
let redacted_ident = format_ident!("Redacted{}", ident);
|
||||||
let kept_redacted_fields = if let syn::Data::Struct(syn::DataStruct {
|
let kept_redacted_fields = if let syn::Data::Struct(syn::DataStruct {
|
||||||
@ -358,9 +359,10 @@ fn generate_event_content_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needs_redacted(input: &[MetaAttrs]) -> bool {
|
fn needs_redacted(input: &[MetaAttrs], content_derives: &[&EventKind]) -> bool {
|
||||||
// `is_custom` means that the content struct does not need a generated
|
// `is_custom` means that the content struct does not need a generated
|
||||||
// redacted struct also. If no `custom_redacted` attrs are found the content
|
// redacted struct also. If no `custom_redacted` attrs are found the content
|
||||||
// needs a redacted struct generated.
|
// needs a redacted struct generated.
|
||||||
!input.iter().any(|a| a.is_custom())
|
!input.iter().any(|a| a.is_custom())
|
||||||
|
&& content_derives.iter().any(|e| e.is_message() || e.is_state())
|
||||||
}
|
}
|
||||||
|
@ -364,16 +364,18 @@ fn expand_content_enum(
|
|||||||
variants: &[EventEnumVariant],
|
variants: &[EventEnumVariant],
|
||||||
ruma_events: &TokenStream,
|
ruma_events: &TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
let ruma_identifiers = quote! { #ruma_events::exports::ruma_identifiers };
|
||||||
let serde = quote! { #ruma_events::exports::serde };
|
let serde = quote! { #ruma_events::exports::serde };
|
||||||
let serde_json = quote! { #ruma_events::exports::serde_json };
|
let serde_json = quote! { #ruma_events::exports::serde_json };
|
||||||
|
|
||||||
let ident = kind.to_content_enum();
|
let ident = kind.to_content_enum();
|
||||||
|
|
||||||
let event_type_str = events;
|
let event_type_str = events;
|
||||||
|
|
||||||
let content: Vec<_> =
|
let content: Vec<_> =
|
||||||
events.iter().map(|ev| to_event_content_path(kind, ev, ruma_events)).collect();
|
events.iter().map(|ev| to_event_content_path(kind, ev, None, ruma_events)).collect();
|
||||||
|
|
||||||
let variant_decls = variants.iter().map(|v| v.decl());
|
let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>();
|
||||||
|
|
||||||
let content_enum = quote! {
|
let content_enum = quote! {
|
||||||
#( #attrs )*
|
#( #attrs )*
|
||||||
@ -394,7 +396,7 @@ fn expand_content_enum(
|
|||||||
let attrs = &v.attrs;
|
let attrs = &v.attrs;
|
||||||
quote! { #(#attrs)* }
|
quote! { #(#attrs)* }
|
||||||
});
|
});
|
||||||
let variant_arms = variants.iter().map(|v| v.match_arm(quote!(Self)));
|
let variant_arms = variants.iter().map(|v| v.match_arm(quote!(Self))).collect::<Vec<_>>();
|
||||||
let variant_ctors = variants.iter().map(|v| v.ctor(quote!(Self)));
|
let variant_ctors = variants.iter().map(|v| v.ctor(quote!(Self)));
|
||||||
|
|
||||||
let event_content_impl = quote! {
|
let event_content_impl = quote! {
|
||||||
@ -430,12 +432,65 @@ fn expand_content_enum(
|
|||||||
|
|
||||||
let marker_trait_impls = marker_traits(kind, ruma_events);
|
let marker_trait_impls = marker_traits(kind, ruma_events);
|
||||||
|
|
||||||
|
let redacted_content_enum = if kind.is_state() || kind.is_message() {
|
||||||
|
let redacted_ident = kind.to_redacted_content_enum();
|
||||||
|
let redaction_variants = variants.iter().map(|v| v.ctor(&redacted_ident));
|
||||||
|
let redacted_content: Vec<_> = events
|
||||||
|
.iter()
|
||||||
|
.map(|ev| to_event_content_path(kind, ev, Some("Redacted"), ruma_events))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#( #attrs )*
|
||||||
|
#[derive(Clone, Debug, #serde::Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
pub enum #redacted_ident {
|
||||||
|
#(
|
||||||
|
#[doc = #event_type_str]
|
||||||
|
#variant_decls(#redacted_content),
|
||||||
|
)*
|
||||||
|
/// Content of a redacted event not defined by the Matrix specification.
|
||||||
|
Custom(#ruma_events::custom::RedactedCustomEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #ruma_events::RedactContent for #ident {
|
||||||
|
type Redacted = #redacted_ident;
|
||||||
|
|
||||||
|
/// Redacts `Self` given a `RoomVersionId`.
|
||||||
|
fn redact(
|
||||||
|
self,
|
||||||
|
version: &#ruma_identifiers::RoomVersionId,
|
||||||
|
) -> #redacted_ident {
|
||||||
|
match self {
|
||||||
|
#(
|
||||||
|
#variant_arms(content) => {
|
||||||
|
#redaction_variants(
|
||||||
|
#ruma_events::RedactContent::redact(content, version)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)*
|
||||||
|
Self::Custom(content) => {
|
||||||
|
#redacted_ident::Custom(
|
||||||
|
#ruma_events::RedactContent::redact(content, version)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TokenStream::new()
|
||||||
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#content_enum
|
#content_enum
|
||||||
|
|
||||||
#event_content_impl
|
#event_content_impl
|
||||||
|
|
||||||
#marker_trait_impls
|
#marker_trait_impls
|
||||||
|
|
||||||
|
#redacted_content_enum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,6 +914,7 @@ fn to_event_path(name: &LitStr, struct_name: &Ident, ruma_events: &TokenStream)
|
|||||||
fn to_event_content_path(
|
fn to_event_content_path(
|
||||||
kind: &EventKind,
|
kind: &EventKind,
|
||||||
name: &LitStr,
|
name: &LitStr,
|
||||||
|
prefix: Option<&str>,
|
||||||
ruma_events: &TokenStream,
|
ruma_events: &TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let span = name.span();
|
let span = name.span();
|
||||||
@ -876,8 +932,10 @@ fn to_event_content_path(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let content_str = match kind {
|
let content_str = match kind {
|
||||||
EventKind::ToDevice => format_ident!("{}ToDeviceEventContent", event),
|
EventKind::ToDevice => {
|
||||||
_ => format_ident!("{}EventContent", event),
|
format_ident!("{}{}ToDeviceEventContent", prefix.unwrap_or(""), event)
|
||||||
|
}
|
||||||
|
_ => format_ident!("{}{}EventContent", prefix.unwrap_or(""), event),
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = path.iter().map(|s| Ident::new(s, span));
|
let path = path.iter().map(|s| Ident::new(s, span));
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use quote::format_ident;
|
use quote::{format_ident, IdentFragment};
|
||||||
use syn::{
|
use syn::{
|
||||||
braced,
|
braced,
|
||||||
parse::{self, Parse, ParseStream},
|
parse::{self, Parse, ParseStream},
|
||||||
@ -88,6 +88,26 @@ impl fmt::Display for EventKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IdentFragment for EventKind {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn span(&self) -> Option<Span> {
|
||||||
|
Some(Span::call_site())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentFragment for EventKindVariation {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn span(&self) -> Option<Span> {
|
||||||
|
Some(Span::call_site())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EventKind {
|
impl EventKind {
|
||||||
pub fn is_state(&self) -> bool {
|
pub fn is_state(&self) -> bool {
|
||||||
matches!(self, Self::State)
|
matches!(self, Self::State)
|
||||||
@ -112,9 +132,7 @@ impl EventKind {
|
|||||||
| (Self::State, V::Redacted)
|
| (Self::State, V::Redacted)
|
||||||
| (Self::Message, V::RedactedSync)
|
| (Self::Message, V::RedactedSync)
|
||||||
| (Self::State, V::RedactedSync)
|
| (Self::State, V::RedactedSync)
|
||||||
| (Self::State, V::RedactedStripped) => {
|
| (Self::State, V::RedactedStripped) => Some(format_ident!("{}{}", var, self)),
|
||||||
Some(Ident::new(&format!("{}{}", var, self), Span::call_site()))
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +143,12 @@ impl EventKind {
|
|||||||
|
|
||||||
/// `Any[kind]EventContent`
|
/// `Any[kind]EventContent`
|
||||||
pub fn to_content_enum(&self) -> Ident {
|
pub fn to_content_enum(&self) -> Ident {
|
||||||
Ident::new(&format!("Any{}Content", self), Span::call_site())
|
format_ident!("Any{}Content", self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `AnyRedacted[kind]EventContent`
|
||||||
|
pub fn to_redacted_content_enum(&self) -> Ident {
|
||||||
|
format_ident!("AnyRedacted{}Content", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +82,8 @@
|
|||||||
//! }
|
//! }
|
||||||
//! });
|
//! });
|
||||||
//!
|
//!
|
||||||
//! // The downside of this event is we cannot use it with event enums, but could be deserialized
|
//! // The downside of this event is we cannot use it with event enums,
|
||||||
//! // from a `Raw<_>` that has failed to deserialize.
|
//! // but could be deserialized from a `Raw<_>` that has failed to deserialize.
|
||||||
//! matches::assert_matches!(
|
//! matches::assert_matches!(
|
||||||
//! serde_json::from_value::<SyncMessageEvent<ReactionEventContent>>(json),
|
//! serde_json::from_value::<SyncMessageEvent<ReactionEventContent>>(json),
|
||||||
//! Ok(SyncMessageEvent {
|
//! Ok(SyncMessageEvent {
|
||||||
|
@ -5,10 +5,7 @@ use ruma_events_macros::{Event, EventContent};
|
|||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{RedactedStateEventContent, Unsigned};
|
||||||
MessageEventContent, RedactedMessageEventContent, RedactedStateEventContent, RoomEventContent,
|
|
||||||
Unsigned,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Redaction event.
|
/// Redaction event.
|
||||||
#[derive(Clone, Debug, Event)]
|
#[derive(Clone, Debug, Event)]
|
||||||
@ -59,17 +56,11 @@ pub struct SyncRedactionEvent {
|
|||||||
|
|
||||||
/// A redaction of an event.
|
/// A redaction of an event.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
|
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
|
||||||
#[ruma_event(type = "m.room.redaction")]
|
#[ruma_event(type = "m.room.redaction", kind = Message)]
|
||||||
pub struct RedactionEventContent {
|
pub struct RedactionEventContent {
|
||||||
/// 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 RoomEventContent for RedactionEventContent {}
|
|
||||||
|
|
||||||
impl MessageEventContent for RedactionEventContent {}
|
|
||||||
|
|
||||||
impl RedactedMessageEventContent for RedactedRedactionEventContent {}
|
|
||||||
|
|
||||||
impl RedactedStateEventContent for RedactedRedactionEventContent {}
|
impl RedactedStateEventContent for RedactedRedactionEventContent {}
|
||||||
|
@ -9,13 +9,17 @@ use ruma_events::{
|
|||||||
message::RedactedMessageEventContent,
|
message::RedactedMessageEventContent,
|
||||||
redaction::{RedactionEventContent, SyncRedactionEvent},
|
redaction::{RedactionEventContent, SyncRedactionEvent},
|
||||||
},
|
},
|
||||||
AnyMessageEvent, AnyRedactedMessageEvent, AnyRedactedSyncMessageEvent,
|
AnyMessageEvent, AnyMessageEventContent, AnyRedactedMessageEvent,
|
||||||
AnyRedactedSyncStateEvent, AnyRoomEvent, AnySyncRoomEvent, Redact, RedactedMessageEvent,
|
AnyRedactedMessageEventContent, AnyRedactedStateEventContent, AnyRedactedSyncMessageEvent,
|
||||||
RedactedSyncMessageEvent, RedactedSyncStateEvent, RedactedUnsigned, Unsigned,
|
AnyRedactedSyncStateEvent, AnyRoomEvent, AnyStateEventContent, AnySyncRoomEvent, EventContent,
|
||||||
|
Redact, RedactContent, RedactedMessageEvent, RedactedSyncMessageEvent, RedactedSyncStateEvent,
|
||||||
|
RedactedUnsigned, Unsigned,
|
||||||
};
|
};
|
||||||
use ruma_identifiers::{event_id, room_id, user_id, RoomVersionId};
|
use ruma_identifiers::{event_id, room_id, user_id, RoomVersionId};
|
||||||
use ruma_serde::Raw;
|
use ruma_serde::Raw;
|
||||||
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, value::to_raw_value,
|
||||||
|
};
|
||||||
|
|
||||||
fn unsigned() -> RedactedUnsigned {
|
fn unsigned() -> RedactedUnsigned {
|
||||||
let mut unsigned = RedactedUnsigned::default();
|
let mut unsigned = RedactedUnsigned::default();
|
||||||
@ -332,3 +336,39 @@ fn redact_method_properly_redacts() {
|
|||||||
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
|
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn redact_message_content() {
|
||||||
|
let json = json!({
|
||||||
|
"body": "test",
|
||||||
|
"msgtype": "m.audio",
|
||||||
|
"url": "mxc://example.com/AuDi0",
|
||||||
|
});
|
||||||
|
|
||||||
|
let content =
|
||||||
|
AnyMessageEventContent::from_parts("m.room.message", to_raw_value(&json).unwrap()).unwrap();
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
content.redact(&RoomVersionId::Version6),
|
||||||
|
AnyRedactedMessageEventContent::RoomMessage(RedactedMessageEventContent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn redact_state_content() {
|
||||||
|
let json = json!({
|
||||||
|
"creator": "@carl:example.com",
|
||||||
|
"m.federate": true,
|
||||||
|
"room_version": "4"
|
||||||
|
});
|
||||||
|
|
||||||
|
let content =
|
||||||
|
AnyStateEventContent::from_parts("m.room.create", to_raw_value(&json).unwrap()).unwrap();
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
content.redact(&RoomVersionId::Version6),
|
||||||
|
AnyRedactedStateEventContent::RoomCreate(RedactedCreateEventContent {
|
||||||
|
creator
|
||||||
|
}) if creator == user_id!("@carl:example.com")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user