ruma_common/push/condition/
push_condition_serde.rs

1use serde::{de, Deserialize, Serialize, Serializer};
2use serde_json::value::RawValue as RawJsonValue;
3
4#[cfg(feature = "unstable-msc3931")]
5use super::RoomVersionFeature;
6use super::{PushCondition, RoomMemberCountIs, ScalarJsonValue};
7use crate::{power_levels::NotificationPowerLevelsKey, serde::from_raw_json_value};
8
9impl Serialize for PushCondition {
10    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
11    where
12        S: Serializer,
13    {
14        match self {
15            PushCondition::_Custom(custom) => custom.serialize(serializer),
16            _ => PushConditionSerDeHelper::from(self.clone()).serialize(serializer),
17        }
18    }
19}
20
21impl<'de> Deserialize<'de> for PushCondition {
22    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
23    where
24        D: de::Deserializer<'de>,
25    {
26        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
27        let ExtractKind { kind } = from_raw_json_value(&json)?;
28
29        match kind.as_ref() {
30            "event_match"
31            | "contains_display_name"
32            | "room_member_count"
33            | "sender_notification_permission"
34            | "event_property_is"
35            | "event_property_contains" => {
36                let helper: PushConditionSerDeHelper = from_raw_json_value(&json)?;
37                Ok(helper.into())
38            }
39            #[cfg(feature = "unstable-msc3931")]
40            "org.matrix.msc3931.room_version_supports" => {
41                let helper: PushConditionSerDeHelper = from_raw_json_value(&json)?;
42                Ok(helper.into())
43            }
44            #[cfg(feature = "unstable-msc4306")]
45            "io.element.msc4306.thread_subscription" => {
46                let helper: PushConditionSerDeHelper = from_raw_json_value(&json)?;
47                Ok(helper.into())
48            }
49            _ => from_raw_json_value(&json).map(Self::_Custom),
50        }
51    }
52}
53
54#[derive(Deserialize)]
55struct ExtractKind {
56    kind: String,
57}
58
59#[derive(Serialize, Deserialize)]
60#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
61#[serde(tag = "kind", rename_all = "snake_case")]
62enum PushConditionSerDeHelper {
63    /// A glob pattern match on a field of the event.
64    EventMatch {
65        /// The dot-separated field of the event to match.
66        key: String,
67
68        /// The glob-style pattern to match against.
69        ///
70        /// Patterns with no special glob characters should be treated as having asterisks
71        /// prepended and appended when testing the condition.
72        pattern: String,
73    },
74
75    /// Matches unencrypted messages where `content.body` contains the owner's display name in that
76    /// room.
77    ContainsDisplayName,
78
79    /// Matches the current number of members in the room.
80    RoomMemberCount {
81        /// The condition on the current number of members in the room.
82        is: RoomMemberCountIs,
83    },
84
85    /// Takes into account the current power levels in the room, ensuring the sender of the event
86    /// has high enough power to trigger the notification.
87    SenderNotificationPermission {
88        /// The field in the power level event the user needs a minimum power level for.
89        ///
90        /// Fields must be specified under the `notifications` property in the power level event's
91        /// `content`.
92        key: NotificationPowerLevelsKey,
93    },
94
95    /// Apply the rule only to rooms that support a given feature.
96    #[cfg(feature = "unstable-msc3931")]
97    #[serde(rename = "org.matrix.msc3931.room_version_supports")]
98    RoomVersionSupports {
99        /// The feature the room must support for the push rule to apply.
100        feature: RoomVersionFeature,
101    },
102
103    EventPropertyIs {
104        key: String,
105        value: ScalarJsonValue,
106    },
107
108    EventPropertyContains {
109        key: String,
110        value: ScalarJsonValue,
111    },
112
113    /// Matches a thread event based on the user's thread subscription status, as defined by
114    /// [MSC4306].
115    ///
116    /// [MSC4306]: https://github.com/matrix-org/matrix-spec-proposals/pull/4306
117    #[cfg(feature = "unstable-msc4306")]
118    #[serde(rename = "io.element.msc4306.thread_subscription")]
119    ThreadSubscription {
120        /// Whether the user must be subscribed to the thread for the condition to match.
121        subscribed: bool,
122    },
123}
124
125impl From<PushConditionSerDeHelper> for PushCondition {
126    fn from(value: PushConditionSerDeHelper) -> Self {
127        match value {
128            PushConditionSerDeHelper::EventMatch { key, pattern } => {
129                Self::EventMatch { key, pattern }
130            }
131            PushConditionSerDeHelper::ContainsDisplayName => Self::ContainsDisplayName,
132            PushConditionSerDeHelper::RoomMemberCount { is } => Self::RoomMemberCount { is },
133            PushConditionSerDeHelper::SenderNotificationPermission { key } => {
134                Self::SenderNotificationPermission { key }
135            }
136            #[cfg(feature = "unstable-msc3931")]
137            PushConditionSerDeHelper::RoomVersionSupports { feature } => {
138                Self::RoomVersionSupports { feature }
139            }
140            PushConditionSerDeHelper::EventPropertyIs { key, value } => {
141                Self::EventPropertyIs { key, value }
142            }
143            PushConditionSerDeHelper::EventPropertyContains { key, value } => {
144                Self::EventPropertyContains { key, value }
145            }
146            #[cfg(feature = "unstable-msc4306")]
147            PushConditionSerDeHelper::ThreadSubscription { subscribed } => {
148                Self::ThreadSubscription { subscribed }
149            }
150        }
151    }
152}
153
154impl From<PushCondition> for PushConditionSerDeHelper {
155    fn from(value: PushCondition) -> Self {
156        match value {
157            PushCondition::EventMatch { key, pattern } => Self::EventMatch { key, pattern },
158            PushCondition::ContainsDisplayName => Self::ContainsDisplayName,
159            PushCondition::RoomMemberCount { is } => Self::RoomMemberCount { is },
160            PushCondition::SenderNotificationPermission { key } => {
161                Self::SenderNotificationPermission { key }
162            }
163            #[cfg(feature = "unstable-msc3931")]
164            PushCondition::RoomVersionSupports { feature } => Self::RoomVersionSupports { feature },
165            PushCondition::EventPropertyIs { key, value } => Self::EventPropertyIs { key, value },
166            PushCondition::EventPropertyContains { key, value } => {
167                Self::EventPropertyContains { key, value }
168            }
169            #[cfg(feature = "unstable-msc4306")]
170            PushCondition::ThreadSubscription { subscribed } => {
171                Self::ThreadSubscription { subscribed }
172            }
173            PushCondition::_Custom(_) => unimplemented!(),
174        }
175    }
176}