1use std::hash::{Hash, Hasher};
18
19use indexmap::Equivalent;
20use salvo::prelude::*;
21use serde::{Deserialize, Serialize};
22
23use crate::push::condition;
24use crate::push::{Action, FlattenedJson, MissingPatternError, PushConditionRoomCtx, PushRule};
25
26#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
33pub struct PatternedPushRule {
34 pub actions: Vec<Action>,
36
37 pub default: bool,
39
40 pub enabled: bool,
42
43 pub rule_id: String,
45
46 pub pattern: String,
48}
49
50impl PatternedPushRule {
51 pub fn applies_to(&self, key: &str, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
58 if event.contains_mentions() {
60 return false;
61 }
62
63 if event.get_str("sender").is_some_and(|sender| sender == context.user_id) {
64 return false;
65 }
66
67 self.enabled && condition::check_event_match(event, key, &self.pattern, context)
68 }
69}
70
71#[derive(Debug)]
76#[allow(clippy::exhaustive_structs)]
77pub struct PatternedPushRuleInit {
78 pub actions: Vec<Action>,
80
81 pub default: bool,
83
84 pub enabled: bool,
86
87 pub rule_id: String,
89
90 pub pattern: String,
92}
93
94impl From<PatternedPushRuleInit> for PatternedPushRule {
95 fn from(init: PatternedPushRuleInit) -> Self {
96 let PatternedPushRuleInit {
97 actions,
98 default,
99 enabled,
100 rule_id,
101 pattern,
102 } = init;
103 Self {
104 actions,
105 default,
106 enabled,
107 rule_id,
108 pattern,
109 }
110 }
111}
112
113impl Hash for PatternedPushRule {
117 fn hash<H: Hasher>(&self, state: &mut H) {
118 self.rule_id.hash(state);
119 }
120}
121
122impl PartialEq for PatternedPushRule {
123 fn eq(&self, other: &Self) -> bool {
124 self.rule_id == other.rule_id
125 }
126}
127
128impl Eq for PatternedPushRule {}
129
130impl Equivalent<PatternedPushRule> for str {
131 fn equivalent(&self, key: &PatternedPushRule) -> bool {
132 self == key.rule_id
133 }
134}
135
136#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
138pub struct NewPatternedPushRule {
139 pub rule_id: String,
141
142 pub pattern: String,
144
145 pub actions: Vec<Action>,
148}
149
150impl NewPatternedPushRule {
151 pub fn new(rule_id: String, pattern: String, actions: Vec<Action>) -> Self {
153 Self {
154 rule_id,
155 pattern,
156 actions,
157 }
158 }
159}
160
161impl From<NewPatternedPushRule> for PatternedPushRule {
162 fn from(new_rule: NewPatternedPushRule) -> Self {
163 let NewPatternedPushRule {
164 rule_id,
165 pattern,
166 actions,
167 } = new_rule;
168 Self {
169 actions,
170 default: false,
171 enabled: true,
172 rule_id,
173 pattern,
174 }
175 }
176}
177
178impl From<PatternedPushRule> for PushRule {
179 fn from(push_rule: PatternedPushRule) -> Self {
180 let PatternedPushRule {
181 actions,
182 default,
183 enabled,
184 rule_id,
185 pattern,
186 ..
187 } = push_rule;
188 Self {
189 actions,
190 default,
191 enabled,
192 rule_id,
193 conditions: None,
194 pattern: Some(pattern),
195 }
196 }
197}
198
199impl From<PatternedPushRuleInit> for PushRule {
200 fn from(init: PatternedPushRuleInit) -> Self {
201 let PatternedPushRuleInit {
202 actions,
203 default,
204 enabled,
205 rule_id,
206 pattern,
207 } = init;
208 Self {
209 actions,
210 default,
211 enabled,
212 rule_id,
213 pattern: Some(pattern),
214 conditions: None,
215 }
216 }
217}
218
219impl TryFrom<PushRule> for PatternedPushRule {
220 type Error = MissingPatternError;
221
222 fn try_from(push_rule: PushRule) -> Result<Self, Self::Error> {
223 if let PushRule {
224 actions,
225 default,
226 enabled,
227 rule_id,
228 pattern: Some(pattern),
229 ..
230 } = push_rule
231 {
232 Ok(PatternedPushRuleInit {
233 actions,
234 default,
235 enabled,
236 rule_id,
237 pattern,
238 }
239 .into())
240 } else {
241 Err(MissingPatternError)
242 }
243 }
244}