diff --git a/bindings/matrix-sdk-ffi/src/room_info.rs b/bindings/matrix-sdk-ffi/src/room_info.rs index 879c89f66..5d3f31e5c 100644 --- a/bindings/matrix-sdk-ffi/src/room_info.rs +++ b/bindings/matrix-sdk-ffi/src/room_info.rs @@ -54,10 +54,10 @@ impl RoomInfo { ) -> matrix_sdk::Result { let unread_notification_counts = room.unread_notification_counts(); - let power_levels = room.room_power_levels().await?; + let power_levels_map = room.users_with_power_levels().await; let mut user_power_levels = HashMap::::new(); - for (id, level) in power_levels.users.iter() { - user_power_levels.insert(id.to_string(), (*level).into()); + for (id, level) in power_levels_map.iter() { + user_power_levels.insert(id.to_string(), *level); } Ok(Self { diff --git a/crates/matrix-sdk/src/room/mod.rs b/crates/matrix-sdk/src/room/mod.rs index 18379367e..61e3e41a3 100644 --- a/crates/matrix-sdk/src/room/mod.rs +++ b/crates/matrix-sdk/src/room/mod.rs @@ -1,6 +1,12 @@ //! High-level room API -use std::{borrow::Borrow, collections::BTreeMap, ops::Deref, sync::Arc, time::Duration}; +use std::{ + borrow::Borrow, + collections::{BTreeMap, HashMap}, + ops::Deref, + sync::Arc, + time::Duration, +}; use eyeball::SharedObservable; use futures_core::Stream; @@ -1589,8 +1595,6 @@ impl Room { /// Run /keys/query requests for all the non-tracked users. #[cfg(feature = "e2e-encryption")] async fn query_keys_for_untracked_users(&self) -> Result<()> { - use std::collections::HashMap; - let olm = self.client.olm_machine().await; let olm = olm.as_ref().expect("Olm machine wasn't started"); @@ -1874,6 +1878,19 @@ impl Room { Ok(event.for_user(user_id).into()) } + /// Gets a map with the `UserId` of users with power levels other than `0` + /// and this power level. + pub async fn users_with_power_levels(&self) -> HashMap { + let power_levels = self.room_power_levels().await.ok(); + let mut user_power_levels = HashMap::::new(); + if let Some(power_levels) = power_levels { + for (id, level) in power_levels.users.into_iter() { + user_power_levels.insert(id, level.into()); + } + } + user_power_levels + } + /// Sets the name of this room. pub async fn set_name(&self, name: String) -> Result { self.send_state_event(RoomNameEventContent::new(name)).await diff --git a/crates/matrix-sdk/tests/integration/room/joined.rs b/crates/matrix-sdk/tests/integration/room/joined.rs index d3dc62031..f8988d352 100644 --- a/crates/matrix-sdk/tests/integration/room/joined.rs +++ b/crates/matrix-sdk/tests/integration/room/joined.rs @@ -787,3 +787,33 @@ async fn get_power_level_for_user() { room.get_user_power_level(user_id!("@non-existing:localhost")).await.unwrap(); assert_eq!(power_level_unknown, 0); } + +#[async_test] +async fn get_users_with_power_levels() { + let (client, server) = logged_in_client_with_server().await; + + mock_sync(&server, &*test_json::sync::SYNC_ADMIN_AND_MOD, None).await; + + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + let _response = client.sync_once(sync_settings).await.unwrap(); + let room = client.get_room(&DEFAULT_TEST_ROOM_ID).unwrap(); + + let users_with_power_levels = room.users_with_power_levels().await; + assert_eq!(users_with_power_levels.len(), 2); + assert_eq!(users_with_power_levels[user_id!("@admin:localhost")], 100); + assert_eq!(users_with_power_levels[user_id!("@mod:localhost")], 50); +} + +#[async_test] +async fn get_users_with_power_levels_is_empty_if_power_level_info_is_not_available() { + let (client, server) = logged_in_client_with_server().await; + + mock_sync(&server, &*test_json::INVITE_SYNC, None).await; + + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + let _response = client.sync_once(sync_settings).await.unwrap(); + // The room doesn't have any power level info + let room = client.get_room(room_id!("!696r7674:example.com")).unwrap(); + + assert!(room.users_with_power_levels().await.is_empty()); +} diff --git a/testing/matrix-sdk-test/src/test_json/sync.rs b/testing/matrix-sdk-test/src/test_json/sync.rs index 6a1e40bf8..3a878d5ae 100644 --- a/testing/matrix-sdk-test/src/test_json/sync.rs +++ b/testing/matrix-sdk-test/src/test_json/sync.rs @@ -1525,3 +1525,192 @@ pub static VOIP_SYNC: Lazy = Lazy::new(|| { } }) }); + +pub static SYNC_ADMIN_AND_MOD: Lazy = Lazy::new(|| { + json!({ + "device_one_time_keys_count": {}, + "next_batch": "s526_47314_0_7_1_1_1_11444_1", + "device_lists": { + "changed": [ + "@admin:example.org" + ], + "left": [] + }, + "rooms": { + "invite": {}, + "join": { + *DEFAULT_TEST_ROOM_ID: { + "summary": { + "m.heroes": [ + "@example2:localhost" + ], + "m.joined_member_count": 2, + "m.invited_member_count": 0 + }, + "account_data": { + "events": [] + }, + "ephemeral": { + "events": [] + }, + "state": { + "events": [ + { + "content": { + "join_rule": "public" + }, + "event_id": "$15139375514WsgmR:localhost", + "origin_server_ts": 151393755000000_u64, + "sender": "@admin:localhost", + "state_key": "", + "type": "m.room.join_rules", + "unsigned": { + "age": 7034220 + } + }, + { + "content": { + "avatar_url": null, + "displayname": "admin", + "membership": "join" + }, + "event_id": "$151800140517rfvjc:localhost", + "membership": "join", + "origin_server_ts": 151800140000000_u64, + "sender": "@admin:localhost", + "state_key": "@admin:localhost", + "type": "m.room.member", + "unsigned": { + "age": 297036, + "replaces_state": "$151800111315tsynI:localhost" + } + }, + { + "content": { + "avatar_url": null, + "displayname": "mod", + "membership": "join" + }, + "event_id": "$151800140518rfvjc:localhost", + "membership": "join", + "origin_server_ts": 1518001450000000_u64, + "sender": "@mod:localhost", + "state_key": "@mod:localhost", + "type": "m.room.member", + "unsigned": { + "age": 297035, + } + }, + { + "content": { + "history_visibility": "shared" + }, + "event_id": "$15139375515VaJEY:localhost", + "origin_server_ts": 151393755000000_u64, + "sender": "@admin:localhost", + "state_key": "", + "type": "m.room.history_visibility", + "unsigned": { + "age": 703422 + } + }, + { + "content": { + "creator": "@example:localhost" + }, + "event_id": "$15139375510KUZHi:localhost", + "origin_server_ts": 151393755000000_u64, + "sender": "@admin:localhost", + "state_key": "", + "type": "m.room.create", + "unsigned": { + "age": 703422 + } + }, + { + "content": { + "topic": "room topic" + }, + "event_id": "$151957878228ssqrJ:localhost", + "origin_server_ts": 151957878000000_u64, + "sender": "@admin:localhost", + "state_key": "", + "type": "m.room.topic", + "unsigned": { + "age": 1392989709, + "prev_content": { + "topic": "test" + }, + "prev_sender": "@example:localhost", + "replaces_state": "$151957069225EVYKm:localhost" + } + }, + { + "content": { + "ban": 50, + "events": { + "m.room.avatar": 50, + "m.room.canonical_alias": 50, + "m.room.history_visibility": 100, + "m.room.name": 50, + "m.room.power_levels": 100 + }, + "events_default": 0, + "invite": 0, + "kick": 50, + "redact": 50, + "state_default": 50, + "users": { + "@admin:localhost": 100, + "@mod:localhost": 50 + }, + "users_default": 0 + }, + "event_id": "$15139375512JaHAW:localhost", + "origin_server_ts": 151393755000000_u64, + "sender": "@admin:localhost", + "state_key": "", + "type": "m.room.power_levels", + "unsigned": { + "age": 703422 + } + } + ] + }, + "timeline": { + "events": [ + { + "content": { + "body": "baba", + "format": "org.matrix.custom.html", + "formatted_body": "baba", + "msgtype": "m.text" + }, + "event_id": "$152037280074GZeOm:localhost", + "origin_server_ts": 152037280000000_u64, + "sender": "@admin:localhost", + "type": "m.room.message", + "unsigned": { + "age": 598971425 + } + } + ], + "limited": true, + "prev_batch": "t392-516_47314_0_7_1_1_1_11444_1" + }, + "unread_notifications": { + "highlight_count": 0, + "notification_count": 11 + } + } + }, + "leave": {} + }, + "to_device": { + "events": [] + }, + "presence": { + "events": [] + } + }) +});