Skip to content

Commit

Permalink
push: Add methods to get and insert push rules in a Ruleset
Browse files Browse the repository at this point in the history
  • Loading branch information
zecakeh committed Oct 31, 2022
1 parent 875e9e9 commit 9f98181
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 0 deletions.
92 changes: 92 additions & 0 deletions crates/ruma-common/src/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@ use crate::{
mod action;
mod condition;
mod iter;
mod operations;
mod predefined;

use self::operations::replace_and_move;
pub use self::{
action::{Action, Tweak},
condition::{
ComparisonOperator, FlattenedJson, PushCondition, PushConditionRoomCtx, RoomMemberCountIs,
},
iter::{AnyPushRule, AnyPushRuleRef, RulesetIntoIter, RulesetIter},
operations::UnknownRuleIdError,
predefined::{
PredefinedContentRuleId, PredefinedOverrideRuleId, PredefinedRuleId,
PredefinedUnderrideRuleId,
Expand Down Expand Up @@ -100,6 +103,95 @@ impl Ruleset {
}
}

/// Adds a rule to the rule set, replacing the existing rule with the same kind and `rule_id`.
///
/// Returns the replaced push rule, if any.
///
/// _Note_ that a user-defined rule should always be added before the server
/// default rules, so `Ruleset::replace_before` should be used instead, if applicable.
pub fn replace(&mut self, rule: AnyPushRule) -> Option<AnyPushRule> {
match rule {
AnyPushRule::Override(r) => self.override_.replace(r).map(AnyPushRule::Override),
AnyPushRule::Underride(r) => self.underride.replace(r).map(AnyPushRule::Underride),
AnyPushRule::Content(r) => self.content.replace(r).map(AnyPushRule::Content),
AnyPushRule::Room(r) => self.room.replace(r).map(AnyPushRule::Room),
AnyPushRule::Sender(r) => self.sender.replace(r).map(AnyPushRule::Sender),
}
}

/// Adds a rule to the rule set, replacing the existing rule with the same kind and `rule_id`,
/// and moving it before the rule that matches the given `before_rule_id`.
///
/// Returns an error if no push rule could be found with the given `before_rule_id`. Otherwise
/// returns the replaced push rule, if any.
///
/// _Note_ that a user-defined rule cannot be added relative to a server
/// default rule through the API, an error should be returned instead.
pub fn replace_before(
&mut self,
rule: AnyPushRule,
before_rule_id: impl AsRef<str>,
) -> Result<Option<AnyPushRule>, UnknownRuleIdError> {
let rule_id = before_rule_id.as_ref();

match rule {
AnyPushRule::Override(r) => replace_and_move(&mut self.override_, r, rule_id, false)
.map(|r| r.map(AnyPushRule::Override)),
AnyPushRule::Underride(r) => replace_and_move(&mut self.underride, r, rule_id, false)
.map(|r| r.map(AnyPushRule::Underride)),
AnyPushRule::Content(r) => replace_and_move(&mut self.content, r, rule_id, false)
.map(|r| r.map(AnyPushRule::Content)),
AnyPushRule::Room(r) => replace_and_move(&mut self.room, r, rule_id, false)
.map(|r| r.map(AnyPushRule::Room)),
AnyPushRule::Sender(r) => replace_and_move(&mut self.sender, r, rule_id, false)
.map(|r| r.map(AnyPushRule::Sender)),
}
}

/// Adds a rule to the rule set, replacing the existing rule with the same kind and `rule_id`,
/// and moving it after the rule that matches the given `after_rule_id`.
///
/// Returns an error if no push rule could be found with the given `after_rule_id`. Otherwise
/// returns the replaced push rule, if any.
///
/// _Note_ that a user-defined rule cannot be added relative to a server
/// default rule through the API, an error should be returned instead.
pub fn replace_after(
&mut self,
rule: AnyPushRule,
after_rule_id: impl AsRef<str>,
) -> Result<Option<AnyPushRule>, UnknownRuleIdError> {
let rule_id = after_rule_id.as_ref();

match rule {
AnyPushRule::Override(r) => replace_and_move(&mut self.override_, r, rule_id, true)
.map(|r| r.map(AnyPushRule::Override)),
AnyPushRule::Underride(r) => replace_and_move(&mut self.underride, r, rule_id, true)
.map(|r| r.map(AnyPushRule::Underride)),
AnyPushRule::Content(r) => replace_and_move(&mut self.content, r, rule_id, true)
.map(|r| r.map(AnyPushRule::Content)),
AnyPushRule::Room(r) => {
replace_and_move(&mut self.room, r, rule_id, true).map(|r| r.map(AnyPushRule::Room))
}
AnyPushRule::Sender(r) => replace_and_move(&mut self.sender, r, rule_id, true)
.map(|r| r.map(AnyPushRule::Sender)),
}
}

/// Get the rule from the given kind and with the given `rule_id` in the rule set.
pub fn get(&self, kind: RuleKind, rule_id: impl AsRef<str>) -> Option<AnyPushRuleRef<'_>> {
let rule_id = rule_id.as_ref();

match kind {
RuleKind::Override => self.override_.get(rule_id).map(AnyPushRuleRef::Override),
RuleKind::Underride => self.underride.get(rule_id).map(AnyPushRuleRef::Underride),
RuleKind::Sender => self.sender.get(rule_id).map(AnyPushRuleRef::Sender),
RuleKind::Room => self.room.get(rule_id).map(AnyPushRuleRef::Room),
RuleKind::Content => self.content.get(rule_id).map(AnyPushRuleRef::Content),
RuleKind::_Custom(_) => None,
}
}

/// Get the first push rule that applies to this event, if any.
///
/// # Arguments
Expand Down
33 changes: 33 additions & 0 deletions crates/ruma-common/src/push/operations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::hash::Hash;

use indexmap::{Equivalent, IndexSet};
use thiserror::Error;

/// The error type returned when trying to move a push rule before or after a push rule with a given
/// rule ID that could not be found.
#[derive(Debug, Error)]
#[non_exhaustive]
#[error("Unknown rule ID")]
pub struct UnknownRuleIdError;

pub fn replace_and_move<T>(
set: &mut IndexSet<T>,
rule: T,
move_rule_id: &str,
move_after: bool,
) -> Result<Option<T>, UnknownRuleIdError>
where
T: Hash + Eq,
str: Equivalent<T>,
{
let (from, replaced) = set.replace_full(rule);
let mut to = set.get_index_of(move_rule_id).ok_or(UnknownRuleIdError)?;

if move_after {
to += 1;
}

set.move_index(from, to);

Ok(replaced)
}

0 comments on commit 9f98181

Please sign in to comment.