use conduwuit::{Err, Result}; use futures::StreamExt; use ruma::OwnedRoomId; use crate::{PAGE_SIZE, admin_command, get_room_info}; #[allow(clippy::fn_params_excessive_bools)] #[admin_command] pub(super) async fn list_rooms( &self, page: Option, exclude_disabled: bool, exclude_banned: bool, include_empty: bool, no_details: bool, ) -> Result { // TODO: i know there's a way to do this with clap, but i can't seem to find it let page = page.unwrap_or(1); let mut rooms = self .services .rooms .metadata .iter_ids() .filter_map(|room_id| async move { (!exclude_disabled || !self.services.rooms.metadata.is_disabled(&room_id).await) .then_some(room_id) }) .filter_map(|room_id| async move { (!exclude_banned || !self.services.rooms.metadata.is_banned(&room_id).await) .then_some(room_id) }) .then(async |room_id| get_room_info(self.services, &room_id).await) .then(|(room_id, total_members, name)| async move { let local_members: Vec<_> = self .services .rooms .state_cache .active_local_users_in_room(&room_id) .collect() .await; let local_members = local_members.len(); (room_id, total_members, local_members, name) }) .filter_map(|(room_id, total_members, local_members, name)| async move { (include_empty || local_members > 0).then_some((room_id, total_members, name)) }) .collect::>() .await; rooms.sort_by_key(|r| r.1); rooms.reverse(); let rooms = rooms .into_iter() .skip(page.saturating_sub(1).saturating_mul(PAGE_SIZE)) .take(PAGE_SIZE) .collect::>(); if rooms.is_empty() { return Err!("No more rooms."); } let body = rooms .iter() .map(|(id, members, name)| { if no_details { format!("{id}") } else { format!("{id}\tMembers: {members}\tName: {name}") } }) .collect::>() .join("\n"); self.write_str(&format!("Rooms ({}):\n```\n{body}\n```", rooms.len())) .await } #[admin_command] pub(super) async fn exists(&self, room_id: OwnedRoomId) -> Result { let result = self.services.rooms.metadata.exists(&room_id).await; self.write_str(&format!("{result}")).await }