Skip to main content

tuwunel_api/client/admin/rooms/
delete_status.rs

1use axum::extract::State;
2use ruma::RoomId;
3use synapse_admin_api::rooms::delete_status::{
4	by_delete_id::{
5		DeleteStatus, DeleteStatusKind, Request as ByDeleteIdRequest,
6		Response as ByDeleteIdResponse,
7	},
8	by_room_id::{Request as ByRoomIdRequest, Response as ByRoomIdResponse},
9};
10use tuwunel_core::{Err, Result, err};
11use tuwunel_service::tasks::{Status, TaskInfo};
12
13use crate::{Ruma, client::admin::require_admin};
14
15/// # `GET /_synapse/admin/v2/rooms/delete_status/{delete_id}`
16///
17/// Reports the stage of an asynchronous room deletion by its task id, including
18/// the shutdown outcome once the task has finished.
19pub(crate) async fn admin_delete_status_by_id_route(
20	State(services): State<crate::State>,
21	body: Ruma<ByDeleteIdRequest>,
22) -> Result<ByDeleteIdResponse> {
23	require_admin(&services, body.sender_user()).await?;
24
25	let task = services
26		.tasks
27		.get(&body.delete_id)
28		.filter(|task| task.action == super::DELETE_ROOM_ACTION)
29		.ok_or_else(|| err!(Request(NotFound("Unknown delete task"))))?;
30
31	Ok(ByDeleteIdResponse { status: delete_status(task)? })
32}
33
34/// # `GET /_synapse/admin/v2/rooms/{room_id}/delete_status`
35///
36/// Lists the room's deletion tasks. Tasks still scheduled are omitted, matching
37/// Synapse, so a just-queued deletion is visible only by its delete id.
38pub(crate) async fn admin_delete_status_by_room_route(
39	State(services): State<crate::State>,
40	body: Ruma<ByRoomIdRequest>,
41) -> Result<ByRoomIdResponse> {
42	require_admin(&services, body.sender_user()).await?;
43
44	let results = services
45		.tasks
46		.by_resource(body.room_id.as_str())
47		.into_iter()
48		.filter(|task| {
49			task.action == super::DELETE_ROOM_ACTION && task.status != Status::Scheduled
50		})
51		.map(delete_status)
52		.collect::<Result<Vec<_>>>()?;
53
54	if results.is_empty() {
55		return Err!(Request(NotFound("No delete task for this room found")));
56	}
57
58	Ok(ByRoomIdResponse { results })
59}
60
61fn delete_status(task: TaskInfo) -> Result<DeleteStatus> {
62	let room_id = RoomId::parse(&task.resource_id)
63		.map_err(|_| err!(Request(NotFound("Delete task has an invalid room id"))))?;
64
65	let shutdown_room = task
66		.result
67		.and_then(|result| serde_json::from_value(result).ok());
68
69	Ok(DeleteStatus {
70		delete_id: task.id.to_string(),
71		room_id,
72		status: delete_status_kind(task.status),
73		shutdown_room,
74	})
75}
76
77fn delete_status_kind(status: Status) -> DeleteStatusKind {
78	match status {
79		| Status::Scheduled => DeleteStatusKind::Scheduled,
80		| Status::Active => DeleteStatusKind::Active,
81		| Status::Complete => DeleteStatusKind::Complete,
82		| Status::Failed => DeleteStatusKind::Failed,
83	}
84}
85
86#[cfg(test)]
87mod tests {
88	use serde_json::json;
89	use tuwunel_service::tasks::Status;
90
91	use super::delete_status_kind;
92
93	#[test]
94	fn maps_each_stage_and_keeps_scheduled_distinct() {
95		let kind = |status| serde_json::to_value(delete_status_kind(status)).unwrap();
96
97		assert_eq!(kind(Status::Scheduled), json!("scheduled"));
98		assert_eq!(kind(Status::Active), json!("active"));
99		assert_eq!(kind(Status::Complete), json!("complete"));
100		assert_eq!(kind(Status::Failed), json!("failed"));
101	}
102}