add support for MSC4168: migrate m.room.* on room upgrades

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-07-29 01:04:26 -04:00
parent 2834d50ddf
commit 1d97858aa6

View file

@ -20,6 +20,7 @@ use ruma::{
tombstone::RoomTombstoneEventContent, tombstone::RoomTombstoneEventContent,
topic::RoomTopicEventContent, topic::RoomTopicEventContent,
}, },
space::child::SpaceChildEventContent,
StateEventType, TimelineEventType, StateEventType, TimelineEventType,
}, },
int, int,
@ -618,22 +619,14 @@ pub(crate) async fn upgrade_room_route(
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => { V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
create_event_content.insert( create_event_content.insert(
"creator".into(), "creator".into(),
json!(&sender_user).try_into().map_err(|e| { json!(&sender_user)
info!("Error forming creation event: {e}"); .try_into()
Error::BadRequest(ErrorKind::BadJson, "Error forming creation event") .map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
})?,
); );
}, },
V11 => {
// "creator" key no longer exists in V11 rooms
create_event_content.remove("creator");
},
_ => { _ => {
warn!("Unexpected or unsupported room version {}", body.new_version); // "creator" key no longer exists in V11+ rooms
return Err(Error::BadRequest( create_event_content.remove("creator");
ErrorKind::BadJson,
"Unexpected or unsupported room version found",
));
}, },
} }
} }
@ -642,26 +635,100 @@ pub(crate) async fn upgrade_room_route(
"room_version".into(), "room_version".into(),
json!(&body.new_version) json!(&body.new_version)
.try_into() .try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?, .map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
); );
create_event_content.insert( create_event_content.insert(
"predecessor".into(), "predecessor".into(),
json!(predecessor) json!(predecessor)
.try_into() .try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?, .map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
); );
// Validate creation event content // if the room was a space:
if serde_json::from_str::<CanonicalJsonObject>( // - migrate m.space.child and/or m.space.parent
to_raw_value(&create_event_content) // - add space type to replacement room m.room.create
.expect("Error forming creation event") //
.get(), // as apart of MSC4168
) if services
.is_err() .rooms
.state_accessor
.get_room_type(&body.room_id)
.unwrap_or(None)
.is_some_and(|room_type| room_type == ruma::room::RoomType::Space)
{ {
return Err(Error::BadRequest(ErrorKind::BadJson, "Error forming creation event")); create_event_content.insert(
"type".into(),
json!(ruma::room::RoomType::Space)
.try_into()
.map_err(|_| err!(Request(BadJson("Error forming creation event"))))?,
);
if let Some(event_content) = services
.rooms
.state_accessor
.room_state_get(&body.room_id, &StateEventType::SpaceChild, body.room_id.as_str())
.unwrap_or(None)
{
// space contents that are empty are not apart of the space
if !event_content.content.get().is_empty() {
// remove all but us from via
let mut new_content: SpaceChildEventContent = serde_json::from_str(event_content.content.get())
.map_err(|_| err!(Database(error!("Invalid m.space.child content in database"))))?;
new_content.via = vec![services.globals.config.server_name.clone()];
services
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: StateEventType::SpaceChild.to_string().into(),
content: to_raw_value(&new_content).expect("we just created it"),
unsigned: None,
state_key: Some(replacement_room.to_string()),
redacts: None,
},
sender_user,
&replacement_room,
&state_lock,
)
.await?;
}
}
if let Some(event_content) = services
.rooms
.state_accessor
.room_state_get(&body.room_id, &StateEventType::SpaceParent, body.room_id.as_str())
.unwrap_or(None)
{
// space contents that are empty are not apart of the space
if !event_content.content.get().is_empty() {
// remove all but us from via
let mut new_content: SpaceChildEventContent = serde_json::from_str(event_content.content.get())
.map_err(|_| err!(Database(error!("Invalid m.space.child content in database"))))?;
new_content.via = vec![services.globals.config.server_name.clone()];
services
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: StateEventType::SpaceParent.to_string().into(),
content: to_raw_value(&new_content).expect("we just created it"),
unsigned: None,
state_key: Some(replacement_room.to_string()),
redacts: None,
},
sender_user,
&replacement_room,
&state_lock,
)
.await?;
}
}
} }
// m.room.create
services services
.rooms .rooms
.timeline .timeline
@ -755,11 +822,11 @@ pub(crate) async fn upgrade_room_route(
.rooms .rooms
.state_accessor .state_accessor
.room_state_get(&body.room_id, &StateEventType::RoomPowerLevels, "")? .room_state_get(&body.room_id, &StateEventType::RoomPowerLevels, "")?
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))? .ok_or_else(|| err!(Database(error!("Found room without m.room.create event."))))?
.content .content
.get(), .get(),
) )
.map_err(|_| Error::bad_database("Invalid room event in database."))?; .map_err(|_| err!(Database(error!("Invalid room event in database."))))?;
// Setting events_default and invite to the greater of 50 and users_default + 1 // Setting events_default and invite to the greater of 50 and users_default + 1
let new_level = max( let new_level = max(
@ -767,9 +834,7 @@ pub(crate) async fn upgrade_room_route(
power_levels_event_content power_levels_event_content
.users_default .users_default
.checked_add(int!(1)) .checked_add(int!(1))
.ok_or_else(|| { .ok_or_else(|| err!(Request(BadJson("users_default power levels event content is not valid"))))?,
Error::BadRequest(ErrorKind::BadJson, "users_default power levels event content is not valid")
})?,
); );
power_levels_event_content.events_default = new_level; power_levels_event_content.events_default = new_level;
power_levels_event_content.invite = new_level; power_levels_event_content.invite = new_level;
@ -833,7 +898,7 @@ fn default_power_levels_content(
if let Some(power_level_content_override) = power_level_content_override { if let Some(power_level_content_override) = power_level_content_override {
let json: JsonObject = serde_json::from_str(power_level_content_override.json().get()) let json: JsonObject = serde_json::from_str(power_level_content_override.json().get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid power_level_content_override."))?; .map_err(|_| err!(Request(BadJson("Invalid power_level_content_override"))))?;
for (key, value) in json { for (key, value) in json {
power_levels_content[key] = value; power_levels_content[key] = value;