-
Nicolas Werner authoredNicolas Werner authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
pushrules.hpp 7.62 KiB
#pragma once
/// @file
/// @brief Pushrules and notification settings.
#if __has_include(<nlohmann/json_fwd.hpp>)
#include <nlohmann/json_fwd.hpp>
#else
#include <nlohmann/json.hpp>
#endif
#include <compare>
#include <string>
#include <variant>
#include <vector>
#include "mtx/events/common.hpp"
#include "mtx/events/power_levels.hpp"
namespace mtx {
namespace events {
namespace collections {
struct TimelineEvent;
}
}
//! Namespace for the pushrules specific endpoints.
namespace pushrules {
//! A condition to match pushrules on.
struct PushCondition
{
//! Required. The kind of condition to apply. See conditions for more information on the
//! allowed kinds and how they work.
std::string kind;
//! Required for event_match conditions. The dot- separated field of the event to match.
//!
//! Required for sender_notification_permission conditions. The field in the power level
//! event the user needs a minimum power level for. Fields must be specified under the
//! notifications property in the power level event's content.
std::string key;
//! Required for event_match conditions. The glob- style pattern to match against. Patterns
//! with no special glob characters should be treated as having asterisks prepended and
//! appended when testing the condition.
std::string pattern;
//! Required for room_member_count conditions. A decimal integer optionally prefixed by one
//! of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly
//! less than the given number and so forth. If no prefix is present, this parameter
//! defaults to ==.
std::string is;
//! The relation type to match on. Only valid for `im.nheko.msc3664.related_event_match`
//! conditions.
mtx::common::RelationType rel_type = mtx::common::RelationType::Unsupported;
//! Wether to match fallback relations or not.
bool include_fallback = false;
friend void to_json(nlohmann::json &obj, const PushCondition &condition);
friend void from_json(const nlohmann::json &obj, PushCondition &condition);
};
//! Namespace for the different push actions.
namespace actions {
//! Notify the user.
struct notify
{
bool operator==(const notify &) const noexcept = default;
};
//! Don't notify the user.
struct dont_notify
{
bool operator==(const dont_notify &) const noexcept = default;
};
/// @brief This enables notifications for matching events but activates homeserver specific
/// behaviour to intelligently coalesce multiple events into a single notification.
///
/// Not all homeservers may support this. Those that do not support it should treat it as the notify
/// action.
struct coalesce
{
bool operator==(const coalesce &) const noexcept = default;
};
//! Play a sound.
struct set_tweak_sound
{
//! The sound to play.
std::string value = "default";
bool operator==(const set_tweak_sound &) const noexcept = default;
};
//! Highlight the message.
struct set_tweak_highlight
{
bool value = true;
bool operator==(const set_tweak_highlight &) const noexcept = default;
};
//! A collection for the different actions.
using Action = std::variant<actions::notify,
actions::dont_notify,
actions::coalesce,
actions::set_tweak_sound,
actions::set_tweak_highlight>;
void
to_json(nlohmann::json &obj, const Action &action);
void
from_json(const nlohmann::json &obj, Action &action);
//! A list of actions.
struct Actions
{
std::vector<Action> actions;
friend void to_json(nlohmann::json &obj, const Actions &action);
friend void from_json(const nlohmann::json &obj, Actions &action);
bool operator==(const Actions &) const noexcept = default;
};
}
//! A pushrule defining the notification behaviour for a message.
struct PushRule
{
//! Required. Whether this is a default rule, or has been set explicitly.
bool default_ = false;
//! Required. Whether the push rule is enabled or not.
bool enabled = true;
//! Required. The actions to perform when this rule is matched.
std::vector<actions::Action> actions;
//! Required. The ID of this rule.
std::string rule_id;
//! The glob-style pattern to match against. Only applicable to content rules.
std::string pattern;
//! The conditions that must hold true for an event in order for a rule to be applied to an
//! event. A rule with no conditions always matches. Only applicable to underride and
//! override rules.
std::vector<PushCondition> conditions;
friend void to_json(nlohmann::json &obj, const PushRule &condition);
friend void from_json(const nlohmann::json &obj, PushRule &condition);
};
//! All the pushrules to evaluate for events.
struct Ruleset
{
//! see https://matrix.org/docs/spec/client_server/latest#push-rules
//
// A push rule is a single rule that states under what conditions an event should be passed
// onto a push gateway and how the notification should be presented. There are different
// "kinds" of push rules and each rule has an associated priority. Every push rule MUST have
// a kind and rule_id. The rule_id is a unique string within the kind of rule and its'
// scope: rule_ids do not need to be unique between rules of the same kind on different
// devices. Rules may have extra keys depending on the value of kind. The different kinds of
// rule in descending order of priority are:
std::vector<PushRule> override_;
std::vector<PushRule> content;
std::vector<PushRule> room;
std::vector<PushRule> sender;
std::vector<PushRule> underride;
friend void to_json(nlohmann::json &obj, const Ruleset &condition);
friend void from_json(const nlohmann::json &obj, Ruleset &condition);
};
//! The global ruleset applied to all events.
struct GlobalRuleset
{
//! The actual ruleset.
Ruleset global;
friend void to_json(nlohmann::json &obj, const GlobalRuleset &set);
friend void from_json(const nlohmann::json &obj, GlobalRuleset &set);
};
//! The response for queries, if a specific ruleset is enabled.
struct Enabled
{
bool enabled = true;
friend void to_json(nlohmann::json &obj, const Enabled &enabled);
friend void from_json(const nlohmann::json &obj, Enabled &enabled);
};
//! An optimized structure to calculate notifications for events.
///
/// You will want to cache this for as long as possible (until the pushrules change), since
/// constructing this is somewhat expensive.
class PushRuleEvaluator
{
public:
//! Construct a new push evaluator. Pass the current set of pushrules to evaluate.
PushRuleEvaluator(const Ruleset &rules);
~PushRuleEvaluator();
//! Additional room information needed to evaluate push rules.
struct RoomContext
{
//! The displayname of the user in the room.
std::string user_display_name;
//! the membercount of the room
std::size_t member_count = 0;
//! The powerlevels event in this room
mtx::events::state::PowerLevels power_levels;
};
//! Evaluate the pushrules for @event .
///
/// You need to have the room_id set for the event.
/// `relatedEvents` is a mapping of rel_type to event. Pass all the events that are related to
/// by this event here.
/// \returns the actions to apply.
[[nodiscard]] std::vector<actions::Action> evaluate(
const mtx::events::collections::TimelineEvent &event,
const RoomContext &ctx,
const std::vector<std::pair<mtx::common::Relation, mtx::events::collections::TimelineEvent>>
&relatedEvents) const;
private:
struct OptimizedRules;
std::unique_ptr<OptimizedRules> rules;
};
}
}