Skip to content

Commit 0469c27

Browse files
authored
ffi: Add methods to get and reset the power levels of a Room
- `Room::build_power_level_changes_from_current()` was replaced by `Room::get_power_levels()`, which now returns an SDK/Ruma `RoomPowerLevels` value containing all the data we need to display these values in UI and not only the customised values. - `Room::reset_power_levels()` was added to the FFI layer.
1 parent f14c00d commit 0469c27

File tree

4 files changed

+250
-8
lines changed

4 files changed

+250
-8
lines changed

bindings/matrix-sdk-ffi/src/room.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ use mime::Mime;
1010
use ruma::{
1111
api::client::room::report_content,
1212
assign,
13-
events::room::{avatar::ImageInfo as RumaAvatarImageInfo, MediaSource},
13+
events::{
14+
room::{
15+
avatar::ImageInfo as RumaAvatarImageInfo,
16+
power_levels::RoomPowerLevels as RumaPowerLevels, MediaSource,
17+
},
18+
TimelineEventType,
19+
},
1420
EventId, Int, UserId,
1521
};
1622
use tokio::sync::RwLock;
@@ -561,11 +567,9 @@ impl Room {
561567
Ok(())
562568
}
563569

564-
pub async fn build_power_level_changes_from_current(
565-
&self,
566-
) -> Result<RoomPowerLevelChanges, ClientError> {
570+
pub async fn get_power_levels(&self) -> Result<RoomPowerLevels, ClientError> {
567571
let power_levels = self.inner.room_power_levels().await?;
568-
Ok(power_levels.into())
572+
Ok(RoomPowerLevels::from(power_levels))
569573
}
570574

571575
pub async fn apply_power_level_changes(
@@ -603,6 +607,58 @@ impl Room {
603607
let user_id = UserId::parse(&user_id)?;
604608
Ok(self.inner.get_suggested_user_role(&user_id).await?)
605609
}
610+
611+
pub async fn reset_power_levels(&self) -> Result<RoomPowerLevels, ClientError> {
612+
Ok(RoomPowerLevels::from(self.inner.reset_power_levels().await?))
613+
}
614+
}
615+
616+
#[derive(uniffi::Record)]
617+
pub struct RoomPowerLevels {
618+
/// The level required to ban a user.
619+
pub ban: i64,
620+
/// The level required to invite a user.
621+
pub invite: i64,
622+
/// The level required to kick a user.
623+
pub kick: i64,
624+
/// The level required to redact an event.
625+
pub redact: i64,
626+
/// The default level required to send message events.
627+
pub events_default: i64,
628+
/// The default level required to send state events.
629+
pub state_default: i64,
630+
/// The default power level for every user in the room.
631+
pub users_default: i64,
632+
/// The level required to change the room's name.
633+
pub room_name: i64,
634+
/// The level required to change the room's avatar.
635+
pub room_avatar: i64,
636+
/// The level required to change the room's topic.
637+
pub room_topic: i64,
638+
}
639+
640+
impl From<RumaPowerLevels> for RoomPowerLevels {
641+
fn from(value: RumaPowerLevels) -> Self {
642+
fn state_event_level_for(
643+
power_levels: &RumaPowerLevels,
644+
event_type: &TimelineEventType,
645+
) -> i64 {
646+
let default_state: i64 = power_levels.state_default.into();
647+
power_levels.events.get(event_type).map_or(default_state, |&level| level.into())
648+
}
649+
Self {
650+
ban: value.ban.into(),
651+
invite: value.invite.into(),
652+
kick: value.kick.into(),
653+
redact: value.redact.into(),
654+
events_default: value.events_default.into(),
655+
state_default: value.state_default.into(),
656+
users_default: value.users_default.into(),
657+
room_name: state_event_level_for(&value, &TimelineEventType::RoomName),
658+
room_avatar: state_event_level_for(&value, &TimelineEventType::RoomAvatar),
659+
room_topic: state_event_level_for(&value, &TimelineEventType::RoomTopic),
660+
}
661+
}
606662
}
607663

608664
#[uniffi::export(callback_interface)]

crates/matrix-sdk/src/room/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,16 @@ impl Room {
18601860
.power_levels())
18611861
}
18621862

