Skip to main content

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