feature (bindings): expose beacon and beacon_info power levels on the FFI

This commit is contained in:
Mauro Romito
2026-05-05 18:22:54 +02:00
committed by Damir Jelić
parent 9909becdd0
commit e673f85a82
2 changed files with 94 additions and 2 deletions

View File

@@ -17,7 +17,10 @@ use std::collections::HashMap;
use anyhow::Result;
use ruma::{
OwnedUserId, UserId,
events::{TimelineEventType, room::power_levels::RoomPowerLevels as RumaPowerLevels},
events::{
MessageLikeEventType as RumaMessageLikeEventType, StateEventType as RumaStateEventType,
TimelineEventType, room::power_levels::RoomPowerLevels as RumaPowerLevels,
},
};
use crate::{
@@ -226,6 +229,10 @@ pub struct RoomPowerLevelsValues {
pub room_topic: i64,
/// The level required to change the space's children.
pub space_child: i64,
/// The level required to send a beacon (live location) message event.
pub beacon: i64,
/// The level required to send a beacon info state event.
pub beacon_info: i64,
}
impl From<RumaPowerLevels> for RoomPowerLevelsValues {
@@ -237,6 +244,13 @@ impl From<RumaPowerLevels> for RoomPowerLevelsValues {
let default_state: i64 = power_levels.state_default.into();
power_levels.events.get(event_type).map_or(default_state, |&level| level.into())
}
fn message_event_level_for(
power_levels: &RumaPowerLevels,
event_type: &TimelineEventType,
) -> i64 {
let default_events: i64 = power_levels.events_default.into();
power_levels.events.get(event_type).map_or(default_events, |&level| level.into())
}
Self {
ban: value.ban.into(),
invite: value.invite.into(),
@@ -249,6 +263,8 @@ impl From<RumaPowerLevels> for RoomPowerLevelsValues {
room_avatar: state_event_level_for(&value, &TimelineEventType::RoomAvatar),
room_topic: state_event_level_for(&value, &TimelineEventType::RoomTopic),
space_child: state_event_level_for(&value, &TimelineEventType::SpaceChild),
beacon: message_event_level_for(&value, &RumaMessageLikeEventType::Beacon.into()),
beacon_info: state_event_level_for(&value, &RumaStateEventType::BeaconInfo.into()),
}
}
}

View File

@@ -5,7 +5,7 @@ use std::collections::HashMap;
use ruma::{
OwnedUserId,
events::{
StateEventType,
MessageLikeEventType, StateEventType,
room::power_levels::{
PossiblyRedactedRoomPowerLevelsEventContent, RoomPowerLevels,
RoomPowerLevelsEventContent,
@@ -57,6 +57,12 @@ pub struct RoomPowerLevelChanges {
/// The level required to change the space's children.
#[cfg_attr(feature = "uniffi", uniffi(default = None))]
pub space_child: Option<i64>,
/// The level required to send a beacon (live location) message event.
#[cfg_attr(feature = "uniffi", uniffi(default = None))]
pub beacon: Option<i64>,
/// The level required to send a beacon info state event.
#[cfg_attr(feature = "uniffi", uniffi(default = None))]
pub beacon_info: Option<i64>,
}
impl RoomPowerLevelChanges {
@@ -74,6 +80,8 @@ impl RoomPowerLevelChanges {
room_avatar: None,
room_topic: None,
space_child: None,
beacon: None,
beacon_info: None,
}
}
}
@@ -114,6 +122,16 @@ impl From<RoomPowerLevels> for RoomPowerLevelChanges {
.get(&StateEventType::SpaceChild.into())
.map(|v| (*v).into())
.or(Some(value.state_default.into())),
beacon: value
.events
.get(&MessageLikeEventType::Beacon.into())
.map(|v| (*v).into())
.or(Some(value.events_default.into())),
beacon_info: value
.events
.get(&StateEventType::BeaconInfo.into())
.map(|v| (*v).into())
.or(Some(value.state_default.into())),
}
}
}
@@ -162,6 +180,12 @@ impl RoomPowerLevelsExt for RoomPowerLevels {
if let Some(space_child) = settings.space_child {
self.events.insert(StateEventType::SpaceChild.into(), space_child.try_into()?);
}
if let Some(beacon) = settings.beacon {
self.events.insert(MessageLikeEventType::Beacon.into(), beacon.try_into()?);
}
if let Some(beacon_info) = settings.beacon_info {
self.events.insert(StateEventType::BeaconInfo.into(), beacon_info.try_into()?);
}
Ok(())
}
@@ -236,6 +260,8 @@ mod tests {
room_avatar: None,
room_topic: None,
space_child: None,
beacon: None,
beacon_info: None,
};
// When applying the settings to the power levels.
@@ -273,6 +299,8 @@ mod tests {
room_avatar: Some(new_level.into()),
room_topic: Some(new_level.into()),
space_child: Some(new_level.into()),
beacon: None,
beacon_info: None,
};
// When applying the settings to the power levels.
@@ -324,6 +352,8 @@ mod tests {
room_avatar: None,
room_topic: None,
space_child: None,
beacon: None,
beacon_info: None,
};
// When applying the settings to the power levels.
@@ -351,6 +381,52 @@ mod tests {
assert_eq!(power_levels.users_default, original_levels.users_default);
}
#[test]
fn test_apply_beacon_settings() {
// Given a set of power levels and some settings that only change the beacon
// and beacon_info event levels.
let mut power_levels = default_power_levels();
let new_level = int!(25);
let settings = RoomPowerLevelChanges {
ban: None,
invite: None,
kick: None,
redact: None,
events_default: None,
state_default: None,
users_default: None,
room_name: None,
room_avatar: None,
room_topic: None,
space_child: None,
beacon: Some(new_level.into()),
beacon_info: Some(new_level.into()),
};
// When applying the settings to the power levels.
let original_levels = power_levels.clone();
power_levels.apply(settings).unwrap();
// Then levels for the beacon events should be added.
assert_eq!(
power_levels.events.get(&MessageLikeEventType::Beacon.into()).copied(),
Some(new_level)
);
assert_eq!(
power_levels.events.get(&StateEventType::BeaconInfo.into()).copied(),
Some(new_level)
);
// And the rest should remain unchanged.
assert_eq!(power_levels.ban, original_levels.ban);
assert_eq!(power_levels.invite, original_levels.invite);
assert_eq!(power_levels.kick, original_levels.kick);
assert_eq!(power_levels.redact, original_levels.redact);
assert_eq!(power_levels.events_default, original_levels.events_default);
assert_eq!(power_levels.state_default, original_levels.state_default);
assert_eq!(power_levels.users_default, original_levels.users_default);
}
#[test]
fn test_user_power_level_changes_add_mod() {
// Given a set of power levels and a new set of power levels that adds a new