1 | #pragma once |
2 | |
3 | /// @file |
4 | /// @brief Pushrules and notification settings. |
5 | |
6 | #if __has_include(<nlohmann/json_fwd.hpp>) |
7 | #include <nlohmann/json_fwd.hpp> |
8 | #else |
9 | #include <nlohmann/json.hpp> |
10 | #endif |
11 | |
12 | #include <compare> |
13 | #include <string> |
14 | #include <variant> |
15 | #include <vector> |
16 | |
17 | #include "mtx/events/common.hpp" |
18 | #include "mtx/events/power_levels.hpp" |
19 | |
20 | namespace mtx { |
21 | namespace events { |
22 | namespace collections { |
23 | struct TimelineEvent; |
24 | } |
25 | } |
26 | |
27 | //! Namespace for the pushrules specific endpoints. |
28 | namespace pushrules { |
29 | //! A condition to match pushrules on. |
30 | struct PushCondition |
31 | { |
32 | //! Required. The kind of condition to apply. See conditions for more information on the |
33 | //! allowed kinds and how they work. |
34 | std::string kind; |
35 | //! Required for event_match conditions. The dot- separated field of the event to match. |
36 | //! |
37 | //! Required for sender_notification_permission conditions. The field in the power level |
38 | //! event the user needs a minimum power level for. Fields must be specified under the |
39 | //! notifications property in the power level event's content. |
40 | std::string key; |
41 | //! Required for event_match conditions. The glob- style pattern to match against. Patterns |
42 | //! with no special glob characters should be treated as having asterisks prepended and |
43 | //! appended when testing the condition. |
44 | std::string pattern; |
45 | //! Required for room_member_count conditions. A decimal integer optionally prefixed by one |
46 | //! of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly |
47 | //! less than the given number and so forth. If no prefix is present, this parameter |
48 | //! defaults to ==. |
49 | std::string is; |
50 | |
51 | //! The relation type to match on. Only valid for `im.nheko.msc3664.related_event_match` |
52 | //! conditions. |
53 | mtx::common::RelationType rel_type = mtx::common::RelationType::Unsupported; |
54 | //! Wether to match fallback relations or not. |
55 | bool include_fallback = false; |
56 | |
57 | friend void to_json(nlohmann::json &obj, const PushCondition &condition); |
58 | friend void from_json(const nlohmann::json &obj, PushCondition &condition); |
59 | }; |
60 | //! Namespace for the different push actions. |
61 | namespace actions { |
62 | //! Notify the user. |
63 | struct notify |
64 | { |
65 | bool operator==(const notify &) const noexcept = default; |
66 | }; |
67 | //! Don't notify the user. |
68 | struct dont_notify |
69 | { |
70 | bool operator==(const dont_notify &) const noexcept = default; |
71 | }; |
72 | /// @brief This enables notifications for matching events but activates homeserver specific |
73 | /// behaviour to intelligently coalesce multiple events into a single notification. |
74 | /// |
75 | /// Not all homeservers may support this. Those that do not support it should treat it as the notify |
76 | /// action. |
77 | struct coalesce |
78 | { |
79 | bool operator==(const coalesce &) const noexcept = default; |
80 | }; |
81 | //! Play a sound. |
82 | struct set_tweak_sound |
83 | { |
84 | //! The sound to play. |
85 | std::string value = "default" ; |
86 | |
87 | bool operator==(const set_tweak_sound &) const noexcept = default; |
88 | }; |
89 | //! Highlight the message. |
90 | struct set_tweak_highlight |
91 | { |
92 | bool value = true; |
93 | |
94 | bool operator==(const set_tweak_highlight &) const noexcept = default; |
95 | }; |
96 | |
97 | //! A collection for the different actions. |
98 | using Action = std::variant<actions::notify, |
99 | actions::dont_notify, |
100 | actions::coalesce, |
101 | actions::set_tweak_sound, |
102 | actions::set_tweak_highlight>; |
103 | |
104 | void |
105 | to_json(nlohmann::json &obj, const Action &action); |
106 | |
107 | void |
108 | from_json(const nlohmann::json &obj, Action &action); |
109 | |
110 | //! A list of actions. |
111 | struct Actions |
112 | { |
113 | std::vector<Action> actions; |
114 | |
115 | friend void to_json(nlohmann::json &obj, const Actions &action); |
116 | friend void from_json(const nlohmann::json &obj, Actions &action); |
117 | |
118 | bool operator==(const Actions &) const noexcept = default; |
119 | }; |
120 | } |
121 | |
122 | //! A pushrule defining the notification behaviour for a message. |
123 | struct PushRule |
124 | { |
125 | //! Required. Whether this is a default rule, or has been set explicitly. |
126 | bool default_ = false; |
127 | //! Required. Whether the push rule is enabled or not. |
128 | bool enabled = true; |
129 | //! Required. The actions to perform when this rule is matched. |
130 | std::vector<actions::Action> actions; |
131 | //! Required. The ID of this rule. |
132 | std::string rule_id; |
133 | //! The glob-style pattern to match against. Only applicable to content rules. |
134 | std::string pattern; |
135 | //! The conditions that must hold true for an event in order for a rule to be applied to an |
136 | //! event. A rule with no conditions always matches. Only applicable to underride and |
137 | //! override rules. |
138 | std::vector<PushCondition> conditions; |
139 | |
140 | friend void to_json(nlohmann::json &obj, const PushRule &condition); |
141 | friend void from_json(const nlohmann::json &obj, PushRule &condition); |
142 | }; |
143 | |
144 | //! All the pushrules to evaluate for events. |
145 | struct Ruleset |
146 | { |
147 | //! see https://matrix.org/docs/spec/client_server/latest#push-rules |
148 | // |
149 | // A push rule is a single rule that states under what conditions an event should be passed |
150 | // onto a push gateway and how the notification should be presented. There are different |
151 | // "kinds" of push rules and each rule has an associated priority. Every push rule MUST have |
152 | // a kind and rule_id. The rule_id is a unique string within the kind of rule and its' |
153 | // scope: rule_ids do not need to be unique between rules of the same kind on different |
154 | // devices. Rules may have extra keys depending on the value of kind. The different kinds of |
155 | // rule in descending order of priority are: |
156 | std::vector<PushRule> override_; |
157 | std::vector<PushRule> content; |
158 | std::vector<PushRule> room; |
159 | std::vector<PushRule> sender; |
160 | std::vector<PushRule> underride; |
161 | |
162 | friend void to_json(nlohmann::json &obj, const Ruleset &condition); |
163 | friend void from_json(const nlohmann::json &obj, Ruleset &condition); |
164 | }; |
165 | |
166 | //! The global ruleset applied to all events. |
167 | struct GlobalRuleset |
168 | { |
169 | //! The actual ruleset. |
170 | Ruleset global; |
171 | |
172 | friend void to_json(nlohmann::json &obj, const GlobalRuleset &set); |
173 | friend void from_json(const nlohmann::json &obj, GlobalRuleset &set); |
174 | }; |
175 | |
176 | //! The response for queries, if a specific ruleset is enabled. |
177 | struct Enabled |
178 | { |
179 | bool enabled = true; |
180 | |
181 | friend void to_json(nlohmann::json &obj, const Enabled &enabled); |
182 | friend void from_json(const nlohmann::json &obj, Enabled &enabled); |
183 | }; |
184 | |
185 | //! An optimized structure to calculate notifications for events. |
186 | /// |
187 | /// You will want to cache this for as long as possible (until the pushrules change), since |
188 | /// constructing this is somewhat expensive. |
189 | class PushRuleEvaluator |
190 | { |
191 | public: |
192 | //! Construct a new push evaluator. Pass the current set of pushrules to evaluate. |
193 | PushRuleEvaluator(const Ruleset &rules); |
194 | ~PushRuleEvaluator(); |
195 | |
196 | //! Additional room information needed to evaluate push rules. |
197 | struct RoomContext |
198 | { |
199 | //! The displayname of the user in the room. |
200 | std::string user_display_name; |
201 | //! the membercount of the room |
202 | std::size_t member_count = 0; |
203 | //! The powerlevels event in this room |
204 | mtx::events::state::PowerLevels power_levels; |
205 | }; |
206 | |
207 | //! Evaluate the pushrules for @event . |
208 | /// |
209 | /// You need to have the room_id set for the event. |
210 | /// `relatedEvents` is a mapping of rel_type to event. Pass all the events that are related to |
211 | /// by this event here. |
212 | /// \returns the actions to apply. |
213 | [[nodiscard]] std::vector<actions::Action> evaluate( |
214 | const mtx::events::collections::TimelineEvent &event, |
215 | const RoomContext &ctx, |
216 | const std::vector<std::pair<mtx::common::Relation, mtx::events::collections::TimelineEvent>> |
217 | &relatedEvents) const; |
218 | |
219 | private: |
220 | struct OptimizedRules; |
221 | std::unique_ptr<OptimizedRules> rules; |
222 | }; |
223 | } |
224 | } |
225 | |