diff --git a/crates/matrix-sdk-base/src/lib.rs b/crates/matrix-sdk-base/src/lib.rs index dd7c68f33cd..fddb67fb0df 100644 --- a/crates/matrix-sdk-base/src/lib.rs +++ b/crates/matrix-sdk-base/src/lib.rs @@ -68,10 +68,7 @@ pub use store::{ QueueWedgeError, StateChanges, StateStore, StateStoreDataKey, StateStoreDataValue, StoreError, ThreadSubscriptionCatchupToken, }; -pub use utils::{ - MinimalRoomMemberEvent, MinimalStateEvent, OriginalMinimalStateEvent, - RawSyncStateEventWithKeys, RedactedMinimalStateEvent, -}; +pub use utils::{MinimalRoomMemberEvent, MinimalStateEvent, RawSyncStateEventWithKeys}; #[cfg(test)] matrix_sdk_test_utils::init_tracing_for_tests!(); diff --git a/crates/matrix-sdk-base/src/response_processors/state_events.rs b/crates/matrix-sdk-base/src/response_processors/state_events.rs index cd35a7b3dac..702fdc650a0 100644 --- a/crates/matrix-sdk-base/src/response_processors/state_events.rs +++ b/crates/matrix-sdk-base/src/response_processors/state_events.rs @@ -427,7 +427,7 @@ pub fn is_tombstone_event_valid( .state_changes .room_infos .get(&successor_room_id) - .and_then(|room_info| Some(room_info.tombstone()?.replacement_room.clone())) + .and_then(|room_info| room_info.tombstone()?.replacement_room.clone()) .or_else(|| { state_store .room(&successor_room_id) diff --git a/crates/matrix-sdk-base/src/room/create.rs b/crates/matrix-sdk-base/src/room/create.rs index 92764726e8b..20d7479ee6d 100644 --- a/crates/matrix-sdk-base/src/room/create.rs +++ b/crates/matrix-sdk-base/src/room/create.rs @@ -16,7 +16,8 @@ use matrix_sdk_common::ROOM_VERSION_RULES_FALLBACK; use ruma::{ OwnedUserId, RoomVersionId, assign, events::{ - EmptyStateKey, RedactContent, RedactedStateEventContent, StateEventType, + EmptyStateKey, PossiblyRedactedStateEventContent, RedactContent, RedactedStateEventContent, + StateEventContent, StateEventType, StaticEventContent, macros::EventContent, room::create::{PreviousRoom, RoomCreateEventContent}, }, @@ -135,10 +136,10 @@ impl RoomCreateWithCreatorEventContent { pub type RedactedRoomCreateWithCreatorEventContent = RoomCreateWithCreatorEventContent; impl RedactedStateEventContent for RedactedRoomCreateWithCreatorEventContent { - type StateKey = EmptyStateKey; + type StateKey = ::StateKey; fn event_type(&self) -> StateEventType { - StateEventType::RoomCreate + RoomCreateWithCreatorEventContent::TYPE.into() } } @@ -156,3 +157,11 @@ impl RedactContent for RoomCreateWithCreatorEventContent { fn default_create_room_version_id() -> RoomVersionId { RoomVersionId::V1 } + +impl PossiblyRedactedStateEventContent for RoomCreateWithCreatorEventContent { + type StateKey = ::StateKey; + + fn event_type(&self) -> StateEventType { + RoomCreateWithCreatorEventContent::TYPE.into() + } +} diff --git a/crates/matrix-sdk-base/src/room/display_name.rs b/crates/matrix-sdk-base/src/room/display_name.rs index 5401cee4e37..06bcc84458b 100644 --- a/crates/matrix-sdk-base/src/room/display_name.rs +++ b/crates/matrix-sdk-base/src/room/display_name.rs @@ -544,9 +544,11 @@ mod tests { events::{ StateEventType, room::{ - canonical_alias::RoomCanonicalAliasEventContent, + canonical_alias::{ + PossiblyRedactedRoomCanonicalAliasEventContent, RoomCanonicalAliasEventContent, + }, member::{MembershipState, RoomMemberEventContent, StrippedRoomMemberEvent}, - name::RoomNameEventContent, + name::{PossiblyRedactedRoomNameEventContent, RoomNameEventContent}, }, }, room_alias_id, room_id, @@ -557,8 +559,7 @@ mod tests { use super::{Room, RoomDisplayName, compute_display_name_from_heroes}; use crate::{ - MinimalStateEvent, OriginalMinimalStateEvent, RoomHero, RoomState, StateChanges, - StateStore, store::MemoryStore, + MinimalStateEvent, RoomHero, RoomState, StateChanges, StateStore, store::MemoryStore, }; fn make_room_test_helper(room_type: RoomState) -> (Arc, Room) { @@ -584,22 +585,22 @@ mod tests { } fn make_canonical_alias_event() -> MinimalStateEvent { - MinimalStateEvent::Original(OriginalMinimalStateEvent { - content: assign!(RoomCanonicalAliasEventContent::new(), { + MinimalStateEvent { + content: assign!(PossiblyRedactedRoomCanonicalAliasEventContent::new(), { alias: Some(room_alias_id!("#test:example.com").to_owned()), }), event_id: None, - }) + } } - fn make_name_event_with(name: &str) -> MinimalStateEvent { - MinimalStateEvent::Original(OriginalMinimalStateEvent { - content: RoomNameEventContent::new(name.to_owned()), + fn make_name_event_with(name: &str) -> MinimalStateEvent { + MinimalStateEvent { + content: RoomNameEventContent::new(name.to_owned()).into(), event_id: None, - }) + } } - fn make_name_event() -> MinimalStateEvent { + fn make_name_event() -> MinimalStateEvent { make_name_event_with("Test Room") } @@ -697,10 +698,7 @@ mod tests { async fn test_display_name_for_invited_room_is_empty_if_room_name_empty() { let (_, room) = make_room_test_helper(RoomState::Invited); - let room_name = MinimalStateEvent::Original(OriginalMinimalStateEvent { - content: RoomNameEventContent::new(String::new()), - event_id: None, - }); + let room_name = make_name_event_with(""); room.info.update(|info| info.base_info.name = Some(room_name)); assert_eq!(room.compute_display_name().await.unwrap().into_inner(), RoomDisplayName::Empty); diff --git a/crates/matrix-sdk-base/src/room/members.rs b/crates/matrix-sdk-base/src/room/members.rs index ad6bfb8c5fa..7d5bf112b27 100644 --- a/crates/matrix-sdk-base/src/room/members.rs +++ b/crates/matrix-sdk-base/src/room/members.rs @@ -259,7 +259,7 @@ impl RoomMember { /// Get the display name of the member if there is one. pub fn display_name(&self) -> Option<&str> { if let Some(p) = self.profile.as_ref() { - p.as_original().and_then(|e| e.content.displayname.as_deref()) + p.content.displayname.as_deref() } else { self.event.displayname_value() } @@ -276,7 +276,7 @@ impl RoomMember { /// Get the avatar url of the member, if there is one. pub fn avatar_url(&self) -> Option<&MxcUri> { if let Some(p) = self.profile.as_ref() { - p.as_original().and_then(|e| e.content.avatar_url.as_deref()) + p.content.avatar_url.as_deref() } else { self.event.avatar_url() } diff --git a/crates/matrix-sdk-base/src/room/mod.rs b/crates/matrix-sdk-base/src/room/mod.rs index f03cbbeac6e..02390bad51c 100644 --- a/crates/matrix-sdk-base/src/room/mod.rs +++ b/crates/matrix-sdk-base/src/room/mod.rs @@ -67,7 +67,7 @@ pub use tombstone::{PredecessorRoom, SuccessorRoom}; use tracing::{info, instrument, warn}; use crate::{ - Error, MinimalStateEvent, + Error, deserialized_responses::MemberEvent, notification_settings::RoomNotificationMode, read_receipts::RoomReadReceipts, @@ -244,10 +244,7 @@ impl Room { /// redacted, all fields except `creator` will be set to their default /// value. pub fn create_content(&self) -> Option { - match self.info.read().base_info.create.as_ref()? { - MinimalStateEvent::Original(ev) => Some(ev.content.clone()), - MinimalStateEvent::Redacted(ev) => Some(ev.content.clone()), - } + Some(self.info.read().base_info.create.as_ref()?.content.clone()) } /// Is this room considered a direct message. diff --git a/crates/matrix-sdk-base/src/room/room_info.rs b/crates/matrix-sdk-base/src/room/room_info.rs index 67572f9c511..6954ec19520 100644 --- a/crates/matrix-sdk-base/src/room/room_info.rs +++ b/crates/matrix-sdk-base/src/room/room_info.rs @@ -29,20 +29,24 @@ use ruma::{ events::{ AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, StateEventType, SyncStateEvent, - call::member::{CallMemberEventContent, CallMemberStateKey, MembershipData}, + call::member::{ + CallMemberStateKey, MembershipData, PossiblyRedactedCallMemberEventContent, + }, direct::OwnedDirectUserIdentifier, room::{ - avatar::{self, RoomAvatarEventContent}, - canonical_alias::RoomCanonicalAliasEventContent, + avatar::{self, PossiblyRedactedRoomAvatarEventContent}, + canonical_alias::PossiblyRedactedRoomCanonicalAliasEventContent, encryption::RoomEncryptionEventContent, - guest_access::{GuestAccess, RoomGuestAccessEventContent}, - history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, - join_rules::{JoinRule, RoomJoinRulesEventContent}, - name::RoomNameEventContent, + guest_access::{GuestAccess, PossiblyRedactedRoomGuestAccessEventContent}, + history_visibility::{ + HistoryVisibility, PossiblyRedactedRoomHistoryVisibilityEventContent, + }, + join_rules::{JoinRule, PossiblyRedactedRoomJoinRulesEventContent}, + name::PossiblyRedactedRoomNameEventContent, pinned_events::RoomPinnedEventsEventContent, redaction::SyncRoomRedactionEvent, - tombstone::RoomTombstoneEventContent, - topic::RoomTopicEventContent, + tombstone::PossiblyRedactedRoomTombstoneEventContent, + topic::PossiblyRedactedRoomTopicEventContent, }, tag::{TagEventContent, TagName, Tags}, }, @@ -58,7 +62,7 @@ use super::{ RoomHero, RoomNotableTags, RoomState, RoomSummary, }; use crate::{ - MinimalStateEvent, OriginalMinimalStateEvent, + MinimalStateEvent, deserialized_responses::RawSyncOrStrippedState, latest_event::LatestEventValue, notification_settings::RoomNotificationMode, @@ -126,9 +130,10 @@ impl Room { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BaseRoomInfo { /// The avatar URL of this room. - pub(crate) avatar: Option>, + pub(crate) avatar: Option>, /// The canonical alias of this room. - pub(crate) canonical_alias: Option>, + pub(crate) canonical_alias: + Option>, /// The `m.room.create` event content of this room. pub(crate) create: Option>, /// A list of user ids this room is considered as direct message, if this @@ -137,24 +142,25 @@ pub struct BaseRoomInfo { /// The `m.room.encryption` event content that enabled E2EE in this room. pub(crate) encryption: Option, /// The guest access policy of this room. - pub(crate) guest_access: Option>, + pub(crate) guest_access: Option>, /// The history visibility policy of this room. - pub(crate) history_visibility: Option>, + pub(crate) history_visibility: + Option>, /// The join rule policy of this room. - pub(crate) join_rules: Option>, + pub(crate) join_rules: Option>, /// The maximal power level that can be found in this room. pub(crate) max_power_level: i64, /// The `m.room.name` of this room. - pub(crate) name: Option>, + pub(crate) name: Option>, /// The `m.room.tombstone` event content of this room. - pub(crate) tombstone: Option>, + pub(crate) tombstone: Option>, /// The topic of this room. - pub(crate) topic: Option>, + pub(crate) topic: Option>, /// All minimal state events that containing one or more running matrixRTC /// memberships. #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] pub(crate) rtc_member_events: - BTreeMap>, + BTreeMap>, /// Whether this room has been manually marked as unread. #[serde(default)] pub(crate) is_marked_unread: bool, @@ -182,10 +188,7 @@ impl BaseRoomInfo { /// For room versions earlier than room version 11, if the event is /// redacted, this will return the default of [`RoomVersionId::V1`]. pub fn room_version(&self) -> Option<&RoomVersionId> { - match self.create.as_ref()? { - MinimalStateEvent::Original(ev) => Some(&ev.content.room_version), - MinimalStateEvent::Redacted(ev) => Some(&ev.content.room_version), - } + Some(&self.create.as_ref()?.content.room_version) } /// Handle a state event for this room and update our info accordingly. @@ -352,10 +355,8 @@ impl BaseRoomInfo { .insert(event.state_key.clone(), SyncStateEvent::Original(event).into()); // Remove all events that don't contain any memberships anymore. - self.rtc_member_events.retain(|_, ev| { - ev.as_original() - .is_some_and(|o| !o.content.active_memberships(None).is_empty()) - }); + self.rtc_member_events + .retain(|_, ev| !ev.content.active_memberships(None).is_empty()); true } else if let Ok(call_member_key) = @@ -464,44 +465,44 @@ impl BaseRoomInfo { .redaction; if let Some(ev) = &mut self.avatar - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.canonical_alias - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.create - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.guest_access - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.history_visibility - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.join_rules - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.name - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.tombstone - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else if let Some(ev) = &mut self.topic - && ev.event_id() == Some(redacts) + && ev.event_id.as_deref() == Some(redacts) { ev.redact(&redaction_rules); } else { self.rtc_member_events - .retain(|_, member_event| member_event.event_id() != Some(redacts)); + .retain(|_, member_event| member_event.event_id.as_deref() != Some(redacts)); } } @@ -857,28 +858,22 @@ impl RoomInfo { /// Returns the current room avatar. pub fn avatar_url(&self) -> Option<&MxcUri> { - self.base_info - .avatar - .as_ref() - .and_then(|e| e.as_original().and_then(|e| e.content.url.as_deref())) + self.base_info.avatar.as_ref().and_then(|e| e.content.url.as_deref()) } /// Update the room avatar. pub fn update_avatar(&mut self, url: Option) { self.base_info.avatar = url.map(|url| { - let mut content = RoomAvatarEventContent::new(); + let mut content = PossiblyRedactedRoomAvatarEventContent::new(); content.url = Some(url); - MinimalStateEvent::Original(OriginalMinimalStateEvent { content, event_id: None }) + MinimalStateEvent { content, event_id: None } }); } /// Returns information about the current room avatar. pub fn avatar_info(&self) -> Option<&avatar::ImageInfo> { - self.base_info - .avatar - .as_ref() - .and_then(|e| e.as_original().and_then(|e| e.content.info.as_deref())) + self.base_info.avatar.as_ref().and_then(|e| e.content.info.as_deref()) } /// Update the notifications count. @@ -974,7 +969,7 @@ impl RoomInfo { /// Get the canonical alias of this room. pub fn canonical_alias(&self) -> Option<&RoomAliasId> { - self.base_info.canonical_alias.as_ref()?.as_original()?.content.alias.as_deref() + self.base_info.canonical_alias.as_ref()?.content.alias.as_deref() } /// Get the alternative aliases of this room. @@ -982,7 +977,6 @@ impl RoomInfo { self.base_info .canonical_alias .as_ref() - .and_then(|ev| ev.as_original()) .map(|ev| ev.content.alt_aliases.as_ref()) .unwrap_or_default() } @@ -1021,35 +1015,27 @@ impl RoomInfo { /// Get the room type of this room. pub fn room_type(&self) -> Option<&RoomType> { - match self.base_info.create.as_ref()? { - MinimalStateEvent::Original(ev) => ev.content.room_type.as_ref(), - MinimalStateEvent::Redacted(ev) => ev.content.room_type.as_ref(), - } + self.base_info.create.as_ref()?.content.room_type.as_ref() } /// Get the creators of this room. pub fn creators(&self) -> Option> { - match self.base_info.create.as_ref()? { - MinimalStateEvent::Original(ev) => Some(ev.content.creators()), - MinimalStateEvent::Redacted(ev) => Some(ev.content.creators()), - } + Some(self.base_info.create.as_ref()?.content.creators()) } pub(super) fn guest_access(&self) -> &GuestAccess { - match &self.base_info.guest_access { - Some(MinimalStateEvent::Original(ev)) => &ev.content.guest_access, - _ => &GuestAccess::Forbidden, - } + self.base_info + .guest_access + .as_ref() + .and_then(|event| event.content.guest_access.as_ref()) + .unwrap_or(&GuestAccess::Forbidden) } /// Returns the history visibility for this room. /// /// Returns None if the event was never seen during sync. pub fn history_visibility(&self) -> Option<&HistoryVisibility> { - match &self.base_info.history_visibility { - Some(MinimalStateEvent::Original(ev)) => Some(&ev.content.history_visibility), - _ => None, - } + Some(&self.base_info.history_visibility.as_ref()?.content.history_visibility) } /// Returns the history visibility for this room, or a sensible default. @@ -1059,40 +1045,33 @@ impl RoomInfo { /// /// [spec]: https://spec.matrix.org/latest/client-server-api/#server-behaviour-7 pub fn history_visibility_or_default(&self) -> &HistoryVisibility { - match &self.base_info.history_visibility { - Some(MinimalStateEvent::Original(ev)) => &ev.content.history_visibility, - _ => &HistoryVisibility::Shared, - } + self.history_visibility().unwrap_or(&HistoryVisibility::Shared) } /// Return the join rule for this room, if the `m.room.join_rules` event is /// available. pub fn join_rule(&self) -> Option<&JoinRule> { - match &self.base_info.join_rules { - Some(MinimalStateEvent::Original(ev)) => Some(&ev.content.join_rule), - _ => None, - } + Some(&self.base_info.join_rules.as_ref()?.content.join_rule) } /// Get the name of this room. pub fn name(&self) -> Option<&str> { - let name = &self.base_info.name.as_ref()?.as_original()?.content.name; - (!name.is_empty()).then_some(name) + self.base_info.name.as_ref()?.content.name.as_deref().filter(|name| !name.is_empty()) } /// Get the content of the `m.room.create` event if any. pub fn create(&self) -> Option<&RoomCreateWithCreatorEventContent> { - Some(&self.base_info.create.as_ref()?.as_original()?.content) + Some(&self.base_info.create.as_ref()?.content) } /// Get the content of the `m.room.tombstone` event if any. - pub fn tombstone(&self) -> Option<&RoomTombstoneEventContent> { - Some(&self.base_info.tombstone.as_ref()?.as_original()?.content) + pub fn tombstone(&self) -> Option<&PossiblyRedactedRoomTombstoneEventContent> { + Some(&self.base_info.tombstone.as_ref()?.content) } /// Returns the topic for this room, if set. pub fn topic(&self) -> Option<&str> { - Some(&self.base_info.topic.as_ref()?.as_original()?.content.topic) + self.base_info.topic.as_ref()?.content.topic.as_deref() } /// Get a list of all the valid (non expired) matrixRTC memberships and @@ -1104,15 +1083,9 @@ impl RoomInfo { .base_info .rtc_member_events .iter() - .filter_map(|(user_id, ev)| { - ev.as_original().map(|ev| { - ev.content - .active_memberships(None) - .into_iter() - .map(move |m| (user_id.clone(), m)) - }) + .flat_map(|(state_key, ev)| { + ev.content.active_memberships(None).into_iter().map(move |m| (state_key.clone(), m)) }) - .flatten() .collect::>(); v.sort_by_key(|(_, m)| m.created_ts()); v diff --git a/crates/matrix-sdk-base/src/room/tombstone.rs b/crates/matrix-sdk-base/src/room/tombstone.rs index 88c831138da..704063e1c29 100644 --- a/crates/matrix-sdk-base/src/room/tombstone.rs +++ b/crates/matrix-sdk-base/src/room/tombstone.rs @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::ops::Not; - -use ruma::{OwnedRoomId, events::room::tombstone::RoomTombstoneEventContent}; +use ruma::{OwnedRoomId, events::room::tombstone::PossiblyRedactedRoomTombstoneEventContent}; use super::Room; @@ -36,7 +34,7 @@ impl Room { /// event has been received. It's faster than using this method. /// /// [`m.room.tombstone`]: https://spec.matrix.org/v1.14/client-server-api/#mroomtombstone - pub fn tombstone_content(&self) -> Option { + pub fn tombstone_content(&self) -> Option { self.info.read().tombstone().cloned() } @@ -48,9 +46,11 @@ impl Room { /// /// [`m.room.tombstone`]: https://spec.matrix.org/v1.14/client-server-api/#mroomtombstone pub fn successor_room(&self) -> Option { - self.tombstone_content().map(|tombstone_event| SuccessorRoom { - room_id: tombstone_event.replacement_room, - reason: tombstone_event.body.is_empty().not().then_some(tombstone_event.body), + self.tombstone_content().and_then(|tombstone_event| { + Some(SuccessorRoom { + room_id: tombstone_event.replacement_room?, + reason: tombstone_event.body.filter(|body| !body.is_empty()), + }) }) } diff --git a/crates/matrix-sdk-base/src/store/ambiguity_map.rs b/crates/matrix-sdk-base/src/store/ambiguity_map.rs index 896a947dfaf..8080022c9a1 100644 --- a/crates/matrix-sdk-base/src/store/ambiguity_map.rs +++ b/crates/matrix-sdk-base/src/store/ambiguity_map.rs @@ -193,14 +193,11 @@ impl AmbiguityCache { let display_name = if let Some(d) = changes .profiles .get(room_id) - .and_then(|p| p.get(user_id)?.as_original()?.content.displayname.as_deref()) + .and_then(|p| p.get(user_id)?.content.displayname.as_deref()) { Some(d.to_owned()) - } else if let Some(d) = self - .store - .get_profile(room_id, user_id) - .await? - .and_then(|p| p.into_original()?.content.displayname) + } else if let Some(d) = + self.store.get_profile(room_id, user_id).await?.and_then(|p| p.content.displayname) { Some(d) } else { diff --git a/crates/matrix-sdk-base/src/store/integration_tests.rs b/crates/matrix-sdk-base/src/store/integration_tests.rs index 2cc066e8153..2207446f03d 100644 --- a/crates/matrix-sdk-base/src/store/integration_tests.rs +++ b/crates/matrix-sdk-base/src/store/integration_tests.rs @@ -1227,7 +1227,7 @@ impl StateStoreIntegrationTests for DynStateStore { // The profile for the invited user has been updated. let invited_member_event = self.get_profile(room_id, invited_user_id).await?.unwrap(); assert_eq!( - invited_member_event.as_original().unwrap().content.displayname.as_deref(), + invited_member_event.content.displayname.as_deref(), Some("example after update") ); assert!(self.get_member_event(room_id, invited_user_id).await?.is_some()); diff --git a/crates/matrix-sdk-base/src/store/migration_helpers.rs b/crates/matrix-sdk-base/src/store/migration_helpers.rs index 6b086250bf0..309842458f5 100644 --- a/crates/matrix-sdk-base/src/store/migration_helpers.rs +++ b/crates/matrix-sdk-base/src/store/migration_helpers.rs @@ -20,27 +20,24 @@ use matrix_sdk_common::deserialized_responses::TimelineEvent; use ruma::{ OwnedRoomId, OwnedUserId, RoomId, events::{ - EmptyStateKey, RedactContent, StateEventContent, StateEventType, direct::OwnedDirectUserIdentifier, room::{ - avatar::RoomAvatarEventContent, - canonical_alias::RoomCanonicalAliasEventContent, - create::RoomCreateEventContent, - encryption::RoomEncryptionEventContent, - guest_access::RoomGuestAccessEventContent, - history_visibility::RoomHistoryVisibilityEventContent, - join_rules::RoomJoinRulesEventContent, - name::{RedactedRoomNameEventContent, RoomNameEventContent}, - tombstone::RoomTombstoneEventContent, - topic::RoomTopicEventContent, + avatar::PossiblyRedactedRoomAvatarEventContent, + canonical_alias::PossiblyRedactedRoomCanonicalAliasEventContent, + create::RoomCreateEventContent, encryption::RoomEncryptionEventContent, + guest_access::PossiblyRedactedRoomGuestAccessEventContent, + history_visibility::PossiblyRedactedRoomHistoryVisibilityEventContent, + join_rules::PossiblyRedactedRoomJoinRulesEventContent, + name::PossiblyRedactedRoomNameEventContent, + tombstone::PossiblyRedactedRoomTombstoneEventContent, + topic::PossiblyRedactedRoomTopicEventContent, }, }, - room_version_rules::RedactionRules, }; use serde::{Deserialize, Serialize}; use crate::{ - MinimalStateEvent, OriginalMinimalStateEvent, RoomInfo, RoomState, + MinimalStateEvent, RoomInfo, RoomState, deserialized_responses::SyncOrStrippedState, latest_event::LatestEventValue, room::{BaseRoomInfo, RoomSummary, SyncInfo}, @@ -143,17 +140,18 @@ fn encryption_state_default() -> bool { /// [`BaseRoomInfo`] version 1. #[derive(Clone, Debug, Serialize, Deserialize)] struct BaseRoomInfoV1 { - avatar: Option>, - canonical_alias: Option>, + avatar: Option>, + canonical_alias: Option>, dm_targets: HashSet, encryption: Option, - guest_access: Option>, - history_visibility: Option>, - join_rules: Option>, + guest_access: Option>, + history_visibility: + Option>, + join_rules: Option>, max_power_level: i64, - name: Option>, - tombstone: Option>, - topic: Option>, + name: Option>, + tombstone: Option>, + topic: Option>, } impl BaseRoomInfoV1 { @@ -180,15 +178,6 @@ impl BaseRoomInfoV1 { SyncOrStrippedState::Sync(e) => e.into(), SyncOrStrippedState::Stripped(e) => e.into(), }); - let name = name.map(|name| match name { - MinimalStateEvent::Original(ev) => { - MinimalStateEvent::Original(OriginalMinimalStateEvent { - content: ev.content.into(), - event_id: ev.event_id, - }) - } - MinimalStateEvent::Redacted(ev) => MinimalStateEvent::Redacted(ev), - }); let mut converted_dm_targets = HashSet::new(); for dm_target in dm_targets { @@ -212,31 +201,3 @@ impl BaseRoomInfoV1 { }) } } - -/// [`RoomNameEventContent`] version 1, with an optional `name`. -#[derive(Clone, Debug, Serialize, Deserialize)] -struct RoomNameEventContentV1 { - name: Option, -} - -impl StateEventContent for RoomNameEventContentV1 { - type StateKey = EmptyStateKey; - - fn event_type(&self) -> StateEventType { - StateEventType::RoomName - } -} - -impl RedactContent for RoomNameEventContentV1 { - type Redacted = RedactedRoomNameEventContent; - - fn redact(self, _rules: &RedactionRules) -> Self::Redacted { - RedactedRoomNameEventContent::new() - } -} - -impl From for RoomNameEventContent { - fn from(value: RoomNameEventContentV1) -> Self { - RoomNameEventContent::new(value.name.unwrap_or_default()) - } -} diff --git a/crates/matrix-sdk-base/src/utils.rs b/crates/matrix-sdk-base/src/utils.rs index c60da6d7348..3615518aec0 100644 --- a/crates/matrix-sdk-base/src/utils.rs +++ b/crates/matrix-sdk-base/src/utils.rs @@ -1,187 +1,151 @@ use ruma::{ - EventId, OwnedEventId, assign, + OwnedEventId, events::{ - AnySyncStateEvent, AnySyncTimelineEvent, RedactContent, RedactedStateEventContent, - StateEventContent, StateEventType, StaticEventContent, StaticStateEventContent, - SyncStateEvent, + AnySyncStateEvent, AnySyncTimelineEvent, PossiblyRedactedStateEventContent, RedactContent, + RedactedStateEventContent, StateEventType, StaticEventContent, StaticStateEventContent, + StrippedStateEvent, SyncStateEvent, room::{ - avatar::{RoomAvatarEventContent, StrippedRoomAvatarEvent}, - canonical_alias::{RoomCanonicalAliasEventContent, StrippedRoomCanonicalAliasEvent}, create::{StrippedRoomCreateEvent, SyncRoomCreateEvent}, - guest_access::{ - RedactedRoomGuestAccessEventContent, RoomGuestAccessEventContent, - StrippedRoomGuestAccessEvent, - }, - history_visibility::{ - RoomHistoryVisibilityEventContent, StrippedRoomHistoryVisibilityEvent, - }, - join_rules::{RoomJoinRulesEventContent, StrippedRoomJoinRulesEvent}, - member::{MembershipState, RoomMemberEventContent}, - name::{RedactedRoomNameEventContent, RoomNameEventContent, StrippedRoomNameEvent}, - tombstone::{ - RedactedRoomTombstoneEventContent, RoomTombstoneEventContent, - StrippedRoomTombstoneEvent, - }, - topic::{RedactedRoomTopicEventContent, RoomTopicEventContent, StrippedRoomTopicEvent}, + member::PossiblyRedactedRoomMemberEventContent, }, }, room_version_rules::RedactionRules, serde::Raw, }; -use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use serde::{Deserialize, Serialize}; use tracing::{error, warn}; use crate::room::RoomCreateWithCreatorEventContent; -// #[serde(bound)] instead of DeserializeOwned in type where clause does not -// work, it can only be a single bound that replaces the default and if a helper -// trait is used, the compiler still complains about Deserialize not being -// implemented for C::Redacted. -// -// It is unclear why a Serialize bound on C::Redacted is not also required. - /// A minimal state event. /// /// This type can hold a possibly-redacted state event with an optional /// event ID. The event ID is optional so this type can also hold events from /// invited rooms, where event IDs are not available. #[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(bound( - serialize = "C: Serialize, C::Redacted: Serialize", - deserialize = "C: DeserializeOwned, C::Redacted: DeserializeOwned" -))] -pub enum MinimalStateEvent -where - C::Redacted: RedactedStateEventContent, -{ - /// An unredacted event. - Original(OriginalMinimalStateEvent), - /// A redacted event. - Redacted(RedactedMinimalStateEvent), -} - -/// An unredacted minimal state event. -/// -/// For more details see [`MinimalStateEvent`]. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct OriginalMinimalStateEvent -where - C: StateEventContent, -{ +#[serde( + bound(serialize = "C: Serialize + Clone"), + from = "MinimalStateEventSerdeHelper", + into = "MinimalStateEventSerdeHelper" +)] +pub struct MinimalStateEvent { /// The event's content. pub content: C, /// The event's ID, if known. pub event_id: Option, } -/// A redacted minimal state event. -/// -/// For more details see [`MinimalStateEvent`]. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct RedactedMinimalStateEvent +impl MinimalStateEvent where - C: RedactedStateEventContent, + C: PossiblyRedactedStateEventContent + RedactContent, + C::Redacted: Into, { - /// The event's content. - pub content: C, - /// The event's ID, if known. - pub event_id: Option, + /// Redacts this event. + /// + /// Does nothing if it is already redacted. + pub fn redact(&mut self, rules: &RedactionRules) + where + C: Clone, + { + self.content = self.content.clone().redact(rules).into() + } } -impl MinimalStateEvent +/// Helper type to (de)serialize [`MinimalStateEvent`]. +#[derive(Serialize, Deserialize)] +enum MinimalStateEventSerdeHelper { + /// Previous variant for a non-redacted event. + Original(MinimalStateEventSerdeHelperInner), + /// Previous variant for a redacted event. + Redacted(MinimalStateEventSerdeHelperInner), + /// New variant. + PossiblyRedacted(MinimalStateEventSerdeHelperInner), +} + +impl From> for MinimalStateEvent where - C: StateEventContent + RedactContent, - C::Redacted: RedactedStateEventContent, + C: PossiblyRedactedStateEventContent + RedactContent, { - /// Get the inner event's ID. - pub fn event_id(&self) -> Option<&EventId> { - match self { - MinimalStateEvent::Original(ev) => ev.event_id.as_deref(), - MinimalStateEvent::Redacted(ev) => ev.event_id.as_deref(), + fn from(value: MinimalStateEventSerdeHelper) -> Self { + match value { + MinimalStateEventSerdeHelper::Original(event) => event, + MinimalStateEventSerdeHelper::Redacted(event) => event, + MinimalStateEventSerdeHelper::PossiblyRedacted(event) => event, } + .into() } +} - /// Returns the inner event, if it isn't redacted. - pub fn as_original(&self) -> Option<&OriginalMinimalStateEvent> { - match self { - MinimalStateEvent::Original(ev) => Some(ev), - MinimalStateEvent::Redacted(_) => None, - } +impl From> for MinimalStateEventSerdeHelper +where + C: PossiblyRedactedStateEventContent + RedactContent, +{ + fn from(value: MinimalStateEvent) -> Self { + Self::PossiblyRedacted(value.into()) } +} - /// Converts `self` to the inner `OriginalMinimalStateEvent`, if it isn't - /// redacted. - pub fn into_original(self) -> Option> { - match self { - MinimalStateEvent::Original(ev) => Some(ev), - MinimalStateEvent::Redacted(_) => None, - } - } +#[derive(Serialize, Deserialize)] +struct MinimalStateEventSerdeHelperInner { + content: C, + event_id: Option, +} - /// Redacts this event. - /// - /// Does nothing if it is already redacted. - pub fn redact(&mut self, rules: &RedactionRules) - where - C: Clone, - { - if let MinimalStateEvent::Original(ev) = self { - *self = MinimalStateEvent::Redacted(RedactedMinimalStateEvent { - content: ev.content.clone().redact(rules), - event_id: ev.event_id.clone(), - }); - } +impl From> for MinimalStateEvent +where + C: PossiblyRedactedStateEventContent + RedactContent, +{ + fn from(value: MinimalStateEventSerdeHelperInner) -> Self { + let MinimalStateEventSerdeHelperInner { content, event_id } = value; + Self { content, event_id } } } -/// A minimal `m.room.member` event. -pub type MinimalRoomMemberEvent = MinimalStateEvent; - -impl MinimalRoomMemberEvent { - /// Obtain the membership state, regardless of whether this event is - /// redacted. - pub fn membership(&self) -> &MembershipState { - match self { - MinimalStateEvent::Original(ev) => &ev.content.membership, - MinimalStateEvent::Redacted(ev) => &ev.content.membership, - } +impl From> for MinimalStateEventSerdeHelperInner +where + C: PossiblyRedactedStateEventContent + RedactContent, +{ + fn from(value: MinimalStateEvent) -> Self { + let MinimalStateEvent { content, event_id } = value; + Self { content, event_id } } } -impl From> for MinimalStateEvent +/// A minimal `m.room.member` event. +pub type MinimalRoomMemberEvent = MinimalStateEvent; + +impl From> for MinimalStateEvent where - C: StaticStateEventContent + RedactContent, - C::Redacted: RedactedStateEventContent, + C1: StaticStateEventContent + RedactContent + Into, + C1::Redacted: RedactedStateEventContent + Into, + C2: PossiblyRedactedStateEventContent + RedactContent, { - fn from(ev: SyncStateEvent) -> Self { + fn from(ev: SyncStateEvent) -> Self { match ev { - SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent { - content: ev.content, - event_id: Some(ev.event_id), - }), - SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent { - content: ev.content, - event_id: Some(ev.event_id), - }), + SyncStateEvent::Original(ev) => { + Self { content: ev.content.into(), event_id: Some(ev.event_id) } + } + SyncStateEvent::Redacted(ev) => { + Self { content: ev.content.into(), event_id: Some(ev.event_id) } + } } } } -impl From<&SyncStateEvent> for MinimalStateEvent +impl From<&SyncStateEvent> for MinimalStateEvent where - C: Clone + StaticStateEventContent + RedactContent, - C::Redacted: Clone + RedactedStateEventContent, + C1: Clone + StaticStateEventContent + RedactContent + Into, + C1::Redacted: Clone + RedactedStateEventContent + Into, + C2: PossiblyRedactedStateEventContent + RedactContent, { - fn from(ev: &SyncStateEvent) -> Self { + fn from(ev: &SyncStateEvent) -> Self { match ev { - SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent { - content: ev.content.clone(), - event_id: Some(ev.event_id.clone()), - }), - SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent { - content: ev.content.clone(), - event_id: Some(ev.event_id.clone()), - }), + SyncStateEvent::Original(ev) => { + Self { content: ev.content.clone().into(), event_id: Some(ev.event_id.clone()) } + } + SyncStateEvent::Redacted(ev) => { + Self { content: ev.content.clone().into(), event_id: Some(ev.event_id.clone()) } + } } } } @@ -189,48 +153,39 @@ where impl From<&SyncRoomCreateEvent> for MinimalStateEvent { fn from(ev: &SyncRoomCreateEvent) -> Self { match ev { - SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent { + SyncStateEvent::Original(ev) => Self { content: RoomCreateWithCreatorEventContent::from_event_content( ev.content.clone(), ev.sender.clone(), ), event_id: Some(ev.event_id.clone()), - }), - SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent { + }, + SyncStateEvent::Redacted(ev) => Self { content: RoomCreateWithCreatorEventContent::from_event_content( ev.content.clone(), ev.sender.clone(), ), event_id: Some(ev.event_id.clone()), - }), + }, } } } -impl From<&StrippedRoomAvatarEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomAvatarEvent) -> Self { - let content = assign!(RoomAvatarEventContent::new(), { - info: event.content.info.clone(), - url: event.content.url.clone(), - }); - // event might actually be redacted, there is no way to tell for - // stripped state events. - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) +impl From> for MinimalStateEvent +where + C: PossiblyRedactedStateEventContent + RedactContent, +{ + fn from(event: StrippedStateEvent) -> Self { + Self { content: event.content, event_id: None } } } -impl From<&StrippedRoomNameEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomNameEvent) -> Self { - match event.content.name.clone() { - Some(name) => { - let content = RoomNameEventContent::new(name); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } - None => { - let content = RedactedRoomNameEventContent::new(); - Self::Redacted(RedactedMinimalStateEvent { content, event_id: None }) - } - } +impl From<&StrippedStateEvent> for MinimalStateEvent +where + C: Clone + PossiblyRedactedStateEventContent + RedactContent, +{ + fn from(event: &StrippedStateEvent) -> Self { + Self { content: event.content.clone(), event_id: None } } } @@ -240,80 +195,7 @@ impl From<&StrippedRoomCreateEvent> for MinimalStateEvent - for MinimalStateEvent -{ - fn from(event: &StrippedRoomHistoryVisibilityEvent) -> Self { - let content = - RoomHistoryVisibilityEventContent::new(event.content.history_visibility.clone()); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } -} - -impl From<&StrippedRoomGuestAccessEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomGuestAccessEvent) -> Self { - match &event.content.guest_access { - Some(guest_access) => { - let content = RoomGuestAccessEventContent::new(guest_access.clone()); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } - None => { - let content = RedactedRoomGuestAccessEventContent::new(); - Self::Redacted(RedactedMinimalStateEvent { content, event_id: None }) - } - } - } -} - -impl From<&StrippedRoomJoinRulesEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomJoinRulesEvent) -> Self { - let content = RoomJoinRulesEventContent::new(event.content.join_rule.clone()); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } -} - -impl From<&StrippedRoomCanonicalAliasEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomCanonicalAliasEvent) -> Self { - let content = assign!(RoomCanonicalAliasEventContent::new(), { - alias: event.content.alias.clone(), - alt_aliases: event.content.alt_aliases.clone(), - }); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } -} - -impl From<&StrippedRoomTopicEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomTopicEvent) -> Self { - match &event.content.topic { - Some(topic) => { - let content = RoomTopicEventContent::new(topic.clone()); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } - None => { - let content = RedactedRoomTopicEventContent::new(); - Self::Redacted(RedactedMinimalStateEvent { content, event_id: None }) - } - } - } -} - -impl From<&StrippedRoomTombstoneEvent> for MinimalStateEvent { - fn from(event: &StrippedRoomTombstoneEvent) -> Self { - match (&event.content.body, &event.content.replacement_room) { - (Some(body), Some(replacement_room)) => { - let content = - RoomTombstoneEventContent::new(body.clone(), replacement_room.clone()); - Self::Original(OriginalMinimalStateEvent { content, event_id: None }) - } - _ => { - let content = RedactedRoomTombstoneEventContent::new(); - Self::Redacted(RedactedMinimalStateEvent { content, event_id: None }) - } - } + Self { content, event_id: None } } } @@ -449,3 +331,49 @@ struct StateEventWithKeysDeHelper { /// other messages in the timeline. state_key: Option, } + +#[cfg(test)] +mod tests { + use ruma::{event_id, events::room::name::PossiblyRedactedRoomNameEventContent}; + + use super::MinimalStateEvent; + + #[test] + fn test_backward_compatible_deserialize_minimal_state_event() { + let event_id = event_id!("$event"); + + // The old format with `Original` and `Redacted` variants works. + let event = + serde_json::from_str::>( + r#"{"Original":{"content":{"name":"My Room"},"event_id":"$event"}}"#, + ) + .unwrap(); + assert_eq!(event.content.name.as_deref(), Some("My Room")); + assert_eq!(event.event_id.as_deref(), Some(event_id)); + + let event = + serde_json::from_str::>( + r#"{"Redacted":{"content":{},"event_id":"$event"}}"#, + ) + .unwrap(); + assert_eq!(event.content.name, None); + assert_eq!(event.event_id.as_deref(), Some(event_id)); + + // The new format works. + let event = + serde_json::from_str::>( + r#"{"PossiblyRedacted":{"content":{"name":"My Room"},"event_id":"$event"}}"#, + ) + .unwrap(); + assert_eq!(event.content.name.as_deref(), Some("My Room")); + assert_eq!(event.event_id.as_deref(), Some(event_id)); + + let event = + serde_json::from_str::>( + r#"{"PossiblyRedacted":{"content":{},"event_id":"$event"}}"#, + ) + .unwrap(); + assert_eq!(event.content.name, None); + assert_eq!(event.event_id.as_deref(), Some(event_id)); + } +} diff --git a/crates/matrix-sdk/tests/integration/sync.rs b/crates/matrix-sdk/tests/integration/sync.rs index 056f9a90272..4361d4743b8 100644 --- a/crates/matrix-sdk/tests/integration/sync.rs +++ b/crates/matrix-sdk/tests/integration/sync.rs @@ -1331,7 +1331,10 @@ async fn test_receive_room_tombstone_event_via_sync() { .await; // The room info is set and the valid state event is in the store. - assert_eq!(room.tombstone_content().unwrap().replacement_room, tombstone_replacement); + assert_eq!( + room.tombstone_content().unwrap().replacement_room.as_deref(), + Some(tombstone_replacement) + ); assert_matches!( room.get_state_event_static::().await, Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))