mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-07 23:44:53 -04:00
Feature: add API for setting underride push rule's actions (#2644)
This commit is contained in:
@@ -147,7 +147,7 @@ pub enum NotificationSettingsError {
|
||||
InvalidRoomId(String),
|
||||
/// Rule not found
|
||||
#[error("Rule not found")]
|
||||
RuleNotFound,
|
||||
RuleNotFound(String),
|
||||
/// Unable to add push rule.
|
||||
#[error("Unable to add push rule")]
|
||||
UnableToAddPushRule,
|
||||
@@ -165,7 +165,7 @@ pub enum NotificationSettingsError {
|
||||
impl From<SdkNotificationSettingsError> for NotificationSettingsError {
|
||||
fn from(value: SdkNotificationSettingsError) -> Self {
|
||||
match value {
|
||||
SdkNotificationSettingsError::RuleNotFound => Self::RuleNotFound,
|
||||
SdkNotificationSettingsError::RuleNotFound(rule_id) => Self::RuleNotFound(rule_id),
|
||||
SdkNotificationSettingsError::UnableToAddPushRule => Self::UnableToAddPushRule,
|
||||
SdkNotificationSettingsError::UnableToRemovePushRule => Self::UnableToRemovePushRule,
|
||||
SdkNotificationSettingsError::UnableToSavePushRules => Self::UnableToSavePushRules,
|
||||
|
||||
@@ -88,7 +88,7 @@ matrix-sdk-sqlite = { version = "0.1.0", path = "../matrix-sdk-sqlite", default-
|
||||
mime = "0.3.16"
|
||||
mime2ext = "0.1.52"
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
ruma = { workspace = true, features = ["rand", "unstable-msc2448", "unstable-msc2965"] }
|
||||
ruma = { workspace = true, features = ["rand", "unstable-msc2448", "unstable-msc2965", "unstable-msc3930"] }
|
||||
serde = { workspace = true }
|
||||
serde_html_form = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -34,7 +34,7 @@ use ruma::{
|
||||
error::{FromHttpResponseError, IntoHttpError},
|
||||
},
|
||||
events::tag::InvalidUserTagName,
|
||||
push::{InsertPushRuleError, RemovePushRuleError, RuleNotFoundError},
|
||||
push::{InsertPushRuleError, RemovePushRuleError},
|
||||
IdParseError,
|
||||
};
|
||||
use serde_json::Error as JsonError;
|
||||
@@ -453,7 +453,7 @@ pub enum NotificationSettingsError {
|
||||
UnableToUpdatePushRule,
|
||||
/// Rule not found
|
||||
#[error("Rule not found")]
|
||||
RuleNotFound,
|
||||
RuleNotFound(String),
|
||||
/// Unable to save the push rules
|
||||
#[error("Unable to save push rules")]
|
||||
UnableToSavePushRules,
|
||||
@@ -471,12 +471,6 @@ impl From<RemovePushRuleError> for NotificationSettingsError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuleNotFoundError> for NotificationSettingsError {
|
||||
fn from(_: RuleNotFoundError) -> Self {
|
||||
Self::RuleNotFound
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("expected: {expected}, got: {got:?}")]
|
||||
pub struct WrongRoomState {
|
||||
|
||||
@@ -7,7 +7,7 @@ use ruma::{
|
||||
delete_pushrule, set_pushrule, set_pushrule_actions, set_pushrule_enabled,
|
||||
},
|
||||
events::push_rules::PushRulesEvent,
|
||||
push::{Action, RuleKind, Ruleset, Tweak},
|
||||
push::{Action, PredefinedUnderrideRuleId, RuleKind, Ruleset, Tweak},
|
||||
RoomId,
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
@@ -54,7 +54,7 @@ impl From<bool> for IsEncrypted {
|
||||
}
|
||||
|
||||
/// Whether or not a room is a `one-to-one`
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IsOneToOne {
|
||||
/// A room is a `one-to-one` room if it has exactly two members.
|
||||
Yes,
|
||||
@@ -186,9 +186,10 @@ impl NotificationSettings {
|
||||
is_one_to_one: IsOneToOne,
|
||||
mode: RoomNotificationMode,
|
||||
) -> Result<(), NotificationSettingsError> {
|
||||
let rules = self.rules.read().await.clone();
|
||||
let rule_id = rules::get_predefined_underride_room_rule_id(is_encrypted, is_one_to_one);
|
||||
let mut rule_commands = RuleCommands::new(rules.ruleset);
|
||||
let rule_ids = vec![
|
||||
rules::get_predefined_underride_room_rule_id(is_encrypted, is_one_to_one.clone()),
|
||||
is_one_to_one.into(),
|
||||
];
|
||||
|
||||
let actions = match mode {
|
||||
RoomNotificationMode::AllMessages => {
|
||||
@@ -199,6 +200,28 @@ impl NotificationSettings {
|
||||
}
|
||||
};
|
||||
|
||||
for rule_id in rule_ids {
|
||||
self.set_underride_push_rule_actions(rule_id, actions.clone()).await?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the push rule actions for a given underride push rule.
|
||||
/// [Underride rules](https://spec.matrix.org/v1.8/client-server-api/#push-rules) are the lowest priority push rules
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `rule_id` - the identifier of the push rule
|
||||
/// * `actions` - the actions to set for the push rule
|
||||
pub async fn set_underride_push_rule_actions(
|
||||
&self,
|
||||
rule_id: PredefinedUnderrideRuleId,
|
||||
actions: Vec<Action>,
|
||||
) -> Result<(), NotificationSettingsError> {
|
||||
let rules = self.rules.read().await.clone();
|
||||
let mut rule_commands = RuleCommands::new(rules.ruleset);
|
||||
|
||||
rule_commands.set_rule_actions(RuleKind::Underride, rule_id.as_str(), actions)?;
|
||||
|
||||
self.run_server_commands(&rule_commands).await?;
|
||||
@@ -926,6 +949,67 @@ mod tests {
|
||||
Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
|
||||
let client = logged_in_client(Some(server.uri())).await;
|
||||
|
||||
// If the initial mode is `AllMessages`
|
||||
let mut ruleset = get_server_default_ruleset();
|
||||
ruleset
|
||||
.set_actions(
|
||||
RuleKind::Underride,
|
||||
PredefinedUnderrideRuleId::Message,
|
||||
vec![Action::Notify],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
ruleset
|
||||
.set_actions(
|
||||
RuleKind::Underride,
|
||||
PredefinedUnderrideRuleId::PollStart,
|
||||
vec![Action::Notify],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let settings = NotificationSettings::new(client, ruleset);
|
||||
assert_eq!(
|
||||
settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
|
||||
RoomNotificationMode::AllMessages
|
||||
);
|
||||
|
||||
// After setting the default mode to `MentionsAndKeywordsOnly`
|
||||
settings
|
||||
.set_default_room_notification_mode(
|
||||
IsEncrypted::No,
|
||||
IsOneToOne::No,
|
||||
RoomNotificationMode::MentionsAndKeywordsOnly,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The list of actions for this rule must be empty
|
||||
assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::Message),
|
||||
Some(AnyPushRuleRef::Underride(rule)) => {
|
||||
assert!(rule.actions.is_empty());
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::PollStart),
|
||||
Some(AnyPushRuleRef::Underride(rule)) => {
|
||||
assert!(rule.actions.is_empty());
|
||||
}
|
||||
);
|
||||
|
||||
// and the new mode returned by `get_default_room_notification_mode()` should
|
||||
// reflect the change.
|
||||
assert_matches!(
|
||||
settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
|
||||
RoomNotificationMode::MentionsAndKeywordsOnly
|
||||
);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_set_default_room_notification_mode_one_to_one() {
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
|
||||
let client = logged_in_client(Some(server.uri())).await;
|
||||
|
||||
// If the initial mode is `AllMessages`
|
||||
let mut ruleset = get_server_default_ruleset();
|
||||
ruleset
|
||||
@@ -936,6 +1020,14 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
ruleset
|
||||
.set_actions(
|
||||
RuleKind::Underride,
|
||||
PredefinedUnderrideRuleId::PollStartOneToOne,
|
||||
vec![Action::Notify],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let settings = NotificationSettings::new(client, ruleset);
|
||||
assert_eq!(
|
||||
settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
|
||||
@@ -959,6 +1051,12 @@ mod tests {
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::PollStartOneToOne),
|
||||
Some(AnyPushRuleRef::Underride(rule)) => {
|
||||
assert!(rule.actions.is_empty());
|
||||
}
|
||||
);
|
||||
|
||||
// and the new mode returned by `get_default_room_notification_mode()` should
|
||||
// reflect the change.
|
||||
assert_matches!(
|
||||
|
||||
@@ -73,7 +73,9 @@ impl RuleCommands {
|
||||
rule_id: &str,
|
||||
enabled: bool,
|
||||
) -> Result<(), NotificationSettingsError> {
|
||||
self.rules.set_enabled(kind.clone(), rule_id, enabled)?;
|
||||
self.rules
|
||||
.set_enabled(kind.clone(), rule_id, enabled)
|
||||
.map_err(|_| NotificationSettingsError::RuleNotFound(rule_id.to_owned()))?;
|
||||
self.commands.push(Command::SetPushRuleEnabled {
|
||||
scope: RuleScope::Global,
|
||||
kind,
|
||||
@@ -163,7 +165,9 @@ impl RuleCommands {
|
||||
rule_id: &str,
|
||||
actions: Vec<Action>,
|
||||
) -> Result<(), NotificationSettingsError> {
|
||||
self.rules.set_actions(kind.clone(), rule_id, actions.clone())?;
|
||||
self.rules
|
||||
.set_actions(kind.clone(), rule_id, actions.clone())
|
||||
.map_err(|_| NotificationSettingsError::RuleNotFound(rule_id.to_owned()))?;
|
||||
self.commands.push(Command::SetPushRuleActions {
|
||||
scope: RuleScope::Global,
|
||||
kind,
|
||||
@@ -349,7 +353,7 @@ mod tests {
|
||||
let mut rule_commands = RuleCommands::new(ruleset);
|
||||
assert_eq!(
|
||||
rule_commands.set_rule_enabled(RuleKind::Room, "unknown_rule_id", true),
|
||||
Err(NotificationSettingsError::RuleNotFound)
|
||||
Err(NotificationSettingsError::RuleNotFound("unknown_rule_id".to_string()))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ impl Rules {
|
||||
} else if let Some(rule) = self.ruleset.get(kind, rule_id) {
|
||||
Ok(rule.enabled())
|
||||
} else {
|
||||
Err(NotificationSettingsError::RuleNotFound)
|
||||
Err(NotificationSettingsError::RuleNotFound(rule_id.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +276,15 @@ pub(crate) fn get_predefined_underride_room_rule_id(
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IsOneToOne> for PredefinedUnderrideRuleId {
|
||||
fn from(is_one_to_one: IsOneToOne) -> Self {
|
||||
match is_one_to_one {
|
||||
IsOneToOne::Yes => Self::PollStartOneToOne,
|
||||
IsOneToOne::No => Self::PollStart,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use imbl::HashSet;
|
||||
@@ -539,7 +548,7 @@ pub(crate) mod tests {
|
||||
|
||||
assert_eq!(
|
||||
rules.is_enabled(RuleKind::Override, "unknown_rule_id"),
|
||||
Err(NotificationSettingsError::RuleNotFound)
|
||||
Err(NotificationSettingsError::RuleNotFound("unknown_rule_id".to_string()))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user