diff --git a/src/commands/keys/generate.rs b/src/commands/keys/generate.rs index 9827c95..527f5ee 100644 --- a/src/commands/keys/generate.rs +++ b/src/commands/keys/generate.rs @@ -42,7 +42,9 @@ impl AspmSubcommand for KeysGenerateCommand { .interact() .context("Unable to prompt on stderr")?; - if !confirmation { return Ok(()) } + if !confirmation { + return Ok(()); + } } let alias = if let Some(alias) = &self.key_alias { diff --git a/src/commands/profiles/list.rs b/src/commands/profiles/list.rs new file mode 100644 index 0000000..35c14d7 --- /dev/null +++ b/src/commands/profiles/list.rs @@ -0,0 +1,76 @@ +use anstyle::{AnsiColor, Reset, Style as Anstyle}; +use anyhow::Context; +use clap::Parser; +use indoc::writedoc; +use sea_orm::EntityTrait; + +use std::io::Write; + +use crate::{commands::AspmSubcommand, entities::prelude::*}; + +/// Lists all of the saved profiles, along with their stored data +#[derive(Parser, Debug)] +pub struct ProfilesListCommand {} + +#[async_trait::async_trait] +impl AspmSubcommand for ProfilesListCommand { + async fn execute(&self, state: crate::AspmState) -> Result<(), anyhow::Error> { + // Fetch data + let profiles = Profiles::find() + .find_with_related(Claims) + .all(&state.db) + .await + .context("Unable to query database for profiles")?; + + // Construct styles + let reset = Reset.render(); + let header_style = Anstyle::new() + .bold() + .underline() + .fg_color(Some(anstyle::Color::Ansi(AnsiColor::BrightMagenta))) + .render(); + let alias_style = Anstyle::new() + .underline() + .fg_color(Some(anstyle::Color::Ansi(AnsiColor::BrightCyan))) + .render(); + let key_style = Anstyle::new() + .fg_color(Some(anstyle::Color::Ansi(AnsiColor::BrightGreen))) + .render(); + let value_style = Anstyle::new() + .fg_color(Some(anstyle::Color::Ansi(AnsiColor::BrightYellow))) + .render(); + + // Display nicely + let _ = writedoc!( + std::io::stdout(), + "{header_style}Saved profiles ({n} total):{reset}\n\n", + n = profiles.len(), + ); + for (profile, claims) in profiles { + let _ = writedoc! { + std::io::stdout(), + " + {alias_style}{alias}{reset}: + {key_style}Fingerprint{reset} {value_style}{fingerprint}{reset} + {key_style}Name{reset} {value_style}{name}{reset} + {key_style}Email{reset} {value_style}{email}{reset} + {key_style}Description{reset} {value_style}{description}{reset} + {key_style}Avatar URL{reset} {value_style}{avatar_url}{reset} + {key_style}Color{reset} {value_style}{color}{reset} + {key_style}Claims{reset} + {claims} + ", + alias = profile.alias, + fingerprint = profile.key, + name = profile.name, + description = profile.description.unwrap_or("None".to_string()), + avatar_url = profile.avatar_url.unwrap_or("None".to_string()), + email = profile.email.unwrap_or("None".to_string()), + color = profile.color.unwrap_or("None".to_string()), + claims = claims.into_iter().map(|claim| format!("\t\t- {value_style}{uri}{reset}", uri = claim.uri)).collect::>().join("\n") + }; + } + + Ok(()) + } +} diff --git a/src/commands/profiles/mod.rs b/src/commands/profiles/mod.rs index bfcbf7a..ee2c971 100644 --- a/src/commands/profiles/mod.rs +++ b/src/commands/profiles/mod.rs @@ -2,6 +2,7 @@ use clap::{Parser, Subcommand}; pub mod create; pub mod export; +pub mod list; /// A subcommand to allow the management of keys, which can then be used to create, modify, or delete profiles. #[derive(Parser)] @@ -14,4 +15,5 @@ pub struct ProfilesSubcommand { pub enum ProfilesSubcommands { Create(create::ProfilesCreateCommand), Export(export::ProfilesExportCommand), + List(list::ProfilesListCommand), } diff --git a/src/main.rs b/src/main.rs index 1d4b3fa..a042aaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -159,6 +159,7 @@ fn cli(parsed: AspmCommand) -> Result<(), anyhow::Error> { AspmSubcommands::Profiles(subcommand) => match &subcommand.subcommand { ProfilesSubcommands::Create(subcommand) => subcommand.execute_sync(state, runtime), ProfilesSubcommands::Export(subcommand) => subcommand.execute_sync(state, runtime), + ProfilesSubcommands::List(subcommand) => subcommand.execute_sync(state, runtime), }, } }