1use ruma::{
2 assign,
3 events::{
4 room::{
5 avatar::{RoomAvatarEventContent, StrippedRoomAvatarEvent},
6 canonical_alias::{RoomCanonicalAliasEventContent, StrippedRoomCanonicalAliasEvent},
7 create::{StrippedRoomCreateEvent, SyncRoomCreateEvent},
8 guest_access::{
9 RedactedRoomGuestAccessEventContent, RoomGuestAccessEventContent,
10 StrippedRoomGuestAccessEvent,
11 },
12 history_visibility::{
13 RoomHistoryVisibilityEventContent, StrippedRoomHistoryVisibilityEvent,
14 },
15 join_rules::{RoomJoinRulesEventContent, StrippedRoomJoinRulesEvent},
16 member::{MembershipState, RoomMemberEventContent},
17 name::{RedactedRoomNameEventContent, RoomNameEventContent, StrippedRoomNameEvent},
18 tombstone::{
19 RedactedRoomTombstoneEventContent, RoomTombstoneEventContent,
20 StrippedRoomTombstoneEvent,
21 },
22 topic::{RedactedRoomTopicEventContent, RoomTopicEventContent, StrippedRoomTopicEvent},
23 },
24 RedactContent, RedactedStateEventContent, StateEventContent, StaticStateEventContent,
25 SyncStateEvent,
26 },
27 room_version_rules::RedactionRules,
28 EventId, OwnedEventId,
29};
30use serde::{de::DeserializeOwned, Deserialize, Serialize};
31
32use crate::room::RoomCreateWithCreatorEventContent;
33
34#[derive(Clone, Debug, Deserialize, Serialize)]
47#[serde(bound(
48 serialize = "C: Serialize, C::Redacted: Serialize",
49 deserialize = "C: DeserializeOwned, C::Redacted: DeserializeOwned"
50))]
51pub enum MinimalStateEvent<C: StateEventContent + RedactContent>
52where
53 C::Redacted: RedactedStateEventContent,
54{
55 Original(OriginalMinimalStateEvent<C>),
57 Redacted(RedactedMinimalStateEvent<C::Redacted>),
59}
60
61#[derive(Clone, Debug, Deserialize, Serialize)]
65pub struct OriginalMinimalStateEvent<C>
66where
67 C: StateEventContent,
68{
69 pub content: C,
71 pub event_id: Option<OwnedEventId>,
73}
74
75#[derive(Clone, Debug, Deserialize, Serialize)]
79pub struct RedactedMinimalStateEvent<C>
80where
81 C: RedactedStateEventContent,
82{
83 pub content: C,
85 pub event_id: Option<OwnedEventId>,
87}
88
89impl<C> MinimalStateEvent<C>
90where
91 C: StateEventContent + RedactContent,
92 C::Redacted: RedactedStateEventContent,
93{
94 pub fn event_id(&self) -> Option<&EventId> {
96 match self {
97 MinimalStateEvent::Original(ev) => ev.event_id.as_deref(),
98 MinimalStateEvent::Redacted(ev) => ev.event_id.as_deref(),
99 }
100 }
101
102 pub fn as_original(&self) -> Option<&OriginalMinimalStateEvent<C>> {
104 match self {
105 MinimalStateEvent::Original(ev) => Some(ev),
106 MinimalStateEvent::Redacted(_) => None,
107 }
108 }
109
110 pub fn into_original(self) -> Option<OriginalMinimalStateEvent<C>> {
113 match self {
114 MinimalStateEvent::Original(ev) => Some(ev),
115 MinimalStateEvent::Redacted(_) => None,
116 }
117 }
118
119 pub fn redact(&mut self, rules: &RedactionRules)
123 where
124 C: Clone,
125 {
126 if let MinimalStateEvent::Original(ev) = self {
127 *self = MinimalStateEvent::Redacted(RedactedMinimalStateEvent {
128 content: ev.content.clone().redact(rules),
129 event_id: ev.event_id.clone(),
130 });
131 }
132 }
133}
134
135pub type MinimalRoomMemberEvent = MinimalStateEvent<RoomMemberEventContent>;
137
138impl MinimalRoomMemberEvent {
139 pub fn membership(&self) -> &MembershipState {
142 match self {
143 MinimalStateEvent::Original(ev) => &ev.content.membership,
144 MinimalStateEvent::Redacted(ev) => &ev.content.membership,
145 }
146 }
147}
148
149impl<C> From<SyncStateEvent<C>> for MinimalStateEvent<C>
150where
151 C: StaticStateEventContent + RedactContent,
152 C::Redacted: RedactedStateEventContent,
153{
154 fn from(ev: SyncStateEvent<C>) -> Self {
155 match ev {
156 SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
157 content: ev.content,
158 event_id: Some(ev.event_id),
159 }),
160 SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
161 content: ev.content,
162 event_id: Some(ev.event_id),
163 }),
164 }
165 }
166}
167
168impl<C> From<&SyncStateEvent<C>> for MinimalStateEvent<C>
169where
170 C: Clone + StaticStateEventContent + RedactContent,
171 C::Redacted: Clone + RedactedStateEventContent,
172{
173 fn from(ev: &SyncStateEvent<C>) -> Self {
174 match ev {
175 SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
176 content: ev.content.clone(),
177 event_id: Some(ev.event_id.clone()),
178 }),
179 SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
180 content: ev.content.clone(),
181 event_id: Some(ev.event_id.clone()),
182 }),
183 }
184 }
185}
186
187impl From<&SyncRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> {
188 fn from(ev: &SyncRoomCreateEvent) -> Self {
189 match ev {
190 SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
191 content: RoomCreateWithCreatorEventContent::from_event_content(
192 ev.content.clone(),
193 ev.sender.clone(),
194 ),
195 event_id: Some(ev.event_id.clone()),
196 }),
197 SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
198 content: RoomCreateWithCreatorEventContent::from_event_content(
199 ev.content.clone(),
200 ev.sender.clone(),
201 ),
202 event_id: Some(ev.event_id.clone()),
203 }),
204 }
205 }
206}
207
208impl From<&StrippedRoomAvatarEvent> for MinimalStateEvent<RoomAvatarEventContent> {
209 fn from(event: &StrippedRoomAvatarEvent) -> Self {
210 let content = assign!(RoomAvatarEventContent::new(), {
211 info: event.content.info.clone(),
212 url: event.content.url.clone(),
213 });
214 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
217 }
218}
219
220impl From<&StrippedRoomNameEvent> for MinimalStateEvent<RoomNameEventContent> {
221 fn from(event: &StrippedRoomNameEvent) -> Self {
222 match event.content.name.clone() {
223 Some(name) => {
224 let content = RoomNameEventContent::new(name);
225 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
226 }
227 None => {
228 let content = RedactedRoomNameEventContent::new();
229 Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
230 }
231 }
232 }
233}
234
235impl From<&StrippedRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> {
236 fn from(event: &StrippedRoomCreateEvent) -> Self {
237 let content = RoomCreateWithCreatorEventContent {
238 creator: event.sender.clone(),
239 federate: event.content.federate,
240 room_version: event.content.room_version.clone(),
241 predecessor: event.content.predecessor.clone(),
242 room_type: event.content.room_type.clone(),
243 };
244 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
245 }
246}
247
248impl From<&StrippedRoomHistoryVisibilityEvent>
249 for MinimalStateEvent<RoomHistoryVisibilityEventContent>
250{
251 fn from(event: &StrippedRoomHistoryVisibilityEvent) -> Self {
252 let content =
253 RoomHistoryVisibilityEventContent::new(event.content.history_visibility.clone());
254 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
255 }
256}
257
258impl From<&StrippedRoomGuestAccessEvent> for MinimalStateEvent<RoomGuestAccessEventContent> {
259 fn from(event: &StrippedRoomGuestAccessEvent) -> Self {
260 match &event.content.guest_access {
261 Some(guest_access) => {
262 let content = RoomGuestAccessEventContent::new(guest_access.clone());
263 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
264 }
265 None => {
266 let content = RedactedRoomGuestAccessEventContent::new();
267 Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
268 }
269 }
270 }
271}
272
273impl From<&StrippedRoomJoinRulesEvent> for MinimalStateEvent<RoomJoinRulesEventContent> {
274 fn from(event: &StrippedRoomJoinRulesEvent) -> Self {
275 let content = RoomJoinRulesEventContent::new(event.content.join_rule.clone());
276 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
277 }
278}
279
280impl From<&StrippedRoomCanonicalAliasEvent> for MinimalStateEvent<RoomCanonicalAliasEventContent> {
281 fn from(event: &StrippedRoomCanonicalAliasEvent) -> Self {
282 let content = assign!(RoomCanonicalAliasEventContent::new(), {
283 alias: event.content.alias.clone(),
284 alt_aliases: event.content.alt_aliases.clone(),
285 });
286 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
287 }
288}
289
290impl From<&StrippedRoomTopicEvent> for MinimalStateEvent<RoomTopicEventContent> {
291 fn from(event: &StrippedRoomTopicEvent) -> Self {
292 match &event.content.topic {
293 Some(topic) => {
294 let content = RoomTopicEventContent::new(topic.clone());
295 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
296 }
297 None => {
298 let content = RedactedRoomTopicEventContent::new();
299 Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
300 }
301 }
302 }
303}
304
305impl From<&StrippedRoomTombstoneEvent> for MinimalStateEvent<RoomTombstoneEventContent> {
306 fn from(event: &StrippedRoomTombstoneEvent) -> Self {
307 match (&event.content.body, &event.content.replacement_room) {
308 (Some(body), Some(replacement_room)) => {
309 let content =
310 RoomTombstoneEventContent::new(body.clone(), replacement_room.clone());
311 Self::Original(OriginalMinimalStateEvent { content, event_id: None })
312 }
313 _ => {
314 let content = RedactedRoomTombstoneEventContent::new();
315 Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
316 }
317 }
318 }
319}