diff --git a/ruma-events/CHANGELOG.md b/ruma-events/CHANGELOG.md index 6879aab1..fa1a3486 100644 --- a/ruma-events/CHANGELOG.md +++ b/ruma-events/CHANGELOG.md @@ -38,6 +38,12 @@ Improvements: * `MessageEventContent::text_html` * `MessageEventContent::notice_plain` * `MessageEventContent::notice_html` +* Add policy rule entities: + * `policy::rule::room` + * `policy::rule::server` + * `policy::rule::user` +* Add policy rule recommendation: + * `Recommendation::Ban` # 0.21.3 diff --git a/ruma-events/src/enums.rs b/ruma-events/src/enums.rs index cbd6975e..fb9fd1a6 100644 --- a/ruma-events/src/enums.rs +++ b/ruma-events/src/enums.rs @@ -48,6 +48,9 @@ event_enum! { /// Any state event. kind: State, events: [ + "m.policy.rule.room", + "m.policy.rule.server", + "m.policy.rule.user", "m.room.aliases", "m.room.avatar", "m.room.canonical_alias", diff --git a/ruma-events/src/event_type.rs b/ruma-events/src/event_type.rs index 751e6ab4..21e8e721 100644 --- a/ruma-events/src/event_type.rs +++ b/ruma-events/src/event_type.rs @@ -55,6 +55,15 @@ pub enum EventType { /// m.ignored_user_list IgnoredUserList, + /// m.policy.rule.room + PolicyRuleRoom, + + /// m.policy.rule.server + PolicyRuleServer, + + /// m.policy.rule.user + PolicyRuleUser, + /// m.presence Presence, @@ -162,6 +171,9 @@ impl EventType { EventType::KeyVerificationRequest => "m.key.verification.request", EventType::KeyVerificationStart => "m.key.verification.start", EventType::IgnoredUserList => "m.ignored_user_list", + EventType::PolicyRuleRoom => "m.policy.rule.room", + EventType::PolicyRuleServer => "m.policy.rule.server", + EventType::PolicyRuleUser => "m.policy.rule.user", EventType::Presence => "m.presence", EventType::PushRules => "m.push_rules", EventType::Receipt => "m.receipt", @@ -222,6 +234,9 @@ where "m.key.verification.request" => EventType::KeyVerificationRequest, "m.key.verification.start" => EventType::KeyVerificationStart, "m.ignored_user_list" => EventType::IgnoredUserList, + "m.policy.rule.room" => EventType::PolicyRuleRoom, + "m.policy.rule.server" => EventType::PolicyRuleServer, + "m.policy.rule.user" => EventType::PolicyRuleUser, "m.presence" => EventType::Presence, "m.push_rules" => EventType::PushRules, "m.receipt" => EventType::Receipt, @@ -286,6 +301,9 @@ mod tests { serde_json_eq(EventType::KeyVerificationRequest, json!("m.key.verification.request")); serde_json_eq(EventType::KeyVerificationStart, json!("m.key.verification.start")); serde_json_eq(EventType::IgnoredUserList, json!("m.ignored_user_list")); + serde_json_eq(EventType::PolicyRuleRoom, json!("m.policy.rule.room")); + serde_json_eq(EventType::PolicyRuleServer, json!("m.policy.rule.server")); + serde_json_eq(EventType::PolicyRuleUser, json!("m.policy.rule.user")); serde_json_eq(EventType::Presence, json!("m.presence")); serde_json_eq(EventType::PushRules, json!("m.push_rules")); serde_json_eq(EventType::Receipt, json!("m.receipt")); diff --git a/ruma-events/src/lib.rs b/ruma-events/src/lib.rs index 69688199..e9677d29 100644 --- a/ruma-events/src/lib.rs +++ b/ruma-events/src/lib.rs @@ -167,6 +167,7 @@ pub mod fully_read; pub mod ignored_user_list; pub mod key; pub mod pdu; +pub mod policy; pub mod presence; pub mod push_rules; pub mod receipt; diff --git a/ruma-events/src/policy.rs b/ruma-events/src/policy.rs new file mode 100644 index 00000000..d58e3b2b --- /dev/null +++ b/ruma-events/src/policy.rs @@ -0,0 +1,3 @@ +//! Modules for events in the *m.policy* namespace. + +pub mod rule; diff --git a/ruma-events/src/policy/rule.rs b/ruma-events/src/policy/rule.rs new file mode 100644 index 00000000..fe7f3c39 --- /dev/null +++ b/ruma-events/src/policy/rule.rs @@ -0,0 +1,60 @@ +//! Modules and types for events in the *m.policy.rule* namespace. + +use std::fmt::{Display, Formatter, Result as FmtResult}; + +use serde::{Deserialize, Serialize}; + +pub mod room; +pub mod server; +pub mod user; + +/// The payload for policy rule events. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct PolicyRuleEventContent { + /// The entity affected by this rule. Glob characters * and ? can be used to match zero or more and one or more characters respectively. + pub entity: String, + + /// The suggested action to take. + pub recommendation: Recommendation, + + /// The human-readable description for the recommendation. + pub reason: String, +} + +impl PolicyRuleEventContent { + /// Creates a new `PolicyRuleEventContent` with the given entity, recommendation and reason. + pub fn new(entity: String, recommendation: Recommendation, reason: String) -> Self { + Self { entity, recommendation, reason } + } +} + +/// Rules recommendations +#[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub enum Recommendation { + /// Entities affected by the rule should be banned from participation where possible. + #[serde(rename = "m.ban")] + Ban, +} + +impl Recommendation { + /// Creates a string slice from this `Recommendation`. + pub fn as_str(&self) -> &str { + match *self { + Recommendation::Ban => "m.ban", + } + } +} + +impl Display for Recommendation { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(self.as_str()) + } +} + +impl From for String { + fn from(recommendation: Recommendation) -> String { + recommendation.to_string() + } +} diff --git a/ruma-events/src/policy/rule/room.rs b/ruma-events/src/policy/rule/room.rs new file mode 100644 index 00000000..75bb4685 --- /dev/null +++ b/ruma-events/src/policy/rule/room.rs @@ -0,0 +1,88 @@ +//! Types for the *m.policy.rule.room* event. + +use ruma_events_macros::StateEventContent; +use serde::{Deserialize, Serialize}; + +use crate::{policy::rule::PolicyRuleEventContent, StateEvent}; + +/// This event type is used to apply rules to room entities. +pub type RoomEvent = StateEvent; + +/// The payload for `RoomEvent`. +#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)] +#[ruma_event(type = "m.policy.rule.room")] +pub struct RoomEventContent(pub PolicyRuleEventContent); + +#[cfg(test)] +mod tests { + use std::time::{Duration, UNIX_EPOCH}; + + use ruma_common::Raw; + use ruma_identifiers::{event_id, room_id, user_id}; + use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; + + use super::{RoomEvent, RoomEventContent}; + use crate::{ + policy::rule::{PolicyRuleEventContent, Recommendation}, + Unsigned, + }; + + #[test] + fn serialization() { + let room_event = RoomEvent { + event_id: event_id!("$143273582443PhrSn:example.org"), + sender: user_id!("@example:example.org"), + origin_server_ts: UNIX_EPOCH + Duration::from_millis(1_432_735_824_653), + room_id: room_id!("!jEsUZKDJdhlrceRyVU:example.org"), + state_key: "rule:#*:example.org".into(), + prev_content: None, + unsigned: Unsigned { age: Some(1234.into()), transaction_id: None }, + content: RoomEventContent(PolicyRuleEventContent { + entity: "#*:example.org".into(), + reason: "undesirable content".into(), + recommendation: Recommendation::Ban, + }), + }; + + let json = json!({ + "content": { + "entity": "#*:example.org", + "reason": "undesirable content", + "recommendation": "m.ban" + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653u64, + "room_id": "!jEsUZKDJdhlrceRyVU:example.org", + "sender": "@example:example.org", + "state_key": "rule:#*:example.org", + "type": "m.policy.rule.room", + "unsigned": { + "age": 1234 + } + }); + + assert_eq!(to_json_value(room_event).unwrap(), json); + } + + #[test] + fn deserialization() { + let json = json!({ + "content": { + "entity": "#*:example.org", + "reason": "undesirable content", + "recommendation": "m.ban" + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653u64, + "room_id": "!jEsUZKDJdhlrceRyVU:example.org", + "sender": "@example:example.org", + "state_key": "rule:#*:example.org", + "type": "m.policy.rule.room", + "unsigned": { + "age": 1234 + } + }); + + assert!(from_json_value::>(json).unwrap().deserialize().is_ok()); + } +} diff --git a/ruma-events/src/policy/rule/server.rs b/ruma-events/src/policy/rule/server.rs new file mode 100644 index 00000000..753beed3 --- /dev/null +++ b/ruma-events/src/policy/rule/server.rs @@ -0,0 +1,14 @@ +//! Types for the *m.policy.rule.server* event. + +use ruma_events_macros::StateEventContent; +use serde::{Deserialize, Serialize}; + +use crate::{policy::rule::PolicyRuleEventContent, StateEvent}; + +/// This event type is used to apply rules to server entities. +pub type ServerEvent = StateEvent; + +/// The payload for `ServerEvent`. +#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)] +#[ruma_event(type = "m.policy.rule.server")] +pub struct ServerEventContent(pub PolicyRuleEventContent); diff --git a/ruma-events/src/policy/rule/user.rs b/ruma-events/src/policy/rule/user.rs new file mode 100644 index 00000000..ceff6de8 --- /dev/null +++ b/ruma-events/src/policy/rule/user.rs @@ -0,0 +1,14 @@ +//! Types for the *m.policy.rule.user* event. + +use ruma_events_macros::StateEventContent; +use serde::{Deserialize, Serialize}; + +use crate::{policy::rule::PolicyRuleEventContent, StateEvent}; + +/// This event type is used to apply rules to user entities. +pub type UserEvent = StateEvent; + +/// The payload for `UserEvent`. +#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)] +#[ruma_event(type = "m.policy.rule.user")] +pub struct UserEventContent(pub PolicyRuleEventContent); diff --git a/ruma-events/src/push_rules.rs b/ruma-events/src/push_rules.rs index 1dcecc23..01812ec1 100644 --- a/ruma-events/src/push_rules.rs +++ b/ruma-events/src/push_rules.rs @@ -1,4 +1,4 @@ -//! Types for the the *m.push_rules* event. +//! Types for the *m.push_rules* event. use ruma_common::push::Ruleset; use ruma_events_macros::BasicEventContent;