matrix_sdk_base/room/
create.rs

1// Copyright 2025 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use matrix_sdk_common::ROOM_VERSION_RULES_FALLBACK;
16use ruma::{
17    OwnedUserId, RoomVersionId, assign,
18    events::{
19        EmptyStateKey, RedactContent, RedactedStateEventContent, StateEventType,
20        macros::EventContent,
21        room::create::{PreviousRoom, RoomCreateEventContent},
22    },
23    room::RoomType,
24    room_version_rules::RedactionRules,
25};
26use serde::{Deserialize, Serialize};
27
28/// The content of an `m.room.create` event, with a required `creator` field.
29///
30/// Starting with room version 11, the `creator` field should be removed and the
31/// `sender` field of the event should be used instead. This is reflected on
32/// [`RoomCreateEventContent`].
33///
34/// This type was created as an alternative for ease of use. When it is used in
35/// the SDK, it is constructed by copying the `sender` of the original event as
36/// the `creator`.
37#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
38#[ruma_event(type = "m.room.create", kind = State, state_key_type = EmptyStateKey, custom_redacted)]
39pub struct RoomCreateWithCreatorEventContent {
40    /// The `user_id` of the room creator.
41    ///
42    /// This is set by the homeserver.
43    ///
44    /// While this should be optional since room version 11, we copy the sender
45    /// of the event so we can still access it.
46    pub creator: OwnedUserId,
47
48    /// Whether or not this room's data should be transferred to other
49    /// homeservers.
50    #[serde(
51        rename = "m.federate",
52        default = "ruma::serde::default_true",
53        skip_serializing_if = "ruma::serde::is_true"
54    )]
55    pub federate: bool,
56
57    /// The version of the room.
58    ///
59    /// Defaults to `RoomVersionId::V1`.
60    #[serde(default = "default_create_room_version_id")]
61    pub room_version: RoomVersionId,
62
63    /// A reference to the room this room replaces, if the previous room was
64    /// upgraded.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub predecessor: Option<PreviousRoom>,
67
68    /// The room type.
69    ///
70    /// This is currently only used for spaces.
71    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
72    pub room_type: Option<RoomType>,
73
74    /// Additional room creators, considered to have "infinite" power level, in
75    /// room versions 12 onwards.
76    #[serde(skip_serializing_if = "Vec::is_empty", default)]
77    pub additional_creators: Vec<OwnedUserId>,
78}
79
80impl RoomCreateWithCreatorEventContent {
81    /// Constructs a `RoomCreateWithCreatorEventContent` with the given original
82    /// content and sender.
83    pub fn from_event_content(content: RoomCreateEventContent, sender: OwnedUserId) -> Self {
84        let RoomCreateEventContent {
85            federate,
86            room_version,
87            predecessor,
88            room_type,
89            additional_creators,
90            ..
91        } = content;
92        Self {
93            creator: sender,
94            federate,
95            room_version,
96            predecessor,
97            room_type,
98            additional_creators,
99        }
100    }
101
102    fn into_event_content(self) -> (RoomCreateEventContent, OwnedUserId) {
103        let Self { creator, federate, room_version, predecessor, room_type, additional_creators } =
104            self;
105
106        #[allow(deprecated)]
107        let content = assign!(RoomCreateEventContent::new_v11(), {
108            creator: Some(creator.clone()),
109            federate,
110            room_version,
111            predecessor,
112            room_type,
113            additional_creators,
114        });
115
116        (content, creator)
117    }
118
119    /// Get the creators of the room from this content, according to the room
120    /// version.
121    pub(crate) fn creators(&self) -> Vec<OwnedUserId> {
122        let rules = self.room_version.rules().unwrap_or(ROOM_VERSION_RULES_FALLBACK);
123
124        if rules.authorization.explicitly_privilege_room_creators {
125            std::iter::once(self.creator.clone())
126                .chain(self.additional_creators.iter().cloned())
127                .collect()
128        } else {
129            vec![self.creator.clone()]
130        }
131    }
132}
133
134/// Redacted form of [`RoomCreateWithCreatorEventContent`].
135pub type RedactedRoomCreateWithCreatorEventContent = RoomCreateWithCreatorEventContent;
136
137impl RedactedStateEventContent for RedactedRoomCreateWithCreatorEventContent {
138    type StateKey = EmptyStateKey;
139
140    fn event_type(&self) -> StateEventType {
141        StateEventType::RoomCreate
142    }
143}
144
145impl RedactContent for RoomCreateWithCreatorEventContent {
146    type Redacted = RedactedRoomCreateWithCreatorEventContent;
147
148    fn redact(self, rules: &RedactionRules) -> Self::Redacted {
149        let (content, sender) = self.into_event_content();
150        // Use Ruma's redaction algorithm.
151        let content = content.redact(rules);
152        Self::from_event_content(content, sender)
153    }
154}
155
156fn default_create_room_version_id() -> RoomVersionId {
157    RoomVersionId::V1
158}