1
0
Fork 0
mirror of https://gitlab.com/famedly/conduit.git synced 2025-07-02 16:38:36 +00:00
conduit/src/api/client_server/room.rs

692 lines
23 KiB
Rust
Raw Normal View History

2021-07-14 07:07:08 +00:00
use crate::{
Error, Result, Ruma, service::pdu::PduBuilder, services, api::client_server::invite_helper,
2021-07-14 07:07:08 +00:00
};
2020-07-30 18:14:47 +02:00
use ruma::{
api::client::{
error::ErrorKind,
2022-02-18 15:33:14 +01:00
room::{self, aliases, create_room, get_room_event, upgrade_room},
2020-07-30 18:14:47 +02:00
},
events::{
room::{
canonical_alias::RoomCanonicalAliasEventContent,
create::RoomCreateEventContent,
guest_access::{GuestAccess, RoomGuestAccessEventContent},
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
join_rules::{JoinRule, RoomJoinRulesEventContent},
member::{MembershipState, RoomMemberEventContent},
name::RoomNameEventContent,
power_levels::RoomPowerLevelsEventContent,
tombstone::RoomTombstoneEventContent,
topic::RoomTopicEventContent,
},
2022-04-06 21:31:29 +02:00
RoomEventType, StateEventType,
2020-07-30 18:14:47 +02:00
},
int,
serde::{CanonicalJsonObject, JsonObject},
RoomAliasId, RoomId,
2020-07-30 18:14:47 +02:00
};
use serde_json::{json, value::to_raw_value};
use std::{cmp::max, collections::BTreeMap, sync::Arc};
use tracing::{info, warn};
2020-07-30 18:14:47 +02:00
2021-08-31 19:14:37 +02:00
/// # `POST /_matrix/client/r0/createRoom`
///
/// Creates a new room.
///
/// - Room ID is randomly generated
/// - Create alias if room_alias_name is set
/// - Send create event
/// - Join sender user
/// - Send power levels event
/// - Send canonical room alias
/// - Send join rules
/// - Send history visibility
/// - Send guest access
/// - Send events listed in initial state
/// - Send events implied by `name` and `topic`
/// - Send invite events
2020-09-14 20:23:19 +02:00
pub async fn create_room_route(
2022-04-06 21:31:29 +02:00
body: Ruma<create_room::v3::IncomingRequest>,
2022-02-18 15:33:14 +01:00
) -> Result<create_room::v3::Response> {
use create_room::v3::RoomPreset;
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-07-30 18:14:47 +02:00
let room_id = RoomId::new(services().globals.server_name());
2020-07-30 18:14:47 +02:00
2022-10-05 09:34:25 +02:00
services().rooms.short.get_or_create_shortroomid(&room_id)?;
2021-08-12 23:04:00 +02:00
2021-08-03 11:10:58 +02:00
let mutex_state = Arc::clone(
services().globals
2021-08-03 11:10:58 +02:00
.roomid_mutex_state
2021-07-13 15:44:25 +02:00
.write()
.unwrap()
.entry(room_id.clone())
.or_default(),
);
2021-08-03 11:10:58 +02:00
let state_lock = mutex_state.lock().await;
2021-07-13 15:44:25 +02:00
if !services().globals.allow_room_creation()
&& !body.from_appservice
&& !services().users.is_admin(sender_user)?
{
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Room creation has been disabled.",
));
}
2021-11-26 20:36:40 +01:00
let alias: Option<Box<RoomAliasId>> =
body.room_alias_name
.as_ref()
.map_or(Ok(None), |localpart| {
// TODO: Check for invalid characters and maximum length
2021-11-27 00:30:28 +01:00
let alias =
RoomAliasId::parse(format!("#{}:{}", localpart, services().globals.server_name()))
2021-11-27 00:30:28 +01:00
.map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias.")
})?;
2020-07-30 18:14:47 +02:00
2022-09-07 13:25:51 +02:00
if services().rooms.alias.resolve_local_alias(&alias)?.is_some() {
Err(Error::BadRequest(
ErrorKind::RoomInUse,
"Room alias already exists.",
))
} else {
Ok(Some(alias))
}
})?;
2020-07-30 18:14:47 +02:00
let room_version = match body.room_version.clone() {
2021-08-07 15:55:03 +02:00
Some(room_version) => {
2022-10-05 12:45:54 +02:00
if services().globals.supported_room_versions().contains(&room_version) {
2021-08-07 15:55:03 +02:00
room_version
} else {
return Err(Error::BadRequest(
ErrorKind::UnsupportedRoomVersion,
"This server does not support that room version.",
));
}
}
None => services().globals.default_room_version(),
2021-08-07 15:55:03 +02:00
};
2020-07-30 18:14:47 +02:00
let content = match &body.creation_content {
Some(content) => {
let mut content = content
.deserialize_as::<CanonicalJsonObject>()
.expect("Invalid creation content");
content.insert(
"creator".into(),
json!(&sender_user).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
})?,
);
content.insert(
"room_version".into(),
json!(room_version.as_str()).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
})?,
);
content
}
None => {
let mut content = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&RoomCreateEventContent::new(sender_user.clone()))
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid creation content"))?
.get(),
)
.unwrap();
content.insert(
"room_version".into(),
json!(room_version.as_str()).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
})?,
);
content
}
};
// Validate creation content
let de_result = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&content)
.expect("Invalid creation content")
.get(),
);
2021-11-26 20:36:40 +01:00
if de_result.is_err() {
return Err(Error::BadRequest(
ErrorKind::BadJson,
"Invalid creation content",
));
}
2020-07-30 18:14:47 +02:00
// 1. The room create event
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomCreate,
content: to_raw_value(&content).expect("event is valid, we just created it"),
2020-10-05 22:19:22 +02:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-07-30 18:14:47 +02:00
// 2. Let the room creator join
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
2020-10-05 22:19:22 +02:00
is_direct: Some(body.is_direct),
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
reason: None,
join_authorized_via_users_server: None,
2020-10-05 22:19:22 +02:00
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(sender_user.to_string()),
2020-10-05 22:19:22 +02:00
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-07-30 18:14:47 +02:00
// 3. Power levels
2021-04-09 21:38:16 +02:00
// Figure out preset. We need it for preset specific events
let preset = body
.preset
.clone()
.unwrap_or_else(|| match &body.visibility {
2022-02-18 15:33:14 +01:00
room::Visibility::Private => RoomPreset::PrivateChat,
room::Visibility::Public => RoomPreset::PublicChat,
_ => RoomPreset::PrivateChat, // Room visibility should not be custom
2021-04-09 21:38:16 +02:00
});
2020-07-30 18:14:47 +02:00
let mut users = BTreeMap::new();
users.insert(sender_user.clone(), int!(100));
2021-04-09 21:38:16 +02:00
2022-02-18 15:33:14 +01:00
if preset == RoomPreset::TrustedPrivateChat {
2021-04-09 21:38:16 +02:00
for invite_ in &body.invite {
users.insert(invite_.clone(), int!(100));
2021-04-09 21:38:16 +02:00
}
2020-07-30 18:14:47 +02:00
}
let mut power_levels_content = serde_json::to_value(RoomPowerLevelsEventContent {
users,
..Default::default()
})
.expect("event is valid, we just created it");
if let Some(power_level_content_override) = &body.power_level_content_override {
let json: JsonObject = serde_json::from_str(power_level_content_override.json().get())
.map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid power_level_content_override.")
})?;
for (key, value) in json {
power_levels_content[key] = value;
}
}
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomPowerLevels,
content: to_raw_value(&power_levels_content)
.expect("to_raw_value always works on serde_json::Value"),
2020-10-05 22:19:22 +02:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-07-30 18:14:47 +02:00
// 4. Canonical room alias
if let Some(room_alias_id) = &alias {
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomCanonicalAlias,
content: to_raw_value(&RoomCanonicalAliasEventContent {
2021-11-26 20:36:40 +01:00
alias: Some(room_alias_id.to_owned()),
alt_aliases: vec![],
})
.expect("We checked that alias earlier, it must be fine"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
&room_id,
&state_lock,
2021-08-12 23:04:00 +02:00
)?;
}
// 5. Events set by preset
// 5.1 Join Rules
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomJoinRules,
content: to_raw_value(&RoomJoinRulesEventContent::new(match preset {
2022-02-18 15:33:14 +01:00
RoomPreset::PublicChat => JoinRule::Public,
2020-10-05 22:19:22 +02:00
// according to spec "invite" is the default
_ => JoinRule::Invite,
}))
.expect("event is valid, we just created it"),
2020-10-05 22:19:22 +02:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
// 5.2 History Visibility
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomHistoryVisibility,
content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
HistoryVisibility::Shared,
2020-10-05 22:19:22 +02:00
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
// 5.3 Guest Access
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomGuestAccess,
content: to_raw_value(&RoomGuestAccessEventContent::new(match preset {
2022-02-18 15:33:14 +01:00
RoomPreset::PublicChat => GuestAccess::Forbidden,
_ => GuestAccess::CanJoin,
}))
.expect("event is valid, we just created it"),
2020-10-05 22:19:22 +02:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
// 6. Events listed in initial_state
2020-10-05 22:19:22 +02:00
for event in &body.initial_state {
let mut pdu_builder = event.deserialize_as::<PduBuilder>().map_err(|e| {
warn!("Invalid initial state event: {:?}", e);
Error::BadRequest(ErrorKind::InvalidParam, "Invalid initial state event.")
})?;
// Implicit state key defaults to ""
pdu_builder.state_key.get_or_insert_with(|| "".to_owned());
2020-10-05 22:19:22 +02:00
// Silently skip encryption events if they are not allowed
if pdu_builder.event_type == RoomEventType::RoomEncryption && !services().globals.allow_encryption()
2022-04-06 21:31:29 +02:00
{
2020-10-05 22:19:22 +02:00
continue;
}
services().rooms
2022-10-05 09:34:25 +02:00
.timeline.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)?;
2020-10-05 22:19:22 +02:00
}
2020-07-30 18:14:47 +02:00
// 7. Events implied by name and topic
2020-10-05 22:19:22 +02:00
if let Some(name) = &body.name {
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-07-30 18:14:47 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomName,
content: to_raw_value(&RoomNameEventContent::new(Some(name.clone())))
2021-07-20 15:24:18 +02:00
.expect("event is valid, we just created it"),
2020-07-30 18:14:47 +02:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-09-12 21:30:07 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
}
2020-07-30 18:14:47 +02:00
2020-10-05 22:19:22 +02:00
if let Some(topic) = &body.topic {
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-07-30 18:14:47 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomTopic,
content: to_raw_value(&RoomTopicEventContent {
2020-10-05 22:19:22 +02:00
topic: topic.clone(),
})
.expect("event is valid, we just created it"),
2020-07-30 18:14:47 +02:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-09-12 21:30:07 +02:00
&room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-07-30 18:14:47 +02:00
}
// 8. Events implied by invite (and TODO: invite_3pid)
2021-08-03 11:10:58 +02:00
drop(state_lock);
2021-04-25 14:10:07 +02:00
for user_id in &body.invite {
let _ = invite_helper(sender_user, user_id, &room_id, body.is_direct).await;
2020-07-30 18:14:47 +02:00
}
// Homeserver specific stuff
if let Some(alias) = alias {
2022-10-05 09:34:25 +02:00
services().rooms.alias.set_alias(&alias, &room_id)?;
2020-07-30 18:14:47 +02:00
}
2020-09-08 17:32:03 +02:00
if body.visibility == room::Visibility::Public {
2022-10-05 09:34:25 +02:00
services().rooms.directory.set_public(&room_id)?;
2020-07-30 18:14:47 +02:00
}
2020-11-15 12:17:21 +01:00
info!("{} created a room", sender_user);
2022-02-18 15:33:14 +01:00
Ok(create_room::v3::Response::new(room_id))
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/rooms/{roomId}/event/{eventId}`
///
/// Gets a single event.
///
/// - You have to currently be joined to the room (TODO: Respect history visibility)
pub async fn get_room_event_route(
2022-04-06 21:31:29 +02:00
body: Ruma<get_room_event::v3::IncomingRequest>,
2022-02-18 15:33:14 +01:00
) -> Result<get_room_event::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-07-30 18:14:47 +02:00
2022-10-05 09:34:25 +02:00
if !services().rooms.state_cache.is_joined(sender_user, &body.room_id)? {
2020-07-30 18:14:47 +02:00
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
2022-02-18 15:33:14 +01:00
Ok(get_room_event::v3::Response {
event: services()
2020-07-30 18:14:47 +02:00
.rooms
2022-10-05 09:34:25 +02:00
.timeline
2020-07-30 18:14:47 +02:00
.get_pdu(&body.event_id)?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?
.to_room_event(),
})
2020-07-30 18:14:47 +02:00
}
2020-08-06 13:21:53 +02:00
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/rooms/{roomId}/aliases`
///
/// Lists all aliases of the room.
///
/// - Only users joined to the room are allowed to call this TODO: Allow any user to call it if history_visibility is world readable
pub async fn get_room_aliases_route(
2022-04-06 21:31:29 +02:00
body: Ruma<aliases::v3::IncomingRequest>,
2022-02-18 15:33:14 +01:00
) -> Result<aliases::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2022-10-05 09:34:25 +02:00
if !services().rooms.state_cache.is_joined(sender_user, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
2022-02-18 15:33:14 +01:00
Ok(aliases::v3::Response {
aliases: services()
.rooms
2022-10-05 09:34:25 +02:00
.alias.local_aliases_for_room(&body.room_id)
.filter_map(|a| a.ok())
.collect(),
})
}
/// # `POST /_matrix/client/r0/rooms/{roomId}/upgrade`
2021-08-31 19:14:37 +02:00
///
/// Upgrades the room.
///
/// - Creates a replacement room
/// - Sends a tombstone event into the current room
/// - Sender user joins the room
/// - Transfers some state events
/// - Moves local aliases
/// - Modifies old room power levels to prevent users from speaking
2020-09-14 20:23:19 +02:00
pub async fn upgrade_room_route(
2022-04-06 21:31:29 +02:00
body: Ruma<upgrade_room::v3::IncomingRequest>,
2022-02-18 15:33:14 +01:00
) -> Result<upgrade_room::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-08-06 13:21:53 +02:00
2022-10-05 12:45:54 +02:00
if !services().globals.supported_room_versions().contains(&body.new_version) {
2020-08-06 13:21:53 +02:00
return Err(Error::BadRequest(
ErrorKind::UnsupportedRoomVersion,
"This server does not support that room version.",
));
}
// Create a replacement room
let replacement_room = RoomId::new(services().globals.server_name());
services().rooms
2022-10-05 09:34:25 +02:00
.short.get_or_create_shortroomid(&replacement_room)?;
2020-08-06 13:21:53 +02:00
2021-08-03 11:10:58 +02:00
let mutex_state = Arc::clone(
services().globals
2021-08-03 11:10:58 +02:00
.roomid_mutex_state
2021-07-13 15:44:25 +02:00
.write()
.unwrap()
.entry(body.room_id.clone())
.or_default(),
);
2021-08-03 11:10:58 +02:00
let state_lock = mutex_state.lock().await;
2021-07-13 15:44:25 +02:00
2020-08-06 13:21:53 +02:00
// Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further
// Fail if the sender does not have the required permissions
2022-10-05 09:34:25 +02:00
let tombstone_event_id = services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomTombstone,
content: to_raw_value(&RoomTombstoneEventContent {
body: "This room has been replaced".to_owned(),
2020-10-05 22:19:22 +02:00
replacement_room: replacement_room.clone(),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&body.room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-08-06 13:21:53 +02:00
2021-08-03 11:10:58 +02:00
// Change lock to replacement room
drop(state_lock);
let mutex_state = Arc::clone(
services().globals
2021-08-03 11:10:58 +02:00
.roomid_mutex_state
.write()
.unwrap()
.entry(replacement_room.clone())
.or_default(),
);
let state_lock = mutex_state.lock().await;
// Get the old room creation event
let mut create_event_content = serde_json::from_str::<CanonicalJsonObject>(
services().rooms
2022-10-05 09:34:25 +02:00
.state_accessor
2022-04-06 21:31:29 +02:00
.room_state_get(&body.room_id, &StateEventType::RoomCreate, "")?
2020-08-06 13:21:53 +02:00
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
2021-06-30 09:52:01 +02:00
.content
.get(),
2020-08-06 13:21:53 +02:00
)
.map_err(|_| Error::bad_database("Invalid room event in database."))?;
2020-08-06 13:21:53 +02:00
// Use the m.room.tombstone event as the predecessor
let predecessor = Some(ruma::events::room::create::PreviousRoom::new(
body.room_id.clone(),
(*tombstone_event_id).to_owned(),
2020-08-06 13:21:53 +02:00
));
// Send a m.room.create event containing a predecessor field and the applicable room_version
create_event_content.insert(
"creator".into(),
json!(&sender_user)
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
);
create_event_content.insert(
"room_version".into(),
json!(&body.new_version)
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
);
create_event_content.insert(
"predecessor".into(),
json!(predecessor)
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
);
// Validate creation event content
let de_result = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&create_event_content)
.expect("Error forming creation event")
.get(),
);
2021-11-26 20:36:40 +01:00
if de_result.is_err() {
return Err(Error::BadRequest(
ErrorKind::BadJson,
"Error forming creation event",
));
}
2020-08-06 13:21:53 +02:00
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomCreate,
content: to_raw_value(&create_event_content)
2020-10-05 22:19:22 +02:00
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&replacement_room,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-08-06 13:21:53 +02:00
// Join the new room
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
2020-10-05 22:19:22 +02:00
is_direct: None,
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
reason: None,
join_authorized_via_users_server: None,
2020-10-05 22:19:22 +02:00
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(sender_user.to_string()),
2020-10-05 22:19:22 +02:00
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&replacement_room,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-08-06 13:21:53 +02:00
// Recommended transferable state events list from the specs
let transferable_state_events = vec![
2022-04-06 21:31:29 +02:00
StateEventType::RoomServerAcl,
StateEventType::RoomEncryption,
StateEventType::RoomName,
StateEventType::RoomAvatar,
StateEventType::RoomTopic,
StateEventType::RoomGuestAccess,
StateEventType::RoomHistoryVisibility,
StateEventType::RoomJoinRules,
StateEventType::RoomPowerLevels,
2020-08-06 13:21:53 +02:00
];
// Replicate transferable state events to the new room
for event_type in transferable_state_events {
2022-10-05 09:34:25 +02:00
let event_content = match services().rooms.state_accessor.room_state_get(&body.room_id, &event_type, "")? {
2021-03-17 22:30:25 +01:00
Some(v) => v.content.clone(),
2020-08-06 13:21:53 +02:00
None => continue, // Skipping missing events.
};
2022-10-05 09:34:25 +02:00
services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: event_type.to_string().into(),
2020-10-05 22:19:22 +02:00
content: event_content,
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&replacement_room,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-08-06 13:21:53 +02:00
}
// Moves any local aliases to the new room
2022-10-05 09:34:25 +02:00
for alias in services().rooms.alias.local_aliases_for_room(&body.room_id).filter_map(|r| r.ok()) {
services().rooms
2022-10-05 09:34:25 +02:00
.alias.set_alias(&alias, &replacement_room)?;
2020-08-06 13:21:53 +02:00
}
// Get the old room power levels
let mut power_levels_event_content: RoomPowerLevelsEventContent = serde_json::from_str(
services().rooms
2022-10-05 09:34:25 +02:00
.state_accessor
2022-04-06 21:31:29 +02:00
.room_state_get(&body.room_id, &StateEventType::RoomPowerLevels, "")?
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
.content
.get(),
)
.map_err(|_| Error::bad_database("Invalid room event in database."))?;
2020-08-06 13:21:53 +02:00
// Setting events_default and invite to the greater of 50 and users_default + 1
let new_level = max(int!(50), power_levels_event_content.users_default + int!(1));
2020-08-06 13:21:53 +02:00
power_levels_event_content.events_default = new_level;
power_levels_event_content.invite = new_level;
// Modify the power levels in the old room to prevent sending of events and inviting new users
2022-10-05 09:34:25 +02:00
let _ = services().rooms.timeline.build_and_append_pdu(
2020-10-05 22:19:22 +02:00
PduBuilder {
2022-04-06 21:31:29 +02:00
event_type: RoomEventType::RoomPowerLevels,
content: to_raw_value(&power_levels_event_content)
2020-10-05 22:19:22 +02:00
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&body.room_id,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-08-06 13:21:53 +02:00
2021-08-03 11:10:58 +02:00
drop(state_lock);
2021-07-13 15:44:25 +02:00
2020-08-06 13:21:53 +02:00
// Return the replacement room id
2022-02-18 15:33:14 +01:00
Ok(upgrade_room::v3::Response { replacement_room })
2020-08-06 13:21:53 +02:00
}
2022-06-19 22:56:14 +02:00