pub use ruma_common::room::{AllowRule, JoinRule, Restricted};
use ruma_common::{
room_version_rules::RedactionRules,
serde::{JsonCastable, JsonObject},
};
use ruma_macros::EventContent;
use serde::{Deserialize, Serialize, de};
use crate::{
EmptyStateKey, RedactContent, RedactedStateEventContent, StateEventContent, StateEventType,
StaticEventContent,
};
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State, state_key_type = EmptyStateKey, custom_redacted)]
#[serde(transparent)]
pub struct RoomJoinRulesEventContent {
#[ruma_event(skip_redaction)]
pub join_rule: JoinRule,
}
impl RoomJoinRulesEventContent {
pub fn new(join_rule: JoinRule) -> Self {
Self { join_rule }
}
pub fn restricted(allow: Vec<AllowRule>) -> Self {
Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
}
pub fn knock_restricted(allow: Vec<AllowRule>) -> Self {
Self { join_rule: JoinRule::KnockRestricted(Restricted::new(allow)) }
}
}
impl RedactContent for RoomJoinRulesEventContent {
type Redacted = RedactedRoomJoinRulesEventContent;
fn redact(self, _rules: &RedactionRules) -> Self::Redacted {
RedactedRoomJoinRulesEventContent { join_rule: self.join_rule }
}
}
impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let join_rule = JoinRule::deserialize(deserializer)?;
Ok(RoomJoinRulesEventContent { join_rule })
}
}
impl JsonCastable<RedactedRoomJoinRulesEventContent> for RoomJoinRulesEventContent {}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
pub struct RedactedRoomJoinRulesEventContent {
#[serde(flatten)]
pub join_rule: JoinRule,
}
impl StaticEventContent for RedactedRoomJoinRulesEventContent {
const TYPE: &'static str = RoomJoinRulesEventContent::TYPE;
type IsPrefix = <RoomJoinRulesEventContent as StaticEventContent>::IsPrefix;
}
impl RedactedStateEventContent for RedactedRoomJoinRulesEventContent {
type StateKey = <RoomJoinRulesEventContent as StateEventContent>::StateKey;
fn event_type(&self) -> StateEventType {
StateEventType::RoomJoinRules
}
}
impl<'de> Deserialize<'de> for RedactedRoomJoinRulesEventContent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let join_rule = JoinRule::deserialize(deserializer)?;
Ok(Self { join_rule })
}
}
impl JsonCastable<JsonObject> for RedactedRoomJoinRulesEventContent {}
impl From<RedactedRoomJoinRulesEventContent> for PossiblyRedactedRoomJoinRulesEventContent {
fn from(value: RedactedRoomJoinRulesEventContent) -> Self {
let RedactedRoomJoinRulesEventContent { join_rule } = value;
Self { join_rule }
}
}
impl RoomJoinRulesEvent {
pub fn join_rule(&self) -> &JoinRule {
match self {
Self::Original(ev) => &ev.content.join_rule,
Self::Redacted(ev) => &ev.content.join_rule,
}
}
}
impl SyncRoomJoinRulesEvent {
pub fn join_rule(&self) -> &JoinRule {
match self {
Self::Original(ev) => &ev.content.join_rule,
Self::Redacted(ev) => &ev.content.join_rule,
}
}
}
#[cfg(test)]
mod tests {
use assert_matches2::assert_matches;
use ruma_common::owned_room_id;
use serde_json::json;
use super::{
AllowRule, JoinRule, OriginalSyncRoomJoinRulesEvent, RedactedRoomJoinRulesEventContent,
RoomJoinRulesEventContent,
};
use crate::room::join_rules::RedactedSyncRoomJoinRulesEvent;
#[test]
fn deserialize_content() {
let json = r#"{"join_rule": "public"}"#;
let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
let event: RedactedRoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
assert_matches!(event, RedactedRoomJoinRulesEventContent { join_rule: JoinRule::Public });
}
#[test]
fn deserialize_restricted() {
let json = r#"{
"join_rule": "restricted",
"allow": [
{
"type": "m.room_membership",
"room_id": "!mods:example.org"
},
{
"type": "m.room_membership",
"room_id": "!users:example.org"
}
]
}"#;
let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
assert_matches!(event.join_rule, JoinRule::Restricted(restricted));
assert_eq!(
restricted.allow,
&[
AllowRule::room_membership(owned_room_id!("!mods:example.org")),
AllowRule::room_membership(owned_room_id!("!users:example.org"))
]
);
let event: RedactedRoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
assert_matches!(event.join_rule, JoinRule::Restricted(restricted));
assert_eq!(
restricted.allow,
&[
AllowRule::room_membership(owned_room_id!("!mods:example.org")),
AllowRule::room_membership(owned_room_id!("!users:example.org"))
]
);
}
#[test]
fn deserialize_restricted_event() {
let json = r#"{
"type": "m.room.join_rules",
"sender": "@admin:community.rs",
"content": {
"join_rule": "restricted",
"allow": [
{ "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
]
},
"state_key": "",
"origin_server_ts":1630508835342,
"unsigned": {
"age":4165521871
},
"event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
}"#;
assert_matches!(serde_json::from_str::<OriginalSyncRoomJoinRulesEvent>(json), Ok(_));
}
#[test]
fn deserialize_redacted_restricted_event() {
let json = r#"{
"type": "m.room.join_rules",
"sender": "@admin:community.rs",
"content": {
"join_rule": "restricted",
"allow": [
{ "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
]
},
"state_key": "",
"origin_server_ts":1630508835342,
"unsigned": {
"age":4165521871,
"redacted_because": {
"type": "m.room.redaction",
"content": {
"redacts": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
},
"event_id": "$h29iv0s8",
"origin_server_ts": 1,
"sender": "@carl:example.com"
}
},
"event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
}"#;
assert_matches!(serde_json::from_str::<RedactedSyncRoomJoinRulesEvent>(json), Ok(_));
}
#[test]
fn restricted_room_no_allow_field() {
let json = r#"{"join_rule":"restricted"}"#;
let join_rules: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
assert_matches!(
join_rules,
RoomJoinRulesEventContent { join_rule: JoinRule::Restricted(_) }
);
}
#[test]
fn reserialize_unsupported_join_rule() {
let json = json!({"join_rule": "local.matrix.custom", "foo": "bar"});
let content = serde_json::from_value::<RoomJoinRulesEventContent>(json.clone()).unwrap();
assert_eq!(content.join_rule.as_str(), "local.matrix.custom");
let data = content.join_rule.data();
assert_eq!(data.get("foo").unwrap().as_str(), Some("bar"));
assert_eq!(serde_json::to_value(&content).unwrap(), json);
}
}