Skip to main content

tuwunel_api/client/admin/rooms/
hierarchy.rs

1use std::str::FromStr;
2
3use axum::extract::State;
4use ruma::{UInt, room::RoomSummary, serde::Raw};
5use synapse_admin_api::rooms::admin_hierarchy::v1::{Request, Response};
6use tuwunel_core::Result;
7use tuwunel_service::rooms::spaces::PaginationToken;
8
9use crate::{
10	Ruma,
11	client::{
12		admin::require_admin,
13		space::{HierarchyArgs, get_client_hierarchy},
14	},
15};
16
17/// # `GET /_synapse/admin/v1/rooms/{room_id}/hierarchy`
18///
19/// Walks a space tree with admin privilege: never federates (remote children
20/// surface as holes) and skips the per-user room-visibility check.
21pub(crate) async fn admin_room_hierarchy_route(
22	State(services): State<crate::State>,
23	body: Ruma<Request>,
24) -> Result<Response> {
25	require_admin(&services, body.sender_user()).await?;
26
27	let limit = body
28		.limit
29		.unwrap_or_else(|| UInt::from(50_u32))
30		.min(UInt::from(50_u32));
31
32	let max_depth = body
33		.max_depth
34		.and_then(|max_depth| max_depth.try_into().ok())
35		.unwrap_or(usize::MAX);
36
37	let skip_room_ids = body
38		.from
39		.as_deref()
40		.and_then(|from| PaginationToken::from_str(from).ok())
41		.map(|token| token.short_room_ids)
42		.unwrap_or_default();
43
44	let response = get_client_hierarchy(&services, HierarchyArgs {
45		sender_user: body.sender_user(),
46		room_id: &body.room_id,
47		limit: limit.try_into().unwrap_or(50),
48		max_depth,
49		suggested_only: false,
50		skip_room_ids: &skip_room_ids,
51		bypass_visibility: true,
52	})
53	.await?;
54
55	let rooms: Vec<Raw<RoomSummary>> = response
56		.rooms
57		.iter()
58		.filter_map(|chunk| Raw::new(chunk).ok().map(Raw::cast_unchecked))
59		.collect();
60
61	Ok(Response { rooms, next_batch: response.next_batch })
62}