diff --git a/src/arguments/delete.rs b/src/arguments/delete.rs new file mode 100644 index 0000000..bcce0d5 --- /dev/null +++ b/src/arguments/delete.rs @@ -0,0 +1,72 @@ +use std::io::{self, Write}; + +use clap::Args; +use color_eyre::eyre::eyre; + +use crate::otp::otp_element::OTPDatabase; + +use super::SubcommandExecutor; + +#[derive(Args)] +pub struct DeleteArgs { + /// Code Index + #[arg(short, long, required_unless_present_any=["issuer", "label"])] + pub index: Option, + + /// Issuer of the first matching code that will be deleted + #[arg(short = 's', long, required_unless_present_any=["index", "label"])] + pub issuer: Option, + + /// Label of the first matching code that will be deleted + #[arg(short, long, required_unless_present_any=["index","issuer"])] + pub label: Option, +} + +impl SubcommandExecutor for DeleteArgs { + fn run_command(self, mut otp_database: OTPDatabase) -> color_eyre::Result { + let index_to_delete = self + .index + .and_then(|i| i.checked_sub(1)) + .or_else(|| get_first_matching_element(&otp_database, &self)) + .ok_or(eyre!("No code has been found using the given arguments"))?; + + let mut output = String::with_capacity(1); + + let element = otp_database.elements_ref().get(index_to_delete).unwrap(); + print!( + "Are you sure you want to delete the {}th code ({}, {}) [Y,N]: ", + index_to_delete + 1, + element.issuer, + element.label + ); + io::stdout().flush()?; + + io::stdin().read_line(&mut output)?; + + if output.trim().eq_ignore_ascii_case("y") { + otp_database.delete_element(index_to_delete); + Ok(otp_database) + } else { + Err(eyre!("Operation interrupt by the user")) + } + } +} + +fn get_first_matching_element( + otp_database: &OTPDatabase, + delete_args: &DeleteArgs, +) -> Option { + otp_database + .elements_ref() + .iter() + .enumerate() + .find(|(_, element)| { + element + .issuer + .contains(delete_args.issuer.as_deref().unwrap_or_default()) + && element + .label + .contains(delete_args.label.as_deref().unwrap_or_default()) + }) + .map(|(index, _)| index) +} diff --git a/src/arguments/mod.rs b/src/arguments/mod.rs index 5755104..1b0edc5 100644 --- a/src/arguments/mod.rs +++ b/src/arguments/mod.rs @@ -2,6 +2,7 @@ use crate::otp::otp_element::OTPDatabase; use crate::{arguments::extract::ExtractArgs, dashboard}; use clap::{Parser, Subcommand}; use color_eyre::eyre::eyre; +use delete::DeleteArgs; use enum_dispatch::enum_dispatch; use self::{ @@ -10,6 +11,7 @@ use self::{ }; mod add; +mod delete; mod edit; mod export; mod extract; @@ -44,6 +46,8 @@ pub enum CotpSubcommands { Edit(EditArgs), /// List codes List(ListArgs), + /// Delete codes + Delete(DeleteArgs), /// Import codes from other apps Import(ImportArgs), /// Export cotp database