From a9f23f663834db818118379da00162c17d4756fa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 20 Sep 2021 20:28:52 +0200 Subject: [PATCH] Add allow to JoinRulesEventContent Co-authored-by: Amanda Graven --- crates/ruma-events/CHANGELOG.md | 4 + crates/ruma-events/src/room/join_rules.rs | 98 ++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/crates/ruma-events/CHANGELOG.md b/crates/ruma-events/CHANGELOG.md index ea540838..064822c6 100644 --- a/crates/ruma-events/CHANGELOG.md +++ b/crates/ruma-events/CHANGELOG.md @@ -1,5 +1,9 @@ # [unreleased] +Improvements: + +* Add (unstable) support for [MSC3083](https://github.com/matrix-org/matrix-doc/blob/main/proposals/3083-restricted-rooms.md) + # 0.24.5 Improvements: diff --git a/crates/ruma-events/src/room/join_rules.rs b/crates/ruma-events/src/room/join_rules.rs index 93415246..486a6508 100644 --- a/crates/ruma-events/src/room/join_rules.rs +++ b/crates/ruma-events/src/room/join_rules.rs @@ -1,8 +1,17 @@ //! Types for the *m.room.join_rules* event. +#[cfg(feature = "unstable-pre-spec")] +use std::collections::BTreeMap; + use ruma_events_macros::EventContent; +#[cfg(feature = "unstable-pre-spec")] +use ruma_identifiers::RoomId; use ruma_serde::StringEnum; +#[cfg(feature = "unstable-pre-spec")] +use serde::de::{DeserializeOwned, Deserializer, Error}; use serde::{Deserialize, Serialize}; +#[cfg(feature = "unstable-pre-spec")] +use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue}; use crate::StateEvent; @@ -17,12 +26,29 @@ pub struct JoinRulesEventContent { /// The type of rules used for users wishing to join this room. #[ruma_event(skip_redaction)] pub join_rule: JoinRule, + + /// Allow rules used for the `restricted` join rule. + #[cfg(feature = "unstable-pre-spec")] + #[serde(default)] + #[ruma_event(skip_redaction)] + pub allow: Vec, } impl JoinRulesEventContent { /// Creates a new `JoinRulesEventContent` with the given rule. pub fn new(join_rule: JoinRule) -> Self { - Self { join_rule } + Self { + join_rule, + #[cfg(feature = "unstable-pre-spec")] + allow: Vec::new(), + } + } + + /// Creates a new `JoinRulesEventContent` with the restricted rule and the given set of allow + /// rules. + #[cfg(feature = "unstable-pre-spec")] + pub fn restricted(allow: Vec) -> Self { + Self { join_rule: JoinRule::Restricted, allow } } } @@ -44,6 +70,11 @@ pub enum JoinRule { /// Reserved but not yet implemented by the Matrix specification. Private, + /// Users can join the room if they are invited, or if they meet any of the conditions + /// described in a set of [`AllowRule`]s. + #[cfg(feature = "unstable-pre-spec")] + Restricted, + /// Anyone can join the room without any prior action. Public, @@ -57,3 +88,68 @@ impl JoinRule { self.as_ref() } } + +/// An allow rule which defines a condition that allows joining a room. +#[cfg(feature = "unstable-pre-spec")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +#[serde(tag = "type")] +pub enum AllowRule { + /// Joining is allowed if a user is already a member of the romm with the id `room_id`. + #[serde(rename = "m.room_membership")] + RoomMembership(RoomMembership), + + #[doc(hidden)] + _Custom(CustomAllowRule), +} + +/// Allow rule which grants permission to join based on the membership of another room. +#[cfg(feature = "unstable-pre-spec")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct RoomMembership { + /// The id of the room which being a member of grants permission to join another room. + pub room_id: RoomId, +} + +#[cfg(feature = "unstable-pre-spec")] +#[doc(hidden)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct CustomAllowRule { + #[serde(rename = "type")] + rule_type: String, + #[serde(flatten)] + extra: BTreeMap, +} + +#[cfg(feature = "unstable-pre-spec")] +impl<'de> Deserialize<'de> for AllowRule { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + fn from_raw_json_value(raw: &RawJsonValue) -> Result { + serde_json::from_str(raw.get()).map_err(E::custom) + } + + let json: Box = Box::deserialize(deserializer)?; + + // Extracts the `type` value. + #[derive(Deserialize)] + struct ExtractType { + rule_type: Option, + } + + // Get the value of `type` if present. + let rule_type = serde_json::from_str::(json.get()) + .map_err(serde::de::Error::custom)? + .rule_type; + + match rule_type.as_deref() { + Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership), + Some(_) => from_raw_json_value(&json).map(Self::_Custom), + None => Err(D::Error::missing_field("type")), + } + } +}