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<()>,
97}
98
99impl NotificationSettings {
100 pub(crate) fn new(client: Client, ruleset: Ruleset) -> Self {
107 let changes_sender = broadcast::Sender::new(100);
108 let rules = Arc::new(RwLock::new(Rules::new(ruleset)));
109
110 let push_rules_event_handler_handle = client.add_event_handler({
112 let changes_sender = changes_sender.clone();
113 let rules = rules.clone();
114 move |ev: PushRulesEvent| async move {
115 *rules.write().await = Rules::new(ev.content.global);
116 let _ = changes_sender.send(());
117 }
118 });
119
120 let _push_rules_event_handler_guard =
121 Arc::new(client.event_handler_drop_guard(push_rules_event_handler_handle));
122
123 Self { client, rules, _push_rules_event_handler_guard, changes_sender }
124 }
125
126 pub fn subscribe_to_changes(&self) -> Receiver<()> {
131 self.changes_sender.subscribe()
132 }
133
134 pub async fn get_user_defined_room_notification_mode(
136 &self,
137 room_id: &RoomId,
138 ) -> Option<RoomNotificationMode> {
139 self.rules.read().await.get_user_defined_room_notification_mode(room_id)
140 }
141
142 pub async fn get_default_room_notification_mode(
150 &self,
151 is_encrypted: IsEncrypted,
152 is_one_to_one: IsOneToOne,
153 ) -> RoomNotificationMode {
154 self.rules.read().await.get_default_room_notification_mode(is_encrypted, is_one_to_one)
155 }
156
157 pub async fn get_rooms_with_user_defined_rules(&self, enabled: Option<bool>) -> Vec<String> {
159 self.rules.read().await.get_rooms_with_user_defined_rules(enabled)
160 }
161
162 pub async fn contains_keyword_rules(&self) -> bool {
164 self.rules.read().await.contains_keyword_rules()
165 }
166
167 pub async fn is_push_rule_enabled(
169 &self,
170 kind: RuleKind,
171 rule_id: impl AsRef<str>,
172 ) -> Result<bool, NotificationSettingsError> {
173 self.rules.read().await.is_enabled(kind, rule_id.as_ref())
174 }
175
176 pub async fn set_push_rule_enabled(
178 &self,
179 kind: RuleKind,
180 rule_id: impl AsRef<str>,
181 enabled: bool,
182 ) -> Result<(), NotificationSettingsError> {
183 let rules = self.rules.read().await.clone();
184
185 let mut rule_commands = RuleCommands::new(rules.ruleset);
186 rule_commands.set_rule_enabled(kind, rule_id.as_ref(), enabled)?;
187
188 self.run_server_commands(&rule_commands).await?;
189
190 let rules = &mut *self.rules.write().await;
191 rules.apply(rule_commands);
192
193 Ok(())
194 }
195
196 pub async fn set_default_room_notification_mode(
205 &self,
206 is_encrypted: IsEncrypted,
207 is_one_to_one: IsOneToOne,
208 mode: RoomNotificationMode,
209 ) -> Result<(), NotificationSettingsError> {
210 let actions = match mode {
211 RoomNotificationMode::AllMessages => {
212 vec![Action::Notify, Action::SetTweak(Tweak::Sound("default".into()))]
213 }
214 _ => {
215 vec![]
216 }
217 };
218
219 let room_rule_id =
220 rules::get_predefined_underride_room_rule_id(is_encrypted, is_one_to_one);
221 self.set_underride_push_rule_actions(room_rule_id, actions.clone()).await?;
222
223 let poll_start_rule_id = rules::get_predefined_underride_poll_start_rule_id(is_one_to_one);
224 if let Err(error) =
225 self.set_underride_push_rule_actions(poll_start_rule_id, actions.clone()).await
226 {
227 if let NotificationSettingsError::RuleNotFound(rule_id) = &error {
230 debug!("Unable to update poll start push rule: rule `{rule_id}` not found");
231 } else {
232 return Err(error);
233 }
234 }
235
236 Ok(())
237 }
238
239 pub async fn set_underride_push_rule_actions(
250 &self,
251 rule_id: PredefinedUnderrideRuleId,
252 actions: Vec<Action>,
253 ) -> Result<(), NotificationSettingsError> {
254 let rules = self.rules.read().await.clone();
255 let rule_kind = RuleKind::Underride;
256 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
257
258 rule_commands.set_rule_actions(rule_kind.clone(), rule_id.as_str(), actions)?;
259
260 if !rules.is_enabled(rule_kind.clone(), rule_id.as_str())? {
261 rule_commands.set_rule_enabled(rule_kind, rule_id.as_str(), true)?
262 }
263
264 self.run_server_commands(&rule_commands).await?;
265
266 let rules = &mut *self.rules.write().await;
267 rules.apply(rule_commands);
268
269 Ok(())
270 }
271
272 pub async fn create_custom_conditional_push_rule(
283 &self,
284 rule_id: String,
285 rule_kind: RuleKind,
286 actions: Vec<Action>,
287 conditions: Vec<ruma::push::PushCondition>,
288 ) -> Result<(), NotificationSettingsError> {
289 let new_conditional_rule =
290 ruma::push::NewConditionalPushRule::new(rule_id, conditions, actions);
291
292 let new_push_rule = match rule_kind {
293 RuleKind::Override => NewPushRule::Override(new_conditional_rule),
294 RuleKind::Underride => NewPushRule::Underride(new_conditional_rule),
295 _ => return Err(NotificationSettingsError::InvalidParameter("rule_kind".to_owned())),
296 };
297
298 let rules = self.rules.read().await.clone();
299 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
300 rule_commands.insert_custom_rule(new_push_rule)?;
301
302 self.run_server_commands(&rule_commands).await?;
303
304 let rules = &mut *self.rules.write().await;
305 rules.apply(rule_commands);
306
307 Ok(())
308 }
309
310 pub async fn set_room_notification_mode(
312 &self,
313 room_id: &RoomId,
314 mode: RoomNotificationMode,
315 ) -> Result<(), NotificationSettingsError> {
316 let rules = self.rules.read().await.clone();
317
318 if rules.get_user_defined_room_notification_mode(room_id) == Some(mode) {
320 return Ok(());
321 }
322
323 let (new_rule_kind, notify) = match mode {
325 RoomNotificationMode::AllMessages => {
326 (RuleKind::Room, true)
328 }
329 RoomNotificationMode::MentionsAndKeywordsOnly => {
330 (RuleKind::Room, false)
332 }
333 RoomNotificationMode::Mute => {
334 (RuleKind::Override, false)
336 }
337 };
338
339 let new_rule_id = room_id.as_str();
341 let custom_rules: Vec<(RuleKind, String)> = rules
342 .get_custom_rules_for_room(room_id)
343 .into_iter()
344 .filter(|(kind, rule_id)| kind != &new_rule_kind || rule_id != new_rule_id)
345 .collect();
346
347 let mut rule_commands = RuleCommands::new(rules.ruleset);
350 rule_commands.insert_rule(new_rule_kind.clone(), room_id, notify)?;
351 for (kind, rule_id) in custom_rules {
352 rule_commands.delete_rule(kind, rule_id)?;
353 }
354
355 self.run_server_commands(&rule_commands).await?;
356
357 let rules = &mut *self.rules.write().await;
358 rules.apply(rule_commands);
359
360 Ok(())
361 }
362
363 pub async fn delete_user_defined_room_rules(
365 &self,
366 room_id: &RoomId,
367 ) -> Result<(), NotificationSettingsError> {
368 let rules = self.rules.read().await.clone();
369
370 let custom_rules = rules.get_custom_rules_for_room(room_id);
371 if custom_rules.is_empty() {
372 return Ok(());
373 }
374
375 let mut rule_commands = RuleCommands::new(rules.ruleset);
376 for (kind, rule_id) in custom_rules {
377 rule_commands.delete_rule(kind, rule_id)?;
378 }
379
380 self.run_server_commands(&rule_commands).await?;
381
382 let rules = &mut *self.rules.write().await;
383 rules.apply(rule_commands);
384
385 Ok(())
386 }
387
388 pub async fn unmute_room(
390 &self,
391 room_id: &RoomId,
392 is_encrypted: IsEncrypted,
393 is_one_to_one: IsOneToOne,
394 ) -> Result<(), NotificationSettingsError> {
395 let rules = self.rules.read().await.clone();
396
397 if let Some(room_mode) = rules.get_user_defined_room_notification_mode(room_id) {
399 if room_mode != RoomNotificationMode::Mute {
400 return Ok(());
402 }
403
404 let default_mode =
406 rules.get_default_room_notification_mode(is_encrypted, is_one_to_one);
407
408 if default_mode == RoomNotificationMode::Mute {
410 self.set_room_notification_mode(room_id, RoomNotificationMode::AllMessages).await
411 } else {
412 self.delete_user_defined_room_rules(room_id).await
414 }
415 } else {
416 self.set_room_notification_mode(room_id, RoomNotificationMode::AllMessages).await
419 }
420 }
421
422 pub async fn enabled_keywords(&self) -> IndexSet<String> {
424 self.rules.read().await.enabled_keywords()
425 }
426
427 pub async fn add_keyword(&self, keyword: String) -> Result<(), NotificationSettingsError> {
433 let rules = self.rules.read().await.clone();
434
435 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
436
437 let existing_rules = rules.keyword_rules(&keyword);
438
439 if existing_rules.is_empty() {
440 rule_commands.insert_keyword_rule(keyword)?;
442 } else {
443 if existing_rules.iter().any(|r| r.enabled) {
444 return Ok(());
446 }
447
448 rule_commands.set_rule_enabled(RuleKind::Content, &existing_rules[0].rule_id, true)?;
450 }
451
452 self.run_server_commands(&rule_commands).await?;
453
454 let rules = &mut *self.rules.write().await;
455 rules.apply(rule_commands);
456
457 Ok(())
458 }
459
460 pub async fn remove_keyword(&self, keyword: &str) -> Result<(), NotificationSettingsError> {
466 let rules = self.rules.read().await.clone();
467
468 let mut rule_commands = RuleCommands::new(rules.clone().ruleset);
469
470 let existing_rules = rules.keyword_rules(keyword);
471
472 if existing_rules.is_empty() {
473 return Ok(());
474 }
475
476 for rule in existing_rules {
477 rule_commands.delete_rule(RuleKind::Content, rule.rule_id.clone())?;
478 }
479
480 self.run_server_commands(&rule_commands).await?;
481
482 let rules = &mut *self.rules.write().await;
483 rules.apply(rule_commands);
484
485 Ok(())
486 }
487
488 async fn run_server_commands(
490 &self,
491 rule_commands: &RuleCommands,
492 ) -> Result<(), NotificationSettingsError> {
493 let request_config = Some(RequestConfig::short_retry());
494 for command in &rule_commands.commands {
495 match command {
496 Command::DeletePushRule { kind, rule_id } => {
497 let request = delete_pushrule::v3::Request::new(kind.clone(), rule_id.clone());
498 self.client.send(request).with_request_config(request_config).await.map_err(
499 |error| {
500 error!("Unable to delete {kind} push rule `{rule_id}`: {error}");
501 NotificationSettingsError::UnableToRemovePushRule
502 },
503 )?;
504 }
505 Command::SetRoomPushRule { room_id, notify: _ } => {
506 let push_rule = command.to_push_rule()?;
507 let request = set_pushrule::v3::Request::new(push_rule);
508 self.client.send(request).with_request_config(request_config).await.map_err(
509 |error| {
510 error!("Unable to set room push rule `{room_id}`: {error}");
511 NotificationSettingsError::UnableToAddPushRule
512 },
513 )?;
514 }
515 Command::SetOverridePushRule { rule_id, room_id: _, notify: _ } => {
516 let push_rule = command.to_push_rule()?;
517 let request = set_pushrule::v3::Request::new(push_rule);
518 self.client.send(request).with_request_config(request_config).await.map_err(
519 |error| {
520 error!("Unable to set override push rule `{rule_id}`: {error}");
521 NotificationSettingsError::UnableToAddPushRule
522 },
523 )?;
524 }
525 Command::SetKeywordPushRule { keyword: _ } => {
526 let push_rule = command.to_push_rule()?;
527 let request = set_pushrule::v3::Request::new(push_rule);
528 self.client
529 .send(request)
530 .with_request_config(request_config)
531 .await
532 .map_err(|_| NotificationSettingsError::UnableToAddPushRule)?;
533 }
534 Command::SetPushRuleEnabled { kind, rule_id, enabled } => {
535 let request = set_pushrule_enabled::v3::Request::new(
536 kind.clone(),
537 rule_id.clone(),
538 *enabled,
539 );
540 self.client.send(request).with_request_config(request_config).await.map_err(
541 |error| {
542 error!("Unable to set {kind} push rule `{rule_id}` enabled: {error}");
543 NotificationSettingsError::UnableToUpdatePushRule
544 },
545 )?;
546 }
547 Command::SetPushRuleActions { kind, rule_id, actions } => {
548 let request = set_pushrule_actions::v3::Request::new(
549 kind.clone(),
550 rule_id.clone(),
551 actions.clone(),
552 );
553 self.client.send(request).with_request_config(request_config).await.map_err(
554 |error| {
555 error!("Unable to set {kind} push rule `{rule_id}` actions: {error}");
556 NotificationSettingsError::UnableToUpdatePushRule
557 },
558 )?;
559 }
560 Command::SetCustomPushRule { rule } => {
561 let request = set_pushrule::v3::Request::new(rule.clone());
562
563 self.client.send(request).with_request_config(request_config).await.map_err(
564 |error| {
565 error!("Unable to set custom push rule `{rule:#?}`: {error}");
566 NotificationSettingsError::UnableToAddPushRule
567 },
568 )?;
569 }
570 }
571 }
572 Ok(())
573 }
574
575 pub async fn ruleset(&self) -> Ruleset {
578 self.rules.read().await.ruleset.clone()
579 }
580}
581
582#[cfg(all(test, not(target_family = "wasm")))]
584mod tests {
585 use std::sync::{
586 atomic::{AtomicBool, Ordering},
587 Arc,
588 };
589
590 use assert_matches::assert_matches;
591 use matrix_sdk_test::{
592 async_test,
593 event_factory::EventFactory,
594 notification_settings::{build_ruleset, get_server_default_ruleset},
595 TestResult,
596 };
597 use ruma::{
598 owned_room_id,
599 push::{
600 Action, AnyPushRuleRef, NewPatternedPushRule, NewPushRule, PredefinedContentRuleId,
601 PredefinedOverrideRuleId, PredefinedUnderrideRuleId, RuleKind, Ruleset,
602 },
603 OwnedRoomId, RoomId,
604 };
605 use stream_assert::{assert_next_eq, assert_pending};
606 use tokio_stream::wrappers::BroadcastStream;
607 use wiremock::{
608 matchers::{method, path, path_regex},
609 Mock, MockServer, ResponseTemplate,
610 };
611
612 use crate::{
613 error::NotificationSettingsError,
614 notification_settings::{
615 IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode,
616 },
617 test_utils::{logged_in_client, mocks::MatrixMockServer},
618 Client,
619 };
620
621 fn get_test_room_id() -> OwnedRoomId {
622 owned_room_id!("!AAAaAAAAAaaAAaaaaa:matrix.org")
623 }
624
625 fn from_insert_rules(
626 client: &Client,
627 rules: Vec<(RuleKind, &RoomId, bool)>,
628 ) -> NotificationSettings {
629 let ruleset = build_ruleset(rules);
630 NotificationSettings::new(client.to_owned(), ruleset)
631 }
632
633 async fn get_custom_rules_for_room(
634 settings: &NotificationSettings,
635 room_id: &RoomId,
636 ) -> Vec<(RuleKind, String)> {
637 settings.rules.read().await.get_custom_rules_for_room(room_id)
638 }
639
640 #[async_test]
641 async fn test_subscribe_to_changes() -> TestResult {
642 let server = MatrixMockServer::new().await;
643 let client = server.client_builder().build().await;
644 let settings = client.notification_settings().await;
645
646 let subscriber = settings.subscribe_to_changes();
647 let mut stream = BroadcastStream::new(subscriber);
648
649 assert_pending!(stream);
650
651 server
652 .mock_sync()
653 .ok_and_run(&client, |sync_response_builder| {
654 let f = EventFactory::new();
655 sync_response_builder.add_global_account_data(
656 f.push_rules(Ruleset::server_default(client.user_id().unwrap())),
657 );
658 })
659 .await;
660
661 assert_next_eq!(stream, Ok(()));
662 assert_pending!(stream);
663
664 Ok(())
665 }
666
667 #[async_test]
668 async fn test_get_custom_rules_for_room() {
669 let server = MockServer::start().await;
670 let client = logged_in_client(Some(server.uri())).await;
671 let room_id = get_test_room_id();
672
673 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
674
675 let custom_rules = get_custom_rules_for_room(&settings, &room_id).await;
676 assert_eq!(custom_rules.len(), 1);
677 assert_eq!(custom_rules[0], (RuleKind::Room, room_id.to_string()));
678
679 let settings = from_insert_rules(
680 &client,
681 vec![(RuleKind::Room, &room_id, true), (RuleKind::Override, &room_id, true)],
682 );
683 let custom_rules = get_custom_rules_for_room(&settings, &room_id).await;
684 assert_eq!(custom_rules.len(), 2);
685 assert_eq!(custom_rules[0], (RuleKind::Override, room_id.to_string()));
686 assert_eq!(custom_rules[1], (RuleKind::Room, room_id.to_string()));
687 }
688
689 #[async_test]
690 async fn test_get_user_defined_room_notification_mode_none() {
691 let server = MockServer::start().await;
692 let client = logged_in_client(Some(server.uri())).await;
693 let room_id = get_test_room_id();
694
695 let settings = client.notification_settings().await;
696 assert!(settings.get_user_defined_room_notification_mode(&room_id).await.is_none());
697 }
698
699 #[async_test]
700 async fn test_get_user_defined_room_notification_mode_all_messages() {
701 let server = MockServer::start().await;
702 let client = logged_in_client(Some(server.uri())).await;
703 let room_id = get_test_room_id();
704
705 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
707
708 assert_eq!(
709 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
710 RoomNotificationMode::AllMessages
711 );
712 }
713
714 #[async_test]
715 async fn test_get_user_defined_room_notification_mode_mentions_and_keywords() {
716 let server = MockServer::start().await;
717 let client = logged_in_client(Some(server.uri())).await;
718 let room_id = get_test_room_id();
719
720 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, false)]);
722 assert_eq!(
723 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
724 RoomNotificationMode::MentionsAndKeywordsOnly
725 );
726 }
727
728 #[async_test]
729 async fn test_get_user_defined_room_notification_mode_mute() {
730 let server = MockServer::start().await;
731 let client = logged_in_client(Some(server.uri())).await;
732 let room_id = get_test_room_id();
733
734 let settings = from_insert_rules(&client, vec![(RuleKind::Override, &room_id, false)]);
736 assert_eq!(
737 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
738 RoomNotificationMode::Mute
739 );
740 }
741
742 #[async_test]
743 async fn test_get_default_room_notification_mode_all_messages() -> TestResult {
744 let server = MockServer::start().await;
745 let client = logged_in_client(Some(server.uri())).await;
746
747 let mut ruleset = get_server_default_ruleset();
748 ruleset.set_actions(
749 RuleKind::Underride,
750 PredefinedUnderrideRuleId::RoomOneToOne,
751 vec![Action::Notify],
752 )?;
753
754 let settings = NotificationSettings::new(client, ruleset);
755 assert_eq!(
756 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
757 RoomNotificationMode::AllMessages
758 );
759
760 Ok(())
761 }
762
763 #[async_test]
764 async fn test_get_default_room_notification_mode_mentions_and_keywords() -> TestResult {
765 let server = MockServer::start().await;
766 let client = logged_in_client(Some(server.uri())).await;
767
768 let mut ruleset = get_server_default_ruleset();
771 ruleset.set_actions(
772 RuleKind::Underride,
773 PredefinedUnderrideRuleId::RoomOneToOne,
774 vec![],
775 )?;
776
777 let settings = NotificationSettings::new(client.to_owned(), ruleset.to_owned());
778 assert_eq!(
779 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
780 RoomNotificationMode::MentionsAndKeywordsOnly
781 );
782
783 ruleset.set_enabled(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne, false)?;
786
787 let settings = NotificationSettings::new(client, ruleset);
788 assert_eq!(
789 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
790 RoomNotificationMode::MentionsAndKeywordsOnly
791 );
792
793 Ok(())
794 }
795
796 #[async_test]
797 async fn test_contains_keyword_rules() -> TestResult {
798 let server = MockServer::start().await;
799 let client = logged_in_client(Some(server.uri())).await;
800
801 let mut ruleset = get_server_default_ruleset();
802 let settings = NotificationSettings::new(client.to_owned(), ruleset.to_owned());
803
804 let contains_keywords_rules = settings.contains_keyword_rules().await;
806 assert!(!contains_keywords_rules);
807
808 let rule = NewPatternedPushRule::new(
810 "keyword_rule_id".into(),
811 "keyword".into(),
812 vec![Action::Notify],
813 );
814 ruleset.insert(NewPushRule::Content(rule), None, None)?;
815
816 let settings = NotificationSettings::new(client, ruleset);
817 let contains_keywords_rules = settings.contains_keyword_rules().await;
818 assert!(contains_keywords_rules);
819
820 Ok(())
821 }
822
823 #[async_test]
824 async fn test_is_push_rule_enabled() -> TestResult {
825 let server = MockServer::start().await;
826 let client = logged_in_client(Some(server.uri())).await;
827
828 let mut ruleset = get_server_default_ruleset();
830 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, false)?;
831
832 let settings = NotificationSettings::new(client.clone(), ruleset);
833
834 let enabled = settings
835 .is_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction)
836 .await?;
837
838 assert!(!enabled);
839
840 let mut ruleset = get_server_default_ruleset();
842 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, true)?;
843
844 let settings = NotificationSettings::new(client, ruleset);
845
846 let enabled = settings
847 .is_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction)
848 .await?;
849
850 assert!(enabled);
851 Ok(())
852 }
853
854 #[async_test]
855 async fn test_set_push_rule_enabled() -> TestResult {
856 let server = MockServer::start().await;
857 let client = logged_in_client(Some(server.uri())).await;
858 let mut ruleset = client.account().push_rules().await?;
859 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, false)?;
861
862 let settings = NotificationSettings::new(client, ruleset);
863
864 Mock::given(method("PUT"))
865 .and(path("/_matrix/client/r0/pushrules/global/override/.m.rule.reaction/enabled"))
866 .respond_with(ResponseTemplate::new(200))
867 .expect(1)
868 .mount(&server)
869 .await;
870
871 settings
872 .set_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::Reaction, true)
873 .await?;
874
875 let rules = settings.rules.read().await;
877 let rule =
878 rules.ruleset.get(RuleKind::Override, PredefinedOverrideRuleId::Reaction).unwrap();
879 assert!(rule.enabled());
880
881 server.verify().await;
882 Ok(())
883 }
884
885 #[async_test]
886 async fn test_set_push_rule_enabled_api_error() -> TestResult {
887 let server = MockServer::start().await;
888 let client = logged_in_client(Some(server.uri())).await;
889 let mut ruleset = client.account().push_rules().await?;
890 ruleset.set_enabled(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention, false)?;
892
893 let settings = NotificationSettings::new(client, ruleset);
894
895 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(500)).mount(&server).await;
897
898 assert_eq!(
900 settings
901 .set_push_rule_enabled(
902 RuleKind::Override,
903 PredefinedOverrideRuleId::IsUserMention,
904 true,
905 )
906 .await,
907 Err(NotificationSettingsError::UnableToUpdatePushRule)
908 );
909
910 let rules = settings.rules.read().await;
912 let rule =
913 rules.ruleset.get(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention).unwrap();
914 assert!(!rule.enabled());
915
916 Ok(())
917 }
918
919 #[async_test]
920 async fn test_set_room_notification_mode() -> TestResult {
921 let server = MockServer::start().await;
922 let client = logged_in_client(Some(server.uri())).await;
923
924 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
925 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
926
927 let settings = client.notification_settings().await;
928 let room_id = get_test_room_id();
929
930 let mode = settings.get_user_defined_room_notification_mode(&room_id).await;
931 assert!(mode.is_none());
932
933 let new_modes = [
934 RoomNotificationMode::AllMessages,
935 RoomNotificationMode::MentionsAndKeywordsOnly,
936 RoomNotificationMode::Mute,
937 ];
938 for new_mode in new_modes {
939 settings.set_room_notification_mode(&room_id, new_mode).await?;
940 assert_eq!(
941 new_mode,
942 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap()
943 );
944 }
945
946 Ok(())
947 }
948
949 #[async_test]
950 async fn test_set_room_notification_mode_requests_order() -> TestResult {
951 let server = MockServer::start().await;
952 let client = logged_in_client(Some(server.uri())).await;
953
954 let put_was_called = Arc::new(AtomicBool::default());
955
956 Mock::given(method("PUT"))
957 .and(path_regex(r"_matrix/client/r0/pushrules/global/override/.*"))
958 .and({
959 let put_was_called = put_was_called.clone();
960 move |_: &wiremock::Request| {
961 put_was_called.store(true, Ordering::SeqCst);
962
963 true
964 }
965 })
966 .respond_with(ResponseTemplate::new(200))
967 .expect(1)
968 .mount(&server)
969 .await;
970
971 Mock::given(method("DELETE"))
972 .and(path_regex(r"_matrix/client/r0/pushrules/global/room/.*"))
973 .and(move |_: &wiremock::Request| {
974 let put_was_called = put_was_called.load(Ordering::SeqCst);
981 assert!(
982 put_was_called,
983 "The PUT /pushrules/global/override/ method should have been called before the \
984 DELETE method"
985 );
986
987 true
988 })
989 .respond_with(ResponseTemplate::new(200))
990 .expect(1)
991 .mount(&server)
992 .await;
993
994 let room_id = get_test_room_id();
995
996 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
998
999 settings.set_room_notification_mode(&room_id, RoomNotificationMode::Mute).await?;
1002
1003 assert_eq!(
1004 RoomNotificationMode::Mute,
1005 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap()
1006 );
1007
1008 server.verify().await;
1009 Ok(())
1010 }
1011
1012 #[async_test]
1013 async fn test_set_room_notification_mode_put_api_error() {
1014 let server = MockServer::start().await;
1015 let client = logged_in_client(Some(server.uri())).await;
1016
1017 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(500)).mount(&server).await;
1019 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1020
1021 let room_id = get_test_room_id();
1022
1023 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
1025
1026 assert_eq!(
1027 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1028 RoomNotificationMode::AllMessages
1029 );
1030
1031 assert_eq!(
1033 settings.set_room_notification_mode(&room_id, RoomNotificationMode::Mute).await,
1034 Err(NotificationSettingsError::UnableToAddPushRule)
1035 );
1036
1037 assert_eq!(
1039 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1040 RoomNotificationMode::AllMessages
1041 );
1042 }
1043
1044 #[async_test]
1045 async fn test_set_room_notification_mode_delete_api_error() {
1046 let server = MockServer::start().await;
1047 let client = logged_in_client(Some(server.uri())).await;
1048
1049 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1051 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(500)).mount(&server).await;
1052
1053 let room_id = get_test_room_id();
1054
1055 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, true)]);
1057
1058 assert_eq!(
1059 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1060 RoomNotificationMode::AllMessages
1061 );
1062
1063 assert_eq!(
1065 settings.set_room_notification_mode(&room_id, RoomNotificationMode::Mute).await,
1066 Err(NotificationSettingsError::UnableToRemovePushRule)
1067 );
1068
1069 assert_eq!(
1071 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1072 RoomNotificationMode::AllMessages
1073 );
1074 }
1075
1076 #[async_test]
1077 async fn test_delete_user_defined_room_rules() -> TestResult {
1078 let server = MockServer::start().await;
1079 let client = logged_in_client(Some(server.uri())).await;
1080 let room_id_a = owned_room_id!("!AAAaAAAAAaaAAaaaaa:matrix.org");
1081 let room_id_b = owned_room_id!("!BBBbBBBBBbbBBbbbbb:matrix.org");
1082
1083 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1084
1085 let settings = from_insert_rules(
1087 &client,
1088 vec![
1089 (RuleKind::Room, &room_id_a, true),
1090 (RuleKind::Room, &room_id_b, true),
1091 (RuleKind::Override, &room_id_b, true),
1092 ],
1093 );
1094
1095 settings.delete_user_defined_room_rules(&room_id_a).await?;
1097
1098 let updated_rules = settings.rules.read().await;
1100 assert_eq!(updated_rules.get_custom_rules_for_room(&room_id_b).len(), 2);
1101 assert!(updated_rules.get_custom_rules_for_room(&room_id_a).is_empty());
1102 Ok(())
1103 }
1104
1105 #[async_test]
1106 async fn test_unmute_room_not_muted() -> TestResult {
1107 let server = MockServer::start().await;
1108 let client = logged_in_client(Some(server.uri())).await;
1109 let room_id = get_test_room_id();
1110
1111 let settings = from_insert_rules(&client, vec![(RuleKind::Room, &room_id, false)]);
1113 assert_eq!(
1114 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1115 RoomNotificationMode::MentionsAndKeywordsOnly
1116 );
1117
1118 settings.unmute_room(&room_id, IsEncrypted::Yes, IsOneToOne::Yes).await?;
1120
1121 assert_eq!(
1123 settings.get_user_defined_room_notification_mode(&room_id).await.unwrap(),
1124 RoomNotificationMode::MentionsAndKeywordsOnly
1125 );
1126
1127 let room_rules = get_custom_rules_for_room(&settings, &room_id).await;
1128 assert_eq!(room_rules.len(), 1);
1129 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Room, &room_id),
1130 Some(AnyPushRuleRef::Room(rule)) => {
1131 assert_eq!(rule.rule_id, room_id);
1132 assert!(rule.actions.is_empty());
1133 }
1134 );
1135
1136 Ok(())
1137 }
1138
1139 #[async_test]
1140 async fn test_unmute_room() -> TestResult {
1141 let server = MockServer::start().await;
1142 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1143 Mock::given(method("DELETE")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1144 let client = logged_in_client(Some(server.uri())).await;
1145 let room_id = get_test_room_id();
1146
1147 let settings = from_insert_rules(&client, vec![(RuleKind::Override, &room_id, false)]);
1149 assert_eq!(
1150 settings.get_user_defined_room_notification_mode(&room_id).await,
1151 Some(RoomNotificationMode::Mute)
1152 );
1153
1154 settings.unmute_room(&room_id, IsEncrypted::No, IsOneToOne::Yes).await?;
1156
1157 assert!(settings.get_user_defined_room_notification_mode(&room_id).await.is_none());
1159
1160 Ok(())
1161 }
1162
1163 #[async_test]
1164 async fn test_unmute_room_default_mode() -> TestResult {
1165 let server = MockServer::start().await;
1166 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1167 let client = logged_in_client(Some(server.uri())).await;
1168 let room_id = get_test_room_id();
1169 let settings = client.notification_settings().await;
1170
1171 settings.unmute_room(&room_id, IsEncrypted::No, IsOneToOne::Yes).await?;
1173
1174 assert_eq!(
1176 Some(RoomNotificationMode::AllMessages),
1177 settings.get_user_defined_room_notification_mode(&room_id).await
1178 );
1179
1180 let room_rules = get_custom_rules_for_room(&settings, &room_id).await;
1181 assert_eq!(room_rules.len(), 1);
1182 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Room, &room_id),
1183 Some(AnyPushRuleRef::Room(rule)) => {
1184 assert_eq!(rule.rule_id, room_id);
1185 assert!(!rule.actions.is_empty());
1186 }
1187 );
1188
1189 Ok(())
1190 }
1191
1192 #[async_test]
1193 async fn test_set_default_room_notification_mode() -> TestResult {
1194 let server = MockServer::start().await;
1195 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1196 let client = logged_in_client(Some(server.uri())).await;
1197
1198 let mut ruleset = get_server_default_ruleset();
1200 ruleset.set_actions(
1201 RuleKind::Underride,
1202 PredefinedUnderrideRuleId::Message,
1203 vec![Action::Notify],
1204 )?;
1205
1206 ruleset.set_actions(
1207 RuleKind::Underride,
1208 PredefinedUnderrideRuleId::PollStart,
1209 vec![Action::Notify],
1210 )?;
1211
1212 let settings = NotificationSettings::new(client, ruleset);
1213 assert_eq!(
1214 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1215 RoomNotificationMode::AllMessages
1216 );
1217
1218 settings
1220 .set_default_room_notification_mode(
1221 IsEncrypted::No,
1222 IsOneToOne::No,
1223 RoomNotificationMode::MentionsAndKeywordsOnly,
1224 )
1225 .await?;
1226
1227 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::Message),
1229 Some(AnyPushRuleRef::Underride(rule)) => {
1230 assert!(rule.actions.is_empty());
1231 }
1232 );
1233
1234 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::PollStart),
1235 Some(AnyPushRuleRef::Underride(rule)) => {
1236 assert!(rule.actions.is_empty());
1237 }
1238 );
1239
1240 assert_matches!(
1243 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1244 RoomNotificationMode::MentionsAndKeywordsOnly
1245 );
1246
1247 Ok(())
1248 }
1249
1250 #[async_test]
1251 async fn test_set_default_room_notification_mode_one_to_one() -> TestResult {
1252 let server = MockServer::start().await;
1253 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1254 let client = logged_in_client(Some(server.uri())).await;
1255
1256 let mut ruleset = get_server_default_ruleset();
1258 ruleset.set_actions(
1259 RuleKind::Underride,
1260 PredefinedUnderrideRuleId::RoomOneToOne,
1261 vec![Action::Notify],
1262 )?;
1263
1264 ruleset.set_actions(
1265 RuleKind::Underride,
1266 PredefinedUnderrideRuleId::PollStartOneToOne,
1267 vec![Action::Notify],
1268 )?;
1269
1270 let settings = NotificationSettings::new(client, ruleset);
1271 assert_eq!(
1272 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
1273 RoomNotificationMode::AllMessages
1274 );
1275
1276 settings
1278 .set_default_room_notification_mode(
1279 IsEncrypted::No,
1280 IsOneToOne::Yes,
1281 RoomNotificationMode::MentionsAndKeywordsOnly,
1282 )
1283 .await?;
1284
1285 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne),
1287 Some(AnyPushRuleRef::Underride(rule)) => {
1288 assert!(rule.actions.is_empty());
1289 }
1290 );
1291
1292 assert_matches!(settings.rules.read().await.ruleset.get(RuleKind::Underride, PredefinedUnderrideRuleId::PollStartOneToOne),
1293 Some(AnyPushRuleRef::Underride(rule)) => {
1294 assert!(rule.actions.is_empty());
1295 }
1296 );
1297
1298 assert_matches!(
1301 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
1302 RoomNotificationMode::MentionsAndKeywordsOnly
1303 );
1304
1305 Ok(())
1306 }
1307
1308 #[async_test]
1309 async fn test_set_default_room_notification_mode_enables_rules() -> TestResult {
1310 let server = MockServer::start().await;
1311 Mock::given(method("PUT")).respond_with(ResponseTemplate::new(200)).mount(&server).await;
1312 let client = logged_in_client(Some(server.uri())).await;
1313
1314 let mut ruleset = get_server_default_ruleset();
1316 ruleset.set_actions(
1317 RuleKind::Underride,
1318 PredefinedUnderrideRuleId::RoomOneToOne,
1319 vec![],
1320 )?;
1321
1322 ruleset.set_actions(
1323 RuleKind::Underride,
1324 PredefinedUnderrideRuleId::PollStartOneToOne,
1325 vec![],
1326 )?;
1327
1328 ruleset.set_enabled(RuleKind::Underride, PredefinedUnderrideRuleId::RoomOneToOne, false)?;
1330
1331 let settings = NotificationSettings::new(client, ruleset);
1332
1333 settings
1335 .set_default_room_notification_mode(
1336 IsEncrypted::No,
1337 IsOneToOne::Yes,
1338 RoomNotificationMode::AllMessages,
1339 )
1340 .await?;
1341
1342 assert_matches!(
1345 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::Yes).await,
1346 RoomNotificationMode::AllMessages
1347 );
1348
1349 Ok(())
1350 }
1351
1352 #[async_test]
1353 async fn test_list_keywords() -> TestResult {
1354 let server = MockServer::start().await;
1355 let client = logged_in_client(Some(server.uri())).await;
1356
1357 let ruleset = get_server_default_ruleset();
1359 let settings = NotificationSettings::new(client.clone(), ruleset);
1360
1361 let keywords = settings.enabled_keywords().await;
1362
1363 assert!(keywords.is_empty());
1364
1365 let mut ruleset = get_server_default_ruleset();
1367 ruleset.insert(
1368 NewPushRule::Content(NewPatternedPushRule::new("a".to_owned(), "a".to_owned(), vec![])),
1369 None,
1370 None,
1371 )?;
1372 ruleset.insert(
1374 NewPushRule::Content(NewPatternedPushRule::new(
1375 "a_bis".to_owned(),
1376 "a".to_owned(),
1377 vec![],
1378 )),
1379 None,
1380 None,
1381 )?;
1382 ruleset.insert(
1383 NewPushRule::Content(NewPatternedPushRule::new("b".to_owned(), "b".to_owned(), vec![])),
1384 None,
1385 None,
1386 )?;
1387
1388 let settings = NotificationSettings::new(client, ruleset);
1389
1390 let keywords = settings.enabled_keywords().await;
1391 assert_eq!(keywords.len(), 2);
1392 assert!(keywords.get("a").is_some());
1393 assert!(keywords.get("b").is_some());
1394
1395 Ok(())
1396 }
1397
1398 #[async_test]
1399 async fn test_add_keyword_missing() -> TestResult {
1400 let server = MockServer::start().await;
1401 let client = logged_in_client(Some(server.uri())).await;
1402 let settings = client.notification_settings().await;
1403
1404 Mock::given(method("PUT"))
1405 .and(path("/_matrix/client/r0/pushrules/global/content/banana"))
1406 .respond_with(ResponseTemplate::new(200))
1407 .expect(1)
1408 .mount(&server)
1409 .await;
1410
1411 settings.add_keyword("banana".to_owned()).await?;
1412
1413 let keywords = settings.enabled_keywords().await;
1415 assert_eq!(keywords.len(), 1);
1416 assert!(keywords.get("banana").is_some());
1417
1418 let rule_enabled = settings.is_push_rule_enabled(RuleKind::Content, "banana").await?;
1420 assert!(rule_enabled);
1421
1422 Ok(())
1423 }
1424
1425 #[async_test]
1426 async fn test_add_keyword_disabled() -> TestResult {
1427 let server = MockServer::start().await;
1428 let client = logged_in_client(Some(server.uri())).await;
1429
1430 let mut ruleset = get_server_default_ruleset();
1431 ruleset.insert(
1432 NewPushRule::Content(NewPatternedPushRule::new(
1433 "banana_two".to_owned(),
1434 "banana".to_owned(),
1435 vec![],
1436 )),
1437 None,
1438 None,
1439 )?;
1440 ruleset.set_enabled(RuleKind::Content, "banana_two", false)?;
1441 ruleset.insert(
1442 NewPushRule::Content(NewPatternedPushRule::new(
1443 "banana_one".to_owned(),
1444 "banana".to_owned(),
1445 vec![],
1446 )),
1447 None,
1448 None,
1449 )?;
1450 ruleset.set_enabled(RuleKind::Content, "banana_one", false)?;
1451
1452 let settings = NotificationSettings::new(client, ruleset);
1453 Mock::given(method("PUT"))
1454 .and(path("/_matrix/client/r0/pushrules/global/content/banana_one/enabled"))
1455 .respond_with(ResponseTemplate::new(200))
1456 .expect(1)
1457 .mount(&server)
1458 .await;
1459
1460 settings.add_keyword("banana".to_owned()).await?;
1461
1462 let keywords = settings.enabled_keywords().await;
1464
1465 assert_eq!(keywords.len(), 1);
1466 assert!(keywords.get("banana").is_some());
1467
1468 let first_rule_enabled =
1470 settings.is_push_rule_enabled(RuleKind::Content, "banana_one").await?;
1471 assert!(first_rule_enabled);
1472 let second_rule_enabled =
1473 settings.is_push_rule_enabled(RuleKind::Content, "banana_two").await?;
1474 assert!(!second_rule_enabled);
1475
1476 Ok(())
1477 }
1478
1479 #[async_test]
1480 async fn test_add_keyword_noop() -> TestResult {
1481 let server = MockServer::start().await;
1482 let client = logged_in_client(Some(server.uri())).await;
1483
1484 let mut ruleset = get_server_default_ruleset();
1485 ruleset.insert(
1486 NewPushRule::Content(NewPatternedPushRule::new(
1487 "banana_two".to_owned(),
1488 "banana".to_owned(),
1489 vec![],
1490 )),
1491 None,
1492 None,
1493 )?;
1494 ruleset.insert(
1495 NewPushRule::Content(NewPatternedPushRule::new(
1496 "banana_one".to_owned(),
1497 "banana".to_owned(),
1498 vec![],
1499 )),
1500 None,
1501 None,
1502 )?;
1503 ruleset.set_enabled(RuleKind::Content, "banana_one", false)?;
1504
1505 let settings = NotificationSettings::new(client, ruleset);
1506 settings.add_keyword("banana".to_owned()).await?;
1507
1508 let keywords = settings.enabled_keywords().await;
1510
1511 assert_eq!(keywords.len(), 1);
1512 assert!(keywords.get("banana").is_some());
1513
1514 let first_rule_enabled =
1515 settings.is_push_rule_enabled(RuleKind::Content, "banana_one").await?;
1516 assert!(!first_rule_enabled);
1517 let second_rule_enabled =
1518 settings.is_push_rule_enabled(RuleKind::Content, "banana_two").await?;
1519 assert!(second_rule_enabled);
1520
1521 Ok(())
1522 }
1523
1524 #[async_test]
1525 async fn test_remove_keyword_all() -> TestResult {
1526 let server = MockServer::start().await;
1527 let client = logged_in_client(Some(server.uri())).await;
1528
1529 let mut ruleset = get_server_default_ruleset();
1530 ruleset.insert(
1531 NewPushRule::Content(NewPatternedPushRule::new(
1532 "banana_two".to_owned(),
1533 "banana".to_owned(),
1534 vec![],
1535 )),
1536 None,
1537 None,
1538 )?;
1539 ruleset.insert(
1540 NewPushRule::Content(NewPatternedPushRule::new(
1541 "banana_one".to_owned(),
1542 "banana".to_owned(),
1543 vec![],
1544 )),
1545 None,
1546 None,
1547 )?;
1548 ruleset.set_enabled(RuleKind::Content, "banana_one", false)?;
1549
1550 let settings = NotificationSettings::new(client, ruleset);
1551
1552 Mock::given(method("DELETE"))
1553 .and(path("/_matrix/client/r0/pushrules/global/content/banana_one"))
1554 .respond_with(ResponseTemplate::new(200))
1555 .expect(1)
1556 .mount(&server)
1557 .await;
1558 Mock::given(method("DELETE"))
1559 .and(path("/_matrix/client/r0/pushrules/global/content/banana_two"))
1560 .respond_with(ResponseTemplate::new(200))
1561 .expect(1)
1562 .mount(&server)
1563 .await;
1564
1565 settings.remove_keyword("banana").await?;
1566
1567 let keywords = settings.enabled_keywords().await;
1569 assert!(keywords.is_empty());
1570
1571 let first_rule_error =
1573 settings.is_push_rule_enabled(RuleKind::Content, "banana_one").await.unwrap_err();
1574 assert_matches!(first_rule_error, NotificationSettingsError::RuleNotFound(_));
1575 let second_rule_error =
1576 settings.is_push_rule_enabled(RuleKind::Content, "banana_two").await.unwrap_err();
1577 assert_matches!(second_rule_error, NotificationSettingsError::RuleNotFound(_));
1578
1579 Ok(())
1580 }
1581
1582 #[async_test]
1583 async fn test_remove_keyword_noop() -> TestResult {
1584 let server = MockServer::start().await;
1585 let client = logged_in_client(Some(server.uri())).await;
1586 let settings = client.notification_settings().await;
1587
1588 settings.remove_keyword("banana").await?;
1589 Ok(())
1590 }
1591
1592 #[async_test]
1593 async fn test_set_default_room_notification_mode_missing_poll_start() -> TestResult {
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
1617 assert_matches!(
1620 settings.get_default_room_notification_mode(IsEncrypted::No, IsOneToOne::No).await,
1621 RoomNotificationMode::MentionsAndKeywordsOnly
1622 );
1623 Ok(())
1624 }
1625
1626 #[async_test]
1627 async fn test_create_custom_conditional_push_rule() -> TestResult {
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
1654 let rules = settings.rules.read().await;
1655 let rule = rules.ruleset.get(RuleKind::Override, "custom_rule").unwrap();
1656
1657 assert_eq!(rule.rule_id(), "custom_rule");
1658 assert!(rule.enabled());
1659
1660 Ok(())
1661 }
1662
1663 #[async_test]
1664 async fn test_create_custom_conditional_push_rule_invalid_kind() {
1665 let server = MockServer::start().await;
1666 let client = logged_in_client(Some(server.uri())).await;
1667 let settings = client.notification_settings().await;
1668
1669 let actions = vec![Action::Notify];
1670 let conditions = vec![ruma::push::PushCondition::EventMatch {
1671 key: "content.body".to_owned(),
1672 pattern: "hello".to_owned(),
1673 }];
1674
1675 let result = settings
1676 .create_custom_conditional_push_rule(
1677 "custom_rule".to_owned(),
1678 RuleKind::Room,
1679 actions,
1680 conditions,
1681 )
1682 .await;
1683
1684 assert_matches!(result, Err(NotificationSettingsError::InvalidParameter(_)));
1685 }
1686
1687 #[async_test]
1688 #[allow(deprecated)]
1689 async fn test_enable_mention_ignore_missing_legacy_push_rules() -> TestResult {
1690 let server = MatrixMockServer::new().await;
1691 let client = server.client_builder().build().await;
1692 let mut ruleset = get_server_default_ruleset();
1693
1694 if let Some(idx) = ruleset
1696 .override_
1697 .iter()
1698 .position(|rule| rule.rule_id == PredefinedOverrideRuleId::ContainsDisplayName.as_ref())
1699 {
1700 ruleset.override_.shift_remove_index(idx);
1701 }
1702
1703 if let Some(idx) = ruleset
1704 .override_
1705 .iter()
1706 .position(|rule| rule.rule_id == PredefinedOverrideRuleId::RoomNotif.as_ref())
1707 {
1708 ruleset.override_.shift_remove_index(idx);
1709 }
1710
1711 if let Some(idx) = ruleset
1712 .content
1713 .iter()
1714 .position(|rule| rule.rule_id == PredefinedContentRuleId::ContainsUserName.as_ref())
1715 {
1716 ruleset.content.shift_remove_index(idx);
1717 }
1718
1719 assert_matches!(
1720 ruleset.iter().find(|rule| {
1721 rule.rule_id() == PredefinedOverrideRuleId::ContainsDisplayName.as_ref()
1722 || rule.rule_id() == PredefinedOverrideRuleId::RoomNotif.as_ref()
1723 || rule.rule_id() == PredefinedContentRuleId::ContainsUserName.as_ref()
1724 }),
1725 None,
1726 "ruleset must not have legacy mention push rules"
1727 );
1728
1729 let settings = NotificationSettings::new(client, ruleset);
1730
1731 server
1732 .mock_enable_push_rule(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention)
1733 .ok()
1734 .mock_once()
1735 .named("is_user_mention")
1736 .mount()
1737 .await;
1738 settings
1739 .set_push_rule_enabled(
1740 RuleKind::Override,
1741 PredefinedOverrideRuleId::IsUserMention,
1742 false,
1743 )
1744 .await?;
1745
1746 server
1747 .mock_enable_push_rule(RuleKind::Override, PredefinedOverrideRuleId::IsRoomMention)
1748 .ok()
1749 .mock_once()
1750 .named("is_room_mention")
1751 .mount()
1752 .await;
1753 settings
1754 .set_push_rule_enabled(
1755 RuleKind::Override,
1756 PredefinedOverrideRuleId::IsRoomMention,
1757 false,
1758 )
1759 .await?;
1760
1761 Ok(())
1762 }
1763}