From 561cc3fb42df3c4a49063935469f15076cc7c73c Mon Sep 17 00:00:00 2001 From: Ty Date: Thu, 29 Feb 2024 22:03:35 -0700 Subject: [PATCH] Add profiles delete command --- src/commands/profiles/delete.rs | 112 ++++++++++++++++++++++++++++++++ src/commands/profiles/mod.rs | 2 + src/main.rs | 1 + 3 files changed, 115 insertions(+) create mode 100644 src/commands/profiles/delete.rs diff --git a/src/commands/profiles/delete.rs b/src/commands/profiles/delete.rs new file mode 100644 index 0000000..9b31600 --- /dev/null +++ b/src/commands/profiles/delete.rs @@ -0,0 +1,112 @@ +use anstyle::{AnsiColor, Reset, Style as Anstyle}; +use anyhow::Context; +use clap::Parser; +use dialoguer::{theme::ColorfulTheme, Confirm, Select}; +use indoc::writedoc; +use sea_orm::{EntityTrait, ModelTrait}; + +use std::io::Write; + +use crate::{commands::AspmSubcommand, entities::prelude::*}; + +/// Deletes a saved profile +#[derive(Parser, Debug)] +pub struct ProfilesDeleteCommand { + /// Will disable any confirmation prompts. This is not recommended unless you knowingly give a full fingerprint, as it is easy to accidentally (and permanently) delete wrong keys otherwise. + #[arg(long)] + no_confirm: bool, + /// The profile to edit. If not provided, it will be queried for interactively. + profile: Option, +} + +#[async_trait::async_trait] +impl AspmSubcommand for ProfilesDeleteCommand { + async fn execute(&self, state: crate::AspmState) -> Result<(), anyhow::Error> { + let profile = match &self.profile { + Some(key) => Profiles::find_by_id(key) + .one(&state.db) + .await + .context("Unable to query database for profile")? + .context("No profile found for the specified key")?, + None => { + let mut profiles = Profiles::find() + .all(&state.db) + .await + .context("Unable to query database for profiles")?; + let choice = Select::with_theme(&ColorfulTheme::default()) + .with_prompt("Please select the profile to delete") + .items( + profiles + .iter() + .map(|profile| &profile.key) + .collect::>() + .as_slice(), + ) + .default(0) + .interact() + .context("Unable to prompt on stderr")?; + + profiles.swap_remove(choice) + } + }; + let claims = profile + .find_related(Claims) + .all(&state.db) + .await + .context("Unable to fetch claims from database")?; + + if !self.no_confirm { + // Construct styles + let reset = Reset.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(); + 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.clone(), + fingerprint = profile.key.clone(), + name = profile.name.clone(), + description = profile.description.clone().unwrap_or("None".to_string()), + avatar_url = profile.avatar_url.clone().unwrap_or("None".to_string()), + email = profile.email.clone().unwrap_or("None".to_string()), + color = profile.color.clone().unwrap_or("None".to_string()), + claims = claims.into_iter().map(|claim| format!("\t\t- {value_style}{uri}{reset}", uri = claim.uri)).collect::>().join("\n") + }; + + let confirmation = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Are you sure you want to delete this profile?") + .interact() + .context("Unable to prompt on stderr")?; + + if !confirmation { + std::process::exit(1); + } + } + + profile.delete(&state.db) + .await + .context("Unable to delete profile and claims from database")?; + + println!("Successfully deleted profile"); + + Ok(()) + } +} diff --git a/src/commands/profiles/mod.rs b/src/commands/profiles/mod.rs index f0d21d4..8cf8ca5 100644 --- a/src/commands/profiles/mod.rs +++ b/src/commands/profiles/mod.rs @@ -4,6 +4,7 @@ pub mod create; pub mod edit; pub mod export; pub mod list; +pub mod delete; /// A subcommand to allow the management of keys, which can then be used to create, modify, or delete profiles. #[derive(Parser)] @@ -18,4 +19,5 @@ pub enum ProfilesSubcommands { Export(export::ProfilesExportCommand), List(list::ProfilesListCommand), Edit(edit::ProfilesEditCommand), + Delete(delete::ProfilesDeleteCommand), } diff --git a/src/main.rs b/src/main.rs index ade5088..5922489 100644 --- a/src/main.rs +++ b/src/main.rs @@ -161,6 +161,7 @@ fn cli(parsed: AspmCommand) -> Result<(), anyhow::Error> { ProfilesSubcommands::Export(subcommand) => subcommand.execute_sync(state, runtime), ProfilesSubcommands::List(subcommand) => subcommand.execute_sync(state, runtime), ProfilesSubcommands::Edit(subcommand) => subcommand.execute_sync(state, runtime), + ProfilesSubcommands::Delete(subcommand) => subcommand.execute_sync(state, runtime), }, } }