From 0c98e26a055a305812fdda5c19110f492aaa6b72 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 4 Mar 2024 16:37:16 +0100 Subject: [PATCH] sdk: create new `users_with_power_levels` fn (#3182) It maps user ids to users' power levels. Also, make sure it just returns an empty map if this info is not available, instead of crashing. Then use it in the FFI side to output updated data for the `RoomInfo`. --- * sdk: create new `users_with_power_levels` fn which maps user ids to users' power levels Also, make sure it just returns an empty map if this info is not available, instead of crashing. * Update crates/matrix-sdk/src/room/mod.rs Co-authored-by: Benjamin Bouvier Signed-off-by: Jorge Martin Espinosa * Improve tests --------- Signed-off-by: Jorge Martin Espinosa Co-authored-by: Benjamin Bouvier --- bindings/matrix-sdk-ffi/src/room_info.rs | 6 +- crates/matrix-sdk/src/room/mod.rs | 23 ++- .../tests/integration/room/joined.rs | 30 +++ testing/matrix-sdk-test/src/test_json/sync.rs | 189 ++++++++++++++++++ 4 files changed, 242 insertions(+), 6 deletions(-) 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": [] + } + }) +});