push: Allow to add custom data for pushers

Due to a clarification in the spec.
This commit is contained in:
Kévin Commaille 2024-12-14 10:35:05 +01:00 committed by strawberry
parent 81611b65f8
commit b1790e05ce
8 changed files with 121 additions and 65 deletions

View File

@ -10,6 +10,8 @@ Improvements:
the `RUMA_UNSTABLE_EXHAUSTIVE_TYPES` environment variable. the `RUMA_UNSTABLE_EXHAUSTIVE_TYPES` environment variable.
- Add `ErrorKind::ThreepidMediumNotSupported`, according to MSC4178. - Add `ErrorKind::ThreepidMediumNotSupported`, according to MSC4178.
- Add `ErrorKind::UserSuspended`, according to MSC3823. - Add `ErrorKind::UserSuspended`, according to MSC3823.
- `EmailPusherData` allows to set custom data for the pusher in the `data` field, due
to a clarification in the spec.
# 0.19.0 # 0.19.0

View File

@ -286,9 +286,13 @@ impl PusherIds {
} }
/// Information for an email pusher. /// Information for an email pusher.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct EmailPusherData; #[serde(transparent, default)]
pub struct EmailPusherData {
/// Custom data for the pusher.
pub data: JsonObject,
}
impl EmailPusherData { impl EmailPusherData {
/// Creates a new empty `EmailPusherData`. /// Creates a new empty `EmailPusherData`.

View File

@ -1,8 +1,8 @@
use ruma_common::serde::{from_raw_json_value, JsonObject}; use ruma_common::serde::from_raw_json_value;
use serde::{de, ser::SerializeStruct, Deserialize, Serialize}; use serde::{de, ser::SerializeStruct, Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
use super::{EmailPusherData, Pusher, PusherIds, PusherKind}; use super::{Pusher, PusherIds, PusherKind};
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct PusherDeHelper { struct PusherDeHelper {
@ -41,9 +41,9 @@ impl Serialize for PusherKind {
st.serialize_field("kind", &"http")?; st.serialize_field("kind", &"http")?;
st.serialize_field("data", data)?; st.serialize_field("data", data)?;
} }
PusherKind::Email(_) => { PusherKind::Email(data) => {
st.serialize_field("kind", &"email")?; st.serialize_field("kind", &"email")?;
st.serialize_field("data", &JsonObject::new())?; st.serialize_field("data", data)?;
} }
PusherKind::_Custom(custom) => { PusherKind::_Custom(custom) => {
st.serialize_field("kind", &custom.kind)?; st.serialize_field("kind", &custom.kind)?;
@ -71,7 +71,7 @@ impl<'de> Deserialize<'de> for PusherKind {
match kind.as_ref() { match kind.as_ref() {
"http" => from_raw_json_value(&data).map(Self::Http), "http" => from_raw_json_value(&data).map(Self::Http),
"email" => Ok(Self::Email(EmailPusherData)), "email" => from_raw_json_value(&data).map(Self::Email),
_ => from_raw_json_value(&json).map(Self::_Custom), _ => from_raw_json_value(&json).map(Self::_Custom),
} }
} }
@ -81,13 +81,17 @@ impl<'de> Deserialize<'de> for PusherKind {
mod tests { mod tests {
use assert_matches2::assert_matches; use assert_matches2::assert_matches;
use ruma_common::{push::HttpPusherData, serde::JsonObject}; use ruma_common::{push::HttpPusherData, serde::JsonObject};
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, to_value as to_json_value, Value as JsonValue,
};
use crate::push::{CustomPusherData, EmailPusherData, PusherKind}; use crate::push::{CustomPusherData, EmailPusherData, PusherKind};
#[test] #[test]
fn serialize_email() { fn serialize_email() {
let action = PusherKind::Email(EmailPusherData::new()); // With default data fields.
let mut data = EmailPusherData::new();
let action = PusherKind::Email(data.clone());
assert_eq!( assert_eq!(
to_json_value(action).unwrap(), to_json_value(action).unwrap(),
@ -96,11 +100,27 @@ mod tests {
"data": {}, "data": {},
}) })
); );
// With custom data fields.
data.data.insert("custom_key".to_owned(), "value".into());
let action = PusherKind::Email(data);
assert_eq!(
to_json_value(action).unwrap(),
json!({
"kind": "email",
"data": {
"custom_key": "value",
},
})
);
} }
#[test] #[test]
fn serialize_http() { fn serialize_http() {
let action = PusherKind::Http(HttpPusherData::new("http://localhost".to_owned())); // With default data fields.
let mut data = HttpPusherData::new("http://localhost".to_owned());
let action = PusherKind::Http(data.clone());
assert_eq!( assert_eq!(
to_json_value(action).unwrap(), to_json_value(action).unwrap(),
@ -111,6 +131,21 @@ mod tests {
}, },
}) })
); );
// With custom data fields.
data.data.insert("custom_key".to_owned(), "value".into());
let action = PusherKind::Http(data);
assert_eq!(
to_json_value(action).unwrap(),
json!({
"kind": "http",
"data": {
"url": "http://localhost",
"custom_key": "value",
},
})
);
} }
#[test] #[test]
@ -131,16 +166,32 @@ mod tests {
#[test] #[test]
fn deserialize_email() { fn deserialize_email() {
// With default data fields.
let json = json!({ let json = json!({
"kind": "email", "kind": "email",
"data": {}, "data": {},
}); });
assert_matches!(from_json_value(json).unwrap(), PusherKind::Email(_)); assert_matches!(from_json_value(json).unwrap(), PusherKind::Email(data));
assert!(data.data.is_empty());
// With custom data fields.
let json = json!({
"kind": "email",
"data": {
"custom_key": "value",
},
});
assert_matches!(from_json_value(json).unwrap(), PusherKind::Email(data));
assert_eq!(data.data.len(), 1);
assert_matches!(data.data.get("custom_key"), Some(JsonValue::String(custom_value)));
assert_eq!(custom_value, "value");
} }
#[test] #[test]
fn deserialize_http() { fn deserialize_http() {
// With default data fields.
let json = json!({ let json = json!({
"kind": "http", "kind": "http",
"data": { "data": {
@ -151,6 +202,21 @@ mod tests {
assert_matches!(from_json_value(json).unwrap(), PusherKind::Http(data)); assert_matches!(from_json_value(json).unwrap(), PusherKind::Http(data));
assert_eq!(data.url, "http://localhost"); assert_eq!(data.url, "http://localhost");
assert_eq!(data.format, None); assert_eq!(data.format, None);
assert!(data.data.is_empty());
// With custom data fields.
let json = json!({
"kind": "http",
"data": {
"url": "http://localhost",
"custom_key": "value",
},
});
assert_matches!(from_json_value(json).unwrap(), PusherKind::Http(data));
assert_eq!(data.data.len(), 1);
assert_matches!(data.data.get("custom_key"), Some(JsonValue::String(custom_value)));
assert_eq!(custom_value, "value");
} }
#[test] #[test]

View File

@ -11,6 +11,15 @@ Improvements:
configured by setting the `RUMA_IDENTIFIERS_STORAGE` environment variable at configured by setting the `RUMA_IDENTIFIERS_STORAGE` environment variable at
compile time. It has the benefit of not requiring to re-compile all the crates compile time. It has the benefit of not requiring to re-compile all the crates
of the dependency chain when the value is changed. of the dependency chain when the value is changed.
- The `unstable-exhaustive-types` cargo feature was replaced by the
`ruma_unstable_exhaustive_types` compile-time `cfg` setting. Like all `cfg`
settings, it can be enabled at compile-time with the `RUSTFLAGS` environment
variable, or inside `.cargo/config.toml`. It can also be enabled by setting
the `RUMA_UNSTABLE_EXHAUSTIVE_TYPES` environment variable.
- `HttpPusherData` allows to set custom data for the pusher in the `data` field,
due to a clarification in the spec.
- The `default_payload` field that was behind the `unstable-unspecified` was
removed. It can be added manually to the custom data.
# 0.14.1 # 0.14.1

View File

@ -18,13 +18,11 @@ use std::hash::{Hash, Hasher};
use indexmap::{Equivalent, IndexSet}; use indexmap::{Equivalent, IndexSet};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "unstable-unspecified")]
use serde_json::Value as JsonValue;
use thiserror::Error; use thiserror::Error;
use tracing::instrument; use tracing::instrument;
use crate::{ use crate::{
serde::{Raw, StringEnum}, serde::{JsonObject, Raw, StringEnum},
OwnedRoomId, OwnedUserId, PrivOwnedStr, OwnedRoomId, OwnedUserId, PrivOwnedStr,
}; };
@ -702,27 +700,15 @@ pub struct HttpPusherData {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<PushFormat>, pub format: Option<PushFormat>,
/// iOS (+ macOS?) specific default payload that will be sent to apple push notification /// Custom data for the pusher.
/// service. #[serde(flatten, default, skip_serializing_if = "JsonObject::is_empty")]
/// pub data: JsonObject,
/// For more information, see [Sygnal docs][sygnal].
///
/// [sygnal]: https://github.com/matrix-org/sygnal/blob/main/docs/applications.md#ios-applications-beware
// Not specified, issue: https://github.com/matrix-org/matrix-spec/issues/921
#[cfg(feature = "unstable-unspecified")]
#[serde(default, skip_serializing_if = "JsonValue::is_null")]
pub default_payload: JsonValue,
} }
impl HttpPusherData { impl HttpPusherData {
/// Creates a new `HttpPusherData` with the given URL. /// Creates a new `HttpPusherData` with the given URL.
pub fn new(url: String) -> Self { pub fn new(url: String) -> Self {
Self { Self { url, format: None, data: JsonObject::default() }
url,
format: None,
#[cfg(feature = "unstable-unspecified")]
default_payload: JsonValue::default(),
}
} }
} }

View File

@ -1,5 +1,21 @@
# [unreleased] # [unreleased]
Improvements:
- The `unstable-exhaustive-types` cargo feature was replaced by the
`ruma_unstable_exhaustive_types` compile-time `cfg` setting. Like all `cfg`
settings, it can be enabled at compile-time with the `RUSTFLAGS` environment
variable, or inside `.cargo/config.toml`. It can also be enabled by setting
the `RUMA_UNSTABLE_EXHAUSTIVE_TYPES` environment variable.
- `PusherData` allows to set custom data for the pusher in the `data` field, due
to a clarification in the spec.
- The `default_payload` field that was behind the `unstable-unspecified` was
removed. It can be added manually to the custom data.
# 0.10.0
Upgrade `ruma-events` to 0.29.0.
# 0.9.0 # 0.9.0
Breaking changes: Breaking changes:

View File

@ -12,14 +12,12 @@ pub mod v1 {
api::{request, response, Metadata}, api::{request, response, Metadata},
metadata, metadata,
push::{PushFormat, Tweak}, push::{PushFormat, Tweak},
serde::StringEnum, serde::{JsonObject, StringEnum},
OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, SecondsSinceUnixEpoch, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, SecondsSinceUnixEpoch,
}; };
use ruma_events::TimelineEventType; use ruma_events::TimelineEventType;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
#[cfg(feature = "unstable-unspecified")]
use serde_json::value::Value as JsonValue;
use crate::PrivOwnedStr; use crate::PrivOwnedStr;
@ -246,16 +244,9 @@ pub mod v1 {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<PushFormat>, pub format: Option<PushFormat>,
/// iOS (+ macOS?) specific default payload that will be sent to apple push notification /// Custom data for the pusher.
/// service. #[serde(flatten, default, skip_serializing_if = "JsonObject::is_empty")]
/// pub data: JsonObject,
/// For more information, see [Sygnal docs][sygnal].
///
/// [sygnal]: https://github.com/matrix-org/sygnal/blob/main/docs/applications.md#ios-applications-beware
// Not specified, issue: https://github.com/matrix-org/matrix-spec/issues/921
#[cfg(feature = "unstable-unspecified")]
#[serde(default, skip_serializing_if = "JsonValue::is_null")]
pub default_payload: JsonValue,
} }
impl PusherData { impl PusherData {
@ -264,34 +255,17 @@ pub mod v1 {
Default::default() Default::default()
} }
/// Returns `true` if all fields are `None`. /// Returns `true` if all fields are `None` or empty.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
#[cfg(not(feature = "unstable-unspecified"))] self.format.is_none() && self.data.is_empty()
{
self.format.is_none()
}
#[cfg(feature = "unstable-unspecified")]
{
self.format.is_none() && self.default_payload.is_null()
}
} }
} }
impl From<ruma_common::push::HttpPusherData> for PusherData { impl From<ruma_common::push::HttpPusherData> for PusherData {
fn from(data: ruma_common::push::HttpPusherData) -> Self { fn from(data: ruma_common::push::HttpPusherData) -> Self {
let ruma_common::push::HttpPusherData { let ruma_common::push::HttpPusherData { format, data, .. } = data;
format,
#[cfg(feature = "unstable-unspecified")]
default_payload,
..
} = data;
Self { Self { format, data }
format,
#[cfg(feature = "unstable-unspecified")]
default_payload,
}
} }
} }

View File

@ -277,7 +277,6 @@ unstable-pdu = ["ruma-events?/unstable-pdu"]
unstable-unspecified = [ unstable-unspecified = [
"ruma-common/unstable-unspecified", "ruma-common/unstable-unspecified",
"ruma-federation-api?/unstable-unspecified", "ruma-federation-api?/unstable-unspecified",
"ruma-push-gateway-api?/unstable-unspecified",
] ]
# Private features, only used in test / benchmarking code # Private features, only used in test / benchmarking code