push: Make SimplePushRule generic over the type of the rule_id

This commit is contained in:
Kévin Commaille 2022-11-11 14:25:18 +01:00 committed by Kévin Commaille
parent ae3394a6df
commit e8bec10c6d
5 changed files with 85 additions and 47 deletions

View File

@ -60,9 +60,13 @@ pub struct PushRule {
pub pattern: Option<String>, pub pattern: Option<String>,
} }
impl From<SimplePushRule> for PushRule { impl<T> From<SimplePushRule<T>> for PushRule
fn from(push_rule: SimplePushRule) -> Self { where
T: Into<String>,
{
fn from(push_rule: SimplePushRule<T>) -> Self {
let SimplePushRule { actions, default, enabled, rule_id, .. } = push_rule; let SimplePushRule { actions, default, enabled, rule_id, .. } = push_rule;
let rule_id = rule_id.into();
Self { actions, default, enabled, rule_id, conditions: None, pattern: None } Self { actions, default, enabled, rule_id, conditions: None, pattern: None }
} }
} }
@ -81,9 +85,13 @@ impl From<ConditionalPushRule> for PushRule {
} }
} }
impl From<SimplePushRuleInit> for PushRule { impl<T> From<SimplePushRuleInit<T>> for PushRule
fn from(init: SimplePushRuleInit) -> Self { where
T: Into<String>,
{
fn from(init: SimplePushRuleInit<T>) -> Self {
let SimplePushRuleInit { actions, default, enabled, rule_id } = init; let SimplePushRuleInit { actions, default, enabled, rule_id } = init;
let rule_id = rule_id.into();
Self { actions, default, enabled, rule_id, pattern: None, conditions: None } Self { actions, default, enabled, rule_id, pattern: None, conditions: None }
} }
} }
@ -102,10 +110,16 @@ impl From<PatternedPushRuleInit> for PushRule {
} }
} }
impl From<PushRule> for SimplePushRule { impl<T> TryFrom<PushRule> for SimplePushRule<T>
fn from(push_rule: PushRule) -> Self { where
T: TryFrom<String>,
{
type Error = <T as TryFrom<String>>::Error;
fn try_from(push_rule: PushRule) -> Result<Self, Self::Error> {
let PushRule { actions, default, enabled, rule_id, .. } = push_rule; let PushRule { actions, default, enabled, rule_id, .. } = push_rule;
SimplePushRuleInit { actions, default, enabled, rule_id }.into() let rule_id = T::try_from(rule_id)?;
Ok(SimplePushRuleInit { actions, default, enabled, rule_id }.into())
} }
} }

View File

