diff --git a/Cargo.lock b/Cargo.lock index c79fc1f8e44..e5acaa8cfed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2048,6 +2048,30 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "headers" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.5.0" @@ -2120,6 +2144,15 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-auth" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "150fa4a9462ef926824cf4519c84ed652ca8f4fbae34cb8af045b5cbcaf98822" +dependencies = [ + "memchr", +] + [[package]] name = "http-body" version = "1.0.1" @@ -3801,7 +3834,6 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "phf_macros", "phf_shared 0.11.2", ] @@ -3835,19 +3867,6 @@ dependencies = [ "rand", ] -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "phf_shared" version = "0.10.0" @@ -4464,8 +4483,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d47e42b7dea75a468dea63a230f51331c58d690ca018ea1c6ac782ea98880c" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "assign", "js_int", @@ -4481,8 +4499,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9e9c613cfda4923b851c5d8bc442305905bee4f0c2b924564b00e71636c8d4" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "as_variant", "assign", @@ -4505,8 +4522,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387e1898e868d32ff7b205e7db327361d5dcf635c00a8ae5865068607595a9cf" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "as_variant", "base64", @@ -4533,13 +4549,13 @@ dependencies = [ "uuid", "web-time", "wildmatch", + "zeroize", ] [[package]] name = "ruma-events" version = "0.30.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cdc7abec9bc2a9ca0b4831cc26ce97a6a8c39a0bde44a19281a719e861b4293" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "as_variant", "indexmap", @@ -4559,32 +4575,34 @@ dependencies = [ "url", "web-time", "wildmatch", + "zeroize", ] [[package]] name = "ruma-federation-api" version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2a705c3911870782e036a3a8b676d0166c6c93800b84f6b8b23c981f78ef08" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ + "headers", "http", + "http-auth", "js_int", "mime", "ruma-common", "ruma-events", "serde", "serde_json", + "thiserror 2.0.11", + "tracing", ] [[package]] name = "ruma-html" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865afa2321e34fa836ea4c1d77ce0c2bb40f7d13fe18ee3e795091fd8d173a1d" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "as_variant", "html5ever", - "phf", "tracing", "wildmatch", ] @@ -4592,8 +4610,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad674b5e5368c53a2c90fde7dac7e30747004aaf7b1827b72874a25fc06d4d8" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "js_int", "thiserror 2.0.11", @@ -4602,8 +4619,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff13fbd6045a7278533390826de316d6116d8582ed828352661337b0c422e1c" +source = "git+https://github.com/ruma/ruma?rev=a3663c04511f79f99376924d739f84d839600de6#a3663c04511f79f99376924d739f84d839600de6" dependencies = [ "cfg-if", "proc-macro-crate", @@ -5008,6 +5024,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" diff --git a/Cargo.toml b/Cargo.toml index a5c595088ec..83721951e17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,12 +59,9 @@ proptest = { version = "1.6.0", default-features = false, features = ["std"] } rand = "0.8.5" reqwest = { version = "0.12.12", default-features = false } rmp-serde = "1.3.0" -# Be careful to use commits from the https://github.com/ruma/ruma/tree/ruma-0.12 -# branch until a proper release with breaking changes happens. -ruma = { version = "0.12.5", features = [ +ruma = { git = "https://github.com/ruma/ruma", rev = "a3663c04511f79f99376924d739f84d839600de6", features = [ "client-api-c", "compat-upload-signatures", - "compat-user-id", "compat-arbitrary-length-ids", "compat-tag-info", "compat-encrypted-stickers", @@ -80,7 +77,7 @@ ruma = { version = "0.12.5", features = [ "unstable-msc4278", "unstable-msc4286", ] } -ruma-common = "0.15.4" +ruma-common = { git = "https://github.com/ruma/ruma", rev = "a3663c04511f79f99376924d739f84d839600de6" } sentry = "0.36.0" sentry-tracing = "0.36.0" serde = { version = "1.0.217", features = ["rc"] } diff --git a/bindings/matrix-sdk-crypto-ffi/src/responses.rs b/bindings/matrix-sdk-crypto-ffi/src/responses.rs index acc1c3defd2..48e296137b4 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/responses.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/responses.rs @@ -27,7 +27,7 @@ use ruma::{ to_device::send_event_to_device::v3::Response as ToDeviceResponse, }, assign, - events::EventContent, + events::MessageLikeEventContent, OwnedTransactionId, UserId, }; use serde_json::json; diff --git a/bindings/matrix-sdk-ffi/CHANGELOG.md b/bindings/matrix-sdk-ffi/CHANGELOG.md index e656472be77..1f1324e2b48 100644 --- a/bindings/matrix-sdk-ffi/CHANGELOG.md +++ b/bindings/matrix-sdk-ffi/CHANGELOG.md @@ -15,6 +15,13 @@ All notable changes to this project will be documented in this file. ### Breaking changes: +- The `reason` argument of `Room::report_room` is now required, do to a clarification in the spec. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) +- `PublicRoomJoinRule` has more variants, supporting all the known values from the spec. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) +- The fields of `MediaPreviewConfig` are both optional, allowing to use the type for room account + data as well as global account data. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) - The `event_id` field of `PredecessorRoom` was removed, due to its removal in the Matrix specification with MSC4291. ([#5419](https://github.com/matrix-org/matrix-rust-sdk/pull/5419)) diff --git a/bindings/matrix-sdk-ffi/Cargo.toml b/bindings/matrix-sdk-ffi/Cargo.toml index a75ae6aa760..f462ea05862 100644 --- a/bindings/matrix-sdk-ffi/Cargo.toml +++ b/bindings/matrix-sdk-ffi/Cargo.toml @@ -58,7 +58,7 @@ matrix-sdk-ffi-macros.workspace = true matrix-sdk-ui = { workspace = true, features = ["uniffi"] } mime = "0.3.16" once_cell.workspace = true -ruma = { workspace = true, features = ["html", "unstable-unspecified", "unstable-msc3488", "compat-unset-avatar", "unstable-msc3245-v1-compat", "unstable-msc4278"] } +ruma = { workspace = true, features = ["html", "unstable-msc3488", "compat-unset-avatar", "unstable-msc3245-v1-compat", "unstable-msc4278"] } serde.workspace = true serde_json.workspace = true sentry = { version = "0.36.0", optional = true, default-features = false, features = [ diff --git a/bindings/matrix-sdk-ffi/src/client.rs b/bindings/matrix-sdk-ffi/src/client.rs index c602deb9554..e37bf6c39d5 100644 --- a/bindings/matrix-sdk-ffi/src/client.rs +++ b/bindings/matrix-sdk-ffi/src/client.rs @@ -1631,7 +1631,7 @@ impl Client { ) -> Result, ClientError> { let configuration = self.inner.account().get_media_preview_config_event_content().await?; match configuration { - Some(configuration) => Ok(Some(configuration.media_previews.into())), + Some(configuration) => Ok(configuration.media_previews.map(Into::into)), None => Ok(None), } } @@ -1652,7 +1652,7 @@ impl Client { ) -> Result, ClientError> { let configuration = self.inner.account().get_media_preview_config_event_content().await?; match configuration { - Some(configuration) => Ok(Some(configuration.invite_avatars.into())), + Some(configuration) => Ok(configuration.invite_avatars.map(Into::into)), None => Ok(None), } } @@ -2468,9 +2468,7 @@ impl TryFrom for RumaAllowRule { match value { AllowRule::RoomMembership { room_id } => { let room_id = RoomId::parse(room_id)?; - Ok(Self::RoomMembership(ruma::events::room::join_rules::RoomMembership::new( - room_id, - ))) + Ok(Self::RoomMembership(ruma::room::RoomMembership::new(room_id))) } AllowRule::Custom { json } => Ok(Self::_Custom(Box::new(serde_json::from_str(&json)?))), } diff --git a/bindings/matrix-sdk-ffi/src/room/mod.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs index a22909f6b4a..1b10853619d 100644 --- a/bindings/matrix-sdk-ffi/src/room/mod.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -484,7 +484,7 @@ impl Room { /// # Errors /// /// Returns an error if the room is not found or on rate limit - pub async fn report_room(&self, reason: Option) -> Result<(), ClientError> { + pub async fn report_room(&self, reason: String) -> Result<(), ClientError> { self.inner.report_room(reason).await?; Ok(()) diff --git a/bindings/matrix-sdk-ffi/src/room_directory_search.rs b/bindings/matrix-sdk-ffi/src/room_directory_search.rs index 099ecbc8ce3..caf1b22d589 100644 --- a/bindings/matrix-sdk-ffi/src/room_directory_search.rs +++ b/bindings/matrix-sdk-ffi/src/room_directory_search.rs @@ -28,15 +28,21 @@ use crate::{error::ClientError, runtime::get_runtime_handle, task_handle::TaskHa pub enum PublicRoomJoinRule { Public, Knock, + Restricted, + KnockRestricted, + Invite, } -impl TryFrom for PublicRoomJoinRule { +impl TryFrom for PublicRoomJoinRule { type Error = String; - fn try_from(value: ruma::directory::PublicRoomJoinRule) -> Result { + fn try_from(value: ruma::room::JoinRuleKind) -> Result { match value { - ruma::directory::PublicRoomJoinRule::Public => Ok(Self::Public), - ruma::directory::PublicRoomJoinRule::Knock => Ok(Self::Knock), + ruma::room::JoinRuleKind::Public => Ok(Self::Public), + ruma::room::JoinRuleKind::Knock => Ok(Self::Knock), + ruma::room::JoinRuleKind::Restricted => Ok(Self::Restricted), + ruma::room::JoinRuleKind::KnockRestricted => Ok(Self::KnockRestricted), + ruma::room::JoinRuleKind::Invite => Ok(Self::Invite), rule => Err(format!("unsupported join rule: {rule:?}")), } } diff --git a/bindings/matrix-sdk-ffi/src/room_preview.rs b/bindings/matrix-sdk-ffi/src/room_preview.rs index 89c95038bbe..b7bfaa9d367 100644 --- a/bindings/matrix-sdk-ffi/src/room_preview.rs +++ b/bindings/matrix-sdk-ffi/src/room_preview.rs @@ -1,10 +1,10 @@ use anyhow::Context as _; use matrix_sdk::{room_preview::RoomPreview as SdkRoomPreview, Client}; -use ruma::{room::RoomType as RumaRoomType, space::SpaceRoomJoinRule}; +use ruma::room::{JoinRuleSummary, RoomType as RumaRoomType}; use tracing::warn; use crate::{ - client::JoinRule, + client::{AllowRule, JoinRule}, error::ClientError, room::{Membership, RoomHero}, room_member::{RoomMember, RoomMemberWithSenderInfo}, @@ -40,7 +40,7 @@ impl RoomPreview { .as_ref() .map(TryInto::try_into) .transpose() - .map_err(|_| anyhow::anyhow!("unhandled SpaceRoomJoinRule kind"))?, + .map_err(|_| anyhow::anyhow!("unhandled JoinRuleSummary kind"))?, is_direct: info.is_direct, heroes: info .heroes @@ -122,20 +122,32 @@ pub struct RoomPreviewInfo { pub heroes: Option>, } -impl TryFrom<&SpaceRoomJoinRule> for JoinRule { +impl TryFrom<&JoinRuleSummary> for JoinRule { type Error = (); - fn try_from(join_rule: &SpaceRoomJoinRule) -> Result { + fn try_from(join_rule: &JoinRuleSummary) -> Result { Ok(match join_rule { - SpaceRoomJoinRule::Invite => JoinRule::Invite, - SpaceRoomJoinRule::Knock => JoinRule::Knock, - SpaceRoomJoinRule::Private => JoinRule::Private, - SpaceRoomJoinRule::Restricted => JoinRule::Restricted { rules: Vec::new() }, - SpaceRoomJoinRule::KnockRestricted => JoinRule::KnockRestricted { rules: Vec::new() }, - SpaceRoomJoinRule::Public => JoinRule::Public, - SpaceRoomJoinRule::_Custom(_) => JoinRule::Custom { repr: join_rule.to_string() }, + JoinRuleSummary::Invite => JoinRule::Invite, + JoinRuleSummary::Knock => JoinRule::Knock, + JoinRuleSummary::Private => JoinRule::Private, + JoinRuleSummary::Restricted(summary) => JoinRule::Restricted { + rules: summary + .allowed_room_ids + .iter() + .map(|room_id| AllowRule::RoomMembership { room_id: room_id.to_string() }) + .collect(), + }, + JoinRuleSummary::KnockRestricted(summary) => JoinRule::KnockRestricted { + rules: summary + .allowed_room_ids + .iter() + .map(|room_id| AllowRule::RoomMembership { room_id: room_id.to_string() }) + .collect(), + }, + JoinRuleSummary::Public => JoinRule::Public, + JoinRuleSummary::_Custom(_) => JoinRule::Custom { repr: join_rule.as_str().to_owned() }, _ => { - warn!("unhandled SpaceRoomJoinRule: {join_rule}"); + warn!("unhandled JoinRuleSummary: {}", join_rule.as_str()); return Err(()); } }) diff --git a/bindings/matrix-sdk-ffi/src/ruma.rs b/bindings/matrix-sdk-ffi/src/ruma.rs index dd9c3397dc7..d1d02285450 100644 --- a/bindings/matrix-sdk-ffi/src/ruma.rs +++ b/bindings/matrix-sdk-ffi/src/ruma.rs @@ -1486,17 +1486,17 @@ impl From for SecretStorageV1AesHmacSh #[derive(Clone, uniffi::Record, Default)] pub struct MediaPreviewConfig { /// The media previews setting for the user. - pub media_previews: MediaPreviews, + pub media_previews: Option, /// The invite avatars setting for the user. - pub invite_avatars: InviteAvatars, + pub invite_avatars: Option, } impl From for MediaPreviewConfig { fn from(value: MediaPreviewConfigEventContent) -> Self { Self { - media_previews: value.media_previews.into(), - invite_avatars: value.invite_avatars.into(), + media_previews: value.media_previews.map(Into::into), + invite_avatars: value.invite_avatars.map(Into::into), } } } diff --git a/bindings/matrix-sdk-ffi/src/timeline/msg_like.rs b/bindings/matrix-sdk-ffi/src/timeline/msg_like.rs index 07926192870..7b7536541b4 100644 --- a/bindings/matrix-sdk-ffi/src/timeline/msg_like.rs +++ b/bindings/matrix-sdk-ffi/src/timeline/msg_like.rs @@ -15,7 +15,7 @@ use std::{collections::HashMap, sync::Arc}; use matrix_sdk::crypto::types::events::UtdCause; -use ruma::events::{room::MediaSource as RumaMediaSource, EventContent}; +use ruma::events::{room::MediaSource as RumaMediaSource, MessageLikeEventContent}; use super::{ content::Reaction, diff --git a/crates/matrix-sdk-base/CHANGELOG.md b/crates/matrix-sdk-base/CHANGELOG.md index b1232f81971..1282fcc4ed6 100644 --- a/crates/matrix-sdk-base/CHANGELOG.md +++ b/crates/matrix-sdk-base/CHANGELOG.md @@ -16,6 +16,14 @@ All notable changes to this project will be documented in this file. ([#5390](https://github.com/matrix-org/matrix-rust-sdk/pull/5390)) ### Refactor +- [**breaking**] `RoomInfo::room_version_or_default()` was replaced with + `room_version_rules_or_default()`. The room version should only be used for + display purposes. The rules contain flags for all the differences in behavior + between all known room versions. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) +- [**breaking**] `MinimalStateEvent::redact()` takes `RedactionRules` instead of + a `RoomVersionId`. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) - [**breaking**] The `event_id` field of `PredecessorRoom` was removed, due to its removal in the Matrix specification with MSC4291. ([#5419](https://github.com/matrix-org/matrix-rust-sdk/pull/5419)) diff --git a/crates/matrix-sdk-base/src/response_processors/timeline.rs b/crates/matrix-sdk-base/src/response_processors/timeline.rs index b61b12a43cf..a9a88a2b5a6 100644 --- a/crates/matrix-sdk-base/src/response_processors/timeline.rs +++ b/crates/matrix-sdk-base/src/response_processors/timeline.rs @@ -16,6 +16,7 @@ use matrix_sdk_common::deserialized_responses::TimelineEvent; #[cfg(feature = "e2e-encryption")] use ruma::events::SyncMessageLikeEvent; use ruma::{ + assign, events::{AnySyncMessageLikeEvent, AnySyncTimelineEvent}, push::{Action, PushConditionRoomCtx}, UInt, UserId, @@ -65,9 +66,9 @@ pub async fn build<'notification, 'e2ee>( AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomRedaction( redaction_event, )) => { - let room_version = room_info.room_version_or_default(); + let redaction_rules = room_info.room_version_rules_or_default().redaction; - if let Some(redacts) = redaction_event.redacts(&room_version) { + if let Some(redacts) = redaction_event.redacts(&redaction_rules) { room_info .handle_redaction(redaction_event, timeline_event.raw().cast_ref()); @@ -238,11 +239,13 @@ pub async fn get_push_room_context( room.power_levels().await.ok() }; - Ok(Some(PushConditionRoomCtx { - user_id: user_id.to_owned(), - room_id: room_id.to_owned(), - member_count: UInt::new(member_count).unwrap_or(UInt::MAX), - user_display_name, - power_levels: power_levels.map(Into::into), - })) + Ok(Some(assign!( + PushConditionRoomCtx::new( + room_id.to_owned(), + UInt::new(member_count).unwrap_or(UInt::MAX), + user_id.to_owned(), + user_display_name + ), + { power_levels: power_levels.map(Into::into) } + ))) } diff --git a/crates/matrix-sdk-base/src/room/create.rs b/crates/matrix-sdk-base/src/room/create.rs index 34b18225fa8..3979c4cccb9 100644 --- a/crates/matrix-sdk-base/src/room/create.rs +++ b/crates/matrix-sdk-base/src/room/create.rs @@ -17,9 +17,10 @@ use ruma::{ events::{ macros::EventContent, room::create::{PreviousRoom, RoomCreateEventContent}, - EmptyStateKey, RedactContent, RedactedStateEventContent, + EmptyStateKey, RedactContent, RedactedStateEventContent, StateEventType, }, room::RoomType, + room_version_rules::RedactionRules, OwnedUserId, RoomVersionId, }; use serde::{Deserialize, Serialize}; @@ -100,15 +101,19 @@ pub type RedactedRoomCreateWithCreatorEventContent = RoomCreateWithCreatorEventC impl RedactedStateEventContent for RedactedRoomCreateWithCreatorEventContent { type StateKey = EmptyStateKey; + + fn event_type(&self) -> StateEventType { + StateEventType::RoomCreate + } } impl RedactContent for RoomCreateWithCreatorEventContent { type Redacted = RedactedRoomCreateWithCreatorEventContent; - fn redact(self, version: &RoomVersionId) -> Self::Redacted { + fn redact(self, rules: &RedactionRules) -> Self::Redacted { let (content, sender) = self.into_event_content(); // Use Ruma's redaction algorithm. - let content = content.redact(version); + let content = content.redact(rules); Self::from_event_content(content, sender) } } diff --git a/crates/matrix-sdk-base/src/room/room_info.rs b/crates/matrix-sdk-base/src/room/room_info.rs index b9d281efa1a..55558f7fcd3 100644 --- a/crates/matrix-sdk-base/src/room/room_info.rs +++ b/crates/matrix-sdk-base/src/room/room_info.rs @@ -19,7 +19,9 @@ use std::{ use bitflags::bitflags; use eyeball::Subscriber; -use matrix_sdk_common::{deserialized_responses::TimelineEventKind, ROOM_VERSION_FALLBACK}; +use matrix_sdk_common::{ + deserialized_responses::TimelineEventKind, ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK, +}; use ruma::{ api::client::sync::sync_events::v3::RoomSummary as RumaSummary, assign, @@ -45,6 +47,7 @@ use ruma::{ RedactedStateEventContent, StateEventType, StaticStateEventContent, SyncStateEvent, }, room::RoomType, + room_version_rules::{RedactionRules, RoomVersionRules}, serde::Raw, EventId, MilliSecondsSinceUnixEpoch, MxcUri, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, RoomVersionId, UserId, @@ -322,27 +325,31 @@ impl BaseRoomInfo { } pub(super) fn handle_redaction(&mut self, redacts: &EventId) { - let room_version = self.room_version().unwrap_or(&ROOM_VERSION_FALLBACK).to_owned(); + let redaction_rules = self + .room_version() + .and_then(|room_version| room_version.rules()) + .unwrap_or(ROOM_VERSION_RULES_FALLBACK) + .redaction; // FIXME: Use let chains once available to get rid of unwrap()s if self.avatar.has_event_id(redacts) { - self.avatar.as_mut().unwrap().redact(&room_version); + self.avatar.as_mut().unwrap().redact(&redaction_rules); } else if self.canonical_alias.has_event_id(redacts) { - self.canonical_alias.as_mut().unwrap().redact(&room_version); + self.canonical_alias.as_mut().unwrap().redact(&redaction_rules); } else if self.create.has_event_id(redacts) { - self.create.as_mut().unwrap().redact(&room_version); + self.create.as_mut().unwrap().redact(&redaction_rules); } else if self.guest_access.has_event_id(redacts) { - self.guest_access.as_mut().unwrap().redact(&room_version); + self.guest_access.as_mut().unwrap().redact(&redaction_rules); } else if self.history_visibility.has_event_id(redacts) { - self.history_visibility.as_mut().unwrap().redact(&room_version); + self.history_visibility.as_mut().unwrap().redact(&redaction_rules); } else if self.join_rules.has_event_id(redacts) { - self.join_rules.as_mut().unwrap().redact(&room_version); + self.join_rules.as_mut().unwrap().redact(&redaction_rules); } else if self.name.has_event_id(redacts) { - self.name.as_mut().unwrap().redact(&room_version); + self.name.as_mut().unwrap().redact(&redaction_rules); } else if self.tombstone.has_event_id(redacts) { - self.tombstone.as_mut().unwrap().redact(&room_version); + self.tombstone.as_mut().unwrap().redact(&redaction_rules); } else if self.topic.has_event_id(redacts) { - self.topic.as_mut().unwrap().redact(&room_version); + self.topic.as_mut().unwrap().redact(&redaction_rules); } else { self.rtc_member_events .retain(|_, member_event| member_event.event_id() != Some(redacts)); @@ -451,11 +458,11 @@ pub struct RoomInfo { /// room state. pub(crate) base_info: Box, - /// Did we already warn about an unknown room version in - /// [`RoomInfo::room_version_or_default`]? This is done to avoid - /// spamming about unknown room versions in the log for the same room. + /// Whether we already warned about unknown room version rules in + /// [`RoomInfo::room_version_rules_or_default`]. This is done to avoid + /// spamming about unknown room versions rules in the log for the same room. #[serde(skip)] - pub(crate) warned_about_unknown_room_version: Arc, + pub(crate) warned_about_unknown_room_version_rules: Arc, /// Cached display name, useful for sync access. /// @@ -502,7 +509,7 @@ impl RoomInfo { latest_event: None, read_receipts: Default::default(), base_info: Box::new(BaseRoomInfo::new()), - warned_about_unknown_room_version: Arc::new(false.into()), + warned_about_unknown_room_version_rules: Arc::new(false.into()), cached_display_name: None, cached_user_defined_notification_mode: None, recency_stamp: None, @@ -670,9 +677,9 @@ impl RoomInfo { event: &SyncRoomRedactionEvent, _raw: &Raw, ) { - let room_version = self.room_version_or_default(); + let redaction_rules = self.room_version_rules_or_default().redaction; - let Some(redacts) = event.redacts(&room_version) else { + let Some(redacts) = event.redacts(&redaction_rules) else { info!("Can't apply redaction, redacts field is missing"); return; }; @@ -681,7 +688,7 @@ impl RoomInfo { if let Some(latest_event) = &mut self.latest_event { tracing::trace!("Checking if redaction applies to latest event"); if latest_event.event_id().as_deref() == Some(redacts) { - match apply_redaction(latest_event.event().raw(), _raw, &room_version) { + match apply_redaction(latest_event.event().raw(), _raw, &redaction_rules) { Some(redacted) => { // Even if the original event was encrypted, redaction removes all its // fields so it cannot possibly be successfully decrypted after redaction. @@ -842,24 +849,26 @@ impl RoomInfo { self.base_info.room_version() } - /// Get the room version of this room, or a sensible default. + /// Get the room version rules of this room, or a sensible default. /// - /// Will warn (at most once) if the room creation event is missing from this - /// [`RoomInfo`]. - pub fn room_version_or_default(&self) -> RoomVersionId { + /// Will warn (at most once) if the room create event is missing from this + /// [`RoomInfo`] or if the room version is unsupported. + pub fn room_version_rules_or_default(&self) -> RoomVersionRules { use std::sync::atomic::Ordering; - self.base_info.room_version().cloned().unwrap_or_else(|| { - if self - .warned_about_unknown_room_version - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { - warn!("Unknown room version, falling back to {ROOM_VERSION_FALLBACK}"); - } + self.base_info.room_version().and_then(|room_version| room_version.rules()).unwrap_or_else( + || { + if self + .warned_about_unknown_room_version_rules + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_ok() + { + warn!("Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}"); + } - ROOM_VERSION_FALLBACK - }) + ROOM_VERSION_RULES_FALLBACK + }, + ) } /// Get the room type of this room. @@ -1109,7 +1118,7 @@ pub(crate) enum SyncInfo { pub fn apply_redaction( event: &Raw, raw_redaction: &Raw, - room_version: &RoomVersionId, + rules: &RedactionRules, ) -> Option> { use ruma::canonical_json::{redact_in_place, RedactedBecause}; @@ -1129,7 +1138,7 @@ pub fn apply_redaction( } }; - let redact_result = redact_in_place(&mut event_json, room_version, Some(redacted_because)); + let redact_result = redact_in_place(&mut event_json, rules, Some(redacted_because)); if let Err(e) = redact_result { warn!("Failed to redact event: {e}"); @@ -1259,7 +1268,7 @@ mod tests { assign!(BaseRoomInfo::new(), { pinned_events: Some(RoomPinnedEventsEventContent::new(vec![owned_event_id!("$a")])) }), ), read_receipts: Default::default(), - warned_about_unknown_room_version: Arc::new(false.into()), + warned_about_unknown_room_version_rules: Arc::new(false.into()), cached_display_name: None, cached_user_defined_notification_mode: None, recency_stamp: Some(42), diff --git a/crates/matrix-sdk-base/src/store/integration_tests.rs b/crates/matrix-sdk-base/src/store/integration_tests.rs index d4d5cb4a466..bf32536913b 100644 --- a/crates/matrix-sdk-base/src/store/integration_tests.rs +++ b/crates/matrix-sdk-base/src/store/integration_tests.rs @@ -476,9 +476,10 @@ impl StateStoreIntegrationTests for DynStateStore { } async fn test_server_info_saving(&self) { - let versions = &[MatrixVersion::V1_1, MatrixVersion::V1_2, MatrixVersion::V1_11]; + let versions = + BTreeSet::from([MatrixVersion::V1_1, MatrixVersion::V1_2, MatrixVersion::V1_11]); let server_info = ServerInfo::new( - versions.iter().map(|version| version.to_string()).collect(), + versions.iter().map(|version| version.as_str().unwrap().to_owned()).collect(), [("org.matrix.experimental".to_owned(), true)].into(), Some(WellKnownResponse { homeserver: HomeserverInfo::new("matrix.example.com".to_owned()), @@ -504,7 +505,7 @@ impl StateStoreIntegrationTests for DynStateStore { let decoded_server_info = stored_info.maybe_decode().unwrap(); let stored_supported = decoded_server_info.supported_versions(); - assert_eq!(stored_supported.versions.as_ref(), versions); + assert_eq!(stored_supported.versions, versions); assert_eq!(stored_supported.features.len(), 1); assert!(stored_supported.features.contains(&FeatureFlag::from("org.matrix.experimental"))); diff --git a/crates/matrix-sdk-base/src/store/memory_store.rs b/crates/matrix-sdk-base/src/store/memory_store.rs index af545001a93..266b8be4f86 100644 --- a/crates/matrix-sdk-base/src/store/memory_store.rs +++ b/crates/matrix-sdk-base/src/store/memory_store.rs @@ -19,7 +19,7 @@ use std::{ use async_trait::async_trait; use growable_bloom_filter::GrowableBloom; -use matrix_sdk_common::ROOM_VERSION_FALLBACK; +use matrix_sdk_common::{ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK}; use ruma::{ canonical_json::{redact, RedactedBecause}, events::{ @@ -439,19 +439,19 @@ impl StateStore for MemoryStore { } } - let make_room_version = |room_info: &HashMap, room_id| { - room_info.get(room_id).map(|info| info.room_version_or_default()).unwrap_or_else(|| { + let make_redaction_rules = |room_info: &HashMap, room_id| { + room_info.get(room_id).map(|info| info.room_version_rules_or_default()).unwrap_or_else(|| { warn!( ?room_id, - "Unable to find the room version, assuming {ROOM_VERSION_FALLBACK}" + "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}" ); - ROOM_VERSION_FALLBACK - }) + ROOM_VERSION_RULES_FALLBACK + }).redaction }; let inner = &mut *inner; for (room_id, redactions) in &changes.redactions { - let mut room_version = None; + let mut redaction_rules = None; if let Some(room) = inner.room_state.get_mut(room_id) { for ref_room_mu in room.values_mut() { @@ -460,8 +460,8 @@ impl StateStore for MemoryStore { if let Some(redaction) = redactions.get(&event_id) { let redacted = redact( raw_evt.deserialize_as::()?, - room_version.get_or_insert_with(|| { - make_room_version(&inner.room_info, room_id) + redaction_rules.get_or_insert_with(|| { + make_redaction_rules(&inner.room_info, room_id) }), Some(RedactedBecause::from_raw_event(redaction)?), ) diff --git a/crates/matrix-sdk-base/src/store/migration_helpers.rs b/crates/matrix-sdk-base/src/store/migration_helpers.rs index 5530eb8ca1c..834ac746c04 100644 --- a/crates/matrix-sdk-base/src/store/migration_helpers.rs +++ b/crates/matrix-sdk-base/src/store/migration_helpers.rs @@ -35,8 +35,9 @@ use ruma::{ tombstone::RoomTombstoneEventContent, topic::RoomTopicEventContent, }, - EmptyStateKey, EventContent, RedactContent, StateEventContent, StateEventType, + EmptyStateKey, RedactContent, StateEventContent, StateEventType, }, + room_version_rules::RedactionRules, OwnedRoomId, OwnedUserId, RoomId, }; use serde::{Deserialize, Serialize}; @@ -117,7 +118,7 @@ impl RoomInfoV1 { latest_event: latest_event.map(|ev| Box::new(LatestEvent::new(ev))), read_receipts: Default::default(), base_info: base_info.migrate(create), - warned_about_unknown_room_version: Arc::new(false.into()), + warned_about_unknown_room_version_rules: Arc::new(false.into()), cached_display_name: None, cached_user_defined_notification_mode: None, recency_stamp: None, @@ -222,22 +223,18 @@ struct RoomNameEventContentV1 { name: Option, } -impl EventContent for RoomNameEventContentV1 { - type EventType = StateEventType; +impl StateEventContent for RoomNameEventContentV1 { + type StateKey = EmptyStateKey; - fn event_type(&self) -> Self::EventType { + fn event_type(&self) -> StateEventType { StateEventType::RoomName } } -impl StateEventContent for RoomNameEventContentV1 { - type StateKey = EmptyStateKey; -} - impl RedactContent for RoomNameEventContentV1 { type Redacted = RedactedRoomNameEventContent; - fn redact(self, _version: &ruma::RoomVersionId) -> Self::Redacted { + fn redact(self, _rules: &RedactionRules) -> Self::Redacted { RedactedRoomNameEventContent::new() } } diff --git a/crates/matrix-sdk-base/src/store/mod.rs b/crates/matrix-sdk-base/src/store/mod.rs index 6beae181d02..6cf77e4db0f 100644 --- a/crates/matrix-sdk-base/src/store/mod.rs +++ b/crates/matrix-sdk-base/src/store/mod.rs @@ -614,7 +614,7 @@ impl StateChanges { where C: StaticEventContent + StaticStateEventContent + RedactContent, C::Redacted: RedactedStateEventContent, - C::PossiblyRedacted: DeserializeOwned, + C::PossiblyRedacted: StaticEventContent + DeserializeOwned, C::StateKey: Borrow, K: AsRef + ?Sized, { diff --git a/crates/matrix-sdk-base/src/store/send_queue.rs b/crates/matrix-sdk-base/src/store/send_queue.rs index 877ad0b4b39..f628e59d190 100644 --- a/crates/matrix-sdk-base/src/store/send_queue.rs +++ b/crates/matrix-sdk-base/src/store/send_queue.rs @@ -20,7 +20,7 @@ use as_variant::as_variant; use ruma::{ events::{ room::{message::RoomMessageEventContent, MediaSource}, - AnyMessageLikeEventContent, EventContent as _, RawExt as _, + AnyMessageLikeEventContent, MessageLikeEventContent as _, RawExt as _, }, serde::Raw, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedEventId, OwnedTransactionId, OwnedUserId, @@ -63,7 +63,7 @@ impl SerializableEventContent { /// Convert a [`SerializableEventContent`] back into a /// [`AnyMessageLikeEventContent`]. pub fn deserialize(&self) -> Result { - self.event.deserialize_with_type(self.event_type.clone().into()) + self.event.deserialize_with_type(&self.event_type) } /// Returns the raw event content along with its type. diff --git a/crates/matrix-sdk-base/src/utils.rs b/crates/matrix-sdk-base/src/utils.rs index fe3943f0874..46bafac76c6 100644 --- a/crates/matrix-sdk-base/src/utils.rs +++ b/crates/matrix-sdk-base/src/utils.rs @@ -24,7 +24,8 @@ use ruma::{ RedactContent, RedactedStateEventContent, StateEventContent, StaticStateEventContent, SyncStateEvent, }, - EventId, OwnedEventId, RoomVersionId, + room_version_rules::RedactionRules, + EventId, OwnedEventId, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -118,13 +119,13 @@ where /// Redacts this event. /// /// Does nothing if it is already redacted. - pub fn redact(&mut self, room_version: &RoomVersionId) + 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(room_version), + content: ev.content.clone().redact(rules), event_id: ev.event_id.clone(), }); } diff --git a/crates/matrix-sdk-common/CHANGELOG.md b/crates/matrix-sdk-common/CHANGELOG.md index 60e8cd04e48..5874a579052 100644 --- a/crates/matrix-sdk-common/CHANGELOG.md +++ b/crates/matrix-sdk-common/CHANGELOG.md @@ -10,10 +10,20 @@ All notable changes to this project will be documented in this file. ### Features +- Expose the `ROOM_VERSION_RULES_FALLBACK` that should be used when the rules of + a room are unknown. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) - Expose the `ROOM_VERSION_FALLBACK` that should be used when the version of a room is unknown. ([#5306](https://github.com/matrix-org/matrix-rust-sdk/pull/5306)) +### Refactor + +- [**breaking**] `extract_bundled_thread_summary()` returns a + `Raw` for the latest event instead of a + `Raw`. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) + ## [0.12.0] - 2025-06-10 No notable changes in this release. diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index 1dd9fb0fa85..8b133fad3b3 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -17,7 +17,10 @@ use std::{collections::BTreeMap, fmt, sync::Arc}; #[cfg(doc)] use ruma::events::AnyTimelineEvent; use ruma::{ - events::{AnyMessageLikeEvent, AnySyncTimelineEvent, AnyToDeviceEvent, MessageLikeEventType}, + events::{ + AnyMessageLikeEvent, AnySyncMessageLikeEvent, AnySyncTimelineEvent, AnyToDeviceEvent, + MessageLikeEventType, + }, push::Action, serde::{ AsRefStr, AsStrAsRefStr, DebugAsRefStr, DeserializeFromCowStr, FromString, JsonObject, Raw, @@ -542,7 +545,7 @@ impl TimelineEvent { /// encryption status for it. fn from_bundled_latest_event( this: &TimelineEventKind, - latest_event: Option>, + latest_event: Option>, ) -> Option> { let latest_event = latest_event?; @@ -559,7 +562,9 @@ impl TimelineEvent { // information around. return Some(Box::new(TimelineEvent::from_decrypted( DecryptedRoomEvent { - event: latest_event, + // Safety: A decrypted event always includes a room_id in its + // payload. + event: latest_event.cast(), encryption_info: encryption_info.clone(), // A bundled latest event is never a thread root. It could have // a replacement event, but we don't carry this information diff --git a/crates/matrix-sdk-common/src/lib.rs b/crates/matrix-sdk-common/src/lib.rs index e5e8152cef7..65b2819051a 100644 --- a/crates/matrix-sdk-common/src/lib.rs +++ b/crates/matrix-sdk-common/src/lib.rs @@ -42,7 +42,7 @@ pub mod ttl_cache; #[cfg(all(target_family = "wasm", not(tarpaulin_include)))] pub mod js_tracing; -use ruma::RoomVersionId; +use ruma::{room_version_rules::RoomVersionRules, RoomVersionId}; pub use store_locks::LEASE_DURATION_MS; /// Alias for `Send` on non-wasm, empty trait (implemented by everything) on @@ -108,3 +108,9 @@ uniffi::setup_scaffolding!(); /// The room version to use as a fallback when the version of a room is unknown. pub const ROOM_VERSION_FALLBACK: RoomVersionId = RoomVersionId::V11; + +/// The room version rules to use as a fallback when the version of a room is +/// unknown or unsupported. +/// +/// These are the rules of the [`ROOM_VERSION_FALLBACK`]. +pub const ROOM_VERSION_RULES_FALLBACK: RoomVersionRules = RoomVersionRules::V11; diff --git a/crates/matrix-sdk-common/src/serde_helpers.rs b/crates/matrix-sdk-common/src/serde_helpers.rs index 14a079e6f10..aad2306efa5 100644 --- a/crates/matrix-sdk-common/src/serde_helpers.rs +++ b/crates/matrix-sdk-common/src/serde_helpers.rs @@ -16,7 +16,7 @@ //! to access some fields. use ruma::{ - events::{relation::BundledThread, AnyMessageLikeEvent, AnySyncTimelineEvent}, + events::{relation::BundledThread, AnySyncMessageLikeEvent, AnySyncTimelineEvent}, serde::Raw, OwnedEventId, }; @@ -76,7 +76,7 @@ struct Unsigned { /// Try to extract a bundled thread summary of a timeline event, if available. pub fn extract_bundled_thread_summary( event: &Raw, -) -> (ThreadSummaryStatus, Option>) { +) -> (ThreadSummaryStatus, Option>) { match event.get_field::("unsigned") { Ok(Some(Unsigned { relations: Some(Relations { thread: Some(bundled_thread) }) })) => { // Take the count from the bundled thread summary, if available. If it can't be diff --git a/crates/matrix-sdk-crypto/src/file_encryption/attachments.rs b/crates/matrix-sdk-crypto/src/file_encryption/attachments.rs index b6241f53262..cadecebc10d 100644 --- a/crates/matrix-sdk-crypto/src/file_encryption/attachments.rs +++ b/crates/matrix-sdk-crypto/src/file_encryption/attachments.rs @@ -136,20 +136,19 @@ impl<'a, R: Read + 'a> AttachmentDecryptor<'a, R> { let hash = info.hashes.get("sha256").ok_or(DecryptorError::MissingHash)?.as_bytes().to_owned(); - let mut key = info.key.k.into_inner(); + let key = info.key.k.as_bytes(); let iv = info.iv.into_inner(); if key.len() != KEY_SIZE { return Err(DecryptorError::KeyNonceLength); } - let key_array = GenericArray::from_slice(&key); + let key_array = GenericArray::from_slice(key); let iv = GenericArray::from_exact_iter(iv).ok_or(DecryptorError::KeyNonceLength)?; let sha = Sha256::default(); let aes = Aes256Ctr::new(key_array, &iv); - key.zeroize(); Ok(AttachmentDecryptor { inner: input, expected_hash: hash, sha, aes }) } diff --git a/crates/matrix-sdk-crypto/src/machine/test_helpers.rs b/crates/matrix-sdk-crypto/src/machine/test_helpers.rs index 148240b4b01..d28e10e4bb7 100644 --- a/crates/matrix-sdk-crypto/src/machine/test_helpers.rs +++ b/crates/matrix-sdk-crypto/src/machine/test_helpers.rs @@ -334,7 +334,7 @@ pub fn bootstrap_requests_to_keys_query_response( /// Helper for [`create_signed_device_of_unverified_user`] and /// [`create_unsigned_device`]. fn dummy_verification_machine() -> VerificationMachine { - let account = Account::new(user_id!("@TEST_USER:example.com")); + let account = Account::new(user_id!("@test_user:example.com")); VerificationMachine::new( account.deref().clone(), Arc::new(Mutex::new(PrivateCrossSigningIdentity::new(account.user_id().to_owned()))), diff --git a/crates/matrix-sdk-crypto/src/machine/tests/mod.rs b/crates/matrix-sdk-crypto/src/machine/tests/mod.rs index 4499aa8d2ba..251683ce3c9 100644 --- a/crates/matrix-sdk-crypto/src/machine/tests/mod.rs +++ b/crates/matrix-sdk-crypto/src/machine/tests/mod.rs @@ -36,8 +36,8 @@ use ruma::{ room::message::{ AddMentions, MessageType, Relation, ReplyWithinThread, RoomMessageEventContent, }, - AnyMessageLikeEvent, AnyMessageLikeEventContent, AnyToDeviceEvent, MessageLikeEvent, - OriginalMessageLikeEvent, ToDeviceEventType, + AnyMessageLikeEvent, AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnyToDeviceEvent, + MessageLikeEvent, OriginalMessageLikeEvent, ToDeviceEventType, }, room_id, serde::Raw, @@ -1442,8 +1442,8 @@ async fn test_unsigned_decryption() { // Encrypt a second message, an edit. let second_message_text = "This is the ~~original~~ edited message"; - let second_message_content = RoomMessageEventContent::text_plain(second_message_text) - .make_replacement(first_message, None); + let second_message_content = + RoomMessageEventContent::text_plain(second_message_text).make_replacement(first_message); let second_message_encrypted_content = alice.encrypt_room_event(room_id, second_message_content).await.unwrap(); @@ -1579,7 +1579,10 @@ async fn test_unsigned_decryption() { assert!(first_message.unsigned.relations.replace.is_some()); // Deserialization of the thread event succeeded, but it is still encrypted. let thread = first_message.unsigned.relations.thread.as_ref().unwrap(); - assert_matches!(thread.latest_event.deserialize(), Ok(AnyMessageLikeEvent::RoomEncrypted(_))); + assert_matches!( + thread.latest_event.deserialize(), + Ok(AnySyncMessageLikeEvent::RoomEncrypted(_)) + ); let unsigned_encryption_info = raw_decrypted_event.unsigned_encryption_info.unwrap(); assert_eq!(unsigned_encryption_info.len(), 2); @@ -1625,7 +1628,7 @@ async fn test_unsigned_decryption() { let thread = &first_message.unsigned.relations.thread.as_ref().unwrap(); assert_matches!( thread.latest_event.deserialize(), - Ok(AnyMessageLikeEvent::RoomMessage(third_message)) + Ok(AnySyncMessageLikeEvent::RoomMessage(third_message)) ); let third_message = third_message.as_original().unwrap(); assert_eq!(third_message.content.body(), third_message_text); diff --git a/crates/matrix-sdk-crypto/src/secret_storage.rs b/crates/matrix-sdk-crypto/src/secret_storage.rs index 044f866fa51..efcfdcb58c9 100644 --- a/crates/matrix-sdk-crypto/src/secret_storage.rs +++ b/crates/matrix-sdk-crypto/src/secret_storage.rs @@ -36,7 +36,7 @@ use ruma::{ }, secret::SecretEncryptedData, }, - EventContent, GlobalAccountDataEventType, + GlobalAccountDataEventContent, GlobalAccountDataEventType, }, serde::Base64, UInt, diff --git a/crates/matrix-sdk-crypto/src/types/events/to_device.rs b/crates/matrix-sdk-crypto/src/types/events/to_device.rs index fb6cf780f48..04919c5a329 100644 --- a/crates/matrix-sdk-crypto/src/types/events/to_device.rs +++ b/crates/matrix-sdk-crypto/src/types/events/to_device.rs @@ -23,7 +23,7 @@ use ruma::{ request::ToDeviceKeyVerificationRequestEvent, start::ToDeviceKeyVerificationStartEvent, }, secret::request::{SecretName, ToDeviceSecretRequestEvent}, - EventContent, ToDeviceEventType, + ToDeviceEventContent, ToDeviceEventType, }, serde::Raw, OwnedUserId, UserId, diff --git a/crates/matrix-sdk-crypto/src/types/requests/to_device.rs b/crates/matrix-sdk-crypto/src/types/requests/to_device.rs index cccd739d459..317c2fd05cd 100644 --- a/crates/matrix-sdk-crypto/src/types/requests/to_device.rs +++ b/crates/matrix-sdk-crypto/src/types/requests/to_device.rs @@ -15,7 +15,7 @@ use std::{collections::BTreeMap, iter}; use ruma::{ - events::{AnyToDeviceEventContent, EventContent, ToDeviceEventType}, + events::{AnyToDeviceEventContent, ToDeviceEventContent, ToDeviceEventType}, serde::Raw, to_device::DeviceIdOrAllDevices, OwnedDeviceId, OwnedTransactionId, OwnedUserId, TransactionId, UserId, diff --git a/crates/matrix-sdk-indexeddb/src/state_store/mod.rs b/crates/matrix-sdk-indexeddb/src/state_store/mod.rs index 6b090a22133..3521e9eec85 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store/mod.rs @@ -30,7 +30,7 @@ use matrix_sdk_base::{ SerializableEventContent, ServerInfo, StateChanges, StateStore, StoreError, }, MinimalRoomMemberEvent, RoomInfo, RoomMemberships, StateStoreDataKey, StateStoreDataValue, - ROOM_VERSION_FALLBACK, + ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK, }; use matrix_sdk_store_encryption::{Error as EncryptionError, StoreCipher}; use ruma::{ @@ -917,32 +917,32 @@ impl_state_store!({ let range = self.encode_to_range(keys::ROOM_STATE, room_id)?; let Some(cursor) = state.open_cursor_with_range(&range)?.await? else { continue }; - let mut room_version = None; + let mut redaction_rules = None; while let Some(key) = cursor.key() { let raw_evt = self.deserialize_value::>(&cursor.value())?; if let Ok(Some(event_id)) = raw_evt.get_field::("event_id") { if let Some(redaction) = redactions.get(&event_id) { - let version = { - if room_version.is_none() { - room_version.replace(room_info + let redaction_rules = { + if redaction_rules.is_none() { + redaction_rules.replace(room_info .get(&self.encode_key(keys::ROOM_INFOS, room_id))? .await? .and_then(|f| self.deserialize_value::(&f).ok()) - .map(|info| info.room_version_or_default()) + .map(|info| info.room_version_rules_or_default()) .unwrap_or_else(|| { - warn!(?room_id, "Unable to find the room version, assuming {ROOM_VERSION_FALLBACK}"); - ROOM_VERSION_FALLBACK - }) + warn!(?room_id, "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}"); + ROOM_VERSION_RULES_FALLBACK + }).redaction ); } - room_version.as_ref().unwrap() + redaction_rules.as_ref().unwrap() }; let redacted = redact( raw_evt.deserialize_as::()?, - version, + redaction_rules, Some(RedactedBecause::from_raw_event(redaction)?), ) .map_err(StoreError::Redaction)?; diff --git a/crates/matrix-sdk-sqlite/src/state_store.rs b/crates/matrix-sdk-sqlite/src/state_store.rs index 03f915507a6..4e7f630dd01 100644 --- a/crates/matrix-sdk-sqlite/src/state_store.rs +++ b/crates/matrix-sdk-sqlite/src/state_store.rs @@ -16,7 +16,7 @@ use matrix_sdk_base::{ RoomLoadSettings, SentRequestKey, }, MinimalRoomMemberEvent, RoomInfo, RoomMemberships, RoomState, StateChanges, StateStore, - StateStoreDataKey, StateStoreDataValue, ROOM_VERSION_FALLBACK, + StateStoreDataKey, StateStoreDataValue, ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK, }; use matrix_sdk_store_encryption::StoreCipher; use ruma::{ @@ -1271,24 +1271,24 @@ impl StateStore for SqliteStateStore { } for (room_id, redactions) in redactions { - let make_room_version = || { + let make_redaction_rules = || { let encoded_room_id = this.encode_key(keys::ROOM_INFO, &room_id); txn.get_room_info(&encoded_room_id) .ok() .flatten() .and_then(|v| this.deserialize_json::(&v).ok()) - .map(|info| info.room_version_or_default()) + .map(|info| info.room_version_rules_or_default()) .unwrap_or_else(|| { warn!( ?room_id, - "Unable to find the room version, assuming {ROOM_VERSION_FALLBACK}" + "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}" ); - ROOM_VERSION_FALLBACK - }) + ROOM_VERSION_RULES_FALLBACK + }).redaction }; let encoded_room_id = this.encode_key(keys::STATE_EVENT, &room_id); - let mut room_version = None; + let mut redaction_rules = None; for (event_id, redaction) in redactions { let event_id = this.encode_key(keys::STATE_EVENT, event_id); @@ -1300,7 +1300,7 @@ impl StateStore for SqliteStateStore { let event = raw_event.deserialize()?; let redacted = redact( raw_event.deserialize_as::()?, - room_version.get_or_insert_with(make_room_version), + redaction_rules.get_or_insert_with(make_redaction_rules), Some(RedactedBecause::from_raw_event(&redaction)?), ) .map_err(Error::Redaction)?; diff --git a/crates/matrix-sdk-ui/CHANGELOG.md b/crates/matrix-sdk-ui/CHANGELOG.md index 9e39c237831..13cb9beb9d4 100644 --- a/crates/matrix-sdk-ui/CHANGELOG.md +++ b/crates/matrix-sdk-ui/CHANGELOG.md @@ -24,6 +24,13 @@ All notable changes to this project will be documented in this file. `matrix_sdk::latest_events::LatestEvents::listen_to_room` ([#5369](https://github.com/matrix-org/matrix-rust-sdk/pull/5369)) +### Refactor + +- [**breaking**] The function provided to `TimelineBuilder::event_filter()` + must take `RoomVersionRules` as second argument instead of a `RoomVersionId`. + The `default_event_filter()` reflects that change. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) + ## [0.12.0] - 2025-06-10 ### Refactor diff --git a/crates/matrix-sdk-ui/src/timeline/builder.rs b/crates/matrix-sdk-ui/src/timeline/builder.rs index 0f116ccf7f8..27b73e5fcb1 100644 --- a/crates/matrix-sdk-ui/src/timeline/builder.rs +++ b/crates/matrix-sdk-ui/src/timeline/builder.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use matrix_sdk::{Room, executor::spawn}; use matrix_sdk_base::{SendOutsideWasm, SyncOutsideWasm}; -use ruma::{RoomVersionId, events::AnySyncTimelineEvent}; +use ruma::{events::AnySyncTimelineEvent, room_version_rules::RoomVersionRules}; use tracing::{Instrument, Span, info_span}; use super::{ @@ -129,7 +129,7 @@ impl TimelineBuilder { /// they couldn't be decrypted when the appropriate room key arrives). pub fn event_filter(mut self, filter: F) -> Self where - F: Fn(&AnySyncTimelineEvent, &RoomVersionId) -> bool + F: Fn(&AnySyncTimelineEvent, &RoomVersionRules) -> bool + SendOutsideWasm + SyncOutsideWasm + 'static, diff --git a/crates/matrix-sdk-ui/src/timeline/controller/aggregations.rs b/crates/matrix-sdk-ui/src/timeline/controller/aggregations.rs index 07eb0f32f0b..d56f973afea 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/aggregations.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/aggregations.rs @@ -42,12 +42,13 @@ use std::{borrow::Cow, collections::HashMap, sync::Arc}; use as_variant::as_variant; use matrix_sdk::deserialized_responses::EncryptionInfo; use ruma::{ - MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, RoomVersionId, + MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, events::{ AnySyncTimelineEvent, poll::unstable_start::NewUnstablePollStartEventContentWithoutRelation, relation::Replacement, room::message::RoomMessageEventContentWithoutRelation, }, + room_version_rules::RoomVersionRules, serde::Raw, }; use tracing::{info, trace, warn}; @@ -191,7 +192,7 @@ impl Aggregation { fn apply( &self, event: &mut Cow<'_, EventTimelineItem>, - room_version: &RoomVersionId, + rules: &RoomVersionRules, ) -> ApplyAggregationResult { match &self.kind { AggregationKind::PollResponse { sender, timestamp, answers } => { @@ -208,7 +209,7 @@ impl Aggregation { if event.content().is_redacted() { ApplyAggregationResult::LeftItemIntact } else { - let new_item = event.redact(room_version); + let new_item = event.redact(&rules.redaction); *event = Cow::Owned(new_item); ApplyAggregationResult::UpdatedItem } @@ -486,7 +487,7 @@ impl Aggregations { item_id: &TimelineEventItemId, event: &mut Cow<'_, EventTimelineItem>, items: &mut ObservableItemsTransaction<'_>, - room_version: &RoomVersionId, + rules: &RoomVersionRules, ) -> Result<(), AggregationError> { let Some(aggregations) = self.related_events.get(item_id) else { return Ok(()); @@ -495,7 +496,7 @@ impl Aggregations { let mut has_edits = false; for a in aggregations { - match a.apply(event, room_version) { + match a.apply(event, rules) { ApplyAggregationResult::Edit => { has_edits = true; } @@ -544,7 +545,7 @@ impl Aggregations { txn_id: OwnedTransactionId, event_id: OwnedEventId, items: &mut ObservableItemsTransaction<'_>, - room_version: &RoomVersionId, + rules: &RoomVersionRules, ) -> bool { let from = TimelineEventItemId::TransactionId(txn_id); let to = TimelineEventItemId::EventId(event_id.clone()); @@ -571,7 +572,7 @@ impl Aggregations { *reaction_status = ReactionStatus::RemoteToRemote(event_id); let found = found.clone(); - find_item_and_apply_aggregation(self, items, &target, found, room_version); + find_item_and_apply_aggregation(self, items, &target, found, rules); } } } @@ -736,7 +737,7 @@ pub(crate) fn find_item_and_apply_aggregation( items: &mut ObservableItemsTransaction<'_>, target: &TimelineEventItemId, aggregation: Aggregation, - room_version: &RoomVersionId, + rules: &RoomVersionRules, ) -> Option { let Some((idx, event_item)) = rfind_event_by_item_id(items, target) else { trace!("couldn't find aggregation's target {target:?}"); @@ -744,7 +745,7 @@ pub(crate) fn find_item_and_apply_aggregation( }; let mut cowed = Cow::Borrowed(&*event_item); - match aggregation.apply(&mut cowed, room_version) { + match aggregation.apply(&mut cowed, rules) { ApplyAggregationResult::UpdatedItem => { trace!("applied aggregation"); let new_event_item = cowed.into_owned(); diff --git a/crates/matrix-sdk-ui/src/timeline/controller/metadata.rs b/crates/matrix-sdk-ui/src/timeline/controller/metadata.rs index b02c4d6fefa..81d6f34dafe 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/metadata.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/metadata.rs @@ -20,12 +20,13 @@ use std::{ use imbl::Vector; use matrix_sdk::deserialized_responses::EncryptionInfo; use ruma::{ - EventId, OwnedEventId, OwnedUserId, RoomVersionId, + EventId, OwnedEventId, OwnedUserId, events::{ AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnySyncTimelineEvent, BundledMessageLikeRelations, poll::unstable_start::UnstablePollStartEventContent, relation::Replacement, room::message::RelationWithoutReplacement, }, + room_version_rules::RoomVersionRules, serde::Raw, }; use tracing::trace; @@ -80,10 +81,10 @@ pub(in crate::timeline) struct TimelineMetadata { /// May be false until we fetch the actual room encryption state. pub is_room_encrypted: bool, - /// Matrix room version of the timeline's room, or a sensible default. + /// Rules of the version of the timeline's room, or a sensible default. /// /// This value is constant over the lifetime of the metadata. - pub room_version: RoomVersionId, + pub room_version_rules: RoomVersionRules, /// The own [`OwnedUserId`] of the client who opened the timeline. pub(crate) own_user_id: OwnedUserId, @@ -129,7 +130,7 @@ pub(in crate::timeline) struct TimelineMetadata { impl TimelineMetadata { pub(in crate::timeline) fn new( own_user_id: OwnedUserId, - room_version: RoomVersionId, + room_version_rules: RoomVersionRules, internal_id_prefix: Option, unable_to_decrypt_hook: Option>, is_room_encrypted: bool, @@ -145,7 +146,7 @@ impl TimelineMetadata { // field, otherwise we'll keep on exiting early in `Self::update_read_marker`. has_up_to_date_read_marker_item: true, read_receipts: Default::default(), - room_version, + room_version_rules, unable_to_decrypt_hook, internal_id_prefix, is_room_encrypted, diff --git a/crates/matrix-sdk-ui/src/timeline/controller/mod.rs b/crates/matrix-sdk-ui/src/timeline/controller/mod.rs index ad9a3b994a8..25befeb00d4 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/mod.rs @@ -32,8 +32,7 @@ use matrix_sdk::{ }, }; use ruma::{ - EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, RoomVersionId, - TransactionId, UserId, + EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, TransactionId, UserId, api::client::receipt::create_receipt::v3::ReceiptType as SendReceiptType, events::{ AnyMessageLikeEventContent, AnySyncEphemeralRoomEvent, AnySyncMessageLikeEvent, @@ -44,6 +43,7 @@ use ruma::{ relation::Annotation, room::message::{MessageType, Relation}, }, + room_version_rules::RoomVersionRules, serde::Raw, }; #[cfg(test)] @@ -218,10 +218,10 @@ impl Default for TimelineSettings { /// If you have a custom filter, it may be best to chain yours with this one if /// you do not want to run into situations where a read receipt is not visible /// because it's living on an event that doesn't have a matching timeline item. -pub fn default_event_filter(event: &AnySyncTimelineEvent, room_version: &RoomVersionId) -> bool { +pub fn default_event_filter(event: &AnySyncTimelineEvent, rules: &RoomVersionRules) -> bool { match event { AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomRedaction(ev)) => { - if ev.redacts(room_version).is_some() { + if ev.redacts(&rules.redaction).is_some() { // This is a redaction of an existing message, we'll only update the previous // message and not render a new entry. false @@ -328,7 +328,7 @@ impl TimelineController { let state = Arc::new(RwLock::new(TimelineState::new( focus.clone(), room_data_provider.own_user_id().to_owned(), - room_data_provider.room_version(), + room_data_provider.room_version_rules(), internal_id_prefix, unable_to_decrypt_hook, is_room_encrypted, @@ -953,7 +953,7 @@ impl TimelineController { txn_id.to_owned(), new_event_id.to_owned(), &mut txn.items, - &txn.meta.room_version, + &txn.meta.room_version_rules, ) { trace!("Aggregation marked as sent"); txn.commit(); @@ -1312,7 +1312,7 @@ impl TimelineController { &mut tr.items, &target, aggregation, - &tr.meta.room_version, + &tr.meta.room_version_rules, ); tr.commit(); diff --git a/crates/matrix-sdk-ui/src/timeline/controller/state.rs b/crates/matrix-sdk-ui/src/timeline/controller/state.rs index cbd505b8987..bf33154a2cb 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/state.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/state.rs @@ -19,8 +19,9 @@ use matrix_sdk::{deserialized_responses::TimelineEvent, send_queue::SendHandle}; #[cfg(test)] use ruma::events::receipt::ReceiptEventContent; use ruma::{ - MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, RoomVersionId, + MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, events::{AnyMessageLikeEventContent, AnySyncEphemeralRoomEvent}, + room_version_rules::RoomVersionRules, serde::Raw, }; use tracing::{instrument, trace, warn}; @@ -53,7 +54,7 @@ impl TimelineState

