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