@ -175,11 +175,13 @@ pub mod v3 {
RuleKind::Sender => { RuleKind::Sender => {
let SimpleRequestBody { actions } = let SimpleRequestBody { actions } =
serde_json::from_slice(request.body().as_ref())?; serde_json::from_slice(request.body().as_ref())?;
let rule_id = rule_id.try_into()?;
NewPushRule::Sender(NewSimplePushRule::new(rule_id, actions)) NewPushRule::Sender(NewSimplePushRule::new(rule_id, actions))
} }
RuleKind::Room => { RuleKind::Room => {
let SimpleRequestBody { actions } = let SimpleRequestBody { actions } =
serde_json::from_slice(request.body().as_ref())?; serde_json::from_slice(request.body().as_ref())?;
let rule_id = rule_id.try_into()?;
NewPushRule::Room(NewSimplePushRule::new(rule_id, actions)) NewPushRule::Room(NewSimplePushRule::new(rule_id, actions))
} }
RuleKind::Content => { RuleKind::Content => {

View File

@ -28,6 +28,7 @@ Breaking changes:
* `MatrixError` is now an enum with the `Json` variant containing the previous fields * `MatrixError` is now an enum with the `Json` variant containing the previous fields
* Change the `ignored_users` field of `IgnoredUserListEventContent` to a map of empty structs, to * Change the `ignored_users` field of `IgnoredUserListEventContent` to a map of empty structs, to
allow eventual fields to be added, as intended by the spec allow eventual fields to be added, as intended by the spec
* Make `SimplePushRule` and associated types generic over the expected type of the `rule_id`
Improvements: Improvements:

View File

@ -25,7 +25,7 @@ use tracing::instrument;
use crate::{ use crate::{
serde::{Raw, StringEnum}, serde::{Raw, StringEnum},
PrivOwnedStr, OwnedRoomId, OwnedUserId, PrivOwnedStr,
}; };
mod action; mod action;
@ -63,10 +63,10 @@ pub struct Ruleset {
pub override_: IndexSet<ConditionalPushRule>, pub override_: IndexSet<ConditionalPushRule>,
/// These rules change the behavior of all messages for a given room. /// These rules change the behavior of all messages for a given room.
pub room: IndexSet<SimplePushRule>, pub room: IndexSet<SimplePushRule<OwnedRoomId>>,
/// These rules configure notification behavior for messages from a specific Matrix user ID. /// These rules configure notification behavior for messages from a specific Matrix user ID.
pub sender: IndexSet<SimplePushRule>, pub sender: IndexSet<SimplePushRule<OwnedUserId>>,
/// These rules are identical to override rules, but have a lower priority than `content`, /// These rules are identical to override rules, but have a lower priority than `content`,
/// `room` and `sender` rules. /// `room` and `sender` rules.
@ -320,7 +320,7 @@ impl Ruleset {
/// `SimplePushRule::from` / `.into()`. /// `SimplePushRule::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SimplePushRule { pub struct SimplePushRule<T> {
/// Actions to determine if and how a notification is delivered for events matching this rule. /// Actions to determine if and how a notification is delivered for events matching this rule.
pub actions: Vec<Action>, pub actions: Vec<Action>,
@ -331,7 +331,9 @@ pub struct SimplePushRule {
pub enabled: bool, pub enabled: bool,
/// The ID of this rule. /// The ID of this rule.
pub rule_id: String, ///
/// This is generally the Matrix ID of the entity that it applies to.
pub rule_id: T,
} }
/// Initial set of fields of `SimplePushRule`. /// Initial set of fields of `SimplePushRule`.
@ -340,7 +342,7 @@ pub struct SimplePushRule {
/// (non-breaking) release of the Matrix specification. /// (non-breaking) release of the Matrix specification.
#[derive(Debug)] #[derive(Debug)]
#[allow(clippy::exhaustive_structs)] #[allow(clippy::exhaustive_structs)]
pub struct SimplePushRuleInit { pub struct SimplePushRuleInit<T> {
/// Actions to determine if and how a notification is delivered for events matching this rule. /// Actions to determine if and how a notification is delivered for events matching this rule.
pub actions: Vec<Action>, pub actions: Vec<Action>,
@ -351,11 +353,13 @@ pub struct SimplePushRuleInit {
pub enabled: bool, pub enabled: bool,
/// The ID of this rule. /// The ID of this rule.
pub rule_id: String, ///
/// This is generally the Matrix ID of the entity that it applies to.
pub rule_id: T,
} }
impl From<SimplePushRuleInit> for SimplePushRule { impl<T> From<SimplePushRuleInit<T>> for SimplePushRule<T> {
fn from(init: SimplePushRuleInit) -> Self { fn from(init: SimplePushRuleInit<T>) -> Self {
let SimplePushRuleInit { actions, default, enabled, rule_id } = init; let SimplePushRuleInit { actions, default, enabled, rule_id } = init;
Self { actions, default, enabled, rule_id } Self { actions, default, enabled, rule_id }
} }
@ -364,23 +368,32 @@ impl From<SimplePushRuleInit> for SimplePushRule {
// The following trait are needed to be able to make // The following trait are needed to be able to make
// an IndexSet of the type // an IndexSet of the type
impl Hash for SimplePushRule { impl<T> Hash for SimplePushRule<T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.rule_id.hash(state); self.rule_id.hash(state);
} }
} }
impl PartialEq for SimplePushRule { impl<T> PartialEq for SimplePushRule<T>
where
T: PartialEq<T>,
{
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.rule_id == other.rule_id self.rule_id == other.rule_id
} }
} }
impl Eq for SimplePushRule {} impl<T> Eq for SimplePushRule<T> where T: Eq {}
impl Equivalent<SimplePushRule> for str { impl<T> Equivalent<SimplePushRule<T>> for str
fn equivalent(&self, key: &SimplePushRule) -> bool { where
self == key.rule_id T: AsRef<str>,
{
fn equivalent(&self, key: &SimplePushRule<T>) -> bool {
self == key.rule_id.as_ref()
} }
} }
@ -668,10 +681,10 @@ pub enum NewPushRule {
Content(NewPatternedPushRule), Content(NewPatternedPushRule),
/// Room-specific rules. /// Room-specific rules.
Room(NewSimplePushRule), Room(NewSimplePushRule<OwnedRoomId>),
/// Sender-specific rules. /// Sender-specific rules.
Sender(NewSimplePushRule), Sender(NewSimplePushRule<OwnedUserId>),
/// Lowest priority rules. /// Lowest priority rules.
Underride(NewConditionalPushRule), Underride(NewConditionalPushRule),
@ -694,8 +707,8 @@ impl NewPushRule {
match self { match self {
NewPushRule::Override(r) => &r.rule_id, NewPushRule::Override(r) => &r.rule_id,
NewPushRule::Content(r) => &r.rule_id, NewPushRule::Content(r) => &r.rule_id,
NewPushRule::Room(r) => &r.rule_id, NewPushRule::Room(r) => r.rule_id.as_ref(),
NewPushRule::Sender(r) => &r.rule_id, NewPushRule::Sender(r) => r.rule_id.as_ref(),
NewPushRule::Underride(r) => &r.rule_id, NewPushRule::Underride(r) => &r.rule_id,
} }
} }
@ -704,24 +717,26 @@ impl NewPushRule {
/// A simple push rule to update or create. /// A simple push rule to update or create.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct NewSimplePushRule { pub struct NewSimplePushRule<T> {
/// The ID of this rule. /// The ID of this rule.
pub rule_id: String, ///
/// This is generally the Matrix ID of the entity that it applies to.
pub rule_id: T,
/// Actions to determine if and how a notification is delivered for events matching this /// Actions to determine if and how a notification is delivered for events matching this
/// rule. /// rule.
pub actions: Vec<Action>, pub actions: Vec<Action>,
} }
impl NewSimplePushRule { impl<T> NewSimplePushRule<T> {
/// Creates a `NewSimplePushRule` with the given ID and actions. /// Creates a `NewSimplePushRule` with the given ID and actions.
pub fn new(rule_id: String, actions: Vec<Action>) -> Self { pub fn new(rule_id: T, actions: Vec<Action>) -> Self {
Self { rule_id, actions } Self { rule_id, actions }
} }
} }
impl From<NewSimplePushRule> for SimplePushRule { impl<T> From<NewSimplePushRule<T>> for SimplePushRule<T> {
fn from(new_rule: NewSimplePushRule) -> Self { fn from(new_rule: NewSimplePushRule<T>) -> Self {
let NewSimplePushRule { rule_id, actions } = new_rule; let NewSimplePushRule { rule_id, actions } = new_rule;
Self { actions, default: false, enabled: true, rule_id } Self { actions, default: false, enabled: true, rule_id }
} }
@ -1002,7 +1017,7 @@ mod tests {
actions: vec![Action::DontNotify], actions: vec![Action::DontNotify],
default: false, default: false,
enabled: false, enabled: false,
rule_id: "!roomid:server.name".into(), rule_id: room_id!("!roomid:server.name").to_owned(),
}; };
let rule_value: JsonValue = to_json_value(rule).unwrap(); let rule_value: JsonValue = to_json_value(rule).unwrap();
@ -1471,7 +1486,7 @@ mod tests {
actions: vec![Action::Notify], actions: vec![Action::Notify],
default: false, default: false,
enabled: true, enabled: true,
rule_id: "@rantanplan:server.name".into(), rule_id: user_id!("@rantanplan:server.name").to_owned(),
}; };
set.sender.insert(sender); set.sender.insert(sender);
@ -1482,7 +1497,7 @@ mod tests {
actions: vec![Action::DontNotify], actions: vec![Action::DontNotify],
default: false, default: false,
enabled: true, enabled: true,
rule_id: "!dm:server.name".into(), rule_id: room_id!("!dm:server.name").to_owned(),
}; };
set.room.insert(room); set.room.insert(room);

View File

@ -4,6 +4,7 @@ use super::{
condition, Action, ConditionalPushRule, FlattenedJson, PatternedPushRule, PushConditionRoomCtx, condition, Action, ConditionalPushRule, FlattenedJson, PatternedPushRule, PushConditionRoomCtx,
Ruleset, SimplePushRule, Ruleset, SimplePushRule,
}; };
use crate::{OwnedRoomId, OwnedUserId};
/// The kinds of push rules that are available. /// The kinds of push rules that are available.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -16,10 +17,10 @@ pub enum AnyPushRule {
Content(PatternedPushRule), Content(PatternedPushRule),
/// Room-specific rules. /// Room-specific rules.
Room(SimplePushRule), Room(SimplePushRule<OwnedRoomId>),
/// Sender-specific rules. /// Sender-specific rules.
Sender(SimplePushRule), Sender(SimplePushRule<OwnedUserId>),
/// Lowest priority rules. /// Lowest priority rules.
Underride(ConditionalPushRule), Underride(ConditionalPushRule),
@ -68,8 +69,8 @@ impl AnyPushRule {
pub struct RulesetIntoIter { pub struct RulesetIntoIter {
content: IndexSetIntoIter<PatternedPushRule>, content: IndexSetIntoIter<PatternedPushRule>,
override_: IndexSetIntoIter<ConditionalPushRule>, override_: IndexSetIntoIter<ConditionalPushRule>,
room: IndexSetIntoIter<SimplePushRule>, room: IndexSetIntoIter<SimplePushRule<OwnedRoomId>>,
sender: IndexSetIntoIter<SimplePushRule>, sender: IndexSetIntoIter<SimplePushRule<OwnedUserId>>,
underride: IndexSetIntoIter<ConditionalPushRule>, underride: IndexSetIntoIter<ConditionalPushRule>,
} }
@ -113,10 +114,10 @@ pub enum AnyPushRuleRef<'a> {
Content(&'a PatternedPushRule), Content(&'a PatternedPushRule),
/// Room-specific rules. /// Room-specific rules.
Room(&'a SimplePushRule), Room(&'a SimplePushRule<OwnedRoomId>),
/// Sender-specific rules. /// Sender-specific rules.
Sender(&'a SimplePushRule), Sender(&'a SimplePushRule<OwnedUserId>),
/// Lowest priority rules. /// Lowest priority rules.
Underride(&'a ConditionalPushRule), Underride(&'a ConditionalPushRule),
@ -162,8 +163,8 @@ impl<'a> AnyPushRuleRef<'a> {
Self::Override(rule) => &rule.rule_id, Self::Override(rule) => &rule.rule_id,
Self::Underride(rule) => &rule.rule_id, Self::Underride(rule) => &rule.rule_id,
Self::Content(rule) => &rule.rule_id, Self::Content(rule) => &rule.rule_id,
Self::Room(rule) => &rule.rule_id, Self::Room(rule) => rule.rule_id.as_ref(),
Self::Sender(rule) => &rule.rule_id, Self::Sender(rule) => rule.rule_id.as_ref(),
} }
} }
@ -184,11 +185,16 @@ impl<'a> AnyPushRuleRef<'a> {
Self::Content(rule) => rule.applies_to("content.body", event, context), Self::Content(rule) => rule.applies_to("content.body", event, context),
Self::Room(rule) => { Self::Room(rule) => {
rule.enabled rule.enabled
&& condition::check_event_match(event, "room_id", &rule.rule_id, context) && condition::check_event_match(
event,
"room_id",
rule.rule_id.as_ref(),
context,
)
} }
Self::Sender(rule) => { Self::Sender(rule) => {
rule.enabled rule.enabled
&& condition::check_event_match(event, "sender", &rule.rule_id, context) && condition::check_event_match(event, "sender", rule.rule_id.as_ref(), context)
} }
} }
} }
@ -199,8 +205,8 @@ impl<'a> AnyPushRuleRef<'a> {
pub struct RulesetIter<'a> { pub struct RulesetIter<'a> {
content: IndexSetIter<'a, PatternedPushRule>, content: IndexSetIter<'a, PatternedPushRule>,
override_: IndexSetIter<'a, ConditionalPushRule>, override_: IndexSetIter<'a, ConditionalPushRule>,
room: IndexSetIter<'a, SimplePushRule>, room: IndexSetIter<'a, SimplePushRule<OwnedRoomId>>,
sender: IndexSetIter<'a, SimplePushRule>, sender: IndexSetIter<'a, SimplePushRule<OwnedUserId>>,
underride: IndexSetIter<'a, ConditionalPushRule>, underride: IndexSetIter<'a, ConditionalPushRule>,
} }