{ pub(super) fn new( focus: Arc>, own_user_id: OwnedUserId, - room_version: RoomVersionId, + room_version_rules: RoomVersionRules, internal_id_prefix: Option, unable_to_decrypt_hook: Option>, is_room_encrypted: bool, @@ -62,7 +63,7 @@ impl TimelineState

{ items: ObservableItems::new(), meta: TimelineMetadata::new( own_user_id, - room_version, + room_version_rules, internal_id_prefix, unable_to_decrypt_hook, is_room_encrypted, diff --git a/crates/matrix-sdk-ui/src/timeline/controller/state_transaction.rs b/crates/matrix-sdk-ui/src/timeline/controller/state_transaction.rs index 6fdf22a128d..ab5fd5b2563 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/state_transaction.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/state_transaction.rs @@ -398,8 +398,9 @@ impl<'a, P: RoomDataProvider> TimelineStateTransaction<'a, P> { thread_root: Option<&EventId>, position: TimelineItemPosition, ) -> bool { - let room_version = room_data_provider.room_version(); - if !(settings.event_filter)(event, &room_version) { + let rules = room_data_provider.room_version_rules(); + + if !(settings.event_filter)(event, &rules) { // The user filtered out the event. return false; } diff --git a/crates/matrix-sdk-ui/src/timeline/date_dividers.rs b/crates/matrix-sdk-ui/src/timeline/date_dividers.rs index b774df677ce..9742799411c 100644 --- a/crates/matrix-sdk-ui/src/timeline/date_dividers.rs +++ b/crates/matrix-sdk-ui/src/timeline/date_dividers.rs @@ -657,7 +657,10 @@ enum DateDividerInsertError { #[cfg(test)] mod tests { use assert_matches2::assert_let; - use ruma::{MilliSecondsSinceUnixEpoch, owned_event_id, owned_user_id, uint}; + use ruma::{ + MilliSecondsSinceUnixEpoch, owned_event_id, owned_user_id, + room_version_rules::RoomVersionRules, uint, + }; use super::{super::controller::ObservableItems, DateDividerAdjuster}; use crate::timeline::{ @@ -691,7 +694,7 @@ mod tests { } fn test_metadata() -> TimelineMetadata { - TimelineMetadata::new(owned_user_id!("@a:b.c"), ruma::RoomVersionId::V11, None, None, false) + TimelineMetadata::new(owned_user_id!("@a:b.c"), RoomVersionRules::V11, None, None, false) } #[test] diff --git a/crates/matrix-sdk-ui/src/timeline/event_handler.rs b/crates/matrix-sdk-ui/src/timeline/event_handler.rs index 6df1a8a115f..4873c51186e 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_handler.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_handler.rs @@ -26,7 +26,7 @@ use ruma::{ TransactionId, events::{ AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnySyncStateEvent, - AnySyncTimelineEvent, EventContent, FullStateEventContent, MessageLikeEventType, + AnySyncTimelineEvent, FullStateEventContent, MessageLikeEventContent, MessageLikeEventType, StateEventType, SyncStateEvent, poll::unstable_start::{ NewUnstablePollStartEventContentWithoutRelation, UnstablePollStartEventContent, @@ -190,7 +190,7 @@ impl TimelineAction { thread_root: Option, thread_summary: Option, ) -> Option { - let room_version = room_data_provider.room_version(); + let redaction_rules = room_data_provider.room_version_rules().redaction; let redacted_message_or_none = |event_type: MessageLikeEventType| { (event_type != MessageLikeEventType::Reaction) @@ -199,7 +199,7 @@ impl TimelineAction { Some(match event { AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomRedaction(ev)) => { - if let Some(redacts) = ev.redacts(&room_version).map(ToOwned::to_owned) { + if let Some(redacts) = ev.redacts(&redaction_rules).map(ToOwned::to_owned) { Self::HandleAggregation { related_event: redacts, kind: HandleAggregationKind::Redaction, @@ -585,7 +585,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { self.items, &target, aggregation, - &self.meta.room_version, + &self.meta.room_version_rules, ) { // Update all events that replied to this message with the edited content. Self::maybe_update_responses(self.meta, self.items, &edited_event_id, &new_item); @@ -628,7 +628,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { self.items, &target, aggregation, - &self.meta.room_version, + &self.meta.room_version_rules, ); } @@ -648,7 +648,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { self.items, &target, aggregation, - &self.meta.room_version, + &self.meta.room_version_rules, ); } @@ -664,7 +664,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { self.items, &target, aggregation, - &self.meta.room_version, + &self.meta.room_version_rules, ); } @@ -695,7 +695,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { self.items, &target, aggregation, - &self.meta.room_version, + &self.meta.room_version_rules, ) { // Look for any timeline event that's a reply to the redacted event, and redact // the replied-to event there as well. @@ -795,7 +795,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { &self.ctx.flow.timeline_item_id(), &mut cowed, self.items, - &self.meta.room_version, + &self.meta.room_version_rules, ) { warn!("discarding aggregations: {err}"); } diff --git a/crates/matrix-sdk-ui/src/timeline/event_item/content/mod.rs b/crates/matrix-sdk-ui/src/timeline/event_item/content/mod.rs index f67da00f27f..93e5a2f79bc 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_item/content/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_item/content/mod.rs @@ -18,7 +18,7 @@ use as_variant::as_variant; use matrix_sdk::crypto::types::events::UtdCause; use matrix_sdk_base::latest_event::{PossibleLatestEvent, is_suitable_for_latest_event}; use ruma::{ - OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedUserId, RoomVersionId, UserId, + OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedUserId, UserId, events::{ AnyFullStateEventContent, AnySyncTimelineEvent, FullStateEventContent, Mentions, MessageLikeEventType, StateEventType, @@ -55,6 +55,7 @@ use ruma::{ sticker::{StickerEventContent, SyncStickerEvent}, }, html::RemoveReplyFallback, + room_version_rules::RedactionRules, }; use tracing::warn; @@ -514,14 +515,14 @@ impl TimelineItemContent { } } - pub(in crate::timeline) fn redact(&self, room_version: &RoomVersionId) -> Self { + pub(in crate::timeline) fn redact(&self, rules: &RedactionRules) -> Self { match self { Self::MsgLike(_) | Self::CallInvite | Self::CallNotify => { TimelineItemContent::MsgLike(MsgLikeContent::redacted()) } - Self::MembershipChange(ev) => Self::MembershipChange(ev.redact(room_version)), + Self::MembershipChange(ev) => Self::MembershipChange(ev.redact(rules)), Self::ProfileChange(ev) => Self::ProfileChange(ev.redact()), - Self::OtherState(ev) => Self::OtherState(ev.redact(room_version)), + Self::OtherState(ev) => Self::OtherState(ev.redact(rules)), Self::FailedToParseMessageLike { .. } | Self::FailedToParseState { .. } => self.clone(), } } @@ -723,10 +724,10 @@ impl RoomMembershipChange { self.change } - fn redact(&self, room_version: &RoomVersionId) -> Self { + fn redact(&self, rules: &RedactionRules) -> Self { Self { user_id: self.user_id.clone(), - content: FullStateEventContent::Redacted(self.content.clone().redact(room_version)), + content: FullStateEventContent::Redacted(self.content.clone().redact(rules)), change: self.change, } } @@ -957,67 +958,67 @@ impl AnyOtherFullStateEventContent { } } - fn redact(&self, room_version: &RoomVersionId) -> Self { + fn redact(&self, rules: &RedactionRules) -> Self { match self { - Self::PolicyRuleRoom(c) => Self::PolicyRuleRoom(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), - Self::PolicyRuleServer(c) => Self::PolicyRuleServer(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), - Self::PolicyRuleUser(c) => Self::PolicyRuleUser(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), + Self::PolicyRuleRoom(c) => { + Self::PolicyRuleRoom(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::PolicyRuleServer(c) => { + Self::PolicyRuleServer(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::PolicyRuleUser(c) => { + Self::PolicyRuleUser(FullStateEventContent::Redacted(c.clone().redact(rules))) + } Self::RoomAliases(c) => { - Self::RoomAliases(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomAliases(FullStateEventContent::Redacted(c.clone().redact(rules))) } Self::RoomAvatar(c) => { - Self::RoomAvatar(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomAvatar(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::RoomCanonicalAlias(c) => { + Self::RoomCanonicalAlias(FullStateEventContent::Redacted(c.clone().redact(rules))) } - Self::RoomCanonicalAlias(c) => Self::RoomCanonicalAlias( - FullStateEventContent::Redacted(c.clone().redact(room_version)), - ), Self::RoomCreate(c) => { - Self::RoomCreate(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomCreate(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::RoomEncryption(c) => { + Self::RoomEncryption(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::RoomGuestAccess(c) => { + Self::RoomGuestAccess(FullStateEventContent::Redacted(c.clone().redact(rules))) } - Self::RoomEncryption(c) => Self::RoomEncryption(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), - Self::RoomGuestAccess(c) => Self::RoomGuestAccess(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), Self::RoomHistoryVisibility(c) => Self::RoomHistoryVisibility( - FullStateEventContent::Redacted(c.clone().redact(room_version)), + FullStateEventContent::Redacted(c.clone().redact(rules)), ), Self::RoomJoinRules(c) => { - Self::RoomJoinRules(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomJoinRules(FullStateEventContent::Redacted(c.clone().redact(rules))) } Self::RoomName(c) => { - Self::RoomName(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomName(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::RoomPinnedEvents(c) => { + Self::RoomPinnedEvents(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::RoomPowerLevels(c) => { + Self::RoomPowerLevels(FullStateEventContent::Redacted(c.clone().redact(rules))) } - Self::RoomPinnedEvents(c) => Self::RoomPinnedEvents(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), - Self::RoomPowerLevels(c) => Self::RoomPowerLevels(FullStateEventContent::Redacted( - c.clone().redact(room_version), - )), Self::RoomServerAcl(c) => { - Self::RoomServerAcl(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomServerAcl(FullStateEventContent::Redacted(c.clone().redact(rules))) + } + Self::RoomThirdPartyInvite(c) => { + Self::RoomThirdPartyInvite(FullStateEventContent::Redacted(c.clone().redact(rules))) } - Self::RoomThirdPartyInvite(c) => Self::RoomThirdPartyInvite( - FullStateEventContent::Redacted(c.clone().redact(room_version)), - ), Self::RoomTombstone(c) => { - Self::RoomTombstone(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomTombstone(FullStateEventContent::Redacted(c.clone().redact(rules))) } Self::RoomTopic(c) => { - Self::RoomTopic(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::RoomTopic(FullStateEventContent::Redacted(c.clone().redact(rules))) } Self::SpaceChild(c) => { - Self::SpaceChild(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::SpaceChild(FullStateEventContent::Redacted(c.clone().redact(rules))) } Self::SpaceParent(c) => { - Self::SpaceParent(FullStateEventContent::Redacted(c.clone().redact(room_version))) + Self::SpaceParent(FullStateEventContent::Redacted(c.clone().redact(rules))) } Self::_Custom { event_type } => Self::_Custom { event_type: event_type.clone() }, } @@ -1042,8 +1043,8 @@ impl OtherState { &self.content } - fn redact(&self, room_version: &RoomVersionId) -> Self { - Self { state_key: self.state_key.clone(), content: self.content.redact(room_version) } + fn redact(&self, rules: &RedactionRules) -> Self { + Self { state_key: self.state_key.clone(), content: self.content.redact(rules) } } } @@ -1052,11 +1053,12 @@ mod tests { use assert_matches2::assert_let; use matrix_sdk_test::ALICE; use ruma::{ - RoomVersionId, assign, + assign, events::{ FullStateEventContent, room::member::{MembershipState, RoomMemberEventContent}, }, + room_version_rules::RedactionRules, }; use super::{MembershipChange, RoomMembershipChange, TimelineItemContent}; @@ -1074,7 +1076,7 @@ mod tests { change: Some(MembershipChange::Banned), }); - let redacted = content.redact(&RoomVersionId::V11); + let redacted = content.redact(&RedactionRules::V11); assert_let!(TimelineItemContent::MembershipChange(inner) = redacted); assert_eq!(inner.change, Some(MembershipChange::Banned)); assert_let!(FullStateEventContent::Redacted(inner_content_redacted) = inner.content); diff --git a/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs b/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs index 3cc67841974..4c08b8a6e62 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs @@ -31,8 +31,9 @@ use matrix_sdk_base::{ use once_cell::sync::Lazy; use ruma::{ EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedTransactionId, - OwnedUserId, RoomId, RoomVersionId, TransactionId, UserId, + OwnedUserId, RoomId, TransactionId, UserId, events::{AnySyncTimelineEvent, receipt::Receipt, room::message::MessageType}, + room_version_rules::RedactionRules, serde::Raw, }; use tracing::warn; @@ -534,8 +535,8 @@ impl EventTimelineItem { } /// Create a clone of the current item, with content that's been redacted. - pub(super) fn redact(&self, room_version: &RoomVersionId) -> Self { - let content = self.content.redact(room_version); + pub(super) fn redact(&self, rules: &RedactionRules) -> Self { + let content = self.content.redact(rules); let kind = match &self.kind { EventTimelineItemKind::Local(l) => EventTimelineItemKind::Local(l.clone()), EventTimelineItemKind::Remote(r) => EventTimelineItemKind::Remote(r.redact()), diff --git a/crates/matrix-sdk-ui/src/timeline/mod.rs b/crates/matrix-sdk-ui/src/timeline/mod.rs index beb28f6a5c7..ec7d3a008e6 100644 --- a/crates/matrix-sdk-ui/src/timeline/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/mod.rs @@ -39,7 +39,7 @@ use matrix_sdk::{ use mime::Mime; use pinned_events_loader::PinnedEventsRoom; use ruma::{ - EventId, OwnedEventId, RoomVersionId, UserId, + EventId, OwnedEventId, UserId, api::client::receipt::create_receipt::v3::ReceiptType, events::{ AnyMessageLikeEventContent, AnySyncTimelineEvent, @@ -50,6 +50,7 @@ use ruma::{ pinned_events::RoomPinnedEventsEventContent, }, }, + room_version_rules::RoomVersionRules, }; #[cfg(feature = "unstable-msc4274")] use ruma::{ @@ -799,9 +800,9 @@ impl Drop for TimelineDropHandle { #[cfg(not(target_family = "wasm"))] pub type TimelineEventFilterFn = - dyn Fn(&AnySyncTimelineEvent, &RoomVersionId) -> bool + Send + Sync; + dyn Fn(&AnySyncTimelineEvent, &RoomVersionRules) -> bool + Send + Sync; #[cfg(target_family = "wasm")] -pub type TimelineEventFilterFn = dyn Fn(&AnySyncTimelineEvent, &RoomVersionId) -> bool; +pub type TimelineEventFilterFn = dyn Fn(&AnySyncTimelineEvent, &RoomVersionRules) -> bool; /// A source for sending an attachment. /// diff --git a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs index 683f7c14199..4998bd74f20 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs @@ -41,7 +41,7 @@ use matrix_sdk_base::{ use matrix_sdk_test::{ALICE, DEFAULT_TEST_ROOM_ID, event_factory::EventFactory}; use ruma::{ EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedTransactionId, - OwnedUserId, RoomVersionId, TransactionId, UInt, UserId, + OwnedUserId, TransactionId, UInt, UserId, assign, events::{ AnyMessageLikeEventContent, AnyTimelineEvent, reaction::ReactionEventContent, @@ -52,6 +52,7 @@ use ruma::{ power_levels::NotificationPowerLevels, push::{PushConditionPowerLevelsCtx, PushConditionRoomCtx, Ruleset}, room_id, + room_version_rules::RoomVersionRules, serde::Raw, uint, }; @@ -349,8 +350,8 @@ impl RoomDataProvider for TestRoomDataProvider { &ALICE } - fn room_version(&self) -> RoomVersionId { - RoomVersionId::V10 + fn room_version_rules(&self) -> RoomVersionRules { + RoomVersionRules::V10 } async fn crypto_context_info(&self) -> CryptoContextInfo { @@ -406,18 +407,20 @@ impl RoomDataProvider for TestRoomDataProvider { async fn push_context(&self) -> Option { let push_rules = Ruleset::server_default(&ALICE); - let power_levels = PushConditionPowerLevelsCtx { - users: BTreeMap::new(), - users_default: int!(0), - notifications: NotificationPowerLevels::new(), - }; - let push_condition_room_ctx = PushConditionRoomCtx { - room_id: room_id!("!my_room:server.name").to_owned(), - member_count: uint!(2), - user_id: ALICE.to_owned(), - user_display_name: "Alice".to_owned(), - power_levels: Some(power_levels), - }; + let power_levels = PushConditionPowerLevelsCtx::new( + BTreeMap::new(), + int!(0), + NotificationPowerLevels::new(), + ); + let push_condition_room_ctx = assign!( + PushConditionRoomCtx::new( + room_id!("!my_room:server.name").to_owned(), + uint!(2), + ALICE.to_owned(), + "Alice".to_owned(), + ), + { power_levels: Some(power_levels) } + ); Some(PushContext::new(push_condition_room_ctx, push_rules)) } diff --git a/crates/matrix-sdk-ui/src/timeline/tests/read_receipts.rs b/crates/matrix-sdk-ui/src/timeline/tests/read_receipts.rs index 3f135d25e72..1ccced229a4 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/read_receipts.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/read_receipts.rs @@ -18,13 +18,15 @@ use eyeball_im::VectorDiff; use matrix_sdk::assert_next_matches_with_timeout; use matrix_sdk_test::{ALICE, BOB, CAROL, async_test, event_factory::EventFactory}; use ruma::{ - RoomVersionId, event_id, + event_id, events::{ AnySyncMessageLikeEvent, AnySyncTimelineEvent, receipt::{Receipt, ReceiptThread, ReceiptType}, room::message::{MessageType, RoomMessageEventContent, SyncRoomMessageEvent}, }, - owned_event_id, room_id, uint, + owned_event_id, room_id, + room_version_rules::RoomVersionRules, + uint, }; use stream_assert::{assert_next_matches, assert_pending}; @@ -34,7 +36,7 @@ use crate::timeline::{ tests::TestTimelineBuilder, }; -fn filter_notice(ev: &AnySyncTimelineEvent, _room_version: &RoomVersionId) -> bool { +fn filter_notice(ev: &AnySyncTimelineEvent, _rules: &RoomVersionRules) -> bool { match ev { AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( SyncRoomMessageEvent::Original(msg), @@ -378,7 +380,6 @@ async fn test_read_receipts_updates_on_message_decryption() { use assert_matches2::assert_let; use matrix_sdk_base::crypto::{OlmMachine, decrypt_room_key_export}; use ruma::{ - RoomVersionId, events::room::encrypted::{ EncryptedEventScheme, MegolmV1AesSha2ContentInit, RoomEncryptedEventContent, }, @@ -387,7 +388,7 @@ async fn test_read_receipts_updates_on_message_decryption() { use crate::timeline::{EncryptedMessage, TimelineItemContent}; - fn filter_text_msg(ev: &AnySyncTimelineEvent, _room_version_id: &RoomVersionId) -> bool { + fn filter_text_msg(ev: &AnySyncTimelineEvent, _rules: &RoomVersionRules) -> bool { match ev { AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( SyncRoomMessageEvent::Original(msg), diff --git a/crates/matrix-sdk-ui/src/timeline/traits.rs b/crates/matrix-sdk-ui/src/timeline/traits.rs index aa735f5f331..e1e376488a2 100644 --- a/crates/matrix-sdk-ui/src/timeline/traits.rs +++ b/crates/matrix-sdk-ui/src/timeline/traits.rs @@ -27,12 +27,13 @@ use matrix_sdk::{ }; use matrix_sdk_base::{RoomInfo, latest_event::LatestEvent}; use ruma::{ - EventId, OwnedEventId, OwnedTransactionId, OwnedUserId, RoomVersionId, UserId, + EventId, OwnedEventId, OwnedTransactionId, OwnedUserId, UserId, events::{ AnyMessageLikeEventContent, AnySyncTimelineEvent, fully_read::FullyReadEventContent, receipt::{Receipt, ReceiptThread, ReceiptType}, }, + room_version_rules::RoomVersionRules, serde::Raw, }; use tracing::error; @@ -90,7 +91,7 @@ pub(super) trait RoomDataProvider: Clone + PaginableRoom + PaginableThread + PinnedEventsRoom + 'static { fn own_user_id(&self) -> &UserId; - fn room_version(&self) -> RoomVersionId; + fn room_version_rules(&self) -> RoomVersionRules; fn crypto_context_info(&self) -> impl Future + SendOutsideWasm + '_; @@ -157,8 +158,8 @@ impl RoomDataProvider for Room { (**self).own_user_id() } - fn room_version(&self) -> RoomVersionId { - (**self).clone_info().room_version_or_default() + fn room_version_rules(&self) -> RoomVersionRules { + (**self).clone_info().room_version_rules_or_default() } async fn crypto_context_info(&self) -> CryptoContextInfo { diff --git a/crates/matrix-sdk-ui/tests/integration/timeline/read_receipts.rs b/crates/matrix-sdk-ui/tests/integration/timeline/read_receipts.rs index d94c9fc9637..10d483d349e 100644 --- a/crates/matrix-sdk-ui/tests/integration/timeline/read_receipts.rs +++ b/crates/matrix-sdk-ui/tests/integration/timeline/read_receipts.rs @@ -28,7 +28,7 @@ use matrix_sdk_test::{ }; use matrix_sdk_ui::timeline::{RoomExt, TimelineFocus}; use ruma::{ - MilliSecondsSinceUnixEpoch, RoomVersionId, + MilliSecondsSinceUnixEpoch, api::client::receipt::create_receipt::v3::ReceiptType as CreateReceiptType, event_id, events::{ @@ -36,13 +36,15 @@ use ruma::{ receipt::{ReceiptThread, ReceiptType as EventReceiptType}, room::message::{MessageType, RoomMessageEventContent, SyncRoomMessageEvent}, }, - owned_event_id, room_id, uint, user_id, + owned_event_id, room_id, + room_version_rules::RoomVersionRules, + uint, user_id, }; use serde_json::json; use stream_assert::{assert_pending, assert_ready}; use tokio::task::yield_now; -fn filter_notice(ev: &AnySyncTimelineEvent, _room_version: &RoomVersionId) -> bool { +fn filter_notice(ev: &AnySyncTimelineEvent, _rules: &RoomVersionRules) -> bool { match ev { AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( SyncRoomMessageEvent::Original(msg), diff --git a/crates/matrix-sdk/CHANGELOG.md b/crates/matrix-sdk/CHANGELOG.md index 09212c74c7f..c3878b01134 100644 --- a/crates/matrix-sdk/CHANGELOG.md +++ b/crates/matrix-sdk/CHANGELOG.md @@ -19,6 +19,16 @@ All notable changes to this project will be documented in this file. - [**breaking**] `OAuth::login` now allows requesting additional scopes for the authorization code grant. ([#5395](https://github.com/matrix-org/matrix-rust-sdk/pull/5395)) +### Refactor + +- [**breaking**] The `reason` argument of `Room::report_room()` is now required, + due to a clarification in the spec. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) +- [**breaking**] The `join_rule` field of `RoomPreview` is now a + `JoinRuleSummary`. It has the same variants as `SpaceRoomJoinRule` but + contains as summary of the allow rules for the restricted variants. + ([#5337](https://github.com/matrix-org/matrix-rust-sdk/pull/5337)) + ## [0.13.0] - 2025-07-10 ### Security Fixes diff --git a/crates/matrix-sdk/src/account.rs b/crates/matrix-sdk/src/account.rs index 8dcf15e71d6..d0eec02a1fb 100644 --- a/crates/matrix-sdk/src/account.rs +++ b/crates/matrix-sdk/src/account.rs @@ -1139,7 +1139,7 @@ impl Account { pub async fn set_media_previews_display_policy(&self, policy: MediaPreviews) -> Result<()> { let mut media_preview_config = self.fetch_media_preview_config_event_content().await?.unwrap_or_default(); - media_preview_config.media_previews = policy; + media_preview_config.media_previews = Some(policy); // Updating the unstable account data let unstable_media_preview_config = @@ -1155,7 +1155,7 @@ impl Account { pub async fn set_invite_avatars_display_policy(&self, policy: InviteAvatars) -> Result<()> { let mut media_preview_config = self.fetch_media_preview_config_event_content().await?.unwrap_or_default(); - media_preview_config.invite_avatars = policy; + media_preview_config.invite_avatars = Some(policy); // Updating the unstable account data let unstable_media_preview_config = diff --git a/crates/matrix-sdk/src/authentication/matrix/mod.rs b/crates/matrix-sdk/src/authentication/matrix/mod.rs index 4ef5115f5d4..ff696667ef0 100644 --- a/crates/matrix-sdk/src/authentication/matrix/mod.rs +++ b/crates/matrix-sdk/src/authentication/matrix/mod.rs @@ -105,20 +105,20 @@ impl MatrixAuth { idp_id: Option<&str>, ) -> Result { let homeserver = self.client.homeserver(); - let server_versions = self.client.server_versions().await?; + let supported_versions = self.client.supported_versions().await?; let request = if let Some(id) = idp_id { sso_login_with_provider::v3::Request::new(id.to_owned(), redirect_url.to_owned()) .try_into_http_request::>( homeserver.as_str(), SendAccessToken::None, - &server_versions, + &supported_versions, ) } else { sso_login::v3::Request::new(redirect_url.to_owned()).try_into_http_request::>( homeserver.as_str(), SendAccessToken::None, - &server_versions, + &supported_versions, ) }; diff --git a/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel.rs b/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel.rs index 2e86adeeab8..ca392ae552b 100644 --- a/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel.rs +++ b/crates/matrix-sdk/src/authentication/oauth/qrcode/rendezvous_channel.rs @@ -114,11 +114,18 @@ impl RendezvousChannel { client: HttpClient, rendezvous_server: &Url, ) -> Result { - use ruma::api::client::rendezvous::create_rendezvous_session; + use ruma::api::{client::rendezvous::create_rendezvous_session, SupportedVersions}; let request = create_rendezvous_session::unstable::Request::default(); let response = client - .send(request, None, rendezvous_server.to_string(), None, &[], Default::default()) + .send( + request, + None, + rendezvous_server.to_string(), + None, + &SupportedVersions { versions: Default::default(), features: Default::default() }, + Default::default(), + ) .await?; let rendezvous_url = response.url; diff --git a/crates/matrix-sdk/src/client/builder/homeserver_config.rs b/crates/matrix-sdk/src/client/builder/homeserver_config.rs index d7a829e913a..f2c46efbaf5 100644 --- a/crates/matrix-sdk/src/client/builder/homeserver_config.rs +++ b/crates/matrix-sdk/src/client/builder/homeserver_config.rs @@ -15,7 +15,7 @@ use ruma::{ api::{ client::discovery::{discover_homeserver, get_supported_versions}, - MatrixVersion, + MatrixVersion, SupportedVersions, }, OwnedServerName, ServerName, }; @@ -185,7 +185,10 @@ async fn discover_homeserver( Some(RequestConfig::short_retry()), server.to_string(), None, - &[MatrixVersion::V1_0], + &SupportedVersions { + versions: [MatrixVersion::V1_0].into(), + features: Default::default(), + }, Default::default(), ) .await @@ -209,7 +212,10 @@ pub(super) async fn get_supported_versions( Some(RequestConfig::short_retry()), homeserver_url.to_string(), None, - &[MatrixVersion::V1_0], + &SupportedVersions { + versions: [MatrixVersion::V1_0].into(), + features: Default::default(), + }, Default::default(), ) .await diff --git a/crates/matrix-sdk/src/client/builder/mod.rs b/crates/matrix-sdk/src/client/builder/mod.rs index c1310d2e387..a601d526bd1 100644 --- a/crates/matrix-sdk/src/client/builder/mod.rs +++ b/crates/matrix-sdk/src/client/builder/mod.rs @@ -17,7 +17,7 @@ mod homeserver_config; #[cfg(feature = "sqlite")] use std::path::Path; -use std::{fmt, sync::Arc}; +use std::{collections::BTreeSet, fmt, sync::Arc}; use homeserver_config::*; #[cfg(feature = "e2e-encryption")] @@ -101,7 +101,7 @@ pub struct ClientBuilder { store_config: BuilderStoreConfig, request_config: RequestConfig, respect_login_well_known: bool, - server_versions: Option>, + server_versions: Option>, handle_refresh_tokens: bool, base_client: Option, #[cfg(feature = "e2e-encryption")] diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index cdf9a791700..d51c9e0728d 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -48,7 +48,7 @@ use ruma::{ directory::{get_public_rooms, get_public_rooms_filtered}, discovery::{ discover_homeserver::{self, RtcFocusInfo}, - get_capabilities::{self, Capabilities}, + get_capabilities::{self, v3::Capabilities}, get_supported_versions, }, error::ErrorKind, @@ -1799,7 +1799,7 @@ impl Client { config, homeserver, access_token.as_deref(), - &self.server_versions().await?, + &self.supported_versions().await?, send_progress, ) .await @@ -1826,7 +1826,10 @@ impl Client { request_config, self.homeserver().to_string(), None, - &[MatrixVersion::V1_0], + &SupportedVersions { + versions: [MatrixVersion::V1_0].into(), + features: Default::default(), + }, Default::default(), ) .await?; @@ -1853,7 +1856,10 @@ impl Client { Some(RequestConfig::short_retry()), server_url_string, None, - &[MatrixVersion::V1_0], + &SupportedVersions { + versions: [MatrixVersion::V1_0].into(), + features: Default::default(), + }, Default::default(), ) .await; @@ -1997,7 +2003,7 @@ impl Client { /// println!("The homeserver supports Matrix 1.1: {supports_1_1:?}"); /// # anyhow::Ok(()) }; /// ``` - pub async fn server_versions(&self) -> HttpResult> { + pub async fn server_versions(&self) -> HttpResult> { self.get_or_load_and_cache_server_info(|server_info| { server_info.supported_versions.as_ref().map(|supported| supported.versions.clone()) }) @@ -3668,8 +3674,8 @@ pub(crate) mod tests { client.account().observe_media_preview_config().await.unwrap(); let initial_value: MediaPreviewConfigEventContent = initial_value.unwrap(); - assert_eq!(initial_value.invite_avatars, InviteAvatars::Off); - assert_eq!(initial_value.media_previews, MediaPreviews::Private); + assert_eq!(initial_value.invite_avatars, Some(InviteAvatars::Off)); + assert_eq!(initial_value.media_previews, Some(MediaPreviews::Private)); pin_mut!(stream); assert_pending!(stream); @@ -3689,8 +3695,8 @@ pub(crate) mod tests { assert_next_matches!( stream, MediaPreviewConfigEventContent { - media_previews: MediaPreviews::Off, - invite_avatars: InviteAvatars::On, + media_previews: Some(MediaPreviews::Off), + invite_avatars: Some(InviteAvatars::On), .. } ); @@ -3719,8 +3725,8 @@ pub(crate) mod tests { client.account().observe_media_preview_config().await.unwrap(); let initial_value: MediaPreviewConfigEventContent = initial_value.unwrap(); - assert_eq!(initial_value.invite_avatars, InviteAvatars::Off); - assert_eq!(initial_value.media_previews, MediaPreviews::Private); + assert_eq!(initial_value.invite_avatars, Some(InviteAvatars::Off)); + assert_eq!(initial_value.media_previews, Some(MediaPreviews::Private)); pin_mut!(stream); assert_pending!(stream); @@ -3740,8 +3746,8 @@ pub(crate) mod tests { assert_next_matches!( stream, MediaPreviewConfigEventContent { - media_previews: MediaPreviews::Off, - invite_avatars: InviteAvatars::On, + media_previews: Some(MediaPreviews::Off), + invite_avatars: Some(InviteAvatars::On), .. } ); diff --git a/crates/matrix-sdk/src/encryption/mod.rs b/crates/matrix-sdk/src/encryption/mod.rs index 3673115429f..2723ef6981f 100644 --- a/crates/matrix-sdk/src/encryption/mod.rs +++ b/crates/matrix-sdk/src/encryption/mod.rs @@ -349,8 +349,9 @@ pub struct OAuthCrossSigningResetInfo { impl OAuthCrossSigningResetInfo { fn from_auth_info(auth_info: &UiaaInfo) -> Result { - let parameters = - serde_json::from_str::(auth_info.params.get())?; + let parameters = serde_json::from_str::( + auth_info.params.as_ref().map(|value| value.get()).unwrap_or_default(), + )?; Ok(OAuthCrossSigningResetInfo { approval_url: parameters.reset.url }) } diff --git a/crates/matrix-sdk/src/encryption/recovery/types.rs b/crates/matrix-sdk/src/encryption/recovery/types.rs index 2c1bd277bc1..10f91308806 100644 --- a/crates/matrix-sdk/src/encryption/recovery/types.rs +++ b/crates/matrix-sdk/src/encryption/recovery/types.rs @@ -13,7 +13,7 @@ // limitations under the License. use matrix_sdk_base::crypto::store::types::RoomKeyCounts; -use ruma::exports::ruma_macros::EventContent; +use ruma::events::macros::EventContent; use serde::{Deserialize, Serialize}; use thiserror::Error; use zeroize::{Zeroize, ZeroizeOnDrop}; diff --git a/crates/matrix-sdk/src/event_cache/mod.rs b/crates/matrix-sdk/src/event_cache/mod.rs index 19ada4ea81a..6b907545ff4 100644 --- a/crates/matrix-sdk/src/event_cache/mod.rs +++ b/crates/matrix-sdk/src/event_cache/mod.rs @@ -577,11 +577,11 @@ impl EventCacheInner { let room = client .get_room(room_id) .ok_or_else(|| EventCacheError::RoomNotFound { room_id: room_id.to_owned() })?; - let room_version = room.clone_info().room_version_or_default(); + let room_version_rules = room.clone_info().room_version_rules_or_default(); let room_state = RoomEventCacheState::new( room_id.to_owned(), - room_version, + room_version_rules, self.store.clone(), pagination_status.clone(), ) diff --git a/crates/matrix-sdk/src/event_cache/room/mod.rs b/crates/matrix-sdk/src/event_cache/room/mod.rs index accca7056c8..63f63696465 100644 --- a/crates/matrix-sdk/src/event_cache/room/mod.rs +++ b/crates/matrix-sdk/src/event_cache/room/mod.rs @@ -632,8 +632,9 @@ mod private { relation::RelationType, room::redaction::SyncRoomRedactionEvent, AnySyncTimelineEvent, MessageLikeEventType, }, + room_version_rules::RoomVersionRules, serde::Raw, - EventId, OwnedEventId, OwnedRoomId, RoomVersionId, + EventId, OwnedEventId, OwnedRoomId, }; use tokio::sync::broadcast::Receiver; use tracing::{debug, error, instrument, trace, warn}; @@ -656,8 +657,8 @@ mod private { /// The room this state relates to. room: OwnedRoomId, - /// The room version for this room. - room_version: RoomVersionId, + /// The rules for the version of this room. + room_version_rules: RoomVersionRules, /// Reference to the underlying backing store. store: EventCacheStoreLock, @@ -696,7 +697,7 @@ mod private { /// [`LinkedChunk`]: matrix_sdk_common::linked_chunk::LinkedChunk pub async fn new( room_id: OwnedRoomId, - room_version: RoomVersionId, + room_version_rules: RoomVersionRules, store: EventCacheStoreLock, pagination_status: SharedObservable, ) -> Result { @@ -736,7 +737,7 @@ mod private { Ok(Self { room: room_id, - room_version, + room_version_rules, store, room_linked_chunk, threads, @@ -1419,7 +1420,7 @@ mod private { return Ok(()); }; - let Some(event_id) = redaction.redacts(&self.room_version) else { + let Some(event_id) = redaction.redacts(&self.room_version_rules.redaction) else { warn!("missing target event id from the redaction event"); return Ok(()); }; @@ -1449,7 +1450,7 @@ mod private { if let Some(redacted_event) = apply_redaction( target_event.raw(), event.raw().cast_ref::(), - &self.room_version, + &self.room_version_rules.redaction, ) { // It's safe to cast `redacted_event` here: // - either the event was an `AnyTimelineEvent` cast to `AnySyncTimelineEvent` diff --git a/crates/matrix-sdk/src/event_handler/static_events.rs b/crates/matrix-sdk/src/event_handler/static_events.rs index 4037b404f60..2ed5667bdfe 100644 --- a/crates/matrix-sdk/src/event_handler/static_events.rs +++ b/crates/matrix-sdk/src/event_handler/static_events.rs @@ -16,11 +16,9 @@ use ruma::{ events::{ - self, - presence::{PresenceEvent, PresenceEventContent}, - AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent, - AnySyncEphemeralRoomEvent, AnySyncMessageLikeEvent, AnySyncStateEvent, - AnySyncTimelineEvent, AnyToDeviceEvent, EphemeralRoomEventContent, + self, presence::PresenceEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, + AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncMessageLikeEvent, + AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent, EphemeralRoomEventContent, GlobalAccountDataEventContent, MessageLikeEventContent, PossiblyRedactedStateEventContent, RedactContent, RedactedMessageLikeEventContent, RedactedStateEventContent, RoomAccountDataEventContent, StaticEventContent, StaticStateEventContent, @@ -141,7 +139,7 @@ where impl SyncEvent for PresenceEvent { const KIND: HandlerKind = HandlerKind::Presence; - const TYPE: Option<&'static str> = Some(PresenceEventContent::TYPE); + const TYPE: Option<&'static str> = None; } impl SyncEvent for AnyGlobalAccountDataEvent { diff --git a/crates/matrix-sdk/src/http_client/mod.rs b/crates/matrix-sdk/src/http_client/mod.rs index 77c4bee20c5..62a3e9e2cb8 100644 --- a/crates/matrix-sdk/src/http_client/mod.rs +++ b/crates/matrix-sdk/src/http_client/mod.rs @@ -14,6 +14,7 @@ use std::{ any::type_name, + borrow::Cow, fmt::Debug, num::NonZeroUsize, sync::{ @@ -29,7 +30,7 @@ use eyeball::SharedObservable; use http::Method; use ruma::api::{ error::{FromHttpResponseError, IntoHttpError}, - AuthScheme, MatrixVersion, OutgoingRequest, SendAccessToken, + AuthScheme, OutgoingRequest, SendAccessToken, SupportedVersions, }; use tokio::sync::{Semaphore, SemaphorePermit}; use tracing::{debug, field::debug, instrument, trace}; @@ -101,17 +102,20 @@ impl HttpClient { config: RequestConfig, homeserver: String, access_token: Option<&str>, - server_versions: &[MatrixVersion], + supported_versions: &SupportedVersions, ) -> Result, IntoHttpError> where R: OutgoingRequest + Debug, { trace!(request_type = type_name::(), "Serializing request"); - let server_versions = if config.force_matrix_version.is_some() { - config.force_matrix_version.as_slice() + let supported_versions = if let Some(matrix_version) = config.force_matrix_version { + Cow::Owned(SupportedVersions { + versions: [matrix_version].into(), + features: Default::default(), + }) } else { - server_versions + Cow::Borrowed(supported_versions) }; let send_access_token = match access_token { @@ -126,7 +130,7 @@ impl HttpClient { }; let request = request - .try_into_http_request::(&homeserver, send_access_token, server_versions)? + .try_into_http_request::(&homeserver, send_access_token, &supported_versions)? .map(|body| body.freeze()); Ok(request) @@ -134,7 +138,7 @@ impl HttpClient { #[allow(clippy::too_many_arguments)] #[instrument( - skip(self, request, config, homeserver, access_token, server_versions, send_progress), + skip(self, request, config, homeserver, access_token, supported_versions, send_progress), fields( uri, method, @@ -152,7 +156,7 @@ impl HttpClient { config: Option, homeserver: String, access_token: Option<&str>, - server_versions: &[MatrixVersion], + supported_versions: &SupportedVersions, send_progress: SharedObservable, ) -> Result where @@ -179,6 +183,7 @@ impl HttpClient { AuthScheme::AccessToken | AuthScheme::AccessTokenOptional | AuthScheme::AppserviceToken + | AuthScheme::AppserviceTokenOptional | AuthScheme::None => {} AuthScheme::ServerSignatures => { return Err(HttpError::NotClientRequest); @@ -186,7 +191,7 @@ impl HttpClient { } let request = self - .serialize_request(request, config, homeserver, access_token, server_versions) + .serialize_request(request, config, homeserver, access_token, supported_versions) .map_err(HttpError::IntoHttp)?; let method = request.method(); diff --git a/crates/matrix-sdk/src/room/edit.rs b/crates/matrix-sdk/src/room/edit.rs index eac942ed42d..d7b8e4dc1ef 100644 --- a/crates/matrix-sdk/src/room/edit.rs +++ b/crates/matrix-sdk/src/room/edit.rs @@ -21,17 +21,16 @@ use ruma::{ UnstablePollStartEventContent, }, room::message::{ - FormattedBody, MessageType, Relation, ReplacementMetadata, RoomMessageEventContent, + FormattedBody, MessageType, ReplacementMetadata, RoomMessageEventContent, RoomMessageEventContentWithoutRelation, }, - AnyMessageLikeEvent, AnyMessageLikeEventContent, AnySyncMessageLikeEvent, - AnySyncTimelineEvent, AnyTimelineEvent, Mentions, MessageLikeEvent, - OriginalMessageLikeEvent, SyncMessageLikeEvent, + AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnySyncTimelineEvent, Mentions, + SyncMessageLikeEvent, }, - EventId, RoomId, UserId, + EventId, UserId, }; use thiserror::Error; -use tracing::{instrument, warn}; +use tracing::instrument; use super::EventSource; use crate::Room; @@ -122,13 +121,12 @@ impl Room { event_id: &EventId, new_content: EditedContent, ) -> Result { - make_edit_event(self, self.room_id(), self.own_user_id(), event_id, new_content).await + make_edit_event(self, self.own_user_id(), event_id, new_content).await } } async fn make_edit_event( source: S, - room_id: &RoomId, own_user_id: &UserId, event_id: &EventId, new_content: EditedContent, @@ -159,14 +157,10 @@ async fn make_edit_event( }); }; - let mentions = original.content.mentions.clone(); - let replied_to_original_room_msg = - extract_replied_to(source, room_id, original.content.relates_to).await; + let mentions = original.content.mentions; - let replacement = new_content.make_replacement( - ReplacementMetadata::new(event_id.to_owned(), mentions), - replied_to_original_room_msg.as_ref(), - ); + let replacement = new_content + .make_replacement(ReplacementMetadata::new(event_id.to_owned(), mentions)); Ok(replacement.into()) } @@ -183,8 +177,6 @@ async fn make_edit_event( }; let original_mentions = original.content.mentions.clone(); - let replied_to_original_room_msg = - extract_replied_to(source, room_id, original.content.relates_to.clone()).await; let mut prev_content = original.content; @@ -195,10 +187,8 @@ async fn make_edit_event( }); } - let replacement = prev_content.make_replacement( - ReplacementMetadata::new(event_id.to_owned(), original_mentions), - replied_to_original_room_msg.as_ref(), - ); + let replacement = prev_content + .make_replacement(ReplacementMetadata::new(event_id.to_owned(), original_mentions)); Ok(replacement.into()) } @@ -292,45 +282,6 @@ pub(crate) fn update_media_caption( } } -/// Try to find the original replied-to event content, in a best-effort manner. -async fn extract_replied_to( - source: S, - room_id: &RoomId, - relates_to: Option>, -) -> Option> { - let replied_to_sync_timeline_event = if let Some(Relation::Reply { in_reply_to }) = relates_to { - source - .get_event(&in_reply_to.event_id) - .await - .map_err(|err| { - warn!("couldn't fetch the replied-to event, when editing: {err}"); - err - }) - .ok() - } else { - None - }; - - replied_to_sync_timeline_event - .and_then(|sync_timeline_event| { - sync_timeline_event - .raw() - .deserialize() - .map_err(|err| warn!("unable to deserialize replied-to event: {err}")) - .ok() - }) - .and_then(|event| { - if let AnyTimelineEvent::MessageLike(AnyMessageLikeEvent::RoomMessage( - MessageLikeEvent::Original(original), - )) = event.into_full_event(room_id.to_owned()) - { - Some(original) - } else { - None - } - }) -} - #[cfg(test)] mod tests { use std::collections::BTreeMap; @@ -344,7 +295,7 @@ mod tests { room::message::{MessageType, Relation, RoomMessageEventContentWithoutRelation}, AnyMessageLikeEventContent, AnySyncTimelineEvent, Mentions, }, - owned_mxc_uri, owned_user_id, room_id, user_id, EventId, OwnedEventId, + owned_mxc_uri, owned_user_id, user_id, EventId, OwnedEventId, }; use super::{make_edit_event, EditError, EventSource}; @@ -373,18 +324,11 @@ mod tests { f.room_name("The room name").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let new_content = RoomMessageEventContentWithoutRelation::text_plain("the edit"); assert_matches!( - make_edit_event( - cache, - room_id, - own_user_id, - event_id, - EditedContent::RoomMessage(new_content), - ) - .await, + make_edit_event(cache, own_user_id, event_id, EditedContent::RoomMessage(new_content),) + .await, Err(EditError::StateEvent) ); } @@ -401,19 +345,12 @@ mod tests { f.text_msg("hi").event_id(event_id).sender(user_id!("@other:saucisse.bzh")).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let own_user_id = user_id!("@me:saucisse.bzh"); let new_content = RoomMessageEventContentWithoutRelation::text_plain("the edit"); assert_matches!( - make_edit_event( - cache, - room_id, - own_user_id, - event_id, - EditedContent::RoomMessage(new_content), - ) - .await, + make_edit_event(cache, own_user_id, event_id, EditedContent::RoomMessage(new_content),) + .await, Err(EditError::NotAuthor) ); } @@ -430,18 +367,12 @@ mod tests { f.text_msg("hi").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let new_content = RoomMessageEventContentWithoutRelation::text_plain("the edit"); - let edit_event = make_edit_event( - cache, - room_id, - own_user_id, - event_id, - EditedContent::RoomMessage(new_content), - ) - .await - .unwrap(); + let edit_event = + make_edit_event(cache, own_user_id, event_id, EditedContent::RoomMessage(new_content)) + .await + .unwrap(); assert_let!(AnyMessageLikeEventContent::RoomMessage(msg) = &edit_event); // This is the fallback text, for clients not supporting edits. @@ -464,11 +395,8 @@ mod tests { f.text_msg("hello world").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); - let err = make_edit_event( cache, - room_id, own_user_id, event_id, EditedContent::MediaCaption { @@ -502,11 +430,8 @@ mod tests { .into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); - let edit_event = make_edit_event( cache, - room_id, own_user_id, event_id, EditedContent::MediaCaption { @@ -564,11 +489,8 @@ mod tests { cache.events.insert(event_id.to_owned(), event); - let room_id = room_id!("!galette:saucisse.bzh"); - let edit_event = make_edit_event( cache, - room_id, own_user_id, event_id, // Remove the caption by setting it to None. @@ -620,15 +542,12 @@ mod tests { cache.events.insert(event_id.to_owned(), event); - let room_id = room_id!("!galette:saucisse.bzh"); - // Add an intentional mention in the caption. let mentioned_user_id = owned_user_id!("@crepe:saucisse.bzh"); let edit_event = { let mentions = Mentions::with_user_ids([mentioned_user_id.clone()]); make_edit_event( cache, - room_id, own_user_id, event_id, EditedContent::MediaCaption { @@ -689,12 +608,10 @@ mod tests { .into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let new_content = RoomMessageEventContentWithoutRelation::text_plain("uh i mean hi too"); let edit_event = make_edit_event( cache, - room_id, own_user_id, resp_event_id, EditedContent::RoomMessage(new_content), @@ -704,12 +621,7 @@ mod tests { assert_let!(AnyMessageLikeEventContent::RoomMessage(msg) = &edit_event); // This is the fallback text, for clients not supporting edits. - assert_eq!( - msg.body(), - r#"> <@steb:saucisse.bzh> hi - -* uh i mean hi too"# - ); + assert_eq!(msg.body(), "* uh i mean hi too"); assert_let!(Some(Relation::Replacement(repl)) = &msg.relates_to); assert_eq!(repl.event_id, resp_event_id); diff --git a/crates/matrix-sdk/src/room/mod.rs b/crates/matrix-sdk/src/room/mod.rs index c61f18fcafd..998d98d8d6f 100644 --- a/crates/matrix-sdk/src/room/mod.rs +++ b/crates/matrix-sdk/src/room/mod.rs @@ -1264,7 +1264,7 @@ impl Room { /// use matrix_sdk::ruma::{ /// events::{ /// marked_unread::MarkedUnreadEventContent, - /// AnyRoomAccountDataEventContent, EventContent, + /// AnyRoomAccountDataEventContent, RoomAccountDataEventContent, /// }, /// serde::Raw, /// }; @@ -2932,13 +2932,15 @@ impl Room { let power_levels = self.power_levels().await.ok().map(Into::into); - Ok(Some(PushConditionRoomCtx { - user_id: user_id.to_owned(), - room_id: room_id.to_owned(), - member_count: UInt::new(member_count).unwrap_or(UInt::MAX), - user_display_name, - power_levels, - })) + Ok(Some(assign!( + PushConditionRoomCtx::new( + room_id.to_owned(), + UInt::new(member_count).unwrap_or(UInt::MAX), + user_id.to_owned(), + user_display_name, + ), + { power_levels } + ))) } /// Retrieves a [`PushContext`] that can be used to compute the push @@ -3155,9 +3157,8 @@ impl Room { /// # Errors /// /// Returns an error if the room is not found or on rate limit - pub async fn report_room(&self, reason: Option) -> Result { - let mut request = report_room::v3::Request::new(self.inner.room_id().to_owned()); - request.reason = reason; + pub async fn report_room(&self, reason: String) -> Result { + let request = report_room::v3::Request::new(self.inner.room_id().to_owned(), reason); Ok(self.client.send(request).await?) } diff --git a/crates/matrix-sdk/src/room/reply.rs b/crates/matrix-sdk/src/room/reply.rs index a86fe2f964a..0fa202cf3e4 100644 --- a/crates/matrix-sdk/src/room/reply.rs +++ b/crates/matrix-sdk/src/room/reply.rs @@ -14,22 +14,20 @@ //! Facilities to reply to existing events. +use as_variant::as_variant; use ruma::{ events::{ - relation::Thread, room::{ encrypted::Relation as EncryptedRelation, message::{ - AddMentions, ForwardThread, OriginalRoomMessageEvent, Relation, ReplyWithinThread, + AddMentions, ForwardThread, ReplyMetadata, ReplyWithinThread, RoomMessageEventContent, RoomMessageEventContentWithoutRelation, }, }, - AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncMessageLikeEvent, + AnySyncTimelineEvent, }, - serde::Raw, - EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, RoomId, UserId, + OwnedEventId, UserId, }; -use serde::Deserialize; use thiserror::Error; use tracing::{error, instrument}; @@ -44,28 +42,6 @@ pub struct Reply { pub enforce_thread: EnforceThread, } -/// Content information needed to reply to an event. -#[derive(Debug, Clone)] -struct RepliedToInfo { - /// The event ID of the event to reply to. - event_id: OwnedEventId, - /// The sender of the event to reply to. - sender: OwnedUserId, - /// The timestamp of the event to reply to. - timestamp: MilliSecondsSinceUnixEpoch, - /// The content of the event to reply to. - content: ReplyContent, -} - -/// The content of a reply. -#[derive(Debug, Clone)] -enum ReplyContent { - /// Content of a message event. - Message(Box), - /// Content of any other kind of event stored as raw JSON. - Raw(Raw), -} - /// Errors specific to unsupported replies. #[derive(Debug, Error)] pub enum ReplyError { @@ -81,6 +57,8 @@ pub enum ReplyError { } /// Whether or not to enforce a [`Relation::Thread`] when sending a reply. +/// +/// [`Relation::Thread`]: ruma::events::room::message::Relation::Thread #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum EnforceThread { /// A thread relation is enforced. If the original message does not have a @@ -114,18 +92,30 @@ impl Room { content: RoomMessageEventContentWithoutRelation, reply: Reply, ) -> Result { - make_reply_event(self, self.room_id(), self.own_user_id(), content, reply).await + make_reply_event(self, self.own_user_id(), content, reply).await } } async fn make_reply_event( source: S, - room_id: &RoomId, own_user_id: &UserId, content: RoomMessageEventContentWithoutRelation, reply: Reply, ) -> Result { - let replied_to_info = replied_to_info_from_event_id(source, &reply.event_id).await?; + let event = + source.get_event(&reply.event_id).await.map_err(|err| ReplyError::Fetch(Box::new(err)))?; + + let raw_event = event.into_raw(); + let event = raw_event.deserialize().map_err(|_| ReplyError::Deserialization)?; + + let relation = as_variant!(&event, AnySyncTimelineEvent::MessageLike) + .ok_or(ReplyError::StateEvent)? + .original_content() + .and_then(|content| content.relation()); + let thread = + relation.as_ref().and_then(|relation| as_variant!(relation, EncryptedRelation::Thread)); + + let reply_metadata = ReplyMetadata::new(event.event_id(), event.sender(), thread); // [The specification](https://spec.matrix.org/v1.10/client-server-api/#user-and-room-mentions) says: // @@ -135,129 +125,21 @@ async fn make_reply_event( // If the replied to event has been written by the current user, let's toggle to // `AddMentions::No`. let mention_the_sender = - if own_user_id == replied_to_info.sender { AddMentions::No } else { AddMentions::Yes }; - - let content = match replied_to_info.content { - ReplyContent::Message(replied_to_content) => { - let event = OriginalRoomMessageEvent { - event_id: replied_to_info.event_id, - sender: replied_to_info.sender, - origin_server_ts: replied_to_info.timestamp, - room_id: room_id.to_owned(), - content: *replied_to_content, - unsigned: Default::default(), - }; - - match reply.enforce_thread { - EnforceThread::Threaded(is_reply) => { - content.make_for_thread(&event, is_reply, mention_the_sender) - } - EnforceThread::MaybeThreaded => { - content.make_reply_to(&event, ForwardThread::Yes, mention_the_sender) - } - EnforceThread::Unthreaded => { - content.make_reply_to(&event, ForwardThread::No, mention_the_sender) - } - } - } + if own_user_id == event.sender() { AddMentions::No } else { AddMentions::Yes }; - ReplyContent::Raw(raw_event) => { - match reply.enforce_thread { - EnforceThread::Threaded(is_reply) => { - // Some of the code below technically belongs into ruma. However, - // reply fallbacks have been removed in Matrix 1.13 which means - // both match arms can use the successor of make_for_thread in - // the next ruma release. - #[derive(Deserialize)] - struct ContentDeHelper { - #[serde(rename = "m.relates_to")] - relates_to: Option, - } - - let previous_content = - raw_event.get_field::("content").ok().flatten(); - - let mut content = if is_reply == ReplyWithinThread::Yes { - content.make_reply_to_raw( - &raw_event, - replied_to_info.event_id.to_owned(), - room_id, - ForwardThread::No, - mention_the_sender, - ) - } else { - content.into() - }; - - let thread_root = if let Some(EncryptedRelation::Thread(thread)) = - previous_content.as_ref().and_then(|c| c.relates_to.as_ref()) - { - thread.event_id.to_owned() - } else { - replied_to_info.event_id.to_owned() - }; - - let thread = if is_reply == ReplyWithinThread::Yes { - Thread::reply(thread_root, replied_to_info.event_id) - } else { - Thread::plain(thread_root, replied_to_info.event_id) - }; - - content.relates_to = Some(Relation::Thread(thread)); - content - } - - EnforceThread::MaybeThreaded => content.make_reply_to_raw( - &raw_event, - replied_to_info.event_id, - room_id, - ForwardThread::Yes, - mention_the_sender, - ), - - EnforceThread::Unthreaded => content.make_reply_to_raw( - &raw_event, - replied_to_info.event_id, - room_id, - ForwardThread::No, - mention_the_sender, - ), - } + let content = match reply.enforce_thread { + EnforceThread::Threaded(is_reply) => { + content.make_for_thread(reply_metadata, is_reply, mention_the_sender) } - }; - - Ok(content) -} - -async fn replied_to_info_from_event_id( - source: S, - event_id: &EventId, -) -> Result { - let event = source.get_event(event_id).await.map_err(|err| ReplyError::Fetch(Box::new(err)))?; - - let raw_event = event.into_raw(); - let event = raw_event.deserialize().map_err(|_| ReplyError::Deserialization)?; - - let reply_content = match &event { - AnySyncTimelineEvent::MessageLike(event) => { - if let AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original( - original_event, - )) = event - { - ReplyContent::Message(Box::new(original_event.content.clone())) - } else { - ReplyContent::Raw(raw_event) - } + EnforceThread::MaybeThreaded => { + content.make_reply_to(reply_metadata, ForwardThread::Yes, mention_the_sender) + } + EnforceThread::Unthreaded => { + content.make_reply_to(reply_metadata, ForwardThread::No, mention_the_sender) } - AnySyncTimelineEvent::State(_) => return Err(ReplyError::StateEvent), }; - Ok(RepliedToInfo { - event_id: event_id.to_owned(), - sender: event.sender().to_owned(), - timestamp: event.origin_server_ts(), - content: reply_content, - }) + Ok(content) } #[cfg(test)] @@ -273,7 +155,6 @@ mod tests { room::message::{Relation, ReplyWithinThread, RoomMessageEventContentWithoutRelation}, AnySyncTimelineEvent, }, - room_id, serde::Raw, user_id, EventId, OwnedEventId, }; @@ -308,13 +189,11 @@ mod tests { f.text_msg("hi").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); assert_matches!( make_reply_event( cache, - room_id, own_user_id, content, Reply { @@ -353,13 +232,11 @@ mod tests { ), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); assert_matches!( make_reply_event( cache, - room_id, own_user_id, content, Reply { event_id: event_id.into(), enforce_thread: EnforceThread::Unthreaded }, @@ -381,13 +258,11 @@ mod tests { f.room_name("lobby").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); assert_matches!( make_reply_event( cache, - room_id, own_user_id, content, Reply { event_id: event_id.into(), enforce_thread: EnforceThread::Unthreaded }, @@ -409,12 +284,10 @@ mod tests { f.text_msg("hi").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); let reply_event = make_reply_event( cache, - room_id, own_user_id, content, Reply { event_id: event_id.into(), enforce_thread: EnforceThread::Unthreaded }, @@ -439,12 +312,10 @@ mod tests { f.text_msg("hi").event_id(event_id).sender(own_user_id).into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); let reply_event = make_reply_event( cache, - room_id, own_user_id, content, Reply { @@ -483,12 +354,10 @@ mod tests { .into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); let reply_event = make_reply_event( cache, - room_id, own_user_id, content, Reply { @@ -527,12 +396,10 @@ mod tests { .into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); let reply_event = make_reply_event( cache, - room_id, own_user_id, content, Reply { @@ -571,12 +438,10 @@ mod tests { .into(), ); - let room_id = room_id!("!galette:saucisse.bzh"); let content = RoomMessageEventContentWithoutRelation::text_plain("the reply"); let reply_event = make_reply_event( cache, - room_id, own_user_id, content, Reply { event_id: event_id.into(), enforce_thread: EnforceThread::MaybeThreaded }, diff --git a/crates/matrix-sdk/src/room_directory_search.rs b/crates/matrix-sdk/src/room_directory_search.rs index d9a1b24a9a0..84c50145c6f 100644 --- a/crates/matrix-sdk/src/room_directory_search.rs +++ b/crates/matrix-sdk/src/room_directory_search.rs @@ -20,8 +20,7 @@ use futures_core::Stream; use imbl::Vector; use ruma::{ api::client::directory::get_public_rooms_filtered::v3::Request as PublicRoomsFilterRequest, - directory::{Filter, PublicRoomJoinRule}, - OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, + directory::Filter, room::JoinRuleKind, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, }; use crate::{Client, OwnedServerName, Result}; @@ -42,7 +41,7 @@ pub struct RoomDescription { /// The room's avatar URL, if any. pub avatar_url: Option, /// The room's join rule. - pub join_rule: PublicRoomJoinRule, + pub join_rule: JoinRuleKind, /// Whether can be previewed pub is_world_readable: bool, /// The number of members that have joined the room. @@ -220,7 +219,9 @@ mod tests { use eyeball_im::VectorDiff; use futures_util::StreamExt; use matrix_sdk_test::{async_test, test_json}; - use ruma::{directory::Filter, owned_server_name, serde::Raw, RoomAliasId, RoomId}; + use ruma::{ + directory::Filter, owned_server_name, room::JoinRuleKind, serde::Raw, RoomAliasId, RoomId, + }; use serde_json::Value as JsonValue; use stream_assert::assert_pending; use wiremock::{ @@ -279,7 +280,7 @@ mod tests { topic: Some("Tasty tasty cheese".into()), alias: None, avatar_url: Some("mxc://bleeker.street/CHEDDARandBRIE".into()), - join_rule: ruma::directory::PublicRoomJoinRule::Public, + join_rule: JoinRuleKind::Public, is_world_readable: true, joined_members: 37, } @@ -292,7 +293,7 @@ mod tests { topic: Some("Tasty tasty pear".into()), alias: RoomAliasId::parse("#murrays:pear.bar").ok(), avatar_url: Some("mxc://bleeker.street/pear".into()), - join_rule: ruma::directory::PublicRoomJoinRule::Knock, + join_rule: JoinRuleKind::Knock, is_world_readable: false, joined_members: 20, } diff --git a/crates/matrix-sdk/src/room_preview.rs b/crates/matrix-sdk/src/room_preview.rs index 61502a88ab5..4321fe1cc98 100644 --- a/crates/matrix-sdk/src/room_preview.rs +++ b/crates/matrix-sdk/src/room_preview.rs @@ -22,9 +22,8 @@ use futures_util::future::join_all; use matrix_sdk_base::{RoomHero, RoomInfo, RoomState}; use ruma::{ api::client::{membership::joined_members, state::get_state_events}, - events::room::{history_visibility::HistoryVisibility, join_rules::JoinRule}, - room::RoomType, - space::SpaceRoomJoinRule, + events::room::history_visibility::HistoryVisibility, + room::{JoinRuleSummary, RoomType}, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, RoomId, RoomOrAliasId, ServerName, }; use tokio::try_join; @@ -63,7 +62,7 @@ pub struct RoomPreview { pub room_type: Option, /// What's the join rule for this room? - pub join_rule: Option, + pub join_rule: Option, /// Is the room world-readable (i.e. is its history_visibility set to /// world_readable)? @@ -101,19 +100,7 @@ impl RoomPreview { topic: room_info.topic().map(ToOwned::to_owned), avatar_url: room_info.avatar_url().map(ToOwned::to_owned), room_type: room_info.room_type().cloned(), - join_rule: room_info.join_rule().map(|rule| match rule { - JoinRule::Invite => SpaceRoomJoinRule::Invite, - JoinRule::Knock => SpaceRoomJoinRule::Knock, - JoinRule::Private => SpaceRoomJoinRule::Private, - JoinRule::Restricted(_) => SpaceRoomJoinRule::Restricted, - JoinRule::KnockRestricted(_) => SpaceRoomJoinRule::KnockRestricted, - JoinRule::Public => SpaceRoomJoinRule::Public, - _ => { - // The JoinRule enum is non-exhaustive. Let's do a white lie and pretend it's - // private (a cautious choice). - SpaceRoomJoinRule::Private - } - }), + join_rule: room_info.join_rule().cloned().map(Into::into), is_world_readable: room_info .history_visibility() .map(|vis| *vis == HistoryVisibility::WorldReadable), @@ -288,7 +275,7 @@ impl RoomPreview { num_joined_members: summary.num_joined_members.into(), num_active_members, room_type: summary.room_type, - join_rule: Some(summary.join_rule.into()), + join_rule: Some(summary.join_rule), is_world_readable: Some(summary.world_readable), state, is_direct, diff --git a/crates/matrix-sdk/src/send_queue/mod.rs b/crates/matrix-sdk/src/send_queue/mod.rs index c100fa1f80a..ec08a4c3ab1 100644 --- a/crates/matrix-sdk/src/send_queue/mod.rs +++ b/crates/matrix-sdk/src/send_queue/mod.rs @@ -161,7 +161,7 @@ use ruma::{ message::{FormattedBody, RoomMessageEventContent}, MediaSource, }, - AnyMessageLikeEventContent, EventContent as _, Mentions, + AnyMessageLikeEventContent, Mentions, MessageLikeEventContent as _, }, serde::Raw, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedTransactionId, RoomId, diff --git a/crates/matrix-sdk/tests/integration/event_cache/mod.rs b/crates/matrix-sdk/tests/integration/event_cache/mod.rs index 5e6bbc92593..e9277c409d2 100644 --- a/crates/matrix-sdk/tests/integration/event_cache/mod.rs +++ b/crates/matrix-sdk/tests/integration/event_cache/mod.rs @@ -29,7 +29,9 @@ use matrix_sdk_test::{ use ruma::{ event_id, events::{AnySyncMessageLikeEvent, AnySyncTimelineEvent, TimelineEventType}, - room_id, user_id, EventId, RoomVersionId, + room_id, + room_version_rules::RedactionRules, + user_id, EventId, }; use serde_json::json; use tokio::{spawn, sync::broadcast, time::sleep}; @@ -1411,7 +1413,7 @@ async fn test_apply_redaction_when_redaction_comes_later() { assert_let!( AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomRedaction(ev)) = ev ); - assert_eq!(ev.redacts(&RoomVersionId::V1).unwrap(), event_id!("$1")); + assert_eq!(ev.redacts(&RedactionRules::V1).unwrap(), event_id!("$1")); } // Then, we have an update for the redacted event. @@ -1641,7 +1643,7 @@ async fn test_apply_redaction_when_redacted_and_redaction_are_in_same_sync() { assert_let!( AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomRedaction(ev)) = ev ); - assert_eq!(ev.redacts(&RoomVersionId::V1).unwrap(), event_id!("$2")); + assert_eq!(ev.redacts(&RedactionRules::V1).unwrap(), event_id!("$2")); } // Then the redaction of the event happens separately. diff --git a/crates/matrix-sdk/tests/integration/room/joined.rs b/crates/matrix-sdk/tests/integration/room/joined.rs index d14067c9e7f..34edd0177f2 100644 --- a/crates/matrix-sdk/tests/integration/room/joined.rs +++ b/crates/matrix-sdk/tests/integration/room/joined.rs @@ -1381,5 +1381,5 @@ async fn test_report_room() { let _response = client.sync_once(sync_settings).await.unwrap(); let room = client.get_room(&DEFAULT_TEST_ROOM_ID).unwrap(); - room.report_room(Some(reason.to_owned())).await.unwrap(); + room.report_room(reason.to_owned()).await.unwrap(); } diff --git a/crates/matrix-sdk/tests/integration/room_preview.rs b/crates/matrix-sdk/tests/integration/room_preview.rs index ff8ba13bdc6..55e07d9126c 100644 --- a/crates/matrix-sdk/tests/integration/room_preview.rs +++ b/crates/matrix-sdk/tests/integration/room_preview.rs @@ -9,12 +9,12 @@ use matrix_sdk_test::{ async_test, InvitedRoomBuilder, JoinedRoomBuilder, KnockedRoomBuilder, SyncResponseBuilder, }; use ruma::{ - api::client::sync::sync_events::{v5 as sliding_sync_http, v5::response::Hero}, + api::client::sync::sync_events::v5::{self as sliding_sync_http, response::Hero}, assign, events::room::member::MembershipState, - owned_user_id, room_id, - space::SpaceRoomJoinRule, - RoomId, + owned_user_id, + room::JoinRuleKind, + room_id, RoomId, }; use serde_json::json; use wiremock::{ @@ -39,7 +39,7 @@ async fn test_room_preview_leave_invited() { mock_unknown_summary( room_id, None, - SpaceRoomJoinRule::Knock, + JoinRuleKind::Knock, Some(MembershipState::Invite), &server, ) @@ -94,14 +94,8 @@ async fn test_room_preview_leave_knocked() { client.sync_once(SyncSettings::default()).await.unwrap(); server.reset().await; - mock_unknown_summary( - room_id, - None, - SpaceRoomJoinRule::Knock, - Some(MembershipState::Knock), - &server, - ) - .await; + mock_unknown_summary(room_id, None, JoinRuleKind::Knock, Some(MembershipState::Knock), &server) + .await; mock_leave(room_id, &server).await; let room_preview = client.get_room_preview(room_id.into(), Vec::new()).await.unwrap(); @@ -141,7 +135,7 @@ async fn test_room_preview_leave_unknown_room_fails() { let (client, server) = logged_in_client_with_server().await; let room_id = room_id!("!room:localhost"); - mock_unknown_summary(room_id, None, SpaceRoomJoinRule::Knock, None, &server).await; + mock_unknown_summary(room_id, None, JoinRuleKind::Knock, None, &server).await; let room_preview = client.get_room_preview(room_id.into(), Vec::new()).await.unwrap(); assert!(room_preview.state.is_none()); @@ -193,7 +187,7 @@ async fn mock_leave(room_id: &RoomId, server: &MockServer) { async fn mock_unknown_summary( room_id: &RoomId, alias: Option, - join_rule: SpaceRoomJoinRule, + join_rule: JoinRuleKind, membership: Option, server: &MockServer, ) { diff --git a/crates/matrix-sdk/tests/integration/send_queue.rs b/crates/matrix-sdk/tests/integration/send_queue.rs index 61b0113399b..360836dfe9b 100644 --- a/crates/matrix-sdk/tests/integration/send_queue.rs +++ b/crates/matrix-sdk/tests/integration/send_queue.rs @@ -36,7 +36,7 @@ use ruma::{ }, MediaSource, }, - AnyMessageLikeEventContent, EventContent as _, Mentions, + AnyMessageLikeEventContent, Mentions, MessageLikeEventContent as _, }, mxc_uri, owned_mxc_uri, owned_user_id, room_id, serde::Raw, diff --git a/testing/matrix-sdk-integration-testing/src/tests/room.rs b/testing/matrix-sdk-integration-testing/src/tests/room.rs index ce1aa6a8a6e..185100452b7 100644 --- a/testing/matrix-sdk-integration-testing/src/tests/room.rs +++ b/testing/matrix-sdk-integration-testing/src/tests/room.rs @@ -9,8 +9,8 @@ use matrix_sdk::{ api::client::room::create_room::v3::Request as CreateRoomRequest, assign, event_id, events, events::{ - AnyRoomAccountDataEventContent, AnySyncStateEvent, AnySyncTimelineEvent, EventContent, - room::message::RoomMessageEventContent, + AnyRoomAccountDataEventContent, AnySyncStateEvent, AnySyncTimelineEvent, + RoomAccountDataEventContent, room::message::RoomMessageEventContent, }, serde::Raw, uint, diff --git a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs index 02e15de07ea..6fde9316dc0 100644 --- a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs +++ b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs @@ -34,9 +34,9 @@ use matrix_sdk::{ message::RoomMessageEventContent, }, }, - mxc_uri, owned_server_name, room_id, - space::SpaceRoomJoinRule, - uint, + mxc_uri, owned_server_name, + room::JoinRuleSummary, + room_id, uint, }, sliding_sync::VersionBuilder, test_utils::{logged_in_client_with_server, mocks::MatrixMockServer}, @@ -1235,7 +1235,7 @@ fn assert_room_preview(preview: &RoomPreview, room_alias: &str) { assert_eq!(preview.avatar_url.as_ref().unwrap(), mxc_uri!("mxc://localhost/alice")); assert_eq!(preview.num_joined_members, 1); assert!(preview.room_type.is_none()); - assert_eq!(preview.join_rule, Some(SpaceRoomJoinRule::Invite)); + assert_eq!(preview.join_rule, Some(JoinRuleSummary::Invite)); assert!(preview.is_world_readable.unwrap()); } diff --git a/testing/matrix-sdk-test/src/event_factory.rs b/testing/matrix-sdk-test/src/event_factory.rs index c76f91d62e6..eaae11c49f3 100644 --- a/testing/matrix-sdk-test/src/event_factory.rs +++ b/testing/matrix-sdk-test/src/event_factory.rs @@ -28,7 +28,7 @@ use ruma::{ OwnedRoomId, OwnedTransactionId, OwnedUserId, OwnedVoipId, RoomId, RoomVersionId, TransactionId, UInt, UserId, VoipVersionId, events::{ - AnyMessageLikeEvent, AnyStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, + AnyStateEvent, AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, BundledMessageLikeRelations, Mentions, RedactedMessageLikeEventContent, RedactedStateEventContent, StateEventContent, StaticEventContent, beacon::BeaconEventContent, @@ -202,7 +202,7 @@ impl EventBuilder { /// this event. pub fn with_bundled_thread_summary( mut self, - latest_event: Raw, + latest_event: Raw, count: usize, current_user_participated: bool, ) -> Self { @@ -238,7 +238,12 @@ impl EventBuilder { self.state_key = Some(state_key.into()); self } +} +impl EventBuilder +where + E: StaticEventContent + Serialize, +{ #[inline(always)] fn construct_json(self, requires_room: bool) -> serde_json::Value { // Use the `sender` preferably, or resort to the `redacted_because` sender if @@ -454,19 +459,28 @@ impl EventBuilder { } } -impl From> for Raw { +impl From> for Raw +where + E: Serialize, +{ fn from(val: EventBuilder) -> Self { val.into_raw_sync() } } -impl From> for Raw { +impl From> for Raw +where + E: Serialize, +{ fn from(val: EventBuilder) -> Self { val.into_raw_timeline() } } -impl From> for TimelineEvent { +impl From> for TimelineEvent +where + E: Serialize, +{ fn from(val: EventBuilder) -> Self { val.into_event() }