use ruma::{
push::{
Action, PredefinedContentRuleId, PredefinedOverrideRuleId, RemovePushRuleError, RuleKind,
Ruleset,
},
RoomId,
};
use super::command::Command;
use crate::NotificationSettingsError;
#[derive(Clone, Debug)]
pub(crate) struct RuleCommands {
pub(crate) commands: Vec<Command>,
pub(crate) rules: Ruleset,
}
impl RuleCommands {
pub(crate) fn new(rules: Ruleset) -> Self {
RuleCommands { commands: vec![], rules }
}
pub(crate) fn insert_rule(
&mut self,
kind: RuleKind,
room_id: &RoomId,
notify: bool,
) -> Result<(), NotificationSettingsError> {
let command = match kind {
RuleKind::Room => Command::SetRoomPushRule { room_id: room_id.to_owned(), notify },
RuleKind::Override => Command::SetOverridePushRule {
rule_id: room_id.to_string(),
room_id: room_id.to_owned(),
notify,
},
_ => {
return Err(NotificationSettingsError::InvalidParameter(
"cannot insert a rule for this kind.".to_owned(),
))
}
};
self.rules.insert(command.to_push_rule()?, None, None)?;
self.commands.push(command);
Ok(())
}
pub(crate) fn insert_keyword_rule(
&mut self,
keyword: String,
) -> Result<(), NotificationSettingsError> {
let command = Command::SetKeywordPushRule { keyword };
self.rules.insert(command.to_push_rule()?, None, None)?;
self.commands.push(command);
Ok(())
}
pub(crate) fn delete_rule(
&mut self,
kind: RuleKind,
rule_id: String,
) -> Result<(), RemovePushRuleError> {
self.rules.remove(kind.clone(), &rule_id)?;
self.commands.push(Command::DeletePushRule { kind, rule_id });
Ok(())
}
fn set_enabled_internal(
&mut self,
kind: RuleKind,
rule_id: &str,
enabled: bool,
) -> Result<(), NotificationSettingsError> {
self.rules
.set_enabled(kind.clone(), rule_id, enabled)
.map_err(|_| NotificationSettingsError::RuleNotFound(rule_id.to_owned()))?;
self.commands.push(Command::SetPushRuleEnabled {
kind,
rule_id: rule_id.to_owned(),
enabled,
});
Ok(())
}
pub(crate) fn set_rule_enabled(
&mut self,
kind: RuleKind,
rule_id: &str,
enabled: bool,
) -> Result<(), NotificationSettingsError> {
if rule_id == PredefinedOverrideRuleId::IsRoomMention.as_str() {
self.set_room_mention_enabled(enabled)
} else if rule_id == PredefinedOverrideRuleId::IsUserMention.as_str() {
self.set_user_mention_enabled(enabled)
} else {
self.set_enabled_internal(kind, rule_id, enabled)
}
}
fn set_user_mention_enabled(&mut self, enabled: bool) -> Result<(), NotificationSettingsError> {
self.set_enabled_internal(
RuleKind::Override,
PredefinedOverrideRuleId::IsUserMention.as_str(),
enabled,
)?;
#[allow(deprecated)]
{
self.set_enabled_internal(
RuleKind::Content,
PredefinedContentRuleId::ContainsUserName.as_str(),
enabled,
)?;
self.set_enabled_internal(
RuleKind::Override,
PredefinedOverrideRuleId::ContainsDisplayName.as_str(),
enabled,
)?;
}
Ok(())
}
fn set_room_mention_enabled(&mut self, enabled: bool) -> Result<(), NotificationSettingsError> {
self.set_enabled_internal(
RuleKind::Override,
PredefinedOverrideRuleId::IsRoomMention.as_str(),
enabled,
)?;
#[allow(deprecated)]
self.set_enabled_internal(
RuleKind::Override,
PredefinedOverrideRuleId::RoomNotif.as_str(),
enabled,
)?;
Ok(())
}
pub(crate) fn set_rule_actions(
&mut self,
kind: RuleKind,
rule_id: &str,
actions: Vec<Action>,
) -> Result<(), NotificationSettingsError> {
self.rules
.set_actions(kind.clone(), rule_id, actions.clone())
.map_err(|_| NotificationSettingsError::RuleNotFound(rule_id.to_owned()))?;
self.commands.push(Command::SetPushRuleActions {
kind,
rule_id: rule_id.to_owned(),
actions,
});
Ok(())
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use matrix_sdk_test::async_test;
use ruma::{
push::{
Action, NewPushRule, NewSimplePushRule, PredefinedContentRuleId,
PredefinedOverrideRuleId, PredefinedUnderrideRuleId, RemovePushRuleError, RuleKind,
Ruleset, Tweak,
},
OwnedRoomId, RoomId, UserId,
};
use super::RuleCommands;
use crate::{error::NotificationSettingsError, notification_settings::command::Command};
fn get_server_default_ruleset() -> Ruleset {
let user_id = UserId::parse("@user:matrix.org").unwrap();
Ruleset::server_default(&user_id)
}
fn get_test_room_id() -> OwnedRoomId {
RoomId::parse("!AAAaAAAAAaaAAaaaaa:matrix.org").unwrap()
}
#[async_test]
async fn test_insert_rule_room() {
let room_id = get_test_room_id();
let mut rule_commands = RuleCommands::new(get_server_default_ruleset());
rule_commands.insert_rule(RuleKind::Room, &room_id, true).unwrap();
assert!(rule_commands.rules.get(RuleKind::Room, &room_id).is_some());
assert_eq!(rule_commands.commands.len(), 1);
assert_matches!(&rule_commands.commands[0],
Command::SetRoomPushRule { room_id: command_room_id, notify } => {
assert_eq!(command_room_id, &room_id);
assert!(notify);
}
);
}
#[async_test]
async fn test_insert_rule_override() {
let room_id = get_test_room_id();
let mut rule_commands = RuleCommands::new(get_server_default_ruleset());
rule_commands.insert_rule(RuleKind::Override, &room_id, true).unwrap();
assert!(rule_commands.rules.get(RuleKind::Override, &room_id).is_some());
assert_eq!(rule_commands.commands.len(), 1);
assert_matches!(&rule_commands.commands[0],
Command::SetOverridePushRule {room_id: command_room_id, rule_id, notify } => {
assert_eq!(command_room_id, &room_id);
assert_eq!(rule_id, room_id.as_str());
assert!(notify);
}
);
}
#[async_test]
async fn test_insert_rule_unsupported() {
let room_id = get_test_room_id();
let mut rule_commands = RuleCommands::new(get_server_default_ruleset());
assert_matches!(
rule_commands.insert_rule(RuleKind::Underride, &room_id, true),
Err(NotificationSettingsError::InvalidParameter(_)) => {}
);
assert_matches!(
rule_commands.insert_rule(RuleKind::Content, &room_id, true),
Err(NotificationSettingsError::InvalidParameter(_)) => {}
);
assert_matches!(
rule_commands.insert_rule(RuleKind::Sender, &room_id, true),
Err(NotificationSettingsError::InvalidParameter(_)) => {}
);
}
#[async_test]
async fn test_delete_rule() {
let room_id = get_test_room_id();
let mut ruleset = get_server_default_ruleset();
let new_rule = NewSimplePushRule::new(room_id.to_owned(), vec![]);
ruleset.insert(NewPushRule::Room(new_rule), None, None).unwrap();
let mut rule_commands = RuleCommands::new(ruleset);
rule_commands.delete_rule(RuleKind::Room, room_id.to_string()).unwrap();
assert!(rule_commands.rules.get(RuleKind::Room, &room_id).is_none());
assert_eq!(rule_commands.commands.len(), 1);
assert_matches!(&rule_commands.commands[0],
Command::DeletePushRule { kind, rule_id } => {
assert_eq!(kind, &RuleKind::Room);
assert_eq!(rule_id, room_id.as_str());
}
);
}
#[async_test]
async fn test_delete_rule_errors() {
let room_id = get_test_room_id();
let ruleset = get_server_default_ruleset();
let mut rule_commands = RuleCommands::new(ruleset);
assert_matches!(
rule_commands.delete_rule(RuleKind::Room, room_id.to_string()),
Err(RemovePushRuleError::NotFound) => {}
);
assert_matches!(
rule_commands.delete_rule(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention.to_string()),
Err(RemovePushRuleError::ServerDefault) => {}
);
assert!(rule_commands.commands.is_empty());
}
#[async_test]
async fn test_set_rule_enabled() {
let mut ruleset = get_server_default_ruleset();
ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, false).unwrap();
let mut rule_commands = RuleCommands::new(ruleset);
rule_commands
.set_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction.as_str(), true)
.unwrap();
let rule = rule_commands
.rules
.get(RuleKind::Override, PredefinedOverrideRuleId::Reaction.as_str())
.unwrap();
assert!(rule.enabled());
assert_eq!(rule_commands.commands.len(), 1);
assert_matches!(&rule_commands.commands[0],
Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
assert_eq!(kind, &RuleKind::Override);
assert_eq!(rule_id, PredefinedOverrideRuleId::Reaction.as_str());
assert!(enabled);
}
);
}
#[async_test]
async fn test_set_rule_enabled_not_found() {
let ruleset = get_server_default_ruleset();
let mut rule_commands = RuleCommands::new(ruleset);
assert_eq!(
rule_commands.set_rule_enabled(RuleKind::Room, "unknown_rule_id", true),
Err(NotificationSettingsError::RuleNotFound("unknown_rule_id".to_owned()))
);
}
#[async_test]
async fn test_set_rule_enabled_user_mention() {
let mut ruleset = get_server_default_ruleset();
let mut rule_commands = RuleCommands::new(ruleset.clone());
ruleset
.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention, false)
.unwrap();
#[allow(deprecated)]
{
ruleset
.set_enabled(
RuleKind::Override,
PredefinedOverrideRuleId::ContainsDisplayName,
false,
)
.unwrap();
ruleset
.set_enabled(RuleKind::Content, PredefinedContentRuleId::ContainsUserName, false)
.unwrap();
}
rule_commands
.set_rule_enabled(
RuleKind::Override,
PredefinedOverrideRuleId::IsUserMention.as_str(),
true,
)
.unwrap();
assert!(rule_commands
.rules
.get(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention)
.unwrap()
.enabled());
#[allow(deprecated)]
{
assert!(rule_commands
.rules
.get(RuleKind::Override, PredefinedOverrideRuleId::ContainsDisplayName)
.unwrap()
.enabled());
assert!(rule_commands
.rules
.get(RuleKind::Content, PredefinedContentRuleId::ContainsUserName)
.unwrap()
.enabled());
}
assert_eq!(rule_commands.commands.len(), 3);
assert_matches!(&rule_commands.commands[0],
Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
assert_eq!(kind, &RuleKind::Override);
assert_eq!(rule_id, PredefinedOverrideRuleId::IsUserMention.as_str());
assert!(enabled);
}
);
#[allow(deprecated)]
{
assert_matches!(&rule_commands.commands[1],
Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
assert_eq!(kind, &RuleKind::Content);
assert_eq!(rule_id, PredefinedContentRuleId::ContainsUserName.as_str());
assert!(enabled);
}
);
assert_matches!(&rule_commands.commands[2],
Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
assert_eq!(kind, &RuleKind::Override);
assert_eq!(rule_id, PredefinedOverrideRuleId::ContainsDisplayName.as_str());
assert!(enabled);
}
);
}
}
#[async_test]
async fn test_set_rule_enabled_room_mention() {
let mut ruleset = get_server_default_ruleset();
let mut rule_commands = RuleCommands::new(ruleset.clone());
ruleset
.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::IsRoomMention, false)
.unwrap();
#[allow(deprecated)]
{
ruleset
.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::RoomNotif, false)
.unwrap();
}
rule_commands
.set_rule_enabled(
RuleKind::Override,
PredefinedOverrideRuleId::IsRoomMention.as_str(),
true,
)
.unwrap();
assert!(rule_commands
.rules
.get(RuleKind::Override, PredefinedOverrideRuleId::IsRoomMention)
.unwrap()
.enabled());
#[allow(deprecated)]
{
assert!(rule_commands
.rules
.get(RuleKind::Override, PredefinedOverrideRuleId::RoomNotif)
.unwrap()
.enabled());
}
assert_eq!(rule_commands.commands.len(), 2);
assert_matches!(&rule_commands.commands[0],
Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
assert_eq!(kind, &RuleKind::Override);
assert_eq!(rule_id, PredefinedOverrideRuleId::IsRoomMention.as_str());
assert!(enabled);
}
);
#[allow(deprecated)]
{
assert_matches!(&rule_commands.commands[1],
Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
assert_eq!(kind, &RuleKind::Override);
assert_eq!(rule_id, PredefinedOverrideRuleId::RoomNotif.as_str());
assert!(enabled);
}
);
}
}
#[async_test]
async fn test_set_rule_actions() {
let mut ruleset = get_server_default_ruleset();
let mut rule_commands = RuleCommands::new(ruleset.clone());
ruleset
.set_actions(RuleKind::Underride, PredefinedUnderrideRuleId::Message, vec![])
.unwrap();
rule_commands
.set_rule_actions(
RuleKind::Underride,
PredefinedUnderrideRuleId::Message.as_str(),
vec![Action::Notify, Action::SetTweak(Tweak::Sound("default".into()))],
)
.unwrap();
let actions = rule_commands
.rules
.get(RuleKind::Underride, PredefinedUnderrideRuleId::Message)
.unwrap()
.actions();
assert_eq!(actions.len(), 2);
assert_eq!(rule_commands.commands.len(), 1);
assert_matches!(&rule_commands.commands[0],
Command::SetPushRuleActions { kind, rule_id, actions } => {
assert_eq!(kind, &RuleKind::Underride);
assert_eq!(rule_id, PredefinedUnderrideRuleId::Message.as_str());
assert_eq!(actions.len(), 2);
assert_matches!(&actions[0], Action::Notify);
assert_matches!(&actions[1], Action::SetTweak(Tweak::Sound(sound)) => {
assert_eq!(sound, "default");
});
}
);
}
}