tuwunel_admin/room/
commands.rs1use 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 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}