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