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