diff --git a/CHANGELOG.md b/CHANGELOG.md index b6177234..4d99c23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Improvements: * Add `unstable_features` to `unversioned::get_supported_versions` (introduced in r0.5.0) * Add request and response parameters for `r0::account::deactivate` * Add `r0::session::sso_login` (introduced in r0.5.0) +* Add `filter` type for `r0::context::get_context` Breaking changes: @@ -21,6 +22,8 @@ Breaking changes: * Replaced `user_id` parameter of `r0::membership::invite_user` with `recipient` to allow invitation of users by either Matrix or third party identifiers. * Remove deprecated endpoint `r0::contact::create_contact` (deprecated in r0.6.0) +* Add lazy-loading options to `r0::filter::RoomEventFilter` (introduced in r0.5.0) +* Change type for `limit` request parameter of `r0::context::get_context` from `u8` to `Option` # 0.6.0 diff --git a/src/r0/context/get_context.rs b/src/r0/context/get_context.rs index 566ac742..c0f753d3 100644 --- a/src/r0/context/get_context.rs +++ b/src/r0/context/get_context.rs @@ -1,9 +1,12 @@ //! [GET /_matrix/client/r0/rooms/{roomId}/context/{eventId}](https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-rooms-roomid-context-eventid) +use js_int::UInt; use ruma_api::ruma_api; use ruma_events::{collections::only, EventResult}; use ruma_identifiers::{EventId, RoomId}; +use crate::r0::filter::RoomEventFilter; + ruma_api! { metadata { description: "Get the events immediately preceding and following a given event.", @@ -22,10 +25,15 @@ ruma_api! { /// /// Defaults to 10 if not supplied. #[ruma_api(query)] - pub limit: u8, + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, /// The room to get events from. #[ruma_api(path)] pub room_id: RoomId, + /// A RoomEventFilter to filter returned events with. + #[serde(skip_serializing_if = "Option::is_none")] + #[ruma_api(query)] + pub filter: Option, } response { diff --git a/src/r0/filter.rs b/src/r0/filter.rs index 2de9de95..2b8de854 100644 --- a/src/r0/filter.rs +++ b/src/r0/filter.rs @@ -3,9 +3,15 @@ pub mod create_filter; pub mod get_filter; +use std::fmt; + use js_int::UInt; use ruma_identifiers::{RoomId, UserId}; -use serde::{Deserialize, Serialize}; +use serde::{ + de::{MapAccess, Visitor}, + ser::SerializeStruct, + Deserialize, Deserializer, Serialize, Serializer, +}; /// Format to use for returned events #[derive(Copy, Clone, Debug, Deserialize, Serialize)] @@ -64,6 +70,9 @@ pub struct RoomEventFilter { /// If this item is absent then all event types are included. #[serde(skip_serializing_if = "Option::is_none")] pub contains_url: Option, + /// Options to control lazy-loading of membership events. + #[serde(flatten)] + pub lazy_load_options: LazyLoadOptions, } impl RoomEventFilter { @@ -203,3 +212,146 @@ impl FilterDefinition { } } } + +/// Specifies options for [lazy-loading membership events][lazy-loading] on +/// supported endpoints +/// +/// [lazy-loading]: https://matrix.org/docs/spec/client_server/r0.6.0#lazy-loading-room-members +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum LazyLoadOptions { + /// Disables lazy-loading of membership events. + Disabled, + /// Enables lazy-loading of events. + Enabled { + /// If `true`, sends all membership events for all events, even if they have + /// already been sent to the client. Defaults to `false`. + include_redundant_members: bool, + }, +} + +impl Serialize for LazyLoadOptions { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state; + match *self { + Self::Enabled { + include_redundant_members: true, + } => { + state = serializer.serialize_struct("LazyLoad", 2)?; + state.serialize_field("lazy_load_members", &true)?; + state.serialize_field("include_redundant_members", &true)?; + } + Self::Enabled { .. } => { + state = serializer.serialize_struct("LazyLoad", 1)?; + state.serialize_field("lazy_load_members", &true)?; + } + _ => { + state = serializer.serialize_struct("LazyLoad", 0)?; + } + } + state.end() + } +} + +impl Default for LazyLoadOptions { + fn default() -> Self { + Self::Disabled + } +} + +struct LazyLoadOptionsVisitor; + +impl<'de> Visitor<'de> for LazyLoadOptionsVisitor { + type Value = LazyLoadOptions; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Lazy load options") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut lazy_load_members = false; + let mut include_redundant_members = false; + while let Some((key, value)) = access.next_entry::()? { + match &*key { + "lazy_load_members" => lazy_load_members = value, + "include_redundant_members" => include_redundant_members = value, + _ => {} + }; + } + + Ok(if lazy_load_members { + LazyLoadOptions::Enabled { + include_redundant_members, + } + } else { + LazyLoadOptions::Disabled + }) + } +} + +impl<'de> Deserialize<'de> for LazyLoadOptions { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(LazyLoadOptionsVisitor) + } +} + +#[cfg(test)] +mod tests { + use serde_json::json; + + use super::LazyLoadOptions; + + #[test] + fn test_serializing_disabled_lazy_load() { + let lazy_load_options = LazyLoadOptions::Disabled; + assert_eq!(serde_json::to_value(lazy_load_options).unwrap(), json!({})); + } + + #[test] + fn test_serializing_lazy_load_no_redundant() { + let lazy_load_options = LazyLoadOptions::Enabled { + include_redundant_members: false, + }; + assert_eq!( + serde_json::to_value(lazy_load_options).unwrap(), + json!({ "lazy_load_members": true }) + ); + } + + #[test] + fn test_serializing_lazy_load_with_redundant() { + let lazy_load_options = LazyLoadOptions::Enabled { + include_redundant_members: true, + }; + assert_eq!( + serde_json::to_value(lazy_load_options).unwrap(), + json!({ "lazy_load_members": true, "include_redundant_members": true }) + ); + } + + #[test] + fn test_deserializing_no_lazy_load() { + let json = json!({}); + assert_eq!( + serde_json::from_value::(json).unwrap(), + LazyLoadOptions::Disabled, + ); + } + + #[test] + fn test_deserializing_ignore_redundant_members_when_no_lazy_load() { + let json = json!({ "include_redundant_members": true }); + assert_eq!( + serde_json::from_value::(json).unwrap(), + LazyLoadOptions::Disabled, + ); + } +}