From 38fc1f7b15d30ddfbc5ce511e9792c2dfbd1bcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Tue, 6 Jun 2023 10:08:34 +0200 Subject: [PATCH] base: Add method to construct RoomMember from parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- .../src/deserialized_responses.rs | 10 ++++ crates/matrix-sdk-base/src/rooms/members.rs | 50 +++++++++++++++- crates/matrix-sdk-base/src/rooms/normal.rs | 58 ++++++++++--------- 3 files changed, 89 insertions(+), 29 deletions(-) diff --git a/crates/matrix-sdk-base/src/deserialized_responses.rs b/crates/matrix-sdk-base/src/deserialized_responses.rs index de51f94f1fc..ebfc38ca65a 100644 --- a/crates/matrix-sdk-base/src/deserialized_responses.rs +++ b/crates/matrix-sdk-base/src/deserialized_responses.rs @@ -267,6 +267,16 @@ impl MemberEvent { pub fn user_id(&self) -> &UserId { self.state_key() } + + /// The name that should be displayed for this member event. + /// + /// It there is no `displayname` in the event's content, the localpart or + /// the user ID is returned. + pub fn display_name(&self) -> &str { + self.original_content() + .and_then(|c| c.displayname.as_deref()) + .unwrap_or_else(|| self.user_id().localpart()) + } } impl SyncOrStrippedState { diff --git a/crates/matrix-sdk-base/src/rooms/members.rs b/crates/matrix-sdk-base/src/rooms/members.rs index ab133f1c4a1..a1a596b7bdb 100644 --- a/crates/matrix-sdk-base/src/rooms/members.rs +++ b/crates/matrix-sdk-base/src/rooms/members.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; +use std::{ + collections::{BTreeMap, BTreeSet}, + sync::Arc, +}; use ruma::{ events::{ @@ -23,7 +26,7 @@ use ruma::{ }, MessageLikeEventType, StateEventType, }, - MxcUri, UserId, + MxcUri, OwnedUserId, UserId, }; use crate::{ @@ -49,6 +52,33 @@ pub struct RoomMember { } impl RoomMember { + pub(crate) fn from_parts(member_info: MemberInfo, room_info: &MemberRoomInfo<'_>) -> Self { + let MemberInfo { event, profile, presence } = member_info; + let MemberRoomInfo { + power_levels, + max_power_level, + room_creator, + users_display_names, + ignored_users, + } = room_info; + + let is_room_creator = room_creator.as_deref() == Some(event.user_id()); + let display_name_ambiguous = + users_display_names.get(event.display_name()).is_some_and(|s| s.len() > 1); + let is_ignored = ignored_users.as_ref().is_some_and(|s| s.contains(event.user_id())); + + Self { + event: event.into(), + profile: profile.into(), + presence: presence.into(), + power_levels: power_levels.clone(), + max_power_level: *max_power_level, + is_room_creator, + display_name_ambiguous, + is_ignored, + } + } + /// Get the unique user id of this member. pub fn user_id(&self) -> &UserId { self.event.user_id() @@ -191,3 +221,19 @@ impl RoomMember { self.is_ignored } } + +// Information about a room member. +pub(crate) struct MemberInfo { + pub event: MemberEvent, + pub(crate) profile: Option, + pub(crate) presence: Option, +} + +// Information about a the room a member is in. +pub(crate) struct MemberRoomInfo<'a> { + pub(crate) power_levels: Arc>>, + pub(crate) max_power_level: i64, + pub(crate) room_creator: Option, + pub(crate) users_display_names: BTreeMap<&'a str, BTreeSet>, + pub(crate) ignored_users: Option>, +} diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index d566879ce80..68b357a08ff 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -41,7 +41,10 @@ use ruma::{ use serde::{Deserialize, Serialize}; use tracing::{debug, info, instrument, warn}; -use super::{BaseRoomInfo, DisplayName, RoomMember}; +use super::{ + members::{MemberInfo, MemberRoomInfo}, + BaseRoomInfo, DisplayName, RoomMember, +}; use crate::{ deserialized_responses::MemberEvent, store::{DynStateStore, Result as StoreResult, StateStoreExt}, @@ -457,51 +460,52 @@ impl Room { let Some(raw_event) = self.store.get_member_event(self.room_id(), user_id).await? else { return Ok(None); }; - let member_event = raw_event.deserialize()?; + let event = raw_event.deserialize()?; let presence = self.store.get_presence_event(user_id).await?.and_then(|e| e.deserialize().ok()); let profile = self.store.get_profile(self.room_id(), user_id).await?; + + let display_names = [event.display_name().to_owned()]; + let room_info = self.member_room_info(&display_names).await?; + + let member_info = MemberInfo { event, profile, presence }; + + Ok(Some(RoomMember::from_parts(member_info, &room_info))) + } + + /// The current `MemberRoomInfo` for this room. + async fn member_room_info<'a>( + &self, + display_names: &'a [String], + ) -> StoreResult> { let max_power_level = self.max_power_level(); - let is_room_creator = self.inner.read().unwrap().creator() == Some(user_id); + let room_creator = self.inner.read().unwrap().creator().map(ToOwned::to_owned); - let power = self + let power_levels = self .store .get_state_event_static(self.room_id()) .await? .and_then(|e| e.deserialize().ok()); - let ambiguous = self - .store - .get_users_with_display_name( - self.room_id(), - member_event - .original_content() - .and_then(|c| c.displayname.as_deref()) - .unwrap_or_else(|| user_id.localpart()), - ) - .await? - .len() - > 1; + let users_display_names = + self.store.get_users_with_display_names(self.room_id(), display_names).await?; - let is_ignored = self + let ignored_users = self .store .get_account_data_event_static::() .await? .map(|c| c.deserialize()) .transpose()? - .is_some_and(|e| e.content.ignored_users.contains_key(member_event.user_id())); + .map(|e| e.content.ignored_users.into_keys().collect()); - Ok(Some(RoomMember { - event: Arc::new(member_event), - profile: profile.into(), - presence: presence.into(), - power_levels: power.into(), + Ok(MemberRoomInfo { + power_levels: power_levels.into(), max_power_level, - is_room_creator, - display_name_ambiguous: ambiguous, - is_ignored, - })) + room_creator, + users_display_names, + ignored_users, + }) } /// Get the `Tags` for this room.