1use indexmap::set::{IntoIter as IndexSetIntoIter, Iter as IndexSetIter};
2
3use super::{
4 condition, Action, ConditionalPushRule, FlattenedJson, PatternedPushRule, PushConditionRoomCtx,
5 Ruleset, SimplePushRule,
6};
7use crate::{OwnedRoomId, OwnedUserId};
8
9#[derive(Clone, Debug)]
11#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
12pub enum AnyPushRule {
13 Override(ConditionalPushRule),
15
16 Content(PatternedPushRule),
18
19 #[cfg(feature = "unstable-msc4306")]
21 PostContent(ConditionalPushRule),
22
23 Room(SimplePushRule<OwnedRoomId>),
25
26 Sender(SimplePushRule<OwnedUserId>),
28
29 Underride(ConditionalPushRule),
31}
32
33impl AnyPushRule {
34 pub fn as_ref(&self) -> AnyPushRuleRef<'_> {
36 match self {
37 Self::Override(o) => AnyPushRuleRef::Override(o),
38 Self::Content(c) => AnyPushRuleRef::Content(c),
39 #[cfg(feature = "unstable-msc4306")]
40 Self::PostContent(c) => AnyPushRuleRef::PostContent(c),
41 Self::Room(r) => AnyPushRuleRef::Room(r),
42 Self::Sender(s) => AnyPushRuleRef::Sender(s),
43 Self::Underride(u) => AnyPushRuleRef::Underride(u),
44 }
45 }
46
47 pub fn enabled(&self) -> bool {
49 self.as_ref().enabled()
50 }
51
52 pub fn actions(&self) -> &[Action] {
54 self.as_ref().actions()
55 }
56
57 pub fn triggers_highlight(&self) -> bool {
59 self.as_ref().triggers_highlight()
60 }
61
62 pub fn triggers_notification(&self) -> bool {
65 self.as_ref().triggers_notification()
66 }
67
68 #[cfg(feature = "unstable-msc3768")]
70 pub fn triggers_remote_notification(&self) -> bool {
71 self.as_ref().triggers_remote_notification()
72 }
73
74 pub fn triggers_sound(&self) -> Option<&str> {
76 self.as_ref().triggers_sound()
77 }
78
79 pub fn rule_id(&self) -> &str {
81 self.as_ref().rule_id()
82 }
83
84 pub fn is_server_default(&self) -> bool {
86 self.as_ref().is_server_default()
87 }
88
89 pub async fn applies(&self, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
96 self.as_ref().applies(event, context).await
97 }
98}
99
100#[derive(Debug)]
102pub struct RulesetIntoIter {
103 content: IndexSetIntoIter<PatternedPushRule>,
104 #[cfg(feature = "unstable-msc4306")]
105 postcontent: IndexSetIntoIter<ConditionalPushRule>,
106 override_: IndexSetIntoIter<ConditionalPushRule>,
107 room: IndexSetIntoIter<SimplePushRule<OwnedRoomId>>,
108 sender: IndexSetIntoIter<SimplePushRule<OwnedUserId>>,
109 underride: IndexSetIntoIter<ConditionalPushRule>,
110}
111
112impl Iterator for RulesetIntoIter {
113 type Item = AnyPushRule;
114
115 fn next(&mut self) -> Option<Self::Item> {
116 let it = self
117 .override_
118 .next()
119 .map(AnyPushRule::Override)
120 .or_else(|| self.content.next().map(AnyPushRule::Content));
121
122 #[cfg(feature = "unstable-msc4306")]
123 let it = it.or_else(|| self.postcontent.next().map(AnyPushRule::PostContent));
124
125 it.or_else(|| self.room.next().map(AnyPushRule::Room))
126 .or_else(|| self.sender.next().map(AnyPushRule::Sender))
127 .or_else(|| self.underride.next().map(AnyPushRule::Underride))
128 }
129}
130
131impl IntoIterator for Ruleset {
132 type Item = AnyPushRule;
133 type IntoIter = RulesetIntoIter;
134
135 fn into_iter(self) -> Self::IntoIter {
136 RulesetIntoIter {
137 content: self.content.into_iter(),
138 #[cfg(feature = "unstable-msc4306")]
139 postcontent: self.postcontent.into_iter(),
140 override_: self.override_.into_iter(),
141 room: self.room.into_iter(),
142 sender: self.sender.into_iter(),
143 underride: self.underride.into_iter(),
144 }
145 }
146}
147
148#[derive(Clone, Copy, Debug)]
150#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
151pub enum AnyPushRuleRef<'a> {
152 Override(&'a ConditionalPushRule),
154
155 Content(&'a PatternedPushRule),
157
158 #[cfg(feature = "unstable-msc4306")]
160 PostContent(&'a ConditionalPushRule),
161
162 Room(&'a SimplePushRule<OwnedRoomId>),
164
165 Sender(&'a SimplePushRule<OwnedUserId>),
167
168 Underride(&'a ConditionalPushRule),
170}
171
172impl<'a> AnyPushRuleRef<'a> {
173 pub fn to_owned(self) -> AnyPushRule {
175 match self {
176 Self::Override(o) => AnyPushRule::Override(o.clone()),
177 Self::Content(c) => AnyPushRule::Content(c.clone()),
178 #[cfg(feature = "unstable-msc4306")]
179 Self::PostContent(c) => AnyPushRule::PostContent(c.clone()),
180 Self::Room(r) => AnyPushRule::Room(r.clone()),
181 Self::Sender(s) => AnyPushRule::Sender(s.clone()),
182 Self::Underride(u) => AnyPushRule::Underride(u.clone()),
183 }
184 }
185
186 pub fn enabled(self) -> bool {
188 match self {
189 Self::Override(rule) => rule.enabled,
190 Self::Underride(rule) => rule.enabled,
191 Self::Content(rule) => rule.enabled,
192 #[cfg(feature = "unstable-msc4306")]
193 Self::PostContent(rule) => rule.enabled,
194 Self::Room(rule) => rule.enabled,
195 Self::Sender(rule) => rule.enabled,
196 }
197 }
198
199 pub fn actions(self) -> &'a [Action] {
201 match self {
202 Self::Override(rule) => &rule.actions,
203 Self::Underride(rule) => &rule.actions,
204 Self::Content(rule) => &rule.actions,
205 #[cfg(feature = "unstable-msc4306")]
206 Self::PostContent(rule) => &rule.actions,
207 Self::Room(rule) => &rule.actions,
208 Self::Sender(rule) => &rule.actions,
209 }
210 }
211
212 pub fn triggers_highlight(self) -> bool {
214 self.actions().iter().any(|a| a.is_highlight())
215 }
216
217 pub fn triggers_notification(self) -> bool {
220 self.actions().iter().any(|a| a.should_notify())
221 }
222
223 #[cfg(feature = "unstable-msc3768")]
225 pub fn triggers_remote_notification(self) -> bool {
226 self.actions().iter().any(|a| a.should_notify_remote())
227 }
228
229 pub fn triggers_sound(self) -> Option<&'a str> {
231 self.actions().iter().find_map(|a| a.sound())
232 }
233
234 pub fn rule_id(self) -> &'a str {
236 match self {
237 Self::Override(rule) => &rule.rule_id,
238 Self::Underride(rule) => &rule.rule_id,
239 Self::Content(rule) => &rule.rule_id,
240 #[cfg(feature = "unstable-msc4306")]
241 Self::PostContent(rule) => &rule.rule_id,
242 Self::Room(rule) => rule.rule_id.as_ref(),
243 Self::Sender(rule) => rule.rule_id.as_ref(),
244 }
245 }
246
247 pub fn is_server_default(self) -> bool {
249 match self {
250 Self::Override(rule) => rule.default,
251 Self::Underride(rule) => rule.default,
252 Self::Content(rule) => rule.default,
253 #[cfg(feature = "unstable-msc4306")]
254 Self::PostContent(rule) => rule.default,
255 Self::Room(rule) => rule.default,
256 Self::Sender(rule) => rule.default,
257 }
258 }
259
260 pub async fn applies(self, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
267 if event.get_str("sender").is_some_and(|sender| sender == context.user_id) {
268 return false;
269 }
270
271 match self {
272 Self::Override(rule) => rule.applies(event, context).await,
273 Self::Underride(rule) => rule.applies(event, context).await,
274 Self::Content(rule) => rule.applies_to("content.body", event, context),
275 #[cfg(feature = "unstable-msc4306")]
276 Self::PostContent(rule) => rule.applies(event, context).await,
277 Self::Room(rule) => {
278 rule.enabled
279 && condition::check_event_match(
280 event,
281 "room_id",
282 rule.rule_id.as_ref(),
283 context,
284 )
285 }
286 Self::Sender(rule) => {
287 rule.enabled
288 && condition::check_event_match(event, "sender", rule.rule_id.as_ref(), context)
289 }
290 }
291 }
292}
293
294#[derive(Debug)]
296pub struct RulesetIter<'a> {
297 content: IndexSetIter<'a, PatternedPushRule>,
298 #[cfg(feature = "unstable-msc4306")]
299 postcontent: IndexSetIter<'a, ConditionalPushRule>,
300 override_: IndexSetIter<'a, ConditionalPushRule>,
301 room: IndexSetIter<'a, SimplePushRule<OwnedRoomId>>,
302 sender: IndexSetIter<'a, SimplePushRule<OwnedUserId>>,
303 underride: IndexSetIter<'a, ConditionalPushRule>,
304}
305
306impl<'a> Iterator for RulesetIter<'a> {
307 type Item = AnyPushRuleRef<'a>;
308
309 fn next(&mut self) -> Option<Self::Item> {
310 let it = self
311 .override_
312 .next()
313 .map(AnyPushRuleRef::Override)
314 .or_else(|| self.content.next().map(AnyPushRuleRef::Content));
315
316 #[cfg(feature = "unstable-msc4306")]
317 let it = it.or_else(|| self.postcontent.next().map(AnyPushRuleRef::PostContent));
318
319 it.or_else(|| self.room.next().map(AnyPushRuleRef::Room))
320 .or_else(|| self.sender.next().map(AnyPushRuleRef::Sender))
321 .or_else(|| self.underride.next().map(AnyPushRuleRef::Underride))
322 }
323}
324
325impl<'a> IntoIterator for &'a Ruleset {
326 type Item = AnyPushRuleRef<'a>;
327 type IntoIter = RulesetIter<'a>;
328
329 fn into_iter(self) -> Self::IntoIter {
330 RulesetIter {
331 content: self.content.iter(),
332 #[cfg(feature = "unstable-msc4306")]
333 postcontent: self.postcontent.iter(),
334 override_: self.override_.iter(),
335 room: self.room.iter(),
336 sender: self.sender.iter(),
337 underride: self.underride.iter(),
338 }
339 }
340}