1use std::sync::Arc;
18
19use indexmap::IndexSet;
20use ruma::{
21 api::client::push::{
22 delete_pushrule, set_pushrule, set_pushrule_actions, set_pushrule_enabled,
23 },
24 events::push_rules::PushRulesEvent,
25 push::{Action, NewPushRule, PredefinedUnderrideRuleId, RuleKind, Ruleset, Tweak},
26 RoomId,
27};
28use tokio::sync::{
29 broadcast::{self, Receiver},
30 RwLock,
31};
32use tracing::{debug, error};
33
34use self::{command::Command, rule_commands::RuleCommands, rules::Rules};
35
36mod command;
37mod rule_commands;
38mod rules;
39
40pub use matrix_sdk_base::notification_settings::RoomNotificationMode;
41
42use crate::{
43 config::RequestConfig, error::NotificationSettingsError, event_handler::EventHandlerDropGuard,
44 Client, Result,
45};
46
47#[derive(Debug, Clone, Copy)]
49pub enum IsEncrypted {
50 Yes,
52 No,
54}
55
56impl From<bool> for IsEncrypted {
57 fn from(value: bool) -> Self {
58 if value {
59 Self::Yes
60 } else {
61 Self::No
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy)]
68pub enum IsOneToOne {
69 Yes,
71 No,
73}
74
75impl From<bool> for IsOneToOne {
76 fn from(value: bool) -> Self {
77 if value {
78 Self::Yes
79 } else {
80 Self::No
81 }
82 }
83}
84
85#[derive(Debug, Clone)]
87pub struct NotificationSettings {
88 client: Client,
90 rules: Arc<RwLock<Rules>>,
92 _push_rules_event_handler_guard: Arc<EventHandlerDropGuard>,
94 changes_sender: broadcast::Sender<()>,
95}
96
97impl NotificationSettings {
98 pub(crate) fn new(client: Client, ruleset: Ruleset) -> Self {
105 let changes_sender = broadcast::Sender::new(100);
106 let rules = Arc::new(RwLock::new(Rules::new(ruleset)));
107
108 let push_rules_event_handler_handle = client.add_event_handler({
110 let changes_sender = changes_sender.clone();
111 let rules = Arc::clone(&rules);
112 move |ev: PushRulesEvent| async move {
113 *rules.write().await = Rules::new(ev.content.global);
114 let _ = changes_sender.send(());
115 }
116 });
117 let _push_rules_event_handler_guard =
118 client.event_handler_drop_guard(push_rules_event_handler_handle).into();
119
120 Self { client, rules, _push_rules_event_handler_guard, changes_sender }
121 }
122
123 pub fn subscribe_to_changes(&self) -> Receiver<()> {
127 self.changes_sender.subscribe()
128 }
129
130 pub async fn get_user_defined_room_notification_mode(
132 &self,
133 room_id: &RoomId,
134 ) -> Option<RoomNotificationMode> {
135 self.rules.read().await.get_user_defined_room_notification_mode(room_id)
136 }
137
138 pub async fn get_default_room_notification_mode(
146 &self,
147 is_encrypted: IsEncrypted,
148 is_one_to_one: IsOneToOne,
149 ) -> RoomNotificationMode {
150 self.rules.read().await.get_default_room_notification_mode(is_encrypted, is_one_to_one)
151 }
152
153 pub async fn get_rooms_with_user_defined_rules(&self, enabled: Option<bool>) -> Vec<String> {
155 self.rules.read().await.get_rooms_with_user_defined_rules(enabled)
156 }
157
158 pub async fn contains_keyword_rules(&self) -> bool {
160 self.rules.read().await.contains_keyword_rules()
161 }
162
163 pub async fn is_push_rule_enabled(
165 &self,
166 kind: RuleKind,
167 rule_id: impl AsRef<str>,
168 ) -> Result<bool, NotificationSettingsError> {
169 self.rules.read().await.is_enabled(kind, rule_id.as_ref())
170 }
171
172 pub async fn set_push_rule_enabled(
174 &self,
175 kind: RuleKind,
176 rule_id: impl AsRef<str>,
177 enabled: bool,
178 ) -> Result<(), NotificationSettingsError> {
179 let rules = self.rules.read().await.clone();
180
181 let mut rule_commands = RuleCommands::new(rules.ruleset);
182 rule_commands.set_rule_enabled(kind, rule_id.as_ref(), enabled)?;
183
184 self.run_server_commands(&rule_commands).await?;
185
186 let rules = &mut *self.rules.write().await;
187 rules.apply(rule_commands);
188
189 Ok(())
190 }
191
192 pub async fn set_default_room_notification_mode(
201 &self,
202 is_encrypted: IsEncrypted,
203 is_one_to_one: IsOneToOne,
204 mode: RoomNotificationMode,
205 ) -> Result<(), NotificationSettingsError> {
206 let actions = match mode {
207 RoomNotificationMode::AllMessages => {
208 vec![Action::Notify, Action::SetTweak(Tweak::Sound("default".into()))]
209 }
210 _ => {
211 vec![]
212 }
213 };
214
215 let room_rule_id =
216 rules::get_predefined_underride_room_rule_id(is_encrypted, is_one_to_one);
217 self.set_underride_push_rule_actions(room_rule_id, actions.clone()).await?;
218
219 let poll_start_rule_id = rules::get_predefined_underride_poll_start_rule_id(is_one_to_one);
220 if let Err(error) =
221 self.set_underride_push_rule_actions(poll_start_rule_id, actions.clone()).await
222 {
223 if let NotificationSettingsError::RuleNotFound(rule_id) = &error {
226 debug!("Unable to update poll start push rule: rule `{rule_id}` not found");
227 } else {
228 return Err(error);
229 }
230 }
231
232 Ok(())
233 }
234
235 pub async fn set_underride_push_rule_actions(
246 &self,
247 rule_id: PredefinedUnderrideRuleId,
248 actions: Vec<Action>,
249 ) -> Result<(), NotificationSettingsError> {
250 let rules = self.rules.read().await.clone();
251 let rule_kind = RuleKind::Underride;
252 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
253
254 rule_commands.set_rule_actions(rule_kind.clone(), rule_id.as_str(), actions)?;
255
256 if !rules.is_enabled(rule_kind.clone(), rule_id.as_str())? {
257 rule_commands.set_rule_enabled(rule_kind, rule_id.as_str(), true)?
258 }
259
260 self.run_server_commands(&rule_commands).await?;
261
262 let rules = &mut *self.rules.write().await;
263 rules.apply(rule_commands);
264
265 Ok(())
266 }
267
268 pub async fn create_custom_conditional_push_rule(
279 &self,
280 rule_id: String,
281 rule_kind: RuleKind,
282 actions: Vec<Action>,
283 conditions: Vec<ruma::push::PushCondition>,
284 ) -> Result<(), NotificationSettingsError> {
285 let new_conditional_rule =
286 ruma::push::NewConditionalPushRule::new(rule_id, conditions, actions);
287
288 let new_push_rule = match rule_kind {
289 RuleKind::Override => NewPushRule::Override(new_conditional_rule),
290 RuleKind::Underride => NewPushRule::Underride(new_conditional_rule),
291 _ => return Err(NotificationSettingsError::InvalidParameter("rule_kind".to_owned())),
292 };
293
294 let rules = self.rules.read().await.clone();
295 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
296 rule_commands.insert_custom_rule(new_push_rule)?;
297
298 self.run_server_commands(&rule_commands).await?;
299
300 let rules = &mut *self.rules.write().await;
301 rules.apply(rule_commands);
302
303 Ok(())
304 }
305
306 pub async fn set_room_notification_mode(
308 &self,
309 room_id: &RoomId,
310 mode: RoomNotificationMode,
311 ) -> Result<(), NotificationSettingsError> {
312 let rules = self.rules.read().await.clone();
313
314 if rules.get_user_defined_room_notification_mode(room_id) == Some(mode) {
316 return Ok(());
317 }
318
319 let (new_rule_kind, notify) = match mode {
321 RoomNotificationMode::AllMessages => {
322 (RuleKind::Room, true)
324 }
325 RoomNotificationMode::MentionsAndKeywordsOnly => {
326 (RuleKind::Room, false)
328 }
329 RoomNotificationMode::Mute => {
330 (RuleKind::Override, false)
332 }
333 };
334
335 let new_rule_id = room_id.as_str();
337 let custom_rules: Vec<(RuleKind, String)> = rules
338 .get_custom_rules_for_room(room_id)
339 .into_iter()
340 .filter(|(kind, rule_id)| kind != &new_rule_kind || rule_id != new_rule_id)
341 .collect();
342
343 let mut rule_commands = RuleCommands::new(rules.ruleset);
346 rule_commands.insert_rule(new_rule_kind.clone(), room_id, notify)?;
347 for (kind, rule_id) in custom_rules {
348 rule_commands.delete_rule(kind, rule_id)?;
349 }
350
351 self.run_server_commands(&rule_commands).await?;
352
353 let rules = &mut *self.rules.write().await;
354 rules.apply(rule_commands);
355
356 Ok(())
357 }
358
359 pub async fn delete_user_defined_room_rules(
361 &self,
362 room_id: &RoomId,
363 ) -> Result<(), NotificationSettingsError> {
364 let rules = self.rules.read().await.clone();
365
366 let custom_rules = rules.get_custom_rules_for_room(room_id);
367 if custom_rules.is_empty() {
368 return Ok(());
369 }
370
371 let mut rule_commands = RuleCommands::new(rules.ruleset);
372 for (kind, rule_id) in custom_rules {
373 rule_commands.delete_rule(kind, rule_id)?;
374 }
375
376 self.run_server_commands(&rule_commands).await?;
377
378 let rules = &mut *self.rules.write().await;
379 rules.apply(rule_commands);
380
381 Ok(())
382 }
383
384 pub async fn unmute_room(
386 &self,
387 room_id: &RoomId,
388 is_encrypted: IsEncrypted,
389 is_one_to_one: IsOneToOne,
390 ) -> Result<(), NotificationSettingsError> {
391 let rules = self.rules.read().await.clone();
392
393 if let Some(room_mode) = rules.get_user_defined_room_notification_mode(room_id) {
395 if room_mode != RoomNotificationMode::Mute {
396 return Ok(());
398 }
399
400 let default_mode =
402 rules.get_default_room_notification_mode(is_encrypted, is_one_to_one);
403
404 if default_mode == RoomNotificationMode::Mute {
406 self.set_room_notification_mode(room_id, RoomNotificationMode::AllMessages).await
407 } else {
408 self.delete_user_defined_room_rules(room_id).await
410 }
411 } else {
412 self.set_room_notification_mode(room_id, RoomNotificationMode::AllMessages).await
415 }
416 }
417
418 pub async fn enabled_keywords(&self) -> IndexSet<String> {
420 self.rules.read().await.enabled_keywords()
421 }
422
423 pub async fn add_keyword(&self, keyword: String) -> Result<(), NotificationSettingsError> {
429 let rules = self.rules.read().await.clone();
430
431 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
432
433 let existing_rules = rules.keyword_rules(&keyword);
434
435 if existing_rules.is_empty() {
436 rule_commands.insert_keyword_rule(keyword)?;
438 } else {
439 if existing_rules.iter().any(|r| r.enabled) {
440 return Ok(());
442 }
443
444 rule_commands.set_rule_enabled(RuleKind::Content, &existing_rules[0].rule_id, true)?;
446 }
447
448 self.run_server_commands(&rule_commands).await?;
449
450 let rules = &mut *self.rules.write().await;
451 rules.apply(rule_commands);
452
453 Ok(())
454 }
455
456 pub async fn remove_keyword(&self, keyword: &str) -> Result<(), NotificationSettingsError> {
462 let rules = self.rules.read().await.clone();
463
464 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
465
466 let existing_rules = rules.keyword_rules(keyword);
467
468 if existing_rules.is_empty() {
469 return Ok(());
470 }
471
472 for rule in existing_rules {
473 rule_commands.delete_rule(RuleKind::Content, rule.rule_id.clone())?;
474 }
475
476 self.run_server_commands(&rule_commands).await?;
477
478 let rules = &mut *self.rules.write().await;
479 rules.apply(rule_commands);
480
481 Ok(())
482 }
483
484 async fn run_server_commands(
486 &self,
487 rule_commands: &RuleCommands,
488 ) -> Result<(), NotificationSettingsError> {
489 let request_config = Some(RequestConfig::short_retry());
490 for command in &rule_commands.commands {
491 match command {
492 Command::DeletePushRule { kind, rule_id } => {
493 let request = delete_pushrule::v3::Request::new(kind.clone(), rule_id.clone());
494 self.client.send(request).with_request_config(request_config).await.map_err(
495 |error| {
496 error!("Unable to delete {kind} push rule `{rule_id}`: {error}");
497 NotificationSettingsError::UnableToRemovePushRule
498 },
499 )?;
500 }
501 Command::SetRoomPushRule { room_id, notify: _ } => {
502 let push_rule = command.to_push_rule()?;
503 let request = set_pushrule::v3::Request::new(push_rule);
504 self.client.send(request).with_request_config(request_config).await.map_err(
505 |error| {
506 error!("Unable to set room push rule `{room_id}`: {error}");
507 NotificationSettingsError::UnableToAddPushRule
508 },
509 )?;
510 }
511 Command::SetOverridePushRule { rule_id, room_id: _, notify: _ } => {
512 let push_rule = command.to_push_rule()?;
513 let request = set_pushrule::v3::Request::new(push_rule);
514 self.client.send(request).with_request_config(request_config).await.map_err(
515 |error| {
516 error!("Unable to set override push rule `{rule_id}`: {error}");
517 NotificationSettingsError::UnableToAddPushRule
518 },
519 )?;
520 }
521 Command::SetKeywordPushRule { keyword: _ } => {
522 let push_rule = command.to_push_rule()?;
523 let request = set_pushrule::v3::Request::new(push_rule);
524 self.client
525 .send(request)
526 .with_request_config(request_config)
527 .await
528 .map_err(|_| NotificationSettingsError::UnableToAddPushRule)?;
529 }
530 Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
531 let request = set_pushrule_enabled::v3::Request::new(
532 kind.clone(),
533 rule_id.clone(),
534 *enabled,
535 );
536 self.client.send(request).with_request_config(request_config).await.map_err(
537 |error| {
538 error!("Unable to set {kind} push rule `{rule_id}` enabled: {error}");
539 NotificationSettingsError::UnableToUpdatePushRule
540 },
541 )?;
542 }
543 Command::SetPushRuleActions { kind, rule_id, actions } => {
544 let request = set_pushrule_actions::v3::Request::new(
545 kind.clone(),
546 rule_id.clone(),
547 actions.clone(),
548 );
549 self.client.send(request).with_request_config(request_config).await.map_err(
550 |error| {
551 error!("Unable to set {kind} push rule `{rule_id}` actions: {error}");
552 NotificationSettingsError::UnableToUpdatePushRule
553 },
554 )?;
555 }
556 Command::SetCustomPushRule { rule } => {
557 let request = set_pushrule::v3::Request::new(rule.clone());
558
559 self.client.send(request).with_request_config(request_config).await.map_err(
560 |error| {
561 error!("Unable to set custom push rule `{rule:#?}`: {error}");
562 NotificationSettingsError::UnableToAddPushRule
563 },
564 )?;
565 }
566 }
567 }
568 Ok(())
569 }
570}
571
572#[cfg(all(test, not(target_arch = "wasm32")))]
574mod tests {
575 use std::sync::{
576 atomic::{AtomicBool, Ordering},
577 Arc,
578 };
579
580 use assert_matches::assert_matches;
581 use matrix_sdk_test::{
582 async_test,
583 notification_settings::{build_ruleset, get_server_default_ruleset},
584 test_json,
585 };
586 use ruma::{
587 push::{
588 Action, AnyPushRuleRef, NewPatternedPushRule, NewPushRule, PredefinedOverrideRuleId,
589 PredefinedUnderrideRuleId, RuleKind,
590 },
591 OwnedRoomId, RoomId,
592 };
593 use serde_json::json;
594 use stream_assert::{assert_next_eq, assert_pending};
595 use tokio_stream::wrappers::BroadcastStream;
596 use wiremock::{
597 matchers::{header, method, path, path_regex},
598 Mock, MockServer, ResponseTemplate,
599 };
600
601 use crate::{
602 config::SyncSettings,
603 error::NotificationSettingsError,
604 notification_settings::{
605 IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode,
606 },
607 test_utils::logged_in_client,
608 Client,
609 };
610
611 fn get_test_room_id() -> OwnedRoomId {
612 RoomId::parse("!AAAaAAAAAaaAAaaaaa:matrix.org").unwrap()
613 }
614
615 fn from_insert_rules(
616 client: &Client,
617 rules: Vec<(RuleKind, &RoomId, bool)>,
618 ) -> NotificationSettings {
619 let ruleset = build_ruleset(rules);
620 NotificationSettings::new(client.to_owned(), ruleset)
621 }
622
623 async fn get_custom_rules_for_room(
624 settings: &NotificationSettings,
625 room_id: &RoomId,
626 ) -> Vec<(RuleKind, String)> {
627 settings.rules.read().await.get_custom_rules_for_room(room_id)
628 }
629
630 #[async_test]
631 async fn test_subscribe_to_changes() {
632 let server = MockServer::start().await;
633 let client = logged_in_client(Some(server.uri())).await;
634 let settings = client.notification_settings().await;
635
636 Mock::given(method("GET"))
637 .and(path("/_matrix/client/r0/sync"))
638 .and(header("authorization", "Bearer 1234"))
639 .respond_with(ResponseTemplate::new(200).set_body_json(json!({
640 "next_batch": "1234",
641 "account_data": {
642 "events": [*test_json::PUSH_RULES]
643 }
644 })))
645 .expect(1)
646 .mount(&server)
647 .await;
648
649 let subscriber = settings.subscribe_to_changes();
650 let mut stream = BroadcastStream::new(subscriber);
651
652 assert_pending!(stream);
653
654 client.sync_once(SyncSettings::default()).await.unwrap();
655
656 assert_next_eq!(stream, Ok(()));
657 assert_pending!(stream);
658 }
659
660 #[async_test]
661 async fn test_get_custom_rules_for_room() {
662 let server = MockServer::start().await;
663 let client = logged_in_client(Some(server.uri())).await;
664 let room_id = get_test_room_id();
665
666 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
667
668 let custom_rules = get_custom_rules_for_room(&settings, &room_id).await;
669 assert_eq!(custom_rules.len(), 1);
670 assert_eq!(custom_rules[0], (RuleKind::Room, room_id.to_string()));
671
672 let settings = from_insert_rules(
673 &client,
674 vec![(RuleKind::Room, &room_id, true), (RuleKind::Override, &room_id, true)],
675 );
676 let custom_rules = get_custom_rules_for_room(&settings, &room_id).await;
677 assert_eq!(custom_rules.len(), 2);
678 assert_eq!(custom_rules[0], (RuleKind::Override, room_id.to_string()));
679 assert_eq!(custom_rules[1], (RuleKind::Room, room_id.to_string()));
680 }
681
682 #[async_test]
683 async fn test_get_user_defined_room_notification_mode_none() {
684 let server = MockServer::start().await;
685 let client = logged_in_client(Some(server.uri())).await;
686 let room_id = get_test_room_id();
687
688 let settings = client.notification_settings().await;
689 assert!(settings.get_user_defined_room_notification_mode(&room_id).await.is_none());
690 }
691
692 #[async_test]
693 async fn test_get_user_defined_room_notification_mode_all_messages() {
694 let server = MockServer::start().await;
695 let client = logged_in_client(Some(server.uri())).await;
696 let room_id = get_test_room_id();
697
698 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
700
701 assert_eq!(
702 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
703 RoomNotificationMode::AllMessages
704 );
705 }
706
707 #[async_test]
708 async fn test_get_user_defined_room_notification_mode_mentions_and_keywords() {
709 let server = MockServer::start().await;
710 let client = logged_in_client(Some(server.uri())).await;
711 let room_id = get_test_room_id();
712
713 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, false)]);
715 assert_eq!(
716 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
717 RoomNotificationMode::MentionsAndKeywordsOnly
718 );
719 }
720
721 #[async_test]
722 async fn test_get_user_defined_room_notification_mode_mute() {
723 let server = MockServer::start().await;
724 let client = logged_in_client(Some(server.uri())).await;
725 let room_id = get_test_room_id();
726
727 let settings = from_insert_rules(&client, vec![(RuleKind::Override, &room_id, false)]);
729 assert_eq!(
730 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
731 RoomNotificationMode::Mute
732 );
733 }
734
735 #[async_test]
736 async fn test_get_default_room_notification_mode_all_messages() {
737 let server = MockServer::start().await;
738 let client = logged_in_client(Some(server.uri())).await;
739
740 let mut ruleset = get_server_default_ruleset();
741 ruleset
742 .set_actions(
743 RuleKind::Underride,
744 PredefinedUnderrideRuleId::RoomOneToOne,
745 vec![Action::Notify],
746 )
747 .unwrap();
748
749 let settings = NotificationSettings::new(client, ruleset);
750 assert_eq!(
751 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
752 RoomNotificationMode::AllMessages
753 );
754 }
755
756 #[async_test]
757 async fn test_get_default_room_notification_mode_mentions_and_keywords() {
758 let server = MockServer::start().await;
759 let client = logged_in_client(Some(server.uri())).await;
760
761 let mut ruleset = get_server_default_ruleset();
764 ruleset
765 .set_actions(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne, vec![])
766 .unwrap();
767
768 let settings = NotificationSettings::new(client.to_owned(), ruleset.to_owned());
769 assert_eq!(
770 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
771 RoomNotificationMode::MentionsAndKeywordsOnly
772 );
773
774 ruleset
777 .set_enabled(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne, false)
778 .unwrap();
779
780 let settings = NotificationSettings::new(client, ruleset);
781 assert_eq!(
782 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
783 RoomNotificationMode::MentionsAndKeywordsOnly
784 );
785 }
786
787 #[async_test]
788 async fn test_contains_keyword_rules() {
789 let server = MockServer::start().await;
790 let client = logged_in_client(Some(server.uri())).await;
791
792 let mut ruleset = get_server_default_ruleset();
793 let settings = NotificationSettings::new(client.to_owned(), ruleset.to_owned());
794
795 let contains_keywords_rules = settings.contains_keyword_rules().await;
797 assert!(!contains_keywords_rules);
798
799 let rule = NewPatternedPushRule::new(
801 "keyword_rule_id".into(),
802 "keyword".into(),
803 vec![Action::Notify],
804 );
805 ruleset.insert(NewPushRule::Content(rule), None, None).unwrap();
806
807 let settings = NotificationSettings::new(client, ruleset);
808 let contains_keywords_rules = settings.contains_keyword_rules().await;
809 assert!(contains_keywords_rules);
810 }
811
812 #[async_test]
813 async fn test_is_push_rule_enabled() {
814 let server = MockServer::start().await;
815 let client = logged_in_client(Some(server.uri())).await;
816
817 let mut ruleset = get_server_default_ruleset();
819 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, false).unwrap();
820
821 let settings = NotificationSettings::new(client.clone(), ruleset);
822
823 let enabled = settings
824 .is_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction)
825 .await
826 .unwrap();
827
828 assert!(!enabled);
829
830 let mut ruleset = get_server_default_ruleset();
832 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, true).unwrap();
833
834 let settings = NotificationSettings::new(client, ruleset);
835
836 let enabled = settings
837 .is_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction)
838 .await
839 .unwrap();
840
841 assert!(enabled);
842 }
843
844 #[async_test]
845 async fn test_set_push_rule_enabled() {
846 let server = MockServer::start().await;
847 let client = logged_in_client(Some(server.uri())).await;
848 let mut ruleset = client.account().push_rules().await.unwrap();
849 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, false).unwrap();
851
852 let settings = NotificationSettings::new(client, ruleset);
853
854 Mock::given(method("PUT"))
855 .and(path("/_matrix/client/r0/pushrules/global/override/.m.rule.reaction/enabled"))
856 .respond_with(ResponseTemplate::new(200))
857 .expect(1)
858 .mount(&server)
859 .await;
860
861 settings
862 .set_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, true)
863 .await
864 .unwrap();
865
866 let rules = settings.rules.read().await;
868 let rule =
869 rules.ruleset.get(RuleKind::Override, PredefinedOverrideRuleId::Reaction).unwrap();
870 assert!(rule.enabled());
871
872 server.verify().await
873 }
874
875 #[async_test]
876 async fn test_set_push_rule_enabled_api_error() {
877 let server = MockServer::start().await;
878 let client = logged_in_client(Some(server.uri())).await;
879 let mut ruleset = client.account().push_rules().await.unwrap();
880 ruleset
882 .set_enabled(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention, false)
883 .unwrap();
884
885 let settings = NotificationSettings::new(client, ruleset);
886
887 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(500)).mount(&server).await;
889
890 assert_eq!(
892 settings
893 .set_push_rule_enabled(
894 RuleKind::Override,
895 PredefinedOverrideRuleId::IsUserMention,
896 true,
897 )
898 .await,
899 Err(NotificationSettingsError::UnableToUpdatePushRule)
900 );
901
902 let rules = settings.rules.read().await;
904 let rule =
905 rules.ruleset.get(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention).unwrap();
906 assert!(!rule.enabled());
907 }
908
909 #[async_test]
910 async fn test_set_room_notification_mode() {
911 let server = MockServer::start().await;
912 let client = logged_in_client(Some(server.uri())).await;
913
914 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
915 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
916
917 let settings = client.notification_settings().await;
918 let room_id = get_test_room_id();
919
920 let mode = settings.get_user_defined_room_notification_mode(&room_id).await;
921 assert!(mode.is_none());
922
923 let new_modes = [
924 RoomNotificationMode::AllMessages,
925 RoomNotificationMode::MentionsAndKeywordsOnly,
926 RoomNotificationMode::Mute,
927 ];
928 for new_mode in new_modes {
929 settings.set_room_notification_mode(&room_id, new_mode).await.unwrap();
930
931 assert_eq!(
932 new_mode,
933 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap()
934 );
935 }
936 }
937
938 #[async_test]
939 async fn test_set_room_notification_mode_requests_order() {
940 let server = MockServer::start().await;
941 let client = logged_in_client(Some(server.uri())).await;
942
943 let put_was_called = Arc::new(AtomicBool::default());
944
945 Mock::given(method("PUT"))
946 .and(path_regex(r"_matrix/client/r0/pushrules/global/override/.*"))
947 .and({
948 let put_was_called = put_was_called.clone();
949 move |_: &wiremock::Request| {
950 put_was_called.store(true, Ordering::SeqCst);
951
952 true
953 }
954 })
955 .respond_with(ResponseTemplate::new(200))
956 .expect(1)
957 .mount(&server)
958 .await;
959
960 Mock::given(method("DELETE"))
961 .and(path_regex(r"_matrix/client/r0/pushrules/global/room/.*"))
962 .and(move |_: &wiremock::Request| {
963 let put_was_called = put_was_called.load(Ordering::SeqCst);
970 assert!(
971 put_was_called,
972 "The PUT /pushrules/global/override/ method should have been called before the \
973 DELETE method"
974 );
975
976 true
977 })
978 .respond_with(ResponseTemplate::new(200))
979 .expect(1)
980 .mount(&server)
981 .await;
982
983 let room_id = get_test_room_id();
984
985 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
987
988 settings.set_room_notification_mode(&room_id, RoomNotificationMode::Mute).await.unwrap();
991
992 assert_eq!(
993 RoomNotificationMode::Mute,
994 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap()
995 );
996
997 server.verify().await
998 }
999
1000 #[async_test]
1001 async fn test_set_room_notification_mode_put_api_error() {
1002 let server = MockServer::start().await;
1003 let client = logged_in_client(Some(server.uri())).await;
1004
1005 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(500)).mount(&server).await;
1007 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1008
1009 let room_id = get_test_room_id();
1010
1011 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
1013
1014 assert_eq!(
1015 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1016 RoomNotificationMode::AllMessages
1017 );
1018
1019 assert_eq!(
1021 settings.set_room_notification_mode(&room_id, RoomNotificationMode::Mute).await,
1022 Err(NotificationSettingsError::UnableToAddPushRule)
1023 );
1024
1025 assert_eq!(
1027 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1028 RoomNotificationMode::AllMessages
1029 );
1030 }
1031
1032 #[async_test]
1033 async fn test_set_room_notification_mode_delete_api_error() {
1034 let server = MockServer::start().await;
1035 let client = logged_in_client(Some(server.uri())).await;
1036
1037 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1039 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(500)).mount(&server).await;
1040
1041 let room_id = get_test_room_id();
1042
1043 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
1045
1046 assert_eq!(
1047 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1048 RoomNotificationMode::AllMessages
1049 );
1050
1051 assert_eq!(
1053 settings.set_room_notification_mode(&room_id, RoomNotificationMode::Mute).await,
1054 Err(NotificationSettingsError::UnableToRemovePushRule)
1055 );
1056
1057 assert_eq!(
1059 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1060 RoomNotificationMode::AllMessages
1061 );
1062 }
1063
1064 #[async_test]
1065 async fn test_delete_user_defined_room_rules() {
1066 let server = MockServer::start().await;
1067 let client = logged_in_client(Some(server.uri())).await;
1068 let room_id_a = RoomId::parse("!AAAaAAAAAaaAAaaaaa:matrix.org").unwrap();
1069 let room_id_b = RoomId::parse("!BBBbBBBBBbbBBbbbbb:matrix.org").unwrap();
1070
1071 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1072
1073 let settings = from_insert_rules(
1075 &client,
1076 vec![
1077 (RuleKind::Room, &room_id_a, true),
1078 (RuleKind::Room, &room_id_b, true),
1079 (RuleKind::Override, &room_id_b, true),
1080 ],
1081 );
1082
1083 settings.delete_user_defined_room_rules(&room_id_a).await.unwrap();
1085
1086 let updated_rules = settings.rules.read().await;
1088 assert_eq!(updated_rules.get_custom_rules_for_room(&room_id_b).len(), 2);
1089 assert!(updated_rules.get_custom_rules_for_room(&room_id_a).is_empty());
1090 }
1091
1092 #[async_test]
1093 async fn test_unmute_room_not_muted() {
1094 let server = MockServer::start().await;
1095 let client = logged_in_client(Some(server.uri())).await;
1096 let room_id = get_test_room_id();
1097
1098 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, false)]);
1100 assert_eq!(
1101 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1102 RoomNotificationMode::MentionsAndKeywordsOnly
1103 );
1104
1105 settings.unmute_room(&room_id, IsEncrypted::Yes, IsOneToOne::Yes).await.unwrap();
1107
1108 assert_eq!(
1110 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1111 RoomNotificationMode::MentionsAndKeywordsOnly
1112 );
1113
1114 let room_rules = get_custom_rules_for_room(&settings, &room_id).await;
1115 assert_eq!(room_rules.len(), 1);
1116 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Room, &room_id),
1117 Some(AnyPushRuleRef::Room(rule)) => {
1118 assert_eq!(rule.rule_id, room_id);
1119 assert!(rule.actions.is_empty());
1120 }
1121 );
1122 }
1123
1124 #[async_test]
1125 async fn test_unmute_room() {
1126 let server = MockServer::start().await;
1127 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1128 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1129 let client = logged_in_client(Some(server.uri())).await;
1130 let room_id = get_test_room_id();
1131
1132 let settings = from_insert_rules(&client, vec![(RuleKind::Override, &room_id, false)]);
1134 assert_eq!(
1135 settings.get_user_defined_room_notification_mode(&room_id).await,
1136 Some(RoomNotificationMode::Mute)
1137 );
1138
1139 settings.unmute_room(&room_id, IsEncrypted::No, IsOneToOne::Yes).await.unwrap();
1141
1142 assert!(settings.get_user_defined_room_notification_mode(&room_id).await.is_none());
1144 }
1145
1146 #[async_test]
1147 async fn test_unmute_room_default_mode() {
1148 let server = MockServer::start().await;
1149 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1150 let client = logged_in_client(Some(server.uri())).await;
1151 let room_id = get_test_room_id();
1152 let settings = client.notification_settings().await;
1153
1154 settings.unmute_room(&room_id, IsEncrypted::No, IsOneToOne::Yes).await.unwrap();
1156
1157 assert_eq!(
1159 Some(RoomNotificationMode::AllMessages),
1160 settings.get_user_defined_room_notification_mode(&room_id).await
1161 );
1162
1163 let room_rules = get_custom_rules_for_room(&settings, &room_id).await;
1164 assert_eq!(room_rules.len(), 1);
1165 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Room, &room_id),
1166 Some(AnyPushRuleRef::Room(rule)) => {
1167 assert_eq!(rule.rule_id, room_id);
1168 assert!(!rule.actions.is_empty());
1169 }
1170 );
1171 }
1172
1173 #[async_test]
1174 async fn test_set_default_room_notification_mode() {
1175 let server = MockServer::start().await;
1176 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1177 let client = logged_in_client(Some(server.uri())).await;
1178
1179 let mut ruleset = get_server_default_ruleset();
1181 ruleset
1182 .set_actions(
1183 RuleKind::Underride,
1184 PredefinedUnderrideRuleId::Message,
1185 vec![Action::Notify],
1186 )
1187 .unwrap();
1188
1189 ruleset
1190 .set_actions(
1191 RuleKind::Underride,
1192 PredefinedUnderrideRuleId::PollStart,
1193 vec![Action::Notify],
1194 )
1195 .unwrap();
1196
1197 let settings = NotificationSettings::new(client, ruleset);
1198 assert_eq!(
1199 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1200 RoomNotificationMode::AllMessages
1201 );
1202
1203 settings
1205 .set_default_room_notification_mode(
1206 IsEncrypted::No,
1207 IsOneToOne::No,
1208 RoomNotificationMode::MentionsAndKeywordsOnly,
1209 )
1210 .await
1211 .unwrap();
1212
1213 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::Message),
1215 Some(AnyPushRuleRef::Underride(rule)) => {
1216 assert!(rule.actions.is_empty());
1217 }
1218 );
1219
1220 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::PollStart),
1221 Some(AnyPushRuleRef::Underride(rule)) => {
1222 assert!(rule.actions.is_empty());
1223 }
1224 );
1225
1226 assert_matches!(
1229 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1230 RoomNotificationMode::MentionsAndKeywordsOnly
1231 );
1232 }
1233
1234 #[async_test]
1235 async fn test_set_default_room_notification_mode_one_to_one() {
1236 let server = MockServer::start().await;
1237 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1238 let client = logged_in_client(Some(server.uri())).await;
1239
1240 let mut ruleset = get_server_default_ruleset();
1242 ruleset
1243 .set_actions(
1244 RuleKind::Underride,
1245 PredefinedUnderrideRuleId::RoomOneToOne,
1246 vec![Action::Notify],
1247 )
1248 .unwrap();
1249
1250 ruleset
1251 .set_actions(
1252 RuleKind::Underride,
1253 PredefinedUnderrideRuleId::PollStartOneToOne,
1254 vec![Action::Notify],
1255 )
1256 .unwrap();
1257
1258 let settings = NotificationSettings::new(client, ruleset);
1259 assert_eq!(
1260 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
1261 RoomNotificationMode::AllMessages
1262 );
1263
1264 settings
1266 .set_default_room_notification_mode(
1267 IsEncrypted::No,
1268 IsOneToOne::Yes,
1269 RoomNotificationMode::MentionsAndKeywordsOnly,
1270 )
1271 .await
1272 .unwrap();
1273
1274 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne),
1276 Some(AnyPushRuleRef::Underride(rule)) => {
1277 assert!(rule.actions.is_empty());
1278 }
1279 );
1280
1281 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::PollStartOneToOne),
1282 Some(AnyPushRuleRef::Underride(rule)) => {
1283 assert!(rule.actions.is_empty());
1284 }
1285 );
1286
1287 assert_matches!(
1290 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
1291 RoomNotificationMode::MentionsAndKeywordsOnly
1292 );
1293 }
1294
1295 #[async_test]
1296 async fn test_set_default_room_notification_mode_enables_rules() {
1297 let server = MockServer::start().await;
1298 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1299 let client = logged_in_client(Some(server.uri())).await;
1300
1301 let mut ruleset = get_server_default_ruleset();
1303 ruleset
1304 .set_actions(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne, vec![])
1305 .unwrap();
1306
1307 ruleset
1308 .set_actions(RuleKind::Underride, PredefinedUnderrideRuleId::PollStartOneToOne, vec![])
1309 .unwrap();
1310
1311 ruleset
1313 .set_enabled(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne, false)
1314 .unwrap();
1315
1316 let settings = NotificationSettings::new(client, ruleset);
1317
1318 settings
1320 .set_default_room_notification_mode(
1321 IsEncrypted::No,
1322 IsOneToOne::Yes,
1323 RoomNotificationMode::AllMessages,
1324 )
1325 .await
1326 .unwrap();
1327
1328 assert_matches!(
1331 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
1332 RoomNotificationMode::AllMessages
1333 );
1334 }
1335
1336 #[async_test]
1337 async fn test_list_keywords() {
1338 let server = MockServer::start().await;
1339 let client = logged_in_client(Some(server.uri())).await;
1340
1341 let ruleset = get_server_default_ruleset();
1343 let settings = NotificationSettings::new(client.clone(), ruleset);
1344
1345 let keywords = settings.enabled_keywords().await;
1346
1347 assert!(keywords.is_empty());
1348
1349 let mut ruleset = get_server_default_ruleset();
1351 ruleset
1352 .insert(
1353 NewPushRule::Content(NewPatternedPushRule::new(
1354 "a".to_owned(),
1355 "a".to_owned(),
1356 vec![],
1357 )),
1358 None,
1359 None,
1360 )
1361 .unwrap();
1362 ruleset
1364 .insert(
1365 NewPushRule::Content(NewPatternedPushRule::new(
1366 "a_bis".to_owned(),
1367 "a".to_owned(),
1368 vec![],
1369 )),
1370 None,
1371 None,
1372 )
1373 .unwrap();
1374 ruleset
1375 .insert(
1376 NewPushRule::Content(NewPatternedPushRule::new(
1377 "b".to_owned(),
1378 "b".to_owned(),
1379 vec![],
1380 )),
1381 None,
1382 None,
1383 )
1384 .unwrap();
1385
1386 let settings = NotificationSettings::new(client, ruleset);
1387
1388 let keywords = settings.enabled_keywords().await;
1389 assert_eq!(keywords.len(), 2);
1390 assert!(keywords.get("a").is_some());
1391 assert!(keywords.get("b").is_some())
1392 }
1393
1394 #[async_test]
1395 async fn test_add_keyword_missing() {
1396 let server = MockServer::start().await;
1397 let client = logged_in_client(Some(server.uri())).await;
1398 let settings = client.notification_settings().await;
1399
1400 Mock::given(method("PUT"))
1401 .and(path("/_matrix/client/r0/pushrules/global/content/banana"))
1402 .respond_with(ResponseTemplate::new(200))
1403 .expect(1)
1404 .mount(&server)
1405 .await;
1406
1407 settings.add_keyword("banana".to_owned()).await.unwrap();
1408
1409 let keywords = settings.enabled_keywords().await;
1411 assert_eq!(keywords.len(), 1);
1412 assert!(keywords.get("banana").is_some());
1413
1414 let rule_enabled =
1416 settings.is_push_rule_enabled(RuleKind::Content, "banana").await.unwrap();
1417 assert!(rule_enabled)
1418 }
1419
1420 #[async_test]
1421 async fn test_add_keyword_disabled() {
1422 let server = MockServer::start().await;
1423 let client = logged_in_client(Some(server.uri())).await;
1424
1425 let mut ruleset = get_server_default_ruleset();
1426 ruleset
1427 .insert(
1428 NewPushRule::Content(NewPatternedPushRule::new(
1429 "banana_two".to_owned(),
1430 "banana".to_owned(),
1431 vec![],
1432 )),
1433 None,
1434 None,
1435 )
1436 .unwrap();
1437 ruleset.set_enabled(RuleKind::Content, "banana_two", false).unwrap();
1438 ruleset
1439 .insert(
1440 NewPushRule::Content(NewPatternedPushRule::new(
1441 "banana_one".to_owned(),
1442 "banana".to_owned(),
1443 vec![],
1444 )),
1445 None,
1446 None,
1447 )
1448 .unwrap();
1449 ruleset.set_enabled(RuleKind::Content, "banana_one", false).unwrap();
1450
1451 let settings = NotificationSettings::new(client, ruleset);
1452 Mock::given(method("PUT"))
1453 .and(path("/_matrix/client/r0/pushrules/global/content/banana_one/enabled"))
1454 .respond_with(ResponseTemplate::new(200))
1455 .expect(1)
1456 .mount(&server)
1457 .await;
1458
1459 settings.add_keyword("banana".to_owned()).await.unwrap();
1460
1461 let keywords = settings.enabled_keywords().await;
1463
1464 assert_eq!(keywords.len(), 1);
1465 assert!(keywords.get("banana").is_some());
1466
1467 let first_rule_enabled =
1469 settings.is_push_rule_enabled(RuleKind::Content, "banana_one").await.unwrap();
1470 assert!(first_rule_enabled);
1471 let second_rule_enabled =
1472 settings.is_push_rule_enabled(RuleKind::Content, "banana_two").await.unwrap();
1473 assert!(!second_rule_enabled);
1474 }
1475
1476 #[async_test]
1477 async fn test_add_keyword_noop() {
1478 let server = MockServer::start().await;
1479 let client = logged_in_client(Some(server.uri())).await;
1480
1481 let mut ruleset = get_server_default_ruleset();
1482 ruleset
1483 .insert(
1484 NewPushRule::Content(NewPatternedPushRule::new(
1485 "banana_two".to_owned(),
1486 "banana".to_owned(),
1487 vec![],
1488 )),
1489 None,
1490 None,
1491 )
1492 .unwrap();
1493 ruleset
1494 .insert(
1495 NewPushRule::Content(NewPatternedPushRule::new(
1496 "banana_one".to_owned(),
1497 "banana".to_owned(),
1498 vec![],
1499 )),
1500 None,
1501 None,
1502 )
1503 .unwrap();
1504 ruleset.set_enabled(RuleKind::Content, "banana_one", false).unwrap();
1505
1506 let settings = NotificationSettings::new(client, ruleset);
1507 settings.add_keyword("banana".to_owned()).await.unwrap();
1508
1509 let keywords = settings.enabled_keywords().await;
1511
1512 assert_eq!(keywords.len(), 1);
1513 assert!(keywords.get("banana").is_some());
1514
1515 let first_rule_enabled =
1516 settings.is_push_rule_enabled(RuleKind::Content, "banana_one").await.unwrap();
1517 assert!(!first_rule_enabled);
1518 let second_rule_enabled =
1519 settings.is_push_rule_enabled(RuleKind::Content, "banana_two").await.unwrap();
1520 assert!(second_rule_enabled);
1521 }
1522
1523 #[async_test]
1524 async fn test_remove_keyword_all() {
1525 let server = MockServer::start().await;
1526 let client = logged_in_client(Some(server.uri())).await;
1527
1528 let mut ruleset = get_server_default_ruleset();
1529 ruleset
1530 .insert(
1531 NewPushRule::Content(NewPatternedPushRule::new(
1532 "banana_two".to_owned(),
1533 "banana".to_owned(),
1534 vec![],
1535 )),
1536 None,
1537 None,
1538 )
1539 .unwrap();
1540 ruleset
1541 .insert(
1542 NewPushRule::Content(NewPatternedPushRule::new(
1543 "banana_one".to_owned(),
1544 "banana".to_owned(),
1545 vec![],
1546 )),
1547 None,
1548 None,
1549 )
1550 .unwrap();
1551 ruleset.set_enabled(RuleKind::Content, "banana_one", false).unwrap();
1552
1553 let settings = NotificationSettings::new(client, ruleset);
1554
1555 Mock::given(method("DELETE"))
1556 .and(path("/_matrix/client/r0/pushrules/global/content/banana_one"))
1557 .respond_with(ResponseTemplate::new(200))
1558 .expect(1)
1559 .mount(&server)
1560 .await;
1561 Mock::given(method("DELETE"))
1562 .and(path("/_matrix/client/r0/pushrules/global/content/banana_two"))
1563 .respond_with(ResponseTemplate::new(200))
1564 .expect(1)
1565 .mount(&server)
1566 .await;
1567
1568 settings.remove_keyword("banana").await.unwrap();
1569
1570 let keywords = settings.enabled_keywords().await;
1572 assert!(keywords.is_empty());
1573
1574 let first_rule_error =
1576 settings.is_push_rule_enabled(RuleKind::Content, "banana_one").await.unwrap_err();
1577 assert_matches!(first_rule_error, NotificationSettingsError::RuleNotFound(_));
1578 let second_rule_error =
1579 settings.is_push_rule_enabled(RuleKind::Content, "banana_two").await.unwrap_err();
1580 assert_matches!(second_rule_error, NotificationSettingsError::RuleNotFound(_));
1581 }
1582
1583 #[async_test]
1584 async fn test_remove_keyword_noop() {
1585 let server = MockServer::start().await;
1586 let client = logged_in_client(Some(server.uri())).await;
1587 let settings = client.notification_settings().await;
1588
1589 settings.remove_keyword("banana").await.unwrap();
1590 }
1591
1592 #[async_test]
1593 async fn test_set_default_room_notification_mode_missing_poll_start() {
1594 let server = MockServer::start().await;
1595 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1596 let client = logged_in_client(Some(server.uri())).await;
1597
1598 let mut ruleset = get_server_default_ruleset();
1600 ruleset.underride.swap_remove(PredefinedUnderrideRuleId::PollStart.as_str());
1601
1602 let settings = NotificationSettings::new(client, ruleset);
1603 assert_eq!(
1604 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1605 RoomNotificationMode::AllMessages
1606 );
1607
1608 settings
1610 .set_default_room_notification_mode(
1611 IsEncrypted::No,
1612 IsOneToOne::No,
1613 RoomNotificationMode::MentionsAndKeywordsOnly,
1614 )
1615 .await
1616 .unwrap();
1617
1618 assert_matches!(
1621 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1622 RoomNotificationMode::MentionsAndKeywordsOnly
1623 );
1624 }
1625
1626 #[async_test]
1627 async fn test_create_custom_conditional_push_rule() {
1628 let server = MockServer::start().await;
1629 let client = logged_in_client(Some(server.uri())).await;
1630 let settings = client.notification_settings().await;
1631
1632 Mock::given(method("PUT"))
1633 .and(path("/_matrix/client/r0/pushrules/global/override/custom_rule"))
1634 .respond_with(ResponseTemplate::new(200))
1635 .expect(1)
1636 .mount(&server)
1637 .await;
1638
1639 let actions = vec![Action::Notify];
1640 let conditions = vec![ruma::push::PushCondition::EventMatch {
1641 key: "content.body".to_owned(),
1642 pattern: "hello".to_owned(),
1643 }];
1644
1645 settings
1646 .create_custom_conditional_push_rule(
1647 "custom_rule".to_owned(),
1648 RuleKind::Override,
1649 actions.clone(),
1650 conditions.clone(),
1651 )
1652 .await
1653 .unwrap();
1654
1655 let rules = settings.rules.read().await;
1656 let rule = rules.ruleset.get(RuleKind::Override, "custom_rule").unwrap();
1657
1658 assert_eq!(rule.rule_id(), "custom_rule");
1659 assert!(rule.enabled());
1660 }
1661
1662 #[async_test]
1663 async fn test_create_custom_conditional_push_rule_invalid_kind() {
1664 let server = MockServer::start().await;
1665 let client = logged_in_client(Some(server.uri())).await;
1666 let settings = client.notification_settings().await;
1667
1668 let actions = vec![Action::Notify];
1669 let conditions = vec![ruma::push::PushCondition::EventMatch {
1670 key: "content.body".to_owned(),
1671 pattern: "hello".to_owned(),
1672 }];
1673
1674 let result = settings
1675 .create_custom_conditional_push_rule(
1676 "custom_rule".to_owned(),
1677 RuleKind::Room,
1678 actions,
1679 conditions,
1680 )
1681 .await;
1682
1683 assert_matches!(result, Err(NotificationSettingsError::InvalidParameter(_)));
1684 }
1685}