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
20namespace mtx {
21namespace events {
22namespace collections {
23struct TimelineEvent;
24}
25}
26
27//! Namespace for the pushrules specific endpoints.
28namespace pushrules {
29//! A condition to match pushrules on.
30struct 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.
61namespace actions {
62//! Notify the user.
63struct notify
64{
65 bool operator==(const notify &) const noexcept = default;
66};
67//! Don't notify the user.
68struct 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.
77struct coalesce
78{
79 bool operator==(const coalesce &) const noexcept = default;
80};
81//! Play a sound.
82struct 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.
90struct 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.
98using Action = std::variant<actions::notify,
99 actions::dont_notify,
100 actions::coalesce,
101 actions::set_tweak_sound,
102 actions::set_tweak_highlight>;
103
104void
105to_json(nlohmann::json &obj, const Action &action);
106
107void
108from_json(const nlohmann::json &obj, Action &action);
109
110//! A list of actions.
111struct 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.
123struct 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.
145struct 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.
167struct 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.
177struct 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.
189class PushRuleEvaluator
190{
191public:
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
219private:
220 struct OptimizedRules;
221 std::unique_ptr<OptimizedRules> rules;
222};
223}
224}
225