Merge pull request #2396 from matrix-org/nicolas/notification_settings_user_defined_room_rules

sdk+ffi: Get the user-defined notification mode for a room and all rooms for which a user-defined rule exists.
This commit is contained in:
Ivan Enderlin
2023-08-10 14:11:35 +02:00
committed by GitHub
3 changed files with 141 additions and 2 deletions

View File

@@ -176,6 +176,24 @@ impl NotificationSettings {
Ok(())
}
/// Get the user defined room notification mode
pub async fn get_user_defined_room_notification_mode(
&self,
room_id: String,
) -> Result<Option<RoomNotificationMode>, NotificationSettingsError> {
let notification_settings = self.sdk_notification_settings.read().await;
let parsed_room_id = RoomId::parse(&room_id)
.map_err(|_e| NotificationSettingsError::InvalidRoomId(room_id))?;
// Get the current user defined mode for this room
if let Some(mode) =
notification_settings.get_user_defined_room_notification_mode(&parsed_room_id).await
{
Ok(Some(mode.into()))
} else {
Ok(None)
}
}
/// Get the default room notification mode
///
/// The mode will depend on the associated `PushRule` based on whether the
@@ -235,6 +253,12 @@ impl NotificationSettings {
Ok(())
}
/// Get all room IDs for which a user-defined rule exists.
pub async fn get_rooms_with_user_defined_rules(&self, enabled: Option<bool>) -> Vec<String> {
let notification_settings = self.sdk_notification_settings.read().await;
notification_settings.get_rooms_with_user_defined_rules(enabled).await
}
/// Get whether some enabled keyword rules exist.
pub async fn contains_keywords_rules(&self) -> bool {
let notification_settings = self.sdk_notification_settings.read().await;

View File

@@ -130,6 +130,11 @@ impl NotificationSettings {
self.rules.read().await.get_default_room_notification_mode(is_encrypted, members_count)
}
/// Get all room IDs for which a user-defined rule exists.
pub async fn get_rooms_with_user_defined_rules(&self, enabled: Option<bool>) -> Vec<String> {
self.rules.read().await.get_rooms_with_user_defined_rules(enabled)
}
/// Get whether the given ruleset contains some enabled keywords rules.
pub async fn contains_keyword_rules(&self) -> bool {
self.rules.read().await.contains_keyword_rules()

View File

@@ -1,9 +1,10 @@
//! Ruleset utility struct
use imbl::HashSet;
use ruma::{
push::{
PredefinedContentRuleId, PredefinedOverrideRuleId, PredefinedUnderrideRuleId,
PushCondition, RuleKind, Ruleset,
AnyPushRuleRef, PredefinedContentRuleId, PredefinedOverrideRuleId,
PredefinedUnderrideRuleId, PushCondition, RuleKind, Ruleset,
},
RoomId,
};
@@ -123,6 +124,39 @@ impl Rules {
}
}
/// Get all room IDs for which a user-defined rule exists.
pub(crate) fn get_rooms_with_user_defined_rules(&self, enabled: Option<bool>) -> Vec<String> {
let test_if_enabled = enabled.is_some();
let must_be_enabled = enabled.unwrap_or(false);
let mut room_ids = HashSet::new();
for rule in &self.ruleset {
if rule.is_server_default() {
continue;
}
if test_if_enabled && rule.enabled() != must_be_enabled {
continue;
}
match rule {
AnyPushRuleRef::Override(r) | AnyPushRuleRef::Underride(r) => {
for condition in &r.conditions {
if let PushCondition::EventMatch { key, pattern } = condition {
if key == "room_id" {
room_ids.insert(pattern.clone());
break;
}
}
}
}
AnyPushRuleRef::Room(r) => {
room_ids.insert(r.rule_id.to_string());
}
_ => {}
}
}
Vec::from_iter(room_ids)
}
/// Get whether the `IsUserMention` rule is enabled.
fn is_user_mention_enabled(&self) -> bool {
// Search for an `Override` rule `IsUserMention` (MSC3952).
@@ -245,6 +279,7 @@ pub(crate) fn get_predefined_underride_room_rule_id(
#[cfg(test)]
pub(crate) mod tests {
use imbl::HashSet;
use matrix_sdk_test::{
async_test,
notification_settings::{build_ruleset, get_server_default_ruleset},
@@ -567,4 +602,79 @@ pub(crate) mod tests {
.is_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction.as_str())
.unwrap());
}
#[async_test]
async fn test_get_rooms_with_user_defined_rules() {
// Without user-defined rules
let rules = Rules::new(get_server_default_ruleset());
let room_ids = rules.get_rooms_with_user_defined_rules(None);
assert!(room_ids.is_empty());
// With one rule.
let room_id = RoomId::parse("!room_a:matrix.org").unwrap();
let ruleset = build_ruleset(vec![(RuleKind::Override, &room_id, false)]);
let rules = Rules::new(ruleset);
let room_ids = rules.get_rooms_with_user_defined_rules(None);
assert_eq!(room_ids.len(), 1);
// With duplicates
let ruleset = build_ruleset(vec![
(RuleKind::Override, &room_id, false),
(RuleKind::Underride, &room_id, false),
(RuleKind::Room, &room_id, false),
]);
let rules = Rules::new(ruleset);
let room_ids = rules.get_rooms_with_user_defined_rules(None);
assert_eq!(room_ids.len(), 1);
assert_eq!(room_ids[0], room_id.to_string());
// With multiple rules
let ruleset = build_ruleset(vec![
(RuleKind::Room, &RoomId::parse("!room_a:matrix.org").unwrap(), false),
(RuleKind::Room, &RoomId::parse("!room_b:matrix.org").unwrap(), false),
(RuleKind::Room, &RoomId::parse("!room_c:matrix.org").unwrap(), false),
(RuleKind::Override, &RoomId::parse("!room_d:matrix.org").unwrap(), false),
(RuleKind::Underride, &RoomId::parse("!room_e:matrix.org").unwrap(), false),
]);
let rules = Rules::new(ruleset);
let room_ids = rules.get_rooms_with_user_defined_rules(None);
assert_eq!(room_ids.len(), 5);
let expected_set: HashSet<String> = vec![
"!room_a:matrix.org",
"!room_b:matrix.org",
"!room_c:matrix.org",
"!room_d:matrix.org",
"!room_e:matrix.org",
]
.into_iter()
.collect();
assert!(expected_set.difference(HashSet::from(room_ids)).is_empty());
// Only disabled rules
let room_ids = rules.get_rooms_with_user_defined_rules(Some(false));
assert_eq!(room_ids.len(), 0);
// Only enabled rules
let room_ids = rules.get_rooms_with_user_defined_rules(Some(true));
assert_eq!(room_ids.len(), 5);
let mut ruleset = build_ruleset(vec![
(RuleKind::Room, &RoomId::parse("!room_a:matrix.org").unwrap(), false),
(RuleKind::Room, &RoomId::parse("!room_b:matrix.org").unwrap(), false),
(RuleKind::Override, &RoomId::parse("!room_c:matrix.org").unwrap(), false),
(RuleKind::Underride, &RoomId::parse("!room_d:matrix.org").unwrap(), false),
]);
ruleset.set_enabled(RuleKind::Room, "!room_b:matrix.org", false).unwrap();
ruleset.set_enabled(RuleKind::Override, "!room_c:matrix.org", false).unwrap();
let rules = Rules::new(ruleset);
// Only room_a and room_d rules are enabled
let room_ids = rules.get_rooms_with_user_defined_rules(Some(true));
assert_eq!(room_ids.len(), 2);
let expected_set: HashSet<String> =
vec!["!room_a:matrix.org", "!room_d:matrix.org"].into_iter().collect();
assert!(expected_set.difference(HashSet::from(room_ids)).is_empty());
}
}