mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-07-27 10:18:30 +00:00
feat(space-upgrades): Update parent spaces in upgrade
This relies on the room being upgraded referencing the space itself, but there isn't an easy way to do it otherwise.
This commit is contained in:
parent
62bdfe1ce8
commit
b2883c3d6e
3 changed files with 124 additions and 5 deletions
|
@ -5,7 +5,7 @@ use conduwuit::{
|
|||
Err, Error, Event, Result, err, info,
|
||||
matrix::{StateKey, pdu::PduBuilder},
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use ruma::{
|
||||
CanonicalJsonObject, RoomId, RoomVersionId,
|
||||
api::client::{error::ErrorKind, room::upgrade_room},
|
||||
|
@ -16,12 +16,13 @@ use ruma::{
|
|||
power_levels::RoomPowerLevelsEventContent,
|
||||
tombstone::RoomTombstoneEventContent,
|
||||
},
|
||||
space::child::{RedactedSpaceChildEventContent, SpaceChildEventContent},
|
||||
},
|
||||
int,
|
||||
};
|
||||
use serde_json::{json, value::to_raw_value};
|
||||
|
||||
use crate::Ruma;
|
||||
use crate::router::Ruma;
|
||||
|
||||
/// Recommended transferable state events list from the spec
|
||||
const TRANSFERABLE_STATE_EVENTS: &[StateEventType; 11] = &[
|
||||
|
@ -36,7 +37,7 @@ const TRANSFERABLE_STATE_EVENTS: &[StateEventType; 11] = &[
|
|||
StateEventType::RoomTopic,
|
||||
// Not explicitly recommended in spec, but very useful.
|
||||
StateEventType::SpaceChild,
|
||||
StateEventType::SpaceParent, // TODO: m.room.policy
|
||||
StateEventType::SpaceParent, // TODO: m.room.policy?
|
||||
];
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/upgrade`
|
||||
|
@ -128,7 +129,7 @@ pub(crate) async fn upgrade_room_route(
|
|||
);
|
||||
},
|
||||
| _ => {
|
||||
// "creator" key no longer exists in V11+ rooms
|
||||
// "creator" key no longer exists in V11 rooms
|
||||
create_event_content.remove("creator");
|
||||
},
|
||||
}
|
||||
|
@ -175,6 +176,7 @@ pub(crate) async fn upgrade_room_route(
|
|||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
|
||||
// Join the new room
|
||||
|
@ -205,6 +207,7 @@ pub(crate) async fn upgrade_room_route(
|
|||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
|
||||
// Replicate transferable state events to the new room
|
||||
|
@ -233,6 +236,7 @@ pub(crate) async fn upgrade_room_route(
|
|||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
}
|
||||
|
||||
|
@ -290,10 +294,76 @@ pub(crate) async fn upgrade_room_route(
|
|||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
// Check if the old room has a space parent, and if so, whether we should update
|
||||
// it (m.space.parent, room_id)
|
||||
let parents = services
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_keys(&body.room_id, &StateEventType::SpaceParent)
|
||||
.await?;
|
||||
|
||||
for raw_space_id in parents {
|
||||
let space_id = RoomId::parse(&raw_space_id)?;
|
||||
let state_key = StateKey::from(raw_space_id.clone());
|
||||
let Ok(child) = services
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get_content::<SpaceChildEventContent>(
|
||||
space_id,
|
||||
&StateEventType::SpaceChild,
|
||||
body.room_id.as_str(),
|
||||
)
|
||||
.await
|
||||
else {
|
||||
// If the space does not have a child event for this room, we can skip it
|
||||
continue;
|
||||
};
|
||||
// First, drop the space's child event
|
||||
let state_lock = services.rooms.state.mutex.lock(space_id).await;
|
||||
services
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: StateEventType::SpaceChild.into(),
|
||||
content: to_raw_value(&RedactedSpaceChildEventContent {})
|
||||
.expect("event is valid, we just created it"),
|
||||
state_key: Some(state_key),
|
||||
..Default::default()
|
||||
},
|
||||
sender_user,
|
||||
space_id,
|
||||
&state_lock,
|
||||
)
|
||||
.boxed()
|
||||
.await
|
||||
.ok();
|
||||
// Now, add a new child event for the replacement room
|
||||
services
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: StateEventType::SpaceChild.into(),
|
||||
content: to_raw_value(&child).expect("event is valid, we just created it"),
|
||||
state_key: Some(StateKey::new()),
|
||||
..Default::default()
|
||||
},
|
||||
sender_user,
|
||||
space_id,
|
||||
&state_lock,
|
||||
)
|
||||
.boxed()
|
||||
.await
|
||||
.ok();
|
||||
drop(state_lock);
|
||||
}
|
||||
|
||||
// Return the replacement room id
|
||||
Ok(upgrade_room::v3::Response { replacement_room })
|
||||
}
|
||||
|
|
|
@ -91,3 +91,22 @@ pub async fn room_state_get(
|
|||
.and_then(|shortstatehash| self.state_get(shortstatehash, event_type, state_key))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns all state keys for the given `room_id` and `event_type`.
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(skip(self), level = "debug")]
|
||||
pub async fn room_state_keys(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: &StateEventType,
|
||||
) -> Result<Vec<String>> {
|
||||
let shortstatehash = self.services.state.get_room_shortstatehash(room_id).await?;
|
||||
|
||||
let state_keys: Vec<String> = self
|
||||
.state_keys(shortstatehash, event_type)
|
||||
.map(|state_key| state_key.to_string())
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
Ok(state_keys)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use conduwuit::{Err, Result, implement, matrix::Event, pdu::PduBuilder};
|
||||
use ruma::{
|
||||
EventId, RoomId, UserId,
|
||||
EventId, Int, RoomId, UserId,
|
||||
events::{
|
||||
StateEventType, TimelineEventType,
|
||||
room::{
|
||||
|
@ -167,3 +167,33 @@ pub async fn user_can_invite(
|
|||
.await
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[implement(super::Service)]
|
||||
pub async fn current_power_levels(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
) -> Result<RoomPowerLevelsEventContent> {
|
||||
// fetches the current power levels event content for a room, returning the
|
||||
// default power levels if no power levels event is found
|
||||
let pl_event_content = self
|
||||
.room_state_get_content::<RoomPowerLevelsEventContent>(
|
||||
room_id,
|
||||
&StateEventType::RoomPowerLevels,
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
if let Ok(pl_event_content) = pl_event_content {
|
||||
Ok(pl_event_content)
|
||||
} else {
|
||||
let mut default_power_levels = RoomPowerLevelsEventContent::default();
|
||||
|
||||
// set the creator as PL100
|
||||
let create_event = self
|
||||
.room_state_get(room_id, &StateEventType::RoomCreate, "")
|
||||
.await?;
|
||||
default_power_levels
|
||||
.users
|
||||
.insert(create_event.sender().to_owned(), Int::from(100));
|
||||
Ok(default_power_levels)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue