From 83d8f8c43e57f00115a47252c532efdd85b64be7 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 15 Jun 2020 19:05:17 +0200 Subject: [PATCH] Move some types from ruma_events::push_rules to ruma_common::push --- ruma-client-api/src/r0/push.rs | 4 +- .../src/r0/push/get_pushrules_all.rs | 4 +- .../src/r0/push/get_pushrules_global_scope.rs | 4 +- ruma-common/src/push.rs | 235 ++++++++++++++++- ruma-events/src/push_rules.rs | 243 +----------------- 5 files changed, 242 insertions(+), 248 deletions(-) diff --git a/ruma-client-api/src/r0/push.rs b/ruma-client-api/src/r0/push.rs index e967b852..9d166675 100644 --- a/ruma-client-api/src/r0/push.rs +++ b/ruma-client-api/src/r0/push.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; +use ruma_common::push::{Action, PushCondition}; use serde::{Deserialize, Serialize}; use strum::{Display, EnumString}; @@ -18,9 +19,6 @@ pub mod set_pushrule; pub mod set_pushrule_actions; pub mod set_pushrule_enabled; -pub use ruma_common::push::Action; -pub use ruma_events::push_rules::PushCondition; - /// The kinds of push rules that are available #[derive( Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display, EnumString, diff --git a/ruma-client-api/src/r0/push/get_pushrules_all.rs b/ruma-client-api/src/r0/push/get_pushrules_all.rs index cb6feaa4..d485689d 100644 --- a/ruma-client-api/src/r0/push/get_pushrules_all.rs +++ b/ruma-client-api/src/r0/push/get_pushrules_all.rs @@ -1,7 +1,7 @@ -//! [GET /_matrix/client/r0/pushrules/](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-pushrules) +//! [GET /_matrix/client/r0/pushrules/](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushrules) use ruma_api::ruma_api; -use ruma_events::push_rules::Ruleset; +use ruma_common::push::Ruleset; ruma_api! { metadata { diff --git a/ruma-client-api/src/r0/push/get_pushrules_global_scope.rs b/ruma-client-api/src/r0/push/get_pushrules_global_scope.rs index eedcce43..0a5bac76 100644 --- a/ruma-client-api/src/r0/push/get_pushrules_global_scope.rs +++ b/ruma-client-api/src/r0/push/get_pushrules_global_scope.rs @@ -1,7 +1,7 @@ -//! [GET /_matrix/client/r0/pushrules/global/](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-pushrules) +//! [GET /_matrix/client/r0/pushrules/global/](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushrules) use ruma_api::ruma_api; -use ruma_events::push_rules::Ruleset; +use ruma_common::push::Ruleset; ruma_api! { metadata { diff --git a/ruma-common/src/push.rs b/ruma-common/src/push.rs index 2d986f7d..653d8e25 100644 --- a/ruma-common/src/push.rs +++ b/ruma-common/src/push.rs @@ -1,6 +1,6 @@ //! Common types for the [push notifications module][push] //! -//! [push]: https://matrix.org/docs/spec/client_server/r0.6.0#id89 +//! [push]: https://matrix.org/docs/spec/client_server/r0.6.1#id89 use std::fmt::{self, Formatter}; @@ -9,6 +9,97 @@ use serde_json::value::RawValue as RawJsonValue; mod tweak_serde; +/// A push ruleset scopes a set of rules according to some criteria. +/// +/// For example, some rules may only be applied for messages from a particular sender, a particular +/// room, or by default. The push ruleset contains the entire set of scopes and rules. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Ruleset { + /// These rules configure behavior for (unencrypted) messages that match certain patterns. + pub content: Vec, + + /// These user-configured rules are given the highest priority. + /// + /// This field is named `override_` instead of `override` because the latter is a reserved + /// keyword in Rust. + #[serde(rename = "override")] + pub override_: Vec, + + /// These rules change the behavior of all messages for a given room. + pub room: Vec, + + /// These rules configure notification behavior for messages from a specific Matrix user ID. + pub sender: Vec, + + /// These rules are identical to override rules, but have a lower priority than `content`, + /// `room` and `sender` rules. + pub underride: Vec, +} + +/// 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. +/// +/// These rules are stored on the user's homeserver. They are manually configured by the user, who +/// can create and view them via the Client/Server API. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct PushRule { + /// Actions to determine if and how a notification is delivered for events matching this rule. + pub actions: Vec, + + /// Whether this is a default rule, or has been set explicitly. + pub default: bool, + + /// Whether the push rule is enabled or not. + pub enabled: bool, + + /// The ID of this rule. + pub rule_id: String, +} + +/// Like `PushRule`, but with an additional `conditions` field. +/// +/// Only applicable to underride and override rules. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ConditionalPushRule { + /// Actions to determine if and how a notification is delivered for events matching this rule. + pub actions: Vec, + + /// Whether this is a default rule, or has been set explicitly. + pub default: bool, + + /// Whether the push rule is enabled or not. + pub enabled: bool, + + /// The ID of this rule. + pub rule_id: String, + + /// 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. + pub conditions: Vec, +} + +/// Like `PushRule`, but with an additional `pattern` field. +/// +/// Only applicable to content rules. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct PatternedPushRule { + /// Actions to determine if and how a notification is delivered for events matching this rule. + pub actions: Vec, + + /// Whether this is a default rule, or has been set explicitly. + pub default: bool, + + /// Whether the push rule is enabled or not. + pub enabled: bool, + + /// The ID of this rule. + pub rule_id: String, + + /// The glob-style pattern to match against. + pub pattern: String, +} + /// This represents the different actions that should be taken when a rule is matched, and /// controls how notifications are delivered to the client. /// @@ -115,12 +206,53 @@ impl Serialize for Action { } } +/// A condition that must apply for an associated push rule's action to be taken. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[non_exhaustive] +#[serde(tag = "kind", rename_all = "snake_case")] +pub enum PushCondition { + /// This is a glob pattern match on a field of the event. + EventMatch { + /// The dot-separated field of the event to match. + key: String, + + /// 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. + pattern: String, + }, + + /// This matches unencrypted messages where `content.body` contains the owner's display name in + /// that room. + ContainsDisplayName, + + /// This matches the current number of members in the room. + RoomMemberCount { + /// 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 `==`. + is: String, + }, + + /// This takes into account the current power levels in the room, ensuring the sender of the + /// event has high enough power to trigger the notification. + SenderNotificationPermission { + /// 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`. + key: String, + }, +} + #[cfg(test)] mod tests { use matches::assert_matches; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; - use super::{Action, Tweak}; + use super::{Action, PushCondition, Tweak}; #[test] fn serialize_string_action() { @@ -184,4 +316,103 @@ mod tests { Action::SetTweak(Tweak::Highlight(true)) ); } + + #[test] + fn serialize_event_match_condition() { + let json_data = json!({ + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + }); + assert_eq!( + to_json_value(&PushCondition::EventMatch { + key: "content.msgtype".to_string(), + pattern: "m.notice".to_string(), + }) + .unwrap(), + json_data + ); + } + + #[test] + fn serialize_contains_display_name_condition() { + assert_eq!( + to_json_value(&PushCondition::ContainsDisplayName).unwrap(), + json!({ "kind": "contains_display_name" }) + ); + } + + #[test] + fn serialize_room_member_count_condition() { + let json_data = json!({ + "is": "2", + "kind": "room_member_count" + }); + assert_eq!( + to_json_value(&PushCondition::RoomMemberCount { is: "2".to_string() }).unwrap(), + json_data + ); + } + + #[test] + fn serialize_sender_notification_permission_condition() { + let json_data = json!({ + "key": "room", + "kind": "sender_notification_permission" + }); + assert_eq!( + json_data, + to_json_value(&PushCondition::SenderNotificationPermission { key: "room".to_string() }) + .unwrap() + ); + } + + #[test] + fn deserialize_event_match_condition() { + let json_data = json!({ + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + }); + assert_matches!( + from_json_value::(json_data).unwrap(), + PushCondition::EventMatch { key, pattern } + if key == "content.msgtype" && pattern == "m.notice" + ); + } + + #[test] + fn deserialize_contains_display_name_condition() { + assert_matches!( + from_json_value::(json!({ "kind": "contains_display_name" })).unwrap(), + PushCondition::ContainsDisplayName + ); + } + + #[test] + fn deserialize_room_member_count_condition() { + let json_data = json!({ + "is": "2", + "kind": "room_member_count" + }); + assert_matches!( + from_json_value::(json_data).unwrap(), + PushCondition::RoomMemberCount { is } + if is == "2" + ); + } + + #[test] + fn deserialize_sender_notification_permission_condition() { + let json_data = json!({ + "key": "room", + "kind": "sender_notification_permission" + }); + assert_matches!( + from_json_value::(json_data).unwrap(), + PushCondition::SenderNotificationPermission { + key + } if key == "room" + ); + } } diff --git a/ruma-events/src/push_rules.rs b/ruma-events/src/push_rules.rs index 9c83a903..1dcecc23 100644 --- a/ruma-events/src/push_rules.rs +++ b/ruma-events/src/push_rules.rs @@ -1,5 +1,6 @@ //! Types for the the *m.push_rules* event. +use ruma_common::push::Ruleset; use ruma_events_macros::BasicEventContent; use serde::{Deserialize, Serialize}; @@ -16,246 +17,11 @@ pub struct PushRulesEventContent { pub global: Ruleset, } -pub use ruma_common::push::Action; - -/// A push ruleset scopes a set of rules according to some criteria. -/// -/// For example, some rules may only be applied for messages from a particular sender, a particular -/// room, or by default. The push ruleset contains the entire set of scopes and rules. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Ruleset { - /// These rules configure behavior for (unencrypted) messages that match certain patterns. - pub content: Vec, - - /// These user-configured rules are given the highest priority. - /// - /// This field is named `override_` instead of `override` because the latter is a reserved - /// keyword in Rust. - #[serde(rename = "override")] - pub override_: Vec, - - /// These rules change the behavior of all messages for a given room. - pub room: Vec, - - /// These rules configure notification behavior for messages from a specific Matrix user ID. - pub sender: Vec, - - /// These rules are identical to override rules, but have a lower priority than `content`, - /// `room` and `sender` rules. - pub underride: Vec, -} - -/// 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. -/// -/// These rules are stored on the user's homeserver. They are manually configured by the user, who -/// can create and view them via the Client/Server API. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct PushRule { - /// Actions to determine if and how a notification is delivered for events matching this rule. - pub actions: Vec, - - /// Whether this is a default rule, or has been set explicitly. - pub default: bool, - - /// Whether the push rule is enabled or not. - pub enabled: bool, - - /// The ID of this rule. - pub rule_id: String, -} - -/// Like `PushRule`, but with an additional `conditions` field. -/// -/// Only applicable to underride and override rules. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct ConditionalPushRule { - /// Actions to determine if and how a notification is delivered for events matching this rule. - pub actions: Vec, - - /// Whether this is a default rule, or has been set explicitly. - pub default: bool, - - /// Whether the push rule is enabled or not. - pub enabled: bool, - - /// The ID of this rule. - pub rule_id: String, - - /// 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. - pub conditions: Vec, -} - -/// Like `PushRule`, but with an additional `pattern` field. -/// -/// Only applicable to content rules. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct PatternedPushRule { - /// Actions to determine if and how a notification is delivered for events matching this rule. - pub actions: Vec, - - /// Whether this is a default rule, or has been set explicitly. - pub default: bool, - - /// Whether the push rule is enabled or not. - pub enabled: bool, - - /// The ID of this rule. - pub rule_id: String, - - /// The glob-style pattern to match against. - pub pattern: String, -} - -/// A condition that must apply for an associated push rule's action to be taken. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum PushCondition { - /// This is a glob pattern match on a field of the event. - EventMatch { - /// The dot-separated field of the event to match. - key: String, - - /// 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. - pattern: String, - }, - - /// This matches unencrypted messages where `content.body` contains the owner's display name in - /// that room. - ContainsDisplayName, - - /// This matches the current number of members in the room. - RoomMemberCount { - /// 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 `==`. - is: String, - }, - - /// This takes into account the current power levels in the room, ensuring the sender of the - /// event has high enough power to trigger the notification. - SenderNotificationPermission { - /// 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`. - key: String, - }, -} - #[cfg(test)] mod tests { - use matches::assert_matches; - use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; + use serde_json::{from_value as from_json_value, json}; - use super::{PushCondition, PushRulesEvent}; - use crate::EventJson; - - #[test] - fn serialize_event_match_condition() { - let json_data = json!({ - "key": "content.msgtype", - "kind": "event_match", - "pattern": "m.notice" - }); - assert_eq!( - to_json_value(&PushCondition::EventMatch { - key: "content.msgtype".to_string(), - pattern: "m.notice".to_string(), - }) - .unwrap(), - json_data - ); - } - - #[test] - fn serialize_contains_display_name_condition() { - assert_eq!( - to_json_value(&PushCondition::ContainsDisplayName).unwrap(), - json!({ "kind": "contains_display_name" }) - ); - } - - #[test] - fn serialize_room_member_count_condition() { - let json_data = json!({ - "is": "2", - "kind": "room_member_count" - }); - assert_eq!( - to_json_value(&PushCondition::RoomMemberCount { is: "2".to_string() }).unwrap(), - json_data - ); - } - - #[test] - fn serialize_sender_notification_permission_condition() { - let json_data = json!({ - "key": "room", - "kind": "sender_notification_permission" - }); - assert_eq!( - json_data, - to_json_value(&PushCondition::SenderNotificationPermission { key: "room".to_string() }) - .unwrap() - ); - } - - #[test] - fn deserialize_event_match_condition() { - let json_data = json!({ - "key": "content.msgtype", - "kind": "event_match", - "pattern": "m.notice" - }); - assert_matches!( - from_json_value::(json_data).unwrap(), - PushCondition::EventMatch { key, pattern } - if key == "content.msgtype" && pattern == "m.notice" - ); - } - - #[test] - fn deserialize_contains_display_name_condition() { - assert_matches!( - from_json_value::(json!({ "kind": "contains_display_name" })).unwrap(), - PushCondition::ContainsDisplayName - ); - } - - #[test] - fn deserialize_room_member_count_condition() { - let json_data = json!({ - "is": "2", - "kind": "room_member_count" - }); - assert_matches!( - from_json_value::(json_data).unwrap(), - PushCondition::RoomMemberCount { is } - if is == "2" - ); - } - - #[test] - fn deserialize_sender_notification_permission_condition() { - let json_data = json!({ - "key": "room", - "kind": "sender_notification_permission" - }); - assert_matches!( - from_json_value::(json_data).unwrap(), - PushCondition::SenderNotificationPermission { - key - } if key == "room" - ); - } + use super::PushRulesEvent; #[test] fn sanity_check() { @@ -452,7 +218,6 @@ mod tests { "type": "m.push_rules" }); - let _ = - from_json_value::>(json_data).unwrap().deserialize().unwrap(); + assert!(from_json_value::(json_data).is_ok()); } }