1863+
/// Resets the room's power levels to the default values
1864+
///
1865+
/// [spec]: https://spec.matrix.org/v1.9/client-server-api/#mroompower_levels
1866+
pub async fn reset_power_levels(&self) -> Result<RoomPowerLevels> {
1867+
let default_power_levels = RoomPowerLevels::from(RoomPowerLevelsEventContent::new());
1868+
let changes = RoomPowerLevelChanges::from(default_power_levels);
1869+
self.apply_power_level_changes(changes).await?;
1870+
self.room_power_levels().await
1871+
}
1872+
18631873
/// Gets the suggested role for the user with the provided `user_id`.
18641874
///
18651875
/// This method checks the `RoomPowerLevels` events instead of loading the

crates/matrix-sdk/tests/integration/room/joined.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ use matrix_sdk::{
1414
};
1515
use matrix_sdk_base::RoomState;
1616
use matrix_sdk_test::{
17-
async_test, test_json, EphemeralTestEvent, JoinedRoomBuilder, SyncResponseBuilder,
18-
DEFAULT_TEST_ROOM_ID,
17+
async_test, test_json, test_json::sync::CUSTOM_ROOM_POWER_LEVELS, EphemeralTestEvent,
18+
JoinedRoomBuilder, SyncResponseBuilder, DEFAULT_TEST_ROOM_ID,
1919
};
2020
use ruma::{
2121
api::client::{membership::Invite3pidInit, receipt::create_receipt::v3::ReceiptType},
2222
assign, event_id,
23-
events::{receipt::ReceiptThread, room::message::RoomMessageEventContent},
23+
events::{receipt::ReceiptThread, room::message::RoomMessageEventContent, TimelineEventType},
2424
int, mxc_uri, owned_event_id, room_id, thirdparty, uint, user_id, OwnedUserId, TransactionId,
2525
};
2626
use serde_json::json;
@@ -817,3 +817,38 @@ async fn get_users_with_power_levels_is_empty_if_power_level_info_is_not_availab
817817

818818
assert!(room.users_with_power_levels().await.is_empty());
819819
}
820+
821+
#[async_test]
822+
async fn reset_power_levels() {
823+
let (client, server) = logged_in_client_with_server().await;
824+
825+
mock_sync(&server, &*CUSTOM_ROOM_POWER_LEVELS, None).await;
826+
827+
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
828+
let _response = client.sync_once(sync_settings).await.unwrap();
829+
let room = client.get_room(&DEFAULT_TEST_ROOM_ID).unwrap();
830+
831+
Mock::given(method("PUT"))
832+
.and(path_regex(r"^/_matrix/client/r0/rooms/.*/state/m.room.power_levels/$"))
833+
.and(header("authorization", "Bearer 1234"))
834+
.and(body_partial_json(json!({
835+
"events": {
836+
// 'm.room.avatar' is 100 here, if we receive a value '50', the reset worked
837+
"m.room.avatar": 50,
838+
"m.room.canonical_alias": 50,
839+
"m.room.history_visibility": 100,
840+
"m.room.name": 50,
841+
"m.room.power_levels": 100,
842+
"m.room.topic": 50
843+
},
844+
})))
845+
.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::EVENT_ID))
846+
.expect(1)
847+
.mount(&server)
848+
.await;
849+
850+
let initial_power_levels = room.room_power_levels().await.unwrap();
851+
assert_eq!(initial_power_levels.events[&TimelineEventType::RoomAvatar], int!(100));
852+
853+
room.reset_power_levels().await.unwrap();
854+
}

