From 84f259d45eba33fc26c43865233a11a9a9eaa384 Mon Sep 17 00:00:00 2001 From: tezlm Date: Wed, 4 Oct 2023 21:33:37 -0700 Subject: [PATCH] List pagination and html tables --- src/service/admin/mod.rs | 73 ++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 5659bc41..887c6a6a 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -37,6 +37,8 @@ use crate::{ use super::pdu::PduBuilder; +const PAGE_SIZE: usize = 100; + #[cfg_attr(test, derive(Debug))] #[derive(Parser)] #[command(name = "@conduit:server.name:", version = env!("CARGO_PKG_VERSION"))] @@ -168,7 +170,9 @@ enum UserCommand { #[derive(Subcommand)] enum RoomCommand { /// List all rooms the server knows about - List, + List { + page: Option, + }, #[command(subcommand)] /// Manage rooms' aliases @@ -231,7 +235,9 @@ enum RoomDirectoryCommand { /// List rooms that are published // TODO: is this really necessary? - List, + List { + page: Option, + }, } #[cfg_attr(test, derive(Debug))] @@ -758,26 +764,46 @@ impl Service { }, } AdminCommand::Room(command) => match command { - RoomCommand::List => { + RoomCommand::List { page } => { + // 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 = services().rooms.metadata.iter_ids() .filter_map(|r| r.ok()) .map(|id| ( id.clone(), - services().rooms.state_accessor.get_name(&id).ok().flatten().unwrap_or(id.to_string()), services().rooms.state_cache.room_joined_count(&id).ok().flatten().unwrap_or(0), + services().rooms.state_accessor.get_name(&id).ok().flatten().unwrap_or(id.to_string()), )) .collect::>(); - rooms.sort_by_key(|r| r.2); + rooms.sort_by_key(|r| r.1); rooms.reverse(); - let output = format!( + + let slice_start = page.saturating_sub(1) * PAGE_SIZE; + let Some(rooms) = rooms.get(slice_start..slice_start + PAGE_SIZE) else { + return Ok(RoomMessageEventContent::text_plain("No more rooms.")); + }; + + let output_plain = format!( "Rooms:\n{}", rooms .iter() - .map(|(id, name, members)| format!("{id}\tName: {name}\tMembers: {members}")) + .map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}")) .collect::>() .join("\n") ); - RoomMessageEventContent::text_plain(output) + let output_html = format!( + "\n\t\t\n{}
Room list - page {page}
idnamemembers
", + rooms + .iter() + .map(|(id, members, name)| format!( + "{}\t{}\t{}\n", + escape_html(&id.to_string()), + members, + escape_html(name), + )) + .collect::() + ); + RoomMessageEventContent::text_html(output_plain, output_html) } // TODO: clean up and deduplicate code RoomCommand::Alias(command) => { @@ -878,26 +904,45 @@ impl Service { Ok(()) => RoomMessageEventContent::text_plain("Room unpublished"), Err(err) => RoomMessageEventContent::text_plain(&format!("Unable to update room: {}", err)), } - RoomDirectoryCommand::List => { + RoomDirectoryCommand::List { page } => { + let page = page.unwrap_or(1); let mut rooms = services().rooms.directory.public_rooms() .filter_map(|r| r.ok()) .map(|id| ( id.clone(), - services().rooms.state_accessor.get_name(&id).ok().flatten().unwrap_or(id.to_string()), services().rooms.state_cache.room_joined_count(&id).ok().flatten().unwrap_or(0), + services().rooms.state_accessor.get_name(&id).ok().flatten().unwrap_or(id.to_string()), )) .collect::>(); - rooms.sort_by_key(|r| r.2); + rooms.sort_by_key(|r| r.1); rooms.reverse(); - let output = format!( + + let slice_start = page.saturating_sub(1) * PAGE_SIZE; + let Some(rooms) = rooms.get(slice_start..slice_start + PAGE_SIZE) else { + return Ok(RoomMessageEventContent::text_plain("No more rooms.")); + }; + + let output_plain = format!( "Rooms:\n{}", rooms .iter() - .map(|(id, name, members)| format!("{id}\tName: {name}\tMembers: {members}")) + .map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}")) .collect::>() .join("\n") ); - RoomMessageEventContent::text_plain(output) + let output_html = format!( + "\n\t\t\n{}
Room directory - page {page}
idnamemembers
", + rooms + .iter() + .map(|(id, members, name)| format!( + "{}\t{}\t{}\n", + escape_html(&id.to_string()), + members, + escape_html(name), + )) + .collect::() + ); + RoomMessageEventContent::text_html(output_plain, output_html) } } }