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