push: Make power levels optional in PushConditionRoomCtx
This commit is contained in:
parent
4efca6fba5
commit
90d3605b87
@ -1,5 +1,11 @@
|
|||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
|
Breaking changes:
|
||||||
|
- The power levels fields in `PushConditionRoomCtx` are grouped in an optional `power_levels` field.
|
||||||
|
If the field is missing, push rules that depend on it will never match. However, this allows to
|
||||||
|
match the `.m.rule.invite_for_me` push rule because usually the `invite_state` doesn't include
|
||||||
|
`m.room.power_levels`.
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
|
||||||
- Stabilize support for `.m.rule.suppress_edits` push rule (MSC3958 / Matrix 1.9)
|
- Stabilize support for `.m.rule.suppress_edits` push rule (MSC3958 / Matrix 1.9)
|
||||||
|
@ -38,8 +38,9 @@ pub use self::condition::RoomVersionFeature;
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
action::{Action, Tweak},
|
action::{Action, Tweak},
|
||||||
condition::{
|
condition::{
|
||||||
ComparisonOperator, FlattenedJson, FlattenedJsonValue, PushCondition, PushConditionRoomCtx,
|
ComparisonOperator, FlattenedJson, FlattenedJsonValue, PushCondition,
|
||||||
RoomMemberCountIs, ScalarJsonValue, _CustomPushCondition,
|
PushConditionPowerLevelsCtx, PushConditionRoomCtx, RoomMemberCountIs, ScalarJsonValue,
|
||||||
|
_CustomPushCondition,
|
||||||
},
|
},
|
||||||
iter::{AnyPushRule, AnyPushRuleRef, RulesetIntoIter, RulesetIter},
|
iter::{AnyPushRule, AnyPushRuleRef, RulesetIntoIter, RulesetIter},
|
||||||
predefined::{
|
predefined::{
|
||||||
@ -988,7 +989,9 @@ mod tests {
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
action::{Action, Tweak},
|
action::{Action, Tweak},
|
||||||
condition::{PushCondition, PushConditionRoomCtx, RoomMemberCountIs},
|
condition::{
|
||||||
|
PushCondition, PushConditionPowerLevelsCtx, PushConditionRoomCtx, RoomMemberCountIs,
|
||||||
|
},
|
||||||
AnyPushRule, ConditionalPushRule, PatternedPushRule, Ruleset, SimplePushRule,
|
AnyPushRule, ConditionalPushRule, PatternedPushRule, Ruleset, SimplePushRule,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -1016,6 +1019,14 @@ mod tests {
|
|||||||
set
|
set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn power_levels() -> PushConditionPowerLevelsCtx {
|
||||||
|
PushConditionPowerLevelsCtx {
|
||||||
|
users: BTreeMap::new(),
|
||||||
|
users_default: int!(50),
|
||||||
|
notifications: NotificationPowerLevels { room: int!(50) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iter() {
|
fn iter() {
|
||||||
let mut set = example_ruleset();
|
let mut set = example_ruleset();
|
||||||
@ -1431,9 +1442,7 @@ mod tests {
|
|||||||
member_count: uint!(2),
|
member_count: uint!(2),
|
||||||
user_id: owned_user_id!("@jj:server.name"),
|
user_id: owned_user_id!("@jj:server.name"),
|
||||||
user_display_name: "Jolly Jumper".into(),
|
user_display_name: "Jolly Jumper".into(),
|
||||||
users_power_levels: BTreeMap::new(),
|
power_levels: Some(power_levels()),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
supported_features: Default::default(),
|
supported_features: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1443,9 +1452,7 @@ mod tests {
|
|||||||
member_count: uint!(100),
|
member_count: uint!(100),
|
||||||
user_id: owned_user_id!("@jj:server.name"),
|
user_id: owned_user_id!("@jj:server.name"),
|
||||||
user_display_name: "Jolly Jumper".into(),
|
user_display_name: "Jolly Jumper".into(),
|
||||||
users_power_levels: BTreeMap::new(),
|
power_levels: Some(power_levels()),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
supported_features: Default::default(),
|
supported_features: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1536,9 +1543,7 @@ mod tests {
|
|||||||
member_count: uint!(2),
|
member_count: uint!(2),
|
||||||
user_id: owned_user_id!("@jj:server.name"),
|
user_id: owned_user_id!("@jj:server.name"),
|
||||||
user_display_name: "Jolly Jumper".into(),
|
user_display_name: "Jolly Jumper".into(),
|
||||||
users_power_levels: BTreeMap::new(),
|
power_levels: Some(power_levels()),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
supported_features: Default::default(),
|
supported_features: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1677,9 +1682,7 @@ mod tests {
|
|||||||
member_count: uint!(100),
|
member_count: uint!(100),
|
||||||
user_id: owned_user_id!("@jj:server.name"),
|
user_id: owned_user_id!("@jj:server.name"),
|
||||||
user_display_name: "Jolly Jumper".into(),
|
user_display_name: "Jolly Jumper".into(),
|
||||||
users_power_levels: BTreeMap::new(),
|
power_levels: Some(power_levels()),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
supported_features: Default::default(),
|
supported_features: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1789,9 +1792,7 @@ mod tests {
|
|||||||
member_count: uint!(100),
|
member_count: uint!(100),
|
||||||
user_id: owned_user_id!("@jj:server.name"),
|
user_id: owned_user_id!("@jj:server.name"),
|
||||||
user_display_name: "Jolly Jumper".into(),
|
user_display_name: "Jolly Jumper".into(),
|
||||||
users_power_levels: BTreeMap::new(),
|
power_levels: Some(power_levels()),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
supported_features: Default::default(),
|
supported_features: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1834,4 +1835,37 @@ mod tests {
|
|||||||
PredefinedOverrideRuleId::IsRoomMention.as_ref()
|
PredefinedOverrideRuleId::IsRoomMention.as_ref()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invite_for_me_applies() {
|
||||||
|
let set = Ruleset::server_default(user_id!("@jolly_jumper:server.name"));
|
||||||
|
|
||||||
|
let context = &PushConditionRoomCtx {
|
||||||
|
room_id: owned_room_id!("!far_west:server.name"),
|
||||||
|
member_count: uint!(100),
|
||||||
|
user_id: owned_user_id!("@jj:server.name"),
|
||||||
|
user_display_name: "Jolly Jumper".into(),
|
||||||
|
// `invite_state` usually doesn't include the power levels.
|
||||||
|
power_levels: None,
|
||||||
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
|
supported_features: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let message = serde_json::from_str::<Raw<JsonValue>>(
|
||||||
|
r#"{
|
||||||
|
"content": {
|
||||||
|
"membership": "invite"
|
||||||
|
},
|
||||||
|
"state_key": "@jolly_jumper:server.name",
|
||||||
|
"sender": "@admin:server.name",
|
||||||
|
"type": "m.room.member"
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
set.get_match(&message, context).unwrap().rule_id(),
|
||||||
|
PredefinedOverrideRuleId::InviteForMe.as_ref()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,8 @@ impl PushCondition {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `event` - The flattened JSON representation of a room message event.
|
/// * `event` - The flattened JSON representation of a room message event.
|
||||||
/// * `context` - The context of the room at the time of the event.
|
/// * `context` - The context of the room at the time of the event. If the power levels context
|
||||||
|
/// is missing from it, conditions that depend on it will never apply.
|
||||||
pub fn applies(&self, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
|
pub fn applies(&self, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
|
||||||
if event.get_str("sender").is_some_and(|sender| sender == context.user_id) {
|
if event.get_str("sender").is_some_and(|sender| sender == context.user_id) {
|
||||||
return false;
|
return false;
|
||||||
@ -173,6 +174,10 @@ impl PushCondition {
|
|||||||
}
|
}
|
||||||
Self::RoomMemberCount { is } => is.contains(&context.member_count),
|
Self::RoomMemberCount { is } => is.contains(&context.member_count),
|
||||||
Self::SenderNotificationPermission { key } => {
|
Self::SenderNotificationPermission { key } => {
|
||||||
|
let Some(power_levels) = &context.power_levels else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
let sender_id = match event.get_str("sender") {
|
let sender_id = match event.get_str("sender") {
|
||||||
Some(v) => match <&UserId>::try_from(v) {
|
Some(v) => match <&UserId>::try_from(v) {
|
||||||
Ok(u) => u,
|
Ok(u) => u,
|
||||||
@ -181,12 +186,10 @@ impl PushCondition {
|
|||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let sender_level = context
|
let sender_level =
|
||||||
.users_power_levels
|
power_levels.users.get(sender_id).unwrap_or(&power_levels.users_default);
|
||||||
.get(sender_id)
|
|
||||||
.unwrap_or(&context.default_power_level);
|
|
||||||
|
|
||||||
match context.notification_power_levels.get(key) {
|
match power_levels.notifications.get(key) {
|
||||||
Some(l) => sender_level >= l,
|
Some(l) => sender_level >= l,
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
@ -231,24 +234,34 @@ pub struct PushConditionRoomCtx {
|
|||||||
/// The number of members in the room.
|
/// The number of members in the room.
|
||||||
pub member_count: UInt,
|
pub member_count: UInt,
|
||||||
|
|
||||||
/// The users matrix ID.
|
/// The user's matrix ID.
|
||||||
pub user_id: OwnedUserId,
|
pub user_id: OwnedUserId,
|
||||||
|
|
||||||
/// The display name of the current user in the room.
|
/// The display name of the current user in the room.
|
||||||
pub user_display_name: String,
|
pub user_display_name: String,
|
||||||
|
|
||||||
|
/// The room power levels context for the room.
|
||||||
|
///
|
||||||
|
/// If this is missing, push rules that require this will never match.
|
||||||
|
pub power_levels: Option<PushConditionPowerLevelsCtx>,
|
||||||
|
|
||||||
|
/// The list of features this room's version or the room itself supports.
|
||||||
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
|
pub supported_features: Vec<RoomVersionFeature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The room power levels context to be able to test the corresponding push conditions.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(clippy::exhaustive_structs)]
|
||||||
|
pub struct PushConditionPowerLevelsCtx {
|
||||||
/// The power levels of the users of the room.
|
/// The power levels of the users of the room.
|
||||||
pub users_power_levels: BTreeMap<OwnedUserId, Int>,
|
pub users: BTreeMap<OwnedUserId, Int>,
|
||||||
|
|
||||||
/// The default power level of the users of the room.
|
/// The default power level of the users of the room.
|
||||||
pub default_power_level: Int,
|
pub users_default: Int,
|
||||||
|
|
||||||
/// The notification power levels of the room.
|
/// The notification power levels of the room.
|
||||||
pub notification_power_levels: NotificationPowerLevels,
|
pub notifications: NotificationPowerLevels,
|
||||||
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
|
||||||
/// The list of features this room's version or the room itself supports.
|
|
||||||
pub supported_features: Vec<RoomVersionFeature>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional functions for character matching.
|
/// Additional functions for character matching.
|
||||||
@ -451,7 +464,10 @@ mod tests {
|
|||||||
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
|
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{FlattenedJson, PushCondition, PushConditionRoomCtx, RoomMemberCountIs, StrExt};
|
use super::{
|
||||||
|
FlattenedJson, PushCondition, PushConditionPowerLevelsCtx, PushConditionRoomCtx,
|
||||||
|
RoomMemberCountIs, StrExt,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
owned_room_id, owned_user_id, power_levels::NotificationPowerLevels, serde::Raw,
|
owned_room_id, owned_user_id, power_levels::NotificationPowerLevels, serde::Raw,
|
||||||
OwnedUserId,
|
OwnedUserId,
|
||||||
@ -647,17 +663,21 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push_context() -> PushConditionRoomCtx {
|
fn push_context() -> PushConditionRoomCtx {
|
||||||
let mut users_power_levels = BTreeMap::new();
|
let mut users = BTreeMap::new();
|
||||||
users_power_levels.insert(sender(), int!(25));
|
users.insert(sender(), int!(25));
|
||||||
|
|
||||||
|
let power_levels = PushConditionPowerLevelsCtx {
|
||||||
|
users,
|
||||||
|
users_default: int!(50),
|
||||||
|
notifications: NotificationPowerLevels { room: int!(50) },
|
||||||
|
};
|
||||||
|
|
||||||
PushConditionRoomCtx {
|
PushConditionRoomCtx {
|
||||||
room_id: owned_room_id!("!room:server.name"),
|
room_id: owned_room_id!("!room:server.name"),
|
||||||
member_count: uint!(3),
|
member_count: uint!(3),
|
||||||
user_id: owned_user_id!("@gorilla:server.name"),
|
user_id: owned_user_id!("@gorilla:server.name"),
|
||||||
user_display_name: "Groovy Gorilla".into(),
|
user_display_name: "Groovy Gorilla".into(),
|
||||||
users_power_levels,
|
power_levels: Some(power_levels),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
#[cfg(feature = "unstable-msc3931")]
|
#[cfg(feature = "unstable-msc3931")]
|
||||||
supported_features: Default::default(),
|
supported_features: Default::default(),
|
||||||
}
|
}
|
||||||
@ -776,9 +796,7 @@ mod tests {
|
|||||||
member_count: uint!(3),
|
member_count: uint!(3),
|
||||||
user_id: owned_user_id!("@gorilla:server.name"),
|
user_id: owned_user_id!("@gorilla:server.name"),
|
||||||
user_display_name: "Groovy Gorilla".into(),
|
user_display_name: "Groovy Gorilla".into(),
|
||||||
users_power_levels: context_not_matching.users_power_levels.clone(),
|
power_levels: context_not_matching.power_levels.clone(),
|
||||||
default_power_level: int!(50),
|
|
||||||
notification_power_levels: NotificationPowerLevels { room: int!(50) },
|
|
||||||
supported_features: vec![super::RoomVersionFeature::ExtensibleEvents],
|
supported_features: vec![super::RoomVersionFeature::ExtensibleEvents],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user