ruma_events/room/
create.rs

1//! Types for the [`m.room.create`] event.
2//!
3//! [`m.room.create`]: https://spec.matrix.org/latest/client-server-api/#mroomcreate
4
5use ruma_common::{
6    room::RoomType, room_version_rules::RedactionRules, OwnedEventId, OwnedRoomId, OwnedUserId,
7    RoomVersionId,
8};
9use ruma_macros::EventContent;
10use serde::{Deserialize, Serialize};
11
12use crate::{EmptyStateKey, RedactContent, RedactedStateEventContent};
13
14/// The content of an `m.room.create` event.
15///
16/// This is the first event in a room and cannot be changed.
17///
18/// It acts as the root of all other events.
19#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
20#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
21#[ruma_event(type = "m.room.create", kind = State, state_key_type = EmptyStateKey, custom_redacted)]
22pub struct RoomCreateEventContent {
23    /// The `user_id` of the room creator.
24    ///
25    /// This is set by the homeserver.
26    ///
27    /// This is required in room versions 1 trough 10, but is removed starting from room version
28    /// 11.
29    #[serde(skip_serializing_if = "Option::is_none")]
30    #[deprecated = "Since Matrix 1.8. This field was removed in Room version 11, clients should use the event's sender instead"]
31    pub creator: Option<OwnedUserId>,
32
33    /// Whether or not this room's data should be transferred to other homeservers.
34    #[serde(
35        rename = "m.federate",
36        default = "ruma_common::serde::default_true",
37        skip_serializing_if = "ruma_common::serde::is_true"
38    )]
39    pub federate: bool,
40
41    /// The version of the room.
42    ///
43    /// Defaults to `RoomVersionId::V1`.
44    #[serde(default = "default_room_version_id")]
45    pub room_version: RoomVersionId,
46
47    /// A reference to the room this room replaces, if the previous room was upgraded.
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub predecessor: Option<PreviousRoom>,
50
51    /// The room type.
52    ///
53    /// This is currently only used for spaces.
54    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
55    pub room_type: Option<RoomType>,
56}
57
58impl RoomCreateEventContent {
59    /// Creates a new `RoomCreateEventContent` with the given creator, as required for room versions
60    /// 1 through 10.
61    pub fn new_v1(creator: OwnedUserId) -> Self {
62        #[allow(deprecated)]
63        Self {
64            creator: Some(creator),
65            federate: true,
66            room_version: default_room_version_id(),
67            predecessor: None,
68            room_type: None,
69        }
70    }
71
72    /// Creates a new `RoomCreateEventContent` with the default values and no creator, as introduced
73    /// in room version 11.
74    ///
75    /// The room version is set to [`RoomVersionId::V11`].
76    pub fn new_v11() -> Self {
77        #[allow(deprecated)]
78        Self {
79            creator: None,
80            federate: true,
81            room_version: RoomVersionId::V11,
82            predecessor: None,
83            room_type: None,
84        }
85    }
86}
87
88impl RedactContent for RoomCreateEventContent {
89    type Redacted = RedactedRoomCreateEventContent;
90
91    fn redact(self, rules: &RedactionRules) -> Self::Redacted {
92        #[allow(deprecated)]
93        if rules.keep_room_create_content {
94            self
95        } else {
96            Self {
97                room_version: default_room_version_id(),
98                creator: self.creator,
99                ..Self::new_v11()
100            }
101        }
102    }
103}
104
105/// A reference to an old room replaced during a room version upgrade.
106#[derive(Clone, Debug, Deserialize, Serialize)]
107#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
108pub struct PreviousRoom {
109    /// The ID of the old room.
110    pub room_id: OwnedRoomId,
111
112    /// The event ID of the last known event in the old room.
113    pub event_id: OwnedEventId,
114}
115
116impl PreviousRoom {
117    /// Creates a new `PreviousRoom` from the given room and event IDs.
118    pub fn new(room_id: OwnedRoomId, event_id: OwnedEventId) -> Self {
119        Self { room_id, event_id }
120    }
121}
122
123/// Used to default the `room_version` field to room version 1.
124fn default_room_version_id() -> RoomVersionId {
125    RoomVersionId::V1
126}
127
128/// Redacted form of [`RoomCreateEventContent`].
129///
130/// The redaction rules of this event changed with room version 11:
131///
132/// - In room versions 1 through 10, the `creator` field was preserved during redaction, starting
133///   from room version 11 the field is removed.
134/// - In room versions 1 through 10, all the other fields were redacted, starting from room version
135///   11 all the fields are preserved.
136pub type RedactedRoomCreateEventContent = RoomCreateEventContent;
137
138impl RedactedStateEventContent for RedactedRoomCreateEventContent {
139    type StateKey = EmptyStateKey;
140}
141
142#[cfg(test)]
143mod tests {
144    use assert_matches2::assert_matches;
145    use ruma_common::{owned_user_id, RoomVersionId};
146    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
147
148    use super::{RoomCreateEventContent, RoomType};
149
150    #[test]
151    fn serialization() {
152        #[allow(deprecated)]
153        let content = RoomCreateEventContent {
154            creator: Some(owned_user_id!("@carl:example.com")),
155            federate: false,
156            room_version: RoomVersionId::V4,
157            predecessor: None,
158            room_type: None,
159        };
160
161        let json = json!({
162            "creator": "@carl:example.com",
163            "m.federate": false,
164            "room_version": "4"
165        });
166
167        assert_eq!(to_json_value(&content).unwrap(), json);
168    }
169
170    #[test]
171    fn space_serialization() {
172        #[allow(deprecated)]
173        let content = RoomCreateEventContent {
174            creator: Some(owned_user_id!("@carl:example.com")),
175            federate: false,
176            room_version: RoomVersionId::V4,
177            predecessor: None,
178            room_type: Some(RoomType::Space),
179        };
180
181        let json = json!({
182            "creator": "@carl:example.com",
183            "m.federate": false,
184            "room_version": "4",
185            "type": "m.space"
186        });
187
188        assert_eq!(to_json_value(&content).unwrap(), json);
189    }
190
191    #[test]
192    #[allow(deprecated)]
193    fn deserialization() {
194        let json = json!({
195            "creator": "@carl:example.com",
196            "m.federate": true,
197            "room_version": "4"
198        });
199
200        let content = from_json_value::<RoomCreateEventContent>(json).unwrap();
201        assert_eq!(content.creator.unwrap(), "@carl:example.com");
202        assert!(content.federate);
203        assert_eq!(content.room_version, RoomVersionId::V4);
204        assert_matches!(content.predecessor, None);
205        assert_eq!(content.room_type, None);
206    }
207
208    #[test]
209    #[allow(deprecated)]
210    fn space_deserialization() {
211        let json = json!({
212            "creator": "@carl:example.com",
213            "m.federate": true,
214            "room_version": "4",
215            "type": "m.space"
216        });
217
218        let content = from_json_value::<RoomCreateEventContent>(json).unwrap();
219        assert_eq!(content.creator.unwrap(), "@carl:example.com");
220        assert!(content.federate);
221        assert_eq!(content.room_version, RoomVersionId::V4);
222        assert_matches!(content.predecessor, None);
223        assert_eq!(content.room_type, Some(RoomType::Space));
224    }
225}