diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ca777b..c945dedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ Breaking changes: * Add `alt_aliases` to `CanonicalAliasEventContent` * Replace `format` and `formatted_body` fields in `TextMessagEventContent`, `NoticeMessageEventContent` and `EmoteMessageEventContent` with `formatted: FormattedBody` +* Rename `override_rules` in `push_rules::Ruleset` to `override_` +* Change `push_rules::PushCondition` variants from newtype variants with separate inner types to + struct variants + * This change removes the types `EventMatchCondition`, `RoomMemberCountCondition` and + `SenderNotificationPermissionCondition` Improvements: diff --git a/src/push_rules.rs b/src/push_rules.rs index 26f1b40f..450c640e 100644 --- a/src/push_rules.rs +++ b/src/push_rules.rs @@ -1,10 +1,7 @@ //! Types for the the *m.push_rules* event. use ruma_events_macros::ruma_event; -use serde::{ - de::Error, ser::SerializeStruct as _, Deserialize, Deserializer, Serialize, Serializer, -}; -use serde_json::{from_value, Value as JsonValue}; +use serde::{Deserialize, Serialize}; ruma_event! { /// Describes all push rules for a user. @@ -30,8 +27,11 @@ pub struct Ruleset { 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_rules: Vec, + pub override_: Vec, /// These rules change the behaviour of all messages for a given room. pub room: Vec, @@ -109,132 +109,43 @@ pub struct PatternedPushRule { } /// A condition that must apply for an associated push rule's action to be taken. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(tag = "kind", rename_all = "snake_case")] pub enum PushCondition { /// This is a glob pattern match on a field of the event. - EventMatch(EventMatchCondition), + 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(RoomMemberCountCondition), + 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(SenderNotificationPermissionCondition), -} - -impl Serialize for PushCondition { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match *self { - PushCondition::EventMatch(ref condition) => condition.serialize(serializer), - PushCondition::ContainsDisplayName => { - let mut state = serializer.serialize_struct("ContainsDisplayNameCondition", 1)?; - - state.serialize_field("kind", "contains_display_name")?; - - state.end() - } - PushCondition::RoomMemberCount(ref condition) => condition.serialize(serializer), - PushCondition::SenderNotificationPermission(ref condition) => { - condition.serialize(serializer) - } - } - } -} - -// TODO: Derive -impl<'de> Deserialize<'de> for PushCondition { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value: JsonValue = Deserialize::deserialize(deserializer)?; - - let kind_value = match value.get("kind") { - Some(value) => value.clone(), - None => return Err(D::Error::missing_field("kind")), - }; - - let kind = match kind_value.as_str() { - Some(kind) => kind, - None => return Err(D::Error::custom("field `kind` must be a string")), - }; - - match kind { - "event_match" => { - let condition = match from_value::(value) { - Ok(condition) => condition, - Err(error) => return Err(D::Error::custom(error.to_string())), - }; - - Ok(PushCondition::EventMatch(condition)) - } - "contains_display_name" => Ok(PushCondition::ContainsDisplayName), - "room_member_count" => { - let condition = match from_value::(value) { - Ok(condition) => condition, - Err(error) => return Err(D::Error::custom(error.to_string())), - }; - - Ok(PushCondition::RoomMemberCount(condition)) - } - "sender_notification_permission" => { - let condition = match from_value::(value) { - Ok(condition) => condition, - Err(error) => return Err(D::Error::custom(error.to_string())), - }; - - Ok(PushCondition::SenderNotificationPermission(condition)) - } - unknown_kind => Err(D::Error::custom(&format!( - "unknown condition kind `{}`", - unknown_kind - ))), - } - } -} - -/// A push condition that matches a glob pattern match on a field of the event. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(tag = "kind", rename = "event_match")] -pub struct EventMatchCondition { - /// The dot-separated field of the event to match. - pub 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. - pub pattern: String, -} - -/// A push condition that matches the current number of members in the room. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(tag = "kind", rename = "room_member_count")] -pub struct RoomMemberCountCondition { - /// 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 `==`. - pub is: String, -} - -/// A push condition that takes into account the current power levels in the room, ensuring the -/// sender of the event has high enough power to trigger the notification. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(tag = "kind", rename = "sender_notification_permission")] -pub struct SenderNotificationPermissionCondition { - /// 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`. - pub key: String, + 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)] @@ -242,10 +153,7 @@ mod tests { use matches::assert_matches; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; - use super::{ - EventMatchCondition, PushCondition, PushRulesEvent, RoomMemberCountCondition, - SenderNotificationPermissionCondition, - }; + use super::{PushCondition, PushRulesEvent}; use crate::EventJson; #[test] @@ -256,10 +164,10 @@ mod tests { "pattern": "m.notice" }); assert_eq!( - to_json_value(&PushCondition::EventMatch(EventMatchCondition { + to_json_value(&PushCondition::EventMatch { key: "content.msgtype".to_string(), pattern: "m.notice".to_string(), - })) + }) .unwrap(), json_data ); @@ -280,9 +188,9 @@ mod tests { "kind": "room_member_count" }); assert_eq!( - to_json_value(&PushCondition::RoomMemberCount(RoomMemberCountCondition { + to_json_value(&PushCondition::RoomMemberCount { is: "2".to_string(), - })) + }) .unwrap(), json_data ); @@ -296,11 +204,9 @@ mod tests { }); assert_eq!( json_data, - to_json_value(&PushCondition::SenderNotificationPermission( - SenderNotificationPermissionCondition { - key: "room".to_string(), - } - )) + to_json_value(&PushCondition::SenderNotificationPermission { + key: "room".to_string(), + }) .unwrap() ); } @@ -314,7 +220,7 @@ mod tests { }); assert_matches!( from_json_value::(json_data).unwrap(), - PushCondition::EventMatch(EventMatchCondition { key, pattern }) + PushCondition::EventMatch { key, pattern } if key == "content.msgtype" && pattern == "m.notice" ); } @@ -335,7 +241,7 @@ mod tests { }); assert_matches!( from_json_value::(json_data).unwrap(), - PushCondition::RoomMemberCount(RoomMemberCountCondition { is }) + PushCondition::RoomMemberCount { is } if is == "2" ); } @@ -348,9 +254,9 @@ mod tests { }); assert_matches!( from_json_value::(json_data).unwrap(), - PushCondition::SenderNotificationPermission(SenderNotificationPermissionCondition { + PushCondition::SenderNotificationPermission { key - }) if key == "room" + } if key == "room" ); } @@ -393,11 +299,11 @@ mod tests { "dont_notify" ], "conditions": [ - { - "key": "content.msgtype", - "kind": "event_match", - "pattern": "m.notice" - } + { + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + } ], "default": true, "enabled": true, @@ -420,11 +326,11 @@ mod tests { } ], "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.call.invite" - } + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } ], "default": true, "enabled": true, @@ -463,10 +369,10 @@ mod tests { } ], "conditions": [ - { - "is": "2", - "kind": "room_member_count" - } + { + "is": "2", + "kind": "room_member_count" + } ], "default": true, "enabled": true, @@ -485,21 +391,21 @@ mod tests { } ], "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.member" - }, - { - "key": "content.membership", - "kind": "event_match", - "pattern": "invite" - }, - { - "key": "state_key", - "kind": "event_match", - "pattern": "@alice:example.com" - } + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "@alice:example.com" + } ], "default": true, "enabled": true, @@ -514,11 +420,11 @@ mod tests { } ], "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.member" - } + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } ], "default": true, "enabled": true,