Skip to main content

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, PossiblyRedactedStateEventContent, RedactContent, RedactedStateEventContent,
20        StateEventContent, StateEventType, StaticEventContent,
21        macros::EventContent,
22        room::create::{PreviousRoom, RoomCreateEventContent},
23    },
24    room::RoomType,
25    room_version_rules::RedactionRules,
26};
27use serde::{Deserialize, Serialize};
28
29/// The content of an `m.room.create` event, with a required `creator` field.
30///
31/// Starting with room version 11, the `creator` field should be removed and the
32/// `sender` field of the event should be used instead. This is reflected on
33/// [`RoomCreateEventContent`].
34///
35/// This type was created as an alternative for ease of use. When it is used in
36/// the SDK, it is constructed by copying the `sender` of the original event as
37/// the `creator`.
38#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
39#[ruma_event(type = "m.room.create", kind = State, state_key_type = EmptyStateKey, custom_redacted)]
40pub struct RoomCreateWithCreatorEventContent {
41    /// The `user_id` of the room creator.
42    ///
43    /// This is set by the homeserver.
44    ///
45    /// While this should be optional since room version 11, we copy the sender
46    /// of the event so we can still access it.
47    pub creator: OwnedUserId,
48
49    /// Whether or not this room's data should be transferred to other
50    /// homeservers.
51    #[serde(
52        rename = "m.federate",
53        default = "ruma::serde::default_true",
54        skip_serializing_if = "ruma::serde::is_true"
55    )]
56    pub federate: bool,
57
58    /// The version of the room.
59    ///
60    /// Defaults to `RoomVersionId::V1`.
61    #[serde(default = "default_create_room_version_id")]
62    pub room_version: RoomVersionId,
63
64    /// A reference to the room this room replaces, if the previous room was
65    /// upgraded.
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub predecessor: Option<PreviousRoom>,
68
69    /// The room type.
70    ///
71    /// This is currently only used for spaces.
72    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
73    pub room_type: Option<RoomType>,
74
75    /// Additional room creators, considered to have "infinite" power level, in
76    /// room versions 12 onwards.
77    #[serde(skip_serializing_if = "Vec::is_empty", default)]
78    pub additional_creators: Vec<OwnedUserId>,
79}
80
81impl RoomCreateWithCreatorEventContent {
82    /// Constructs a `RoomCreateWithCreatorEventContent` with the given original
83    /// content and sender.
84    pub fn from_event_content(content: RoomCreateEventContent, sender: OwnedUserId) -> Self {
85        let RoomCreateEventContent {
86            federate,
87            room_version,
88            predecessor,
89            room_type,
90            additional_creators,
91            ..
92        } = content;
93        Self {
94            creator: sender,
95            federate,
96            room_version,
97            predecessor,
98            room_type,
99            additional_creators,
100        }
101    }
102
103    fn into_event_content(self) -> (RoomCreateEventContent, OwnedUserId) {
104        let Self { creator, federate, room_version, predecessor, room_type, additional_creators } =
105            self;
106
107        #[allow(deprecated)]
108        let content = assign!(RoomCreateEventContent::new_v11(), {
109            creator: Some(creator.clone()),
110            federate,
111            room_version,
112            predecessor,
113            room_type,
114            additional_creators,
115        });
116
117        (content, creator)
118    }
119
120    /// Get the creators of the room from this content, according to the room
121    /// version.
122    pub(crate) fn creators(&self) -> Vec<OwnedUserId> {
123        let rules = self.room_version.rules().unwrap_or(ROOM_VERSION_RULES_FALLBACK);
124
125        if rules.authorization.explicitly_privilege_room_creators {
126            std::iter::once(self.creator.clone())
127                .chain(self.additional_creators.iter().cloned())
128                .collect()
129        } else {
130            vec![self.creator.clone()]
131        }
132    }
133}
134
135/// Redacted form of [`RoomCreateWithCreatorEventContent`].
136pub type RedactedRoomCreateWithCreatorEventContent = RoomCreateWithCreatorEventContent;
137
138impl RedactedStateEventContent for RedactedRoomCreateWithCreatorEventContent {
139    type StateKey = <RoomCreateWithCreatorEventContent as StateEventContent>::StateKey;
140
141    fn event_type(&self) -> StateEventType {
142        RoomCreateWithCreatorEventContent::TYPE.into()
143    }
144}
145
146impl RedactContent for RoomCreateWithCreatorEventContent {
147    type Redacted = RedactedRoomCreateWithCreatorEventContent;
148
149    fn redact(self, rules: &RedactionRules) -> Self::Redacted {
150        let (content, sender) = self.into_event_content();
151        // Use Ruma's redaction algorithm.
152        let content = content.redact(rules);
153        Self::from_event_content(content, sender)
154    }
155}
156
157fn default_create_room_version_id() -> RoomVersionId {
158    RoomVersionId::V1
159}
160
161impl PossiblyRedactedStateEventContent for RoomCreateWithCreatorEventContent {
162    type StateKey = <RoomCreateWithCreatorEventContent as StateEventContent>::StateKey;
163
164    fn event_type(&self) -> StateEventType {
165        RoomCreateWithCreatorEventContent::TYPE.into()
166    }
167}