tuwunel_core/matrix/event/
redact.rs1use ruma::{
2 OwnedEventId,
3 events::{TimelineEventType, room::redaction::RoomRedactionEventContent},
4 room_version_rules::RoomVersionRules,
5};
6use serde::Deserialize;
7use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
8
9use super::Event;
10
11#[must_use]
25pub(super) fn copy<E: Event>(event: &E) -> (Option<OwnedEventId>, Box<RawJsonValue>) {
26 if *event.event_type() != TimelineEventType::RoomRedaction {
27 return (event.redacts().map(ToOwned::to_owned), event.content().to_owned());
28 }
29
30 let Ok(mut content) = event.get_content::<RoomRedactionEventContent>() else {
31 return (event.redacts().map(ToOwned::to_owned), event.content().to_owned());
32 };
33
34 if let Some(redacts) = content.redacts {
35 return (Some(redacts), event.content().to_owned());
36 }
37
38 if let Some(redacts) = event.redacts().map(ToOwned::to_owned) {
39 content.redacts = Some(redacts);
40 return (
41 event.redacts().map(ToOwned::to_owned),
42 to_raw_value(&content).expect("Must be valid, we only added redacts field"),
43 );
44 }
45
46 (event.redacts().map(ToOwned::to_owned), event.content().to_owned())
47}
48
49#[must_use]
50pub(super) fn is_redacted<E: Event>(event: &E) -> bool {
51 let Some(unsigned) = event.unsigned() else {
52 return false;
53 };
54
55 let Ok(unsigned) = ExtractRedactedBecause::deserialize(unsigned) else {
56 return false;
57 };
58
59 unsigned.redacted_because.is_some()
60}
61
62#[must_use]
63pub(super) fn redacts_id<E: Event>(
64 event: &E,
65 room_rules: &RoomVersionRules,
66) -> Option<OwnedEventId> {
67 if *event.kind() != TimelineEventType::RoomRedaction {
68 return None;
69 }
70
71 if room_rules.redaction.content_field_redacts {
72 event
73 .get_content::<RoomRedactionEventContent>()
74 .ok()?
75 .redacts
76 } else {
77 event.redacts().map(ToOwned::to_owned)
78 }
79}
80
81#[derive(Deserialize)]
82struct ExtractRedactedBecause {
83 redacted_because: Option<serde::de::IgnoredAny>,
84}