From 21d8d57f72e3fc4571cc2e5dbf418bd6f9e0c1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 20 Feb 2023 18:26:10 +0100 Subject: [PATCH] add create and delete folder commands #54 --- CHANGELOG.md | 6 ++++++ src/domain/folder/args.rs | 16 ++++++++++++++++ src/domain/folder/handlers.rs | 33 +++++++++++++++++++++++++++++++-- src/main.rs | 30 +++++++++++++++++++++++++----- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8afdb04..d32b16c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added `create` and `delete` folder commands [sourcehut#54]. + ### Fixed - Fixed config deserialization issue with `email-hooks` and @@ -670,3 +674,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#356]: https://github.com/soywod/himalaya/issues/356 [#419]: https://github.com/soywod/himalaya/issues/419 [#430]: https://github.com/soywod/himalaya/issues/430 + +[sourcehut#54]: https://todo.sr.ht/~soywod/pimalaya/54 diff --git a/src/domain/folder/args.rs b/src/domain/folder/args.rs index 4ddf949..e55c08f 100644 --- a/src/domain/folder/args.rs +++ b/src/domain/folder/args.rs @@ -11,6 +11,8 @@ use crate::ui::table; const ARG_SOURCE: &str = "source"; const ARG_TARGET: &str = "target"; +const CMD_CREATE: &str = "create"; +const CMD_DELETE: &str = "delete"; const CMD_EXPUNGE: &str = "expunge"; const CMD_FOLDERS: &str = "folders"; const CMD_LIST: &str = "list"; @@ -18,8 +20,10 @@ const CMD_LIST: &str = "list"; /// Represents the folder commands. #[derive(Debug, PartialEq, Eq)] pub enum Cmd { + Create, List(table::args::MaxTableWidth), Expunge, + Delete, } /// Represents the folder command matcher. @@ -28,10 +32,16 @@ pub fn matches(m: &ArgMatches) -> Result> { if let Some(_) = m.subcommand_matches(CMD_EXPUNGE) { info!("expunge folder subcommand matched"); Some(Cmd::Expunge) + } else if let Some(_) = m.subcommand_matches(CMD_CREATE) { + debug!("create folder command matched"); + Some(Cmd::Create) } else if let Some(m) = m.subcommand_matches(CMD_LIST) { debug!("list folders command matched"); let max_table_width = table::args::parse_max_width(m); Some(Cmd::List(max_table_width)) + } else if let Some(_) = m.subcommand_matches(CMD_DELETE) { + debug!("delete folder command matched"); + Some(Cmd::Delete) } else { info!("no folder subcommand matched, falling back to subcommand list"); Some(Cmd::List(None)) @@ -49,9 +59,15 @@ pub fn subcmd() -> Command { .about("Manage folders") .subcommands([ Command::new(CMD_EXPUNGE).about("Delete emails marked for deletion"), + Command::new(CMD_CREATE) + .aliases(["add", "new"]) + .about("Create a new folder"), Command::new(CMD_LIST) .about("List folders") .arg(table::args::max_width()), + Command::new(CMD_DELETE) + .aliases(["remove", "rm"]) + .about("Delete a folder with all its emails"), ]) } diff --git a/src/domain/folder/handlers.rs b/src/domain/folder/handlers.rs index 3fd8e9b..dc7b7f4 100644 --- a/src/domain/folder/handlers.rs +++ b/src/domain/folder/handlers.rs @@ -3,7 +3,9 @@ //! This module gathers all folder actions triggered by the CLI. use anyhow::Result; +use dialoguer::Confirm; use himalaya_lib::{AccountConfig, Backend}; +use std::process; use crate::{ printer::{PrintTableOpts, Printer}, @@ -11,19 +13,19 @@ use crate::{ }; pub fn expunge( - folder: &str, printer: &mut P, backend: &mut B, + folder: &str, ) -> Result<()> { backend.expunge_folder(folder)?; printer.print(format!("Folder {folder} successfully expunged!")) } pub fn list( - max_width: Option, config: &AccountConfig, printer: &mut P, backend: &mut B, + max_width: Option, ) -> Result<()> { let folders: Folders = backend.list_folders()?.into(); printer.print_table( @@ -36,6 +38,33 @@ pub fn list( ) } +pub fn create( + printer: &mut P, + backend: &mut B, + folder: &str, +) -> Result<()> { + backend.add_folder(folder)?; + printer.print("Folder successfully created!") +} + +pub fn delete( + printer: &mut P, + backend: &mut B, + folder: &str, +) -> Result<()> { + if let Some(false) | None = Confirm::new() + .with_prompt(format!("Confirm deletion of folder {folder}?")) + .default(false) + .report(false) + .interact_opt()? + { + process::exit(0); + }; + + backend.delete_folder(folder)?; + printer.print("Folder successfully deleted!") +} + #[cfg(test)] mod tests { use himalaya_lib::{ diff --git a/src/main.rs b/src/main.rs index 797af9b..8b83d47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{anyhow, Context, Result}; use clap::Command; use std::{borrow::Cow, env}; use url::Url; @@ -147,24 +147,44 @@ fn main() -> Result<()> { // checks folder commands match folder::args::matches(&m)? { - Some(folder::args::Cmd::Expunge) => { - let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?; + Some(folder::args::Cmd::Create) => { + let folder = folder + .ok_or_else(|| anyhow!("the folder argument is missing")) + .context("cannot create folder")?; + let folder = account_config.folder_alias(folder)?; let mut backend = BackendBuilder::new() .disable_cache(disable_cache) .build(&account_config, &backend_config)?; - return folder::handlers::expunge(&folder, &mut printer, backend.as_mut()); + return folder::handlers::create(&mut printer, backend.as_mut(), &folder); } Some(folder::args::Cmd::List(max_width)) => { let mut backend = BackendBuilder::new() .disable_cache(disable_cache) .build(&account_config, &backend_config)?; return folder::handlers::list( - max_width, &account_config, &mut printer, backend.as_mut(), + max_width, ); } + Some(folder::args::Cmd::Expunge) => { + let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?; + let mut backend = BackendBuilder::new() + .disable_cache(disable_cache) + .build(&account_config, &backend_config)?; + return folder::handlers::expunge(&mut printer, backend.as_mut(), &folder); + } + Some(folder::args::Cmd::Delete) => { + let folder = folder + .ok_or_else(|| anyhow!("the folder argument is missing")) + .context("cannot delete folder")?; + let folder = account_config.folder_alias(folder)?; + let mut backend = BackendBuilder::new() + .disable_cache(disable_cache) + .build(&account_config, &backend_config)?; + return folder::handlers::delete(&mut printer, backend.as_mut(), &folder); + } _ => (), }