testing/matrix-sdk-test/src/test_json/sync.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,3 +1714,144 @@ pub static SYNC_ADMIN_AND_MOD: Lazy<JsonValue> = Lazy::new(|| {
17141714
}
17151715
})
17161716
});
1717+
1718+
pub static CUSTOM_ROOM_POWER_LEVELS: Lazy<JsonValue> = Lazy::new(|| {
1719+
json!({
1720+
"device_one_time_keys_count": {},
1721+
"next_batch": "s526_47314_0_7_1_1_1_11444_1",
1722+
"device_lists": {
1723+
"changed": [
1724+
"@admin:example.org"
1725+
],
1726+
"left": []
1727+
},
1728+
"rooms": {
1729+
"invite": {},
1730+
"join": {
1731+
*DEFAULT_TEST_ROOM_ID: {
1732+
"summary": {
1733+
"m.heroes": [
1734+
"@example2:localhost"
1735+
],
1736+
"m.joined_member_count": 1,
1737+
"m.invited_member_count": 0
1738+
},
1739+
"account_data": {
1740+
"events": []
1741+
},
1742+
"ephemeral": {
1743+
"events": []
1744+
},
1745+
"state": {
1746+
"events": [
1747+
{
1748+
"content": {
1749+
"join_rule": "public"
1750+
},
1751+
"event_id": "$15139375514WsgmR:localhost",
1752+
"origin_server_ts": 151393755000000_u64,
1753+
"sender": "@admin:localhost",
1754+
"state_key": "",
1755+
"type": "m.room.join_rules",
1756+
"unsigned": {
1757+
"age": 7034220
1758+
}
1759+
},
1760+
{
1761+
"content": {
1762+
"avatar_url": null,
1763+
"displayname": "admin",
1764+
"membership": "join"
1765+
},
1766+
"event_id": "$151800140517rfvjc:localhost",
1767+
"membership": "join",
1768+
"origin_server_ts": 151800140000000_u64,
1769+
"sender": "@admin:localhost",
1770+
"state_key": "@admin:localhost",
1771+
"type": "m.room.member",
1772+
"unsigned": {
1773+
"age": 297036,
1774+
"replaces_state": "$151800111315tsynI:localhost"
1775+
}
1776+
},
1777+
{
1778+
"content": {
1779+
"creator": "@example:localhost"
1780+
},
1781+
"event_id": "$15139375510KUZHi:localhost",
1782+
"origin_server_ts": 151393755000000_u64,
1783+
"sender": "@admin:localhost",
1784+
"state_key": "",
1785+
"type": "m.room.create",
1786+
"unsigned": {
1787+
"age": 703422
1788+
}
1789+
},
1790+
{
1791+
"content": {
1792+
"ban": 100,
1793+
"events": {
1794+
"m.room.avatar": 100,
1795+
"m.room.canonical_alias": 50,
1796+
"m.room.history_visibility": 100,
1797+
"m.room.name": 50,
1798+
"m.room.power_levels": 100
1799+
},
1800+
"events_default": 0,
1801+
"invite": 0,
1802+
"kick": 50,
1803+
"redact": 50,
1804+
"state_default": 50,
1805+
"users": {
1806+
"@admin:localhost": 100
1807+
},
1808+
"users_default": 0
1809+
},
1810+
"event_id": "$15139375512JaHAW:localhost",
1811+
"origin_server_ts": 151393755000000_u64,
1812+
"sender": "@admin:localhost",
1813+
"state_key": "",
1814+
"type": "m.room.power_levels",
1815+
"unsigned": {
1816+
"age": 703422
1817+
}
1818+
}
1819+
]
1820+
},
1821+
"timeline": {
1822+
"events": [
1823+
{
1824+
"content": {
1825+
"body": "baba",
1826+
"format": "org.matrix.custom.html",
1827+
"formatted_body": "<strong>baba</strong>",
1828+
"msgtype": "m.text"
1829+
},
1830+
"event_id": "$152037280074GZeOm:localhost",
1831+
"origin_server_ts": 152037280000000_u64,
1832+
"sender": "@admin:localhost",
1833+
"type": "m.room.message",
1834+
"unsigned": {
1835+
"age": 598971425
1836+
}
1837+
}
1838+
],
1839+
"limited": true,
1840+
"prev_batch": "t392-516_47314_0_7_1_1_1_11444_1"
1841+
},
1842+
"unread_notifications": {
1843+
"highlight_count": 0,
1844+
"notification_count": 11
1845+
}
1846+
}
1847+
},
1848+
"leave": {}
1849+
},
1850+
"to_device": {
1851+
"events": []
1852+
},
1853+
"presence": {
1854+
"events": []
1855+
}
1856+
})
1857+
});

0 commit comments

Comments
 (0)