Skip to main content

palpo_core/push/
predefined.rs

1//! Constructors for [predefined push rules].
2//!
3//! [predefined push rules]: https://spec.matrix.org/latest/client-server-api/#predefined-rules
4
5use palpo_macros::StringEnum;
6
7use super::{Action, ConditionalPushRule, PushCondition::*, RoomMemberCountIs, RuleKind, Ruleset, Tweak};
8use crate::{PrivOwnedStr, UserId};
9
10impl Ruleset {
11    /// The list of all [predefined push rules].
12    ///
13    /// # Parameters
14    ///
15    /// - `user_id`: the user for which to generate the default rules. Some rules depend on the
16    ///   user's ID (for instance those to send notifications when they are mentioned).
17    ///
18    /// [predefined push rules]: https://spec.matrix.org/latest/client-server-api/#predefined-rules
19    pub fn server_default(user_id: &UserId) -> Self {
20        Self {
21            content: Default::default(),
22            override_: [
23                ConditionalPushRule::master(),
24                ConditionalPushRule::suppress_notices(),
25                ConditionalPushRule::invite_for_me(user_id),
26                ConditionalPushRule::member_event(),
27                ConditionalPushRule::is_user_mention(user_id),
28                ConditionalPushRule::is_room_mention(),
29                ConditionalPushRule::tombstone(),
30                ConditionalPushRule::reaction(),
31                ConditionalPushRule::server_acl(),
32                ConditionalPushRule::suppress_edits(),
33                #[cfg(feature = "unstable-msc3930")]
34                ConditionalPushRule::poll_response(),
35            ]
36            .into(),
37            underride: [
38                ConditionalPushRule::call(),
39                ConditionalPushRule::encrypted_room_one_to_one(),
40                ConditionalPushRule::room_one_to_one(),
41                ConditionalPushRule::message(),
42                ConditionalPushRule::encrypted(),
43                #[cfg(feature = "unstable-msc3930")]
44                ConditionalPushRule::poll_start_one_to_one(),
45                #[cfg(feature = "unstable-msc3930")]
46                ConditionalPushRule::poll_start(),
47                #[cfg(feature = "unstable-msc3930")]
48                ConditionalPushRule::poll_end_one_to_one(),
49                #[cfg(feature = "unstable-msc3930")]
50                ConditionalPushRule::poll_end(),
51            ]
52            .into(),
53            ..Default::default()
54        }
55    }
56
57    /// Update this ruleset with the given server-default push rules.
58    ///
59    /// This will replace the server-default rules in this ruleset (with `default` set to `true`)
60    /// with the given ones while keeping the `enabled` and `actions` fields in the same state.
61    ///
62    /// The default rules in this ruleset that are not in the new server-default rules are removed.
63    ///
64    /// # Parameters
65    ///
66    /// - `server_default`: the new server-default push rules. This ruleset must not contain
67    ///   non-default rules.
68    pub fn update_with_server_default(&mut self, mut new_server_default: Ruleset) {
69        // Copy the default rules states from the old rules to the new rules and remove the
70        // server-default rules from the old rules.
71        macro_rules! copy_rules_state {
72            ($new_ruleset:ident, $old_ruleset:ident, @fields $($field_name:ident),+) => {
73                $(
74                    $new_ruleset.$field_name = $new_ruleset
75                        .$field_name
76                        .into_iter()
77                        .map(|mut new_rule| {
78                            if let Some(old_rule) =
79                                $old_ruleset.$field_name.swap_take(new_rule.rule_id.as_str())
80                            {
81                                new_rule.enabled = old_rule.enabled;
82                                new_rule.actions = old_rule.actions;
83                            }
84
85                            new_rule
86                        })
87                        .collect();
88                )+
89            };
90        }
91        copy_rules_state!(new_server_default, self, @fields override_, content, room, sender, underride);
92
93        // Remove the remaining server-default rules from the old rules.
94        macro_rules! remove_remaining_default_rules {
95            ($ruleset:ident, @fields $($field_name:ident),+) => {
96                $(
97                    $ruleset.$field_name.retain(|rule| !rule.default);
98                )+
99            };
100        }
101        remove_remaining_default_rules!(self, @fields override_, content, room, sender, underride);
102
103        // `.m.rule.master` comes before all other push rules, while the other server-default push
104        // rules come after.
105        if let Some(master_rule) = new_server_default
106            .override_
107            .take(PredefinedOverrideRuleId::Master.as_str())
108        {
109            let (pos, _) = self.override_.insert_full(master_rule);
110            self.override_.move_index(pos, 0);
111        }
112
113        // Merge the new server-default rules into the old rules.
114        macro_rules! merge_rules {
115            ($old_ruleset:ident, $new_ruleset:ident, @fields $($field_name:ident),+) => {
116                $(
117                    $old_ruleset.$field_name.extend($new_ruleset.$field_name);
118                )+
119            };
120        }
121        merge_rules!(self, new_server_default, @fields override_, content, room, sender, underride);
122    }
123}
124
125/// Default override push rules
126impl ConditionalPushRule {
127    /// Matches all events, this can be enabled to turn off all push notifications other than those
128    /// generated by override rules set by the user.
129    pub fn master() -> Self {
130        Self {
131            actions: vec![],
132            default: true,
133            enabled: false,
134            rule_id: PredefinedOverrideRuleId::Master.to_string(),
135            conditions: vec![],
136        }
137    }
138
139    /// Matches messages with a `msgtype` of `notice`.
140    pub fn suppress_notices() -> Self {
141        Self {
142            actions: vec![],
143            default: true,
144            enabled: true,
145            rule_id: PredefinedOverrideRuleId::SuppressNotices.to_string(),
146            conditions: vec![EventMatch {
147                key: "content.msgtype".into(),
148                pattern: "m.notice".into(),
149            }],
150        }
151    }
152
153    /// Matches any invites to a new room for this user.
154    pub fn invite_for_me(user_id: &UserId) -> Self {
155        Self {
156            actions: vec![
157                Action::Notify,
158                Action::SetTweak(Tweak::Sound("default".into())),
159                Action::SetTweak(Tweak::Highlight(false)),
160            ],
161            default: true,
162            enabled: true,
163            rule_id: PredefinedOverrideRuleId::InviteForMe.to_string(),
164            conditions: vec![
165                EventMatch {
166                    key: "type".into(),
167                    pattern: "m.room.member".into(),
168                },
169                EventMatch {
170                    key: "content.membership".into(),
171                    pattern: "invite".into(),
172                },
173                EventMatch {
174                    key: "state_key".into(),
175                    pattern: user_id.to_string(),
176                },
177            ],
178        }
179    }
180
181    /// Matches any `m.room.member_event`.
182    pub fn member_event() -> Self {
183        Self {
184            actions: vec![],
185            default: true,
186            enabled: true,
187            rule_id: PredefinedOverrideRuleId::MemberEvent.to_string(),
188            conditions: vec![EventMatch {
189                key: "type".into(),
190                pattern: "m.room.member".into(),
191            }],
192        }
193    }
194
195    /// Matches any message which contains the user’s Matrix ID in the list of `user_ids` under the
196    /// `m.mentions` property.
197    pub fn is_user_mention(user_id: &UserId) -> Self {
198        Self {
199            actions: vec![
200                Action::Notify,
201                Action::SetTweak(Tweak::Sound("default".to_owned())),
202                Action::SetTweak(Tweak::Highlight(true)),
203            ],
204            default: true,
205            enabled: true,
206            rule_id: PredefinedOverrideRuleId::IsUserMention.to_string(),
207            conditions: vec![EventPropertyContains {
208                key: r"content.m\.mentions.user_ids".to_owned(),
209                value: user_id.as_str().into(),
210            }],
211        }
212    }
213
214    /// Matches any state event whose type is `m.room.tombstone`. This
215    /// is intended to notify users of a room when it is upgraded,
216    /// similar to what an `@room` notification would accomplish.
217    pub fn tombstone() -> Self {
218        Self {
219            actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(true))],
220            default: true,
221            enabled: true,
222            rule_id: PredefinedOverrideRuleId::Tombstone.to_string(),
223            conditions: vec![
224                EventMatch {
225                    key: "type".into(),
226                    pattern: "m.room.tombstone".into(),
227                },
228                EventMatch {
229                    key: "state_key".into(),
230                    pattern: "".into(),
231                },
232            ],
233        }
234    }
235
236    /// Matches any message from a sender with the proper power level with the `room` property of
237    /// the `m.mentions` property set to `true`.
238    pub fn is_room_mention() -> Self {
239        Self {
240            actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(true))],
241            default: true,
242            enabled: true,
243            rule_id: PredefinedOverrideRuleId::IsRoomMention.to_string(),
244            conditions: vec![
245                EventPropertyIs {
246                    key: r"content.m\.mentions.room".to_owned(),
247                    value: true.into(),
248                },
249                SenderNotificationPermission { key: "room".to_owned() },
250            ],
251        }
252    }
253
254    /// Matches [reactions] to a message.
255    ///
256    /// [reactions]: https://spec.matrix.org/latest/client-server-api/#event-annotations-and-reactions
257    pub fn reaction() -> Self {
258        Self {
259            actions: vec![],
260            default: true,
261            enabled: true,
262            rule_id: PredefinedOverrideRuleId::Reaction.to_string(),
263            conditions: vec![EventMatch {
264                key: "type".into(),
265                pattern: "m.reaction".into(),
266            }],
267        }
268    }
269
270    /// Matches [room server ACLs].
271    ///
272    /// [room server ACLs]: https://spec.matrix.org/latest/client-server-api/#server-access-control-lists-acls-for-rooms
273    pub fn server_acl() -> Self {
274        Self {
275            actions: vec![],
276            default: true,
277            enabled: true,
278            rule_id: PredefinedOverrideRuleId::RoomServerAcl.to_string(),
279            conditions: vec![
280                EventMatch {
281                    key: "type".into(),
282                    pattern: "m.room.server_acl".into(),
283                },
284                EventMatch {
285                    key: "state_key".into(),
286                    pattern: "".into(),
287                },
288            ],
289        }
290    }
291
292    /// Matches [event replacements].
293    ///
294    /// [event replacements]: https://spec.matrix.org/latest/client-server-api/#event-replacements
295    pub fn suppress_edits() -> Self {
296        Self {
297            actions: vec![],
298            default: true,
299            enabled: true,
300            rule_id: PredefinedOverrideRuleId::SuppressEdits.to_string(),
301            conditions: vec![EventPropertyIs {
302                key: r"content.m\.relates_to.rel_type".to_owned(),
303                value: "m.replace".into(),
304            }],
305        }
306    }
307
308    /// Matches a poll response event sent in any room.
309    ///
310    /// This rule uses the unstable prefixes defined in [MSC3381] and [MSC3930].
311    ///
312    /// [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
313    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
314    #[cfg(feature = "unstable-msc3930")]
315    pub fn poll_response() -> Self {
316        Self {
317            rule_id: PredefinedOverrideRuleId::PollResponse.to_string(),
318            default: true,
319            enabled: true,
320            conditions: vec![EventPropertyIs {
321                key: "type".to_owned(),
322                value: "org.matrix.msc3381.poll.response".into(),
323            }],
324            actions: vec![],
325        }
326    }
327}
328
329/// Default underrides push rules
330impl ConditionalPushRule {
331    /// Matches any incoming VOIP call.
332    pub fn call() -> Self {
333        Self {
334            rule_id: PredefinedUnderrideRuleId::Call.to_string(),
335            default: true,
336            enabled: true,
337            conditions: vec![EventMatch {
338                key: "type".into(),
339                pattern: "m.call.invite".into(),
340            }],
341            actions: vec![
342                Action::Notify,
343                Action::SetTweak(Tweak::Sound("ring".into())),
344                Action::SetTweak(Tweak::Highlight(false)),
345            ],
346        }
347    }
348
349    /// Matches any encrypted event sent in a room with exactly two members.
350    ///
351    /// Unlike other push rules, this rule cannot be matched against the content of the event by
352    /// nature of it being encrypted. This causes the rule to be an "all or nothing" match where it
353    /// either matches all events that are encrypted (in 1:1 rooms) or none.
354    pub fn encrypted_room_one_to_one() -> Self {
355        Self {
356            rule_id: PredefinedUnderrideRuleId::EncryptedRoomOneToOne.to_string(),
357            default: true,
358            enabled: true,
359            conditions: vec![
360                RoomMemberCount {
361                    is: RoomMemberCountIs::from(2),
362                },
363                EventMatch {
364                    key: "type".into(),
365                    pattern: "m.room.encrypted".into(),
366                },
367            ],
368            actions: vec![
369                Action::Notify,
370                Action::SetTweak(Tweak::Sound("default".into())),
371                Action::SetTweak(Tweak::Highlight(false)),
372            ],
373        }
374    }
375
376    /// Matches any message sent in a room with exactly two members.
377    pub fn room_one_to_one() -> Self {
378        Self {
379            rule_id: PredefinedUnderrideRuleId::RoomOneToOne.to_string(),
380            default: true,
381            enabled: true,
382            conditions: vec![
383                RoomMemberCount {
384                    is: RoomMemberCountIs::from(2),
385                },
386                EventMatch {
387                    key: "type".into(),
388                    pattern: "m.room.message".into(),
389                },
390            ],
391            actions: vec![
392                Action::Notify,
393                Action::SetTweak(Tweak::Sound("default".into())),
394                Action::SetTweak(Tweak::Highlight(false)),
395            ],
396        }
397    }
398
399    /// Matches all chat messages.
400    pub fn message() -> Self {
401        Self {
402            rule_id: PredefinedUnderrideRuleId::Message.to_string(),
403            default: true,
404            enabled: true,
405            conditions: vec![EventMatch {
406                key: "type".into(),
407                pattern: "m.room.message".into(),
408            }],
409            actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(false))],
410        }
411    }
412
413    /// Matches all encrypted events.
414    ///
415    /// Unlike other push rules, this rule cannot be matched against the content of the event by
416    /// nature of it being encrypted. This causes the rule to be an "all or nothing" match where it
417    /// either matches all events that are encrypted (in group rooms) or none.
418    pub fn encrypted() -> Self {
419        Self {
420            rule_id: PredefinedUnderrideRuleId::Encrypted.to_string(),
421            default: true,
422            enabled: true,
423            conditions: vec![EventMatch {
424                key: "type".into(),
425                pattern: "m.room.encrypted".into(),
426            }],
427            actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(false))],
428        }
429    }
430
431    /// Matches a poll start event sent in a room with exactly two members.
432    ///
433    /// This rule uses the unstable prefixes defined in [MSC3381] and [MSC3930].
434    ///
435    /// [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
436    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
437    #[cfg(feature = "unstable-msc3930")]
438    pub fn poll_start_one_to_one() -> Self {
439        Self {
440            rule_id: PredefinedUnderrideRuleId::PollStartOneToOne.to_string(),
441            default: true,
442            enabled: true,
443            conditions: vec![
444                RoomMemberCount {
445                    is: RoomMemberCountIs::from(2),
446                },
447                EventPropertyIs {
448                    key: "type".to_owned(),
449                    value: "org.matrix.msc3381.poll.start".into(),
450                },
451            ],
452            actions: vec![Notify, SetTweak(Tweak::Sound("default".into()))],
453        }
454    }
455
456    /// Matches a poll start event sent in any room.
457    ///
458    /// This rule uses the unstable prefixes defined in [MSC3381] and [MSC3930].
459    ///
460    /// [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
461    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
462    #[cfg(feature = "unstable-msc3930")]
463    pub fn poll_start() -> Self {
464        Self {
465            rule_id: PredefinedUnderrideRuleId::PollStart.to_string(),
466            default: true,
467            enabled: true,
468            conditions: vec![EventPropertyIs {
469                key: "type".to_owned(),
470                value: "org.matrix.msc3381.poll.start".into(),
471            }],
472            actions: vec![Notify],
473        }
474    }
475
476    /// Matches a poll end event sent in a room with exactly two members.
477    ///
478    /// This rule uses the unstable prefixes defined in [MSC3381] and [MSC3930].
479    ///
480    /// [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
481    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
482    #[cfg(feature = "unstable-msc3930")]
483    pub fn poll_end_one_to_one() -> Self {
484        Self {
485            rule_id: PredefinedUnderrideRuleId::PollEndOneToOne.to_string(),
486            default: true,
487            enabled: true,
488            conditions: vec![
489                RoomMemberCount {
490                    is: RoomMemberCountIs::from(2),
491                },
492                EventPropertyIs {
493                    key: "type".to_owned(),
494                    value: "org.matrix.msc3381.poll.end".into(),
495                },
496            ],
497            actions: vec![Notify, SetTweak(Tweak::Sound("default".into()))],
498        }
499    }
500
501    /// Matches a poll end event sent in any room.
502    ///
503    /// This rule uses the unstable prefixes defined in [MSC3381] and [MSC3930].
504    ///
505    /// [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
506    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
507    #[cfg(feature = "unstable-msc3930")]
508    pub fn poll_end() -> Self {
509        Self {
510            rule_id: PredefinedUnderrideRuleId::PollEnd.to_string(),
511            default: true,
512            enabled: true,
513            conditions: vec![EventPropertyIs {
514                key: "type".to_owned(),
515                value: "org.matrix.msc3381.poll.end".into(),
516            }],
517            actions: vec![Notify],
518        }
519    }
520}
521
522/// The rule IDs of the predefined server push rules.
523#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
524#[non_exhaustive]
525pub enum PredefinedRuleId {
526    /// User-configured rules that override all other kinds.
527    Override(PredefinedOverrideRuleId),
528
529    /// Lowest priority user-defined rules.
530    Underride(PredefinedUnderrideRuleId),
531
532    /// Content-specific rules.
533    Content(PredefinedContentRuleId),
534}
535
536impl PredefinedRuleId {
537    /// Creates a string slice from this `PredefinedRuleId`.
538    pub fn as_str(&self) -> &str {
539        match self {
540            Self::Override(id) => id.as_str(),
541            Self::Underride(id) => id.as_str(),
542            Self::Content(id) => id.as_str(),
543        }
544    }
545
546    /// Get the kind of this `PredefinedRuleId`.
547    pub fn kind(&self) -> RuleKind {
548        match self {
549            Self::Override(id) => id.kind(),
550            Self::Underride(id) => id.kind(),
551            Self::Content(id) => id.kind(),
552        }
553    }
554}
555
556impl AsRef<str> for PredefinedRuleId {
557    fn as_ref(&self) -> &str {
558        self.as_str()
559    }
560}
561
562/// The rule IDs of the predefined override server push rules.
563#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
564#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
565#[palpo_enum(rename_all = ".m.rule.snake_case")]
566#[non_exhaustive]
567pub enum PredefinedOverrideRuleId {
568    /// `.m.rule.master`
569    Master,
570
571    /// `.m.rule.suppress_notices`
572    SuppressNotices,
573
574    /// `.m.rule.invite_for_me`
575    InviteForMe,
576
577    /// `.m.rule.member_event`
578    MemberEvent,
579
580    /// `.m.rule.is_user_mention`
581    IsUserMention,
582
583    /// `.m.rule.is_room_mention`
584    IsRoomMention,
585
586    /// `.m.rule.tombstone`
587    Tombstone,
588
589    /// `.m.rule.reaction`
590    Reaction,
591
592    /// `.m.rule.room.server_acl`
593    #[palpo_enum(rename = ".m.rule.room.server_acl")]
594    RoomServerAcl,
595
596    /// `.m.rule.suppress_edits`
597    SuppressEdits,
598
599    /// `.m.rule.poll_response`
600    ///
601    /// This uses the unstable prefix defined in [MSC3930].
602    ///
603    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
604    #[cfg(feature = "unstable-msc3930")]
605    #[palpo_enum(rename = ".org.matrix.msc3930.rule.poll_response")]
606    PollResponse,
607
608    #[doc(hidden)]
609    _Custom(PrivOwnedStr),
610}
611
612impl PredefinedOverrideRuleId {
613    /// Get the kind of this `PredefinedOverrideRuleId`.
614    pub fn kind(&self) -> RuleKind {
615        RuleKind::Override
616    }
617}
618
619/// The rule IDs of the predefined underride server push rules.
620#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
621#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
622#[palpo_enum(rename_all = ".m.rule.snake_case")]
623#[non_exhaustive]
624pub enum PredefinedUnderrideRuleId {
625    /// `.m.rule.call`
626    Call,
627
628    /// `.m.rule.encrypted_room_one_to_one`
629    EncryptedRoomOneToOne,
630
631    /// `.m.rule.room_one_to_one`
632    RoomOneToOne,
633
634    /// `.m.rule.message`
635    Message,
636
637    /// `.m.rule.encrypted`
638    Encrypted,
639
640    /// `.m.rule.poll_start_one_to_one`
641    ///
642    /// This uses the unstable prefix defined in [MSC3930].
643    ///
644    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
645    #[cfg(feature = "unstable-msc3930")]
646    #[palpo_enum(rename = ".org.matrix.msc3930.rule.poll_start_one_to_one")]
647    PollStartOneToOne,
648
649    /// `.m.rule.poll_start`
650    ///
651    /// This uses the unstable prefix defined in [MSC3930].
652    ///
653    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
654    #[cfg(feature = "unstable-msc3930")]
655    #[palpo_enum(rename = ".org.matrix.msc3930.rule.poll_start")]
656    PollStart,
657
658    /// `.m.rule.poll_end_one_to_one`
659    ///
660    /// This uses the unstable prefix defined in [MSC3930].
661    ///
662    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
663    #[cfg(feature = "unstable-msc3930")]
664    #[palpo_enum(rename = ".org.matrix.msc3930.rule.poll_end_one_to_one")]
665    PollEndOneToOne,
666
667    /// `.m.rule.poll_end`
668    ///
669    /// This uses the unstable prefix defined in [MSC3930].
670    ///
671    /// [MSC3930]: https://github.com/matrix-org/matrix-spec-proposals/pull/3930
672    #[cfg(feature = "unstable-msc3930")]
673    #[palpo_enum(rename = ".org.matrix.msc3930.rule.poll_end")]
674    PollEnd,
675
676    #[doc(hidden)]
677    _Custom(PrivOwnedStr),
678}
679
680impl PredefinedUnderrideRuleId {
681    /// Get the kind of this `PredefinedUnderrideRuleId`.
682    pub fn kind(&self) -> RuleKind {
683        RuleKind::Underride
684    }
685}
686
687/// The rule IDs of the predefined content server push rules.
688#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
689#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
690#[palpo_enum(rename_all = ".m.rule.snake_case")]
691#[non_exhaustive]
692pub enum PredefinedContentRuleId {
693    #[doc(hidden)]
694    _Custom(PrivOwnedStr),
695}
696
697impl PredefinedContentRuleId {
698    /// Get the kind of this `PredefinedContentRuleId`.
699    pub fn kind(&self) -> RuleKind {
700        RuleKind::Content
701    }
702}
703
704// #[cfg(test)]
705// mod tests {
706//     use assert_matches2::assert_matches;
707//     use assign::assign;
708
709//     use super::PredefinedOverrideRuleId;
710//     use crate::{
711//         push::{Action, ConditionalPushRule, ConditionalPushRuleInit, Ruleset},
712//         user_id,
713//     };
714
715//     #[test]
716//     fn update_with_server_default() {
717//         let user_rule_id = "user_always_true";
718//         let default_rule_id = ".default_always_true";
719
720//         let override_ = [
721//             // Default `.m.rule.master` push rule with non-default state.
722//             assign!(ConditionalPushRule::master(), { enabled: true, actions: vec![Action::Notify]}),
723//             // User-defined push rule.
724//             ConditionalPushRuleInit {
725//                 actions: vec![],
726//                 default: false,
727//                 enabled: false,
728//                 rule_id: user_rule_id.to_owned(),
729//                 conditions: vec![],
730//             }
731//             .into(),
732//             // Old server-default push rule.
733//             ConditionalPushRuleInit {
734//                 actions: vec![],
735//                 default: true,
736//                 enabled: true,
737//                 rule_id: default_rule_id.to_owned(),
738//                 conditions: vec![],
739//             }
740//             .into(),
741//         ]
742//         .into_iter()
743//         .collect();
744//         let mut ruleset = Ruleset {
745//             override_,
746//             ..Default::default()
747//         };
748
749//         let new_server_default = Ruleset::server_default(user_id!("@user:localhost"));
750
751//         ruleset.update_with_server_default(new_server_default);
752
753//         // Master rule is in first position.
754//         let master_rule = &ruleset.override_[0];
755//         assert_eq!(master_rule.rule_id, PredefinedOverrideRuleId::Master.as_str());
756
757//         // `enabled` and `actions` have been copied from the old rules.
758//         assert!(master_rule.enabled);
759//         assert_eq!(master_rule.actions.len(), 1);
760//         assert_matches!(&master_rule.actions[0], Action::Notify);
761
762//         // Non-server-default rule is still present and hasn't changed.
763//         let user_rule = ruleset.override_.get(user_rule_id).unwrap();
764//         assert!(!user_rule.enabled);
765//         assert_eq!(user_rule.actions.len(), 0);
766
767//         // Old server-default rule is gone.
768//         assert_matches!(ruleset.override_.get(default_rule_id), None);
769
770//         // New server-default rule is present and hasn't changed.
771//         let member_event_rule = ruleset
772//             .override_
773//             .get(PredefinedOverrideRuleId::MemberEvent.as_str())
774//             .unwrap();
775//         assert!(member_event_rule.enabled);
776//         assert_eq!(member_event_rule.actions.len(), 0);
777//     }
778// }