Skip to main content

tuwunel_admin/room/
commands.rs

1use futures::{FutureExt, StreamExt};
2use ruma::OwnedRoomId;
3use tuwunel_core::{Err, Result, utils::FutureBoolExt};
4
5use crate::{PAGE_SIZE, admin_command, get_room_info};
6
7#[admin_command]
8pub(super) async fn room_list(
9	&self,
10	page: Option<usize>,
11	exclude_disabled: bool,
12	exclude_banned: bool,
13	no_details: bool,
14) -> Result {
15	// TODO: i know there's a way to do this with clap, but i can't seem to find it
16	let page = page.unwrap_or(1);
17	let mut rooms = self
18		.services
19		.metadata
20		.iter_ids()
21		.filter_map(async |room_id| {
22			(!exclude_disabled || !self.services.metadata.is_disabled(room_id).await)
23				.then_some(room_id)
24		})
25		.filter_map(async |room_id| {
26			(!exclude_banned || !self.services.metadata.is_banned(room_id).await)
27				.then_some(room_id)
28		})
29		.then(|room_id| get_room_info(self.services, room_id))
30		.collect::<Vec<_>>()
31		.await;
32
33	rooms.sort_by_key(|r| r.1);
34	rooms.reverse();
35
36	let rooms = rooms
37		.into_iter()
38		.skip(page.saturating_sub(1).saturating_mul(PAGE_SIZE))
39		.take(PAGE_SIZE)
40		.collect::<Vec<_>>();
41
42	if rooms.is_empty() {
43		return Err!("No more rooms.");
44	}
45
46	let body = rooms
47		.iter()
48		.map(|(id, members, name)| {
49			if no_details {
50				format!("{id}")
51			} else {
52				format!("{id}\tMembers: {members}\tName: {name}")
53			}
54		})
55		.collect::<Vec<_>>()
56		.join("\n");
57
58	self.write_str(&format!("Rooms ({}):\n```\n{body}\n```", rooms.len()))
59		.await
60}
61
62#[admin_command]
63pub(super) async fn room_exists(&self, room_id: OwnedRoomId) -> Result {
64	let result = self.services.metadata.exists(&room_id).await;
65
66	self.write_str(&format!("{result}")).await
67}
68
69#[admin_command]
70pub(super) async fn room_delete(&self, room_id: OwnedRoomId, force: bool) -> Result {
71	if self.services.admin.is_admin_room(&room_id).await {
72		return Err!("Cannot delete admin room");
73	}
74
75	let state_lock = self.services.state.mutex.lock(&room_id).await;
76
77	self.services
78		.delete
79		.delete_room(&room_id, force, state_lock)
80		.await?;
81
82	self.write_str("Successfully deleted the room from our database.")
83		.await?;
84
85	Ok(())
86}
87
88#[admin_command]
89pub(super) async fn room_prune_empty(&self, force: bool) -> Result {
90	let rooms = self
91		.services
92		.metadata
93		.iter_ids()
94		.filter(|room_id| {
95			let has_no_local_users = self
96				.services
97				.state_cache
98				.local_users_in_room(room_id)
99				.boxed()
100				.into_future()
101				.map(|(next, ..)| next.is_none())
102				.boxed();
103
104			let has_no_local_invites = self
105				.services
106				.state_cache
107				.local_users_invited_to_room(room_id)
108				.boxed()
109				.into_future()
110				.map(|(next, ..)| next.is_none())
111				.boxed();
112
113			has_no_local_users.and(has_no_local_invites)
114		})
115		.map(ToOwned::to_owned)
116		.collect::<Vec<_>>()
117		.await;
118
119	for room_id in &rooms {
120		let state_lock = self.services.state.mutex.lock(room_id).await;
121
122		self.services
123			.delete
124			.delete_room(room_id, force, state_lock)
125			.await?;
126	}
127
128	let rooms_len = rooms.len();
129
130	self.write_str(&format!("Successfully deleted {rooms_len} rooms from our database."))
131		.await?;
132
133	Ok(())
134}