conduit/src/client_server/room.rs

657 lines
21 KiB
Rust
Raw Normal View History

2021-07-14 07:07:08 +00:00
use crate::{
client_server::invite_helper, database::DatabaseGuard, pdu::PduBuilder, ConduitResult, Error,
Ruma,
};
2020-07-30 16:14:47 +00:00
use ruma::{
api::client::{
error::ErrorKind,
r0::room::{self, aliases, create_room, get_room_event, upgrade_room},
2020-07-30 16:14:47 +00:00
},
events::{
2021-07-20 13:24:18 +00:00
room::{guest_access, history_visibility, join_rules, member, name, topic},
2020-07-30 16:14:47 +00:00
EventType,
},
serde::Raw,
RoomAliasId, RoomId, RoomVersionId,
2020-07-30 16:14:47 +00:00
};
2021-07-13 13:44:25 +00:00
use std::{cmp::max, collections::BTreeMap, convert::TryFrom, sync::Arc};
use tracing::{info, warn};
2020-07-30 16:14:47 +00:00
#[cfg(feature = "conduit_bin")]
use rocket::{get, post};
2021-08-31 17:14:37 +00: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-07-30 16:14:47 +00:00
#[cfg_attr(
feature = "conduit_bin",
post("/_matrix/client/r0/createRoom", data = "<body>")
)]
2021-02-28 11:41:03 +00:00
#[tracing::instrument(skip(db, body))]
2020-09-14 18:23:19 +00:00
pub async fn create_room_route(
2021-07-14 07:07:08 +00:00
db: DatabaseGuard,
2020-09-08 15:32:03 +00:00
body: Ruma<create_room::Request<'_>>,
2020-07-30 16:14:47 +00:00
) -> ConduitResult<create_room::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-07-30 16:14:47 +00:00
let room_id = RoomId::new(db.globals.server_name());
2021-08-12 21:04:00 +00:00
db.rooms.get_or_create_shortroomid(&room_id, &db.globals)?;
2021-08-03 09:10:58 +00:00
let mutex_state = Arc::clone(
2021-07-13 13:44:25 +00:00
db.globals
2021-08-03 09:10:58 +00:00
.roomid_mutex_state
2021-07-13 13:44:25 +00:00
.write()
.unwrap()
.entry(room_id.clone())
.or_default(),
);
2021-08-03 09:10:58 +00:00
let state_lock = mutex_state.lock().await;
2021-07-13 13:44:25 +00:00
let alias: Option<RoomAliasId> =
body.room_alias_name
.as_ref()
.map_or(Ok(None), |localpart| {
// TODO: Check for invalid characters and maximum length
let alias =
RoomAliasId::try_from(format!("#{}:{}", localpart, db.globals.server_name()))
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias."))?;
2020-07-30 16:14:47 +00:00
if db.rooms.id_from_alias(&alias)?.is_some() {
Err(Error::BadRequest(
ErrorKind::RoomInUse,
"Room alias already exists.",
))
} else {
Ok(Some(alias))
}
})?;
2020-07-30 16:14:47 +00:00
let mut content = ruma::events::room::create::CreateEventContent::new(sender_user.clone());
2020-09-08 15:32:03 +00:00
content.federate = body.creation_content.federate;
content.predecessor = body.creation_content.predecessor.clone();
2021-08-07 13:55:03 +00:00
content.room_version = match body.room_version.clone() {
Some(room_version) => {
if room_version == RoomVersionId::Version5 || room_version == RoomVersionId::Version6 {
room_version
} else {
return Err(Error::BadRequest(
ErrorKind::UnsupportedRoomVersion,
"This server does not support that room version.",
));
}
}
None => RoomVersionId::Version6,
};
2020-07-30 16:14:47 +00:00
// 1. The room create event
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomCreate,
content: serde_json::to_value(content).expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-07-30 16:14:47 +00:00
// 2. Let the room creator join
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Join,
displayname: db.users.displayname(sender_user)?,
avatar_url: db.users.avatar_url(sender_user)?,
2020-10-05 20:19:22 +00:00
is_direct: Some(body.is_direct),
third_party_invite: None,
blurhash: db.users.blurhash(sender_user)?,
reason: None,
2020-10-05 20:19:22 +00:00
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(sender_user.to_string()),
2020-10-05 20:19:22 +00:00
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-07-30 16:14:47 +00:00
// 3. Power levels
2021-04-09 19:38:16 +00:00
// Figure out preset. We need it for preset specific events
let preset = body
.preset
.clone()
.unwrap_or_else(|| match &body.visibility {
room::Visibility::Private => create_room::RoomPreset::PrivateChat,
room::Visibility::Public => create_room::RoomPreset::PublicChat,
2021-07-15 17:54:04 +00:00
_ => create_room::RoomPreset::PrivateChat, // Room visibility should not be custom
2021-04-09 19:38:16 +00:00
});
2020-07-30 16:14:47 +00:00
let mut users = BTreeMap::new();
users.insert(sender_user.clone(), 100.into());
2021-04-09 19:38:16 +00:00
if preset == create_room::RoomPreset::TrustedPrivateChat {
for invite_ in &body.invite {
users.insert(invite_.clone(), 100.into());
}
2020-07-30 16:14:47 +00:00
}
let mut power_levels_content =
2020-07-30 16:14:47 +00:00
serde_json::to_value(ruma::events::room::power_levels::PowerLevelsEventContent {
users,
..Default::default()
2020-07-30 16:14:47 +00:00
})
.expect("event is valid, we just created it");
if let Some(power_level_content_override) = &body.power_level_content_override {
let json = serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(
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;
}
}
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomPowerLevels,
content: power_levels_content,
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-07-30 16:14:47 +00:00
// 4. Canonical room alias
if let Some(room_alias_id) = &alias {
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomCanonicalAlias,
content: serde_json::to_value(
ruma::events::room::canonical_alias::CanonicalAliasEventContent {
alias: Some(room_alias_id.clone()),
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,
&db,
&state_lock,
2021-08-12 21:04:00 +00:00
)?;
}
// 5. Events set by preset
// 5.1 Join Rules
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomJoinRules,
content: match preset {
create_room::RoomPreset::PublicChat => serde_json::to_value(
join_rules::JoinRulesEventContent::new(join_rules::JoinRule::Public),
)
.expect("event is valid, we just created it"),
// according to spec "invite" is the default
_ => serde_json::to_value(join_rules::JoinRulesEventContent::new(
join_rules::JoinRule::Invite,
))
.expect("event is valid, we just created it"),
},
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
// 5.2 History Visibility
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomHistoryVisibility,
content: serde_json::to_value(history_visibility::HistoryVisibilityEventContent::new(
history_visibility::HistoryVisibility::Shared,
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
// 5.3 Guest Access
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomGuestAccess,
content: match preset {
create_room::RoomPreset::PublicChat => {
serde_json::to_value(guest_access::GuestAccessEventContent::new(
guest_access::GuestAccess::Forbidden,
2020-07-30 16:14:47 +00:00
))
2020-10-05 20:19:22 +00:00
.expect("event is valid, we just created it")
}
_ => serde_json::to_value(guest_access::GuestAccessEventContent::new(
guest_access::GuestAccess::CanJoin,
))
.expect("event is valid, we just created it"),
2020-07-30 16:14:47 +00:00
},
2020-10-05 20:19:22 +00:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
// 6. Events listed in initial_state
2020-10-05 20:19:22 +00:00
for event in &body.initial_state {
let pdu_builder = PduBuilder::from(event.deserialize().map_err(|e| {
warn!("Invalid initial state event: {:?}", e);
Error::BadRequest(ErrorKind::InvalidParam, "Invalid initial state event.")
})?);
2020-10-05 20:19:22 +00:00
// Silently skip encryption events if they are not allowed
2021-01-01 12:47:53 +00:00
if pdu_builder.event_type == EventType::RoomEncryption && !db.globals.allow_encryption() {
2020-10-05 20:19:22 +00:00
continue;
}
2021-01-24 15:05:52 +00:00
db.rooms
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &db, &state_lock)?;
2020-10-05 20:19:22 +00:00
}
2020-07-30 16:14:47 +00:00
// 7. Events implied by name and topic
2020-10-05 20:19:22 +00:00
if let Some(name) = &body.name {
db.rooms.build_and_append_pdu(
2020-07-30 16:14:47 +00:00
PduBuilder {
2020-10-05 20:19:22 +00:00
event_type: EventType::RoomName,
2021-07-20 13:24:18 +00:00
content: serde_json::to_value(name::NameEventContent::new(Some(name.clone())))
.expect("event is valid, we just created it"),
2020-07-30 16:14:47 +00:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-09-12 19:30:07 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
}
2020-07-30 16:14:47 +00:00
2020-10-05 20:19:22 +00:00
if let Some(topic) = &body.topic {
db.rooms.build_and_append_pdu(
2020-07-30 16:14:47 +00:00
PduBuilder {
2020-10-05 20:19:22 +00:00
event_type: EventType::RoomTopic,
content: serde_json::to_value(topic::TopicEventContent {
topic: topic.clone(),
})
.expect("event is valid, we just created it"),
2020-07-30 16:14:47 +00:00
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-09-12 19:30:07 +00:00
&room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-07-30 16:14:47 +00:00
}
// 8. Events implied by invite (and TODO: invite_3pid)
2021-08-03 09:10:58 +00:00
drop(state_lock);
2021-04-25 12:10:07 +00:00
for user_id in &body.invite {
let _ = invite_helper(sender_user, user_id, &room_id, &db, body.is_direct).await;
2020-07-30 16:14:47 +00:00
}
// Homeserver specific stuff
if let Some(alias) = alias {
db.rooms.set_alias(&alias, Some(&room_id), &db.globals)?;
}
2020-09-08 15:32:03 +00:00
if body.visibility == room::Visibility::Public {
2020-07-30 16:14:47 +00:00
db.rooms.set_public(&room_id, true)?;
}
2020-11-15 11:17:21 +00:00
info!("{} created a room", sender_user);
db.flush()?;
Ok(create_room::Response::new(room_id).into())
2020-07-30 16:14:47 +00:00
}
2021-08-31 17:14:37 +00: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)
2020-07-30 16:14:47 +00:00
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/client/r0/rooms/<_>/event/<_>", data = "<body>")
)]
2021-02-28 11:41:03 +00:00
#[tracing::instrument(skip(db, body))]
pub async fn get_room_event_route(
2021-07-14 07:07:08 +00:00
db: DatabaseGuard,
2020-09-08 15:32:03 +00:00
body: Ruma<get_room_event::Request<'_>>,
2020-07-30 16:14:47 +00:00
) -> ConduitResult<get_room_event::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-07-30 16:14:47 +00:00
if !db.rooms.is_joined(sender_user, &body.room_id)? {
2020-07-30 16:14:47 +00:00
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
Ok(get_room_event::Response {
event: db
.rooms
.get_pdu(&body.event_id)?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?
.to_room_event(),
}
.into())
}
2020-08-06 11:21:53 +00:00
2021-08-31 17:14:37 +00: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
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/client/r0/rooms/<_>/aliases", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_room_aliases_route(
db: DatabaseGuard,
body: Ruma<aliases::Request<'_>>,
) -> ConduitResult<aliases::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if !db.rooms.is_joined(sender_user, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
Ok(aliases::Response {
aliases: db
.rooms
.room_aliases(&body.room_id)
.filter_map(|a| a.ok())
.collect(),
}
.into())
}
2021-08-31 17:14:37 +00:00
/// # `GET /_matrix/client/r0/rooms/{roomId}/upgrade`
///
/// 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-08-06 11:21:53 +00:00
#[cfg_attr(
feature = "conduit_bin",
2021-08-03 09:10:58 +00:00
post("/_matrix/client/r0/rooms/<_>/upgrade", data = "<body>")
2020-08-06 11:21:53 +00:00
)]
2021-02-28 11:41:03 +00:00
#[tracing::instrument(skip(db, body))]
2020-09-14 18:23:19 +00:00
pub async fn upgrade_room_route(
2021-07-14 07:07:08 +00:00
db: DatabaseGuard,
body: Ruma<upgrade_room::Request<'_>>,
2020-08-06 11:21:53 +00:00
) -> ConduitResult<upgrade_room::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-08-06 11:21:53 +00:00
2021-07-21 09:29:13 +00:00
if !matches!(
body.new_version,
RoomVersionId::Version5 | RoomVersionId::Version6
) {
2020-08-06 11:21:53 +00:00
return Err(Error::BadRequest(
ErrorKind::UnsupportedRoomVersion,
"This server does not support that room version.",
));
}
// Create a replacement room
let replacement_room = RoomId::new(db.globals.server_name());
2021-08-22 11:05:56 +00:00
db.rooms
.get_or_create_shortroomid(&replacement_room, &db.globals)?;
2020-08-06 11:21:53 +00:00
2021-08-03 09:10:58 +00:00
let mutex_state = Arc::clone(
2021-07-13 13:44:25 +00:00
db.globals
2021-08-03 09:10:58 +00:00
.roomid_mutex_state
2021-07-13 13:44:25 +00:00
.write()
.unwrap()
.entry(body.room_id.clone())
.or_default(),
);
2021-08-03 09:10:58 +00:00
let state_lock = mutex_state.lock().await;
2021-07-13 13:44:25 +00:00
2020-08-06 11:21:53 +00: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
2020-10-05 20:19:22 +00:00
let tombstone_event_id = db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomTombstone,
content: serde_json::to_value(ruma::events::room::tombstone::TombstoneEventContent {
body: "This room has been replaced".to_string(),
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 20:19:22 +00:00
&body.room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-08-06 11:21:53 +00:00
2021-08-03 09:10:58 +00:00
// Change lock to replacement room
drop(state_lock);
let mutex_state = Arc::clone(
db.globals
.roomid_mutex_state
.write()
.unwrap()
.entry(replacement_room.clone())
.or_default(),
);
let state_lock = mutex_state.lock().await;
2020-08-06 11:21:53 +00:00
// Get the old room federations status
let federate = serde_json::from_value::<Raw<ruma::events::room::create::CreateEventContent>>(
db.rooms
.room_state_get(&body.room_id, &EventType::RoomCreate, "")?
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
2021-09-22 10:27:21 +00:00
.content_value()
,
2020-08-06 11:21:53 +00:00
)
.expect("Raw::from_value always works")
.deserialize()
.map_err(|_| Error::bad_database("Invalid room event in database."))?
.federate;
// 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,
));
// Send a m.room.create event containing a predecessor field and the applicable room_version
let mut create_event_content =
ruma::events::room::create::CreateEventContent::new(sender_user.clone());
2020-08-06 11:21:53 +00:00
create_event_content.federate = federate;
2020-10-07 10:29:19 +00:00
create_event_content.room_version = body.new_version.clone();
2020-08-06 11:21:53 +00:00
create_event_content.predecessor = predecessor;
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomCreate,
content: serde_json::to_value(create_event_content)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&replacement_room,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-08-06 11:21:53 +00:00
// Join the new room
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Join,
displayname: db.users.displayname(sender_user)?,
avatar_url: db.users.avatar_url(sender_user)?,
2020-10-05 20:19:22 +00:00
is_direct: None,
third_party_invite: None,
blurhash: db.users.blurhash(sender_user)?,
reason: None,
2020-10-05 20:19:22 +00:00
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(sender_user.to_string()),
2020-10-05 20:19:22 +00:00
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&replacement_room,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-08-06 11:21:53 +00:00
// Recommended transferable state events list from the specs
let transferable_state_events = vec![
EventType::RoomServerAcl,
EventType::RoomEncryption,
EventType::RoomName,
EventType::RoomAvatar,
EventType::RoomTopic,
EventType::RoomGuestAccess,
EventType::RoomHistoryVisibility,
EventType::RoomJoinRules,
EventType::RoomPowerLevels,
];
// Replicate transferable state events to the new room
for event_type in transferable_state_events {
let event_content = match db.rooms.room_state_get(&body.room_id, &event_type, "")? {
2021-09-22 10:27:21 +00:00
Some(v) => v.content_value().clone(),
2020-08-06 11:21:53 +00:00
None => continue, // Skipping missing events.
};
2020-10-05 20:19:22 +00:00
db.rooms.build_and_append_pdu(
PduBuilder {
event_type,
content: event_content,
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&replacement_room,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-08-06 11:21:53 +00:00
}
// Moves any local aliases to the new room
for alias in db.rooms.room_aliases(&body.room_id).filter_map(|r| r.ok()) {
db.rooms
.set_alias(&alias, Some(&replacement_room), &db.globals)?;
}
// Get the old room power levels
let mut power_levels_event_content =
serde_json::from_value::<Raw<ruma::events::room::power_levels::PowerLevelsEventContent>>(
db.rooms
.room_state_get(&body.room_id, &EventType::RoomPowerLevels, "")?
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
2021-09-22 10:27:21 +00:00
.content_value()
,
2020-08-06 11:21:53 +00:00
)
.expect("database contains invalid PDU")
.deserialize()
.map_err(|_| Error::bad_database("Invalid room event in database."))?;
// Setting events_default and invite to the greater of 50 and users_default + 1
let new_level = max(
50.into(),
power_levels_event_content.users_default + 1.into(),
);
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
2020-10-05 20:19:22 +00:00
let _ = db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomPowerLevels,
content: serde_json::to_value(power_levels_event_content)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
2020-10-05 20:19:22 +00:00
&body.room_id,
2021-01-15 16:05:57 +00:00
&db,
2021-08-03 09:10:58 +00:00
&state_lock,
2020-10-05 20:19:22 +00:00
)?;
2020-08-06 11:21:53 +00:00
2021-08-03 09:10:58 +00:00
drop(state_lock);
2021-07-13 13:44:25 +00:00
db.flush()?;
2020-08-06 11:21:53 +00:00
// Return the replacement room id
Ok(upgrade_room::Response { replacement_room }.into())
}