diff --git a/src/actions/delete_album.rs b/src/actions/delete_album.rs new file mode 100644 index 0000000..638bc12 --- /dev/null +++ b/src/actions/delete_album.rs @@ -0,0 +1,115 @@ +use color_eyre::eyre::Result; +use log::info; + +use crate::{context::Context, models::album::Album}; + +use super::action::Action; + +pub struct DeleteAlbum { + album: Album, +} + +impl Action for DeleteAlbum { + type Input = Album; + type Output = (); + + fn new(input: Self::Input) -> Self { + Self { album: input } + } + + fn describe(&self) -> String { + format!("Deleting album {}", self.album.name,) + } + + async fn execute(&self, ctx: &Context) -> Result { + info!("{}", self.describe()); + + if !ctx.dry_run { + ctx.client.delete_album(&self.album.id).await?; + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::tests::apimock::MockServerExt; + use chrono::{DateTime, Utc}; + use httpmock::MockServer; + use uuid::Uuid; + + use crate::Client; + + use super::*; + + #[test] + fn test_describe() { + let album = Album { + id: Uuid::parse_str("123e4567-e89b-12d3-a456-426655440000").unwrap(), + name: String::from("My christmas holidays"), + assets_count: 473, + updated_at: DateTime::::from_str("2024-11-17T12:55:12Z").unwrap(), + }; + let action = DeleteAlbum::new(album); + + let description = action.describe(); + + assert_eq!(description, "Deleting album My christmas holidays"); + } + + #[tokio::test] + async fn calls_server() { + let id = "123e4567-e89b-12d3-a456-426655440000"; + let server = MockServer::start(); + let mock = server.delete_album(|when, then| { + when.id(&Uuid::from_str(id).unwrap()); + then.ok(); + }); + let client = Client::new(&server.url("")); + let ctx = Context::builder() + .client(client) + .dry_run(false) + .no_confirm(true) + .build(); + + DeleteAlbum::new(Album { + id: Uuid::from_str(id).unwrap(), + name: String::from("My christmas holidays"), + assets_count: 473, + updated_at: DateTime::::from_str("2024-11-17T12:55:12Z").unwrap(), + }) + .execute(&ctx) + .await + .unwrap(); + + mock.assert_async().await; + } + + #[tokio::test] + async fn does_not_call_server_in_dry_run() { + let id = "123e4567-e89b-12d3-a456-426655440000"; + let server = MockServer::start(); + let mock = server.delete_album(|_when, _then| {}); + let client = Client::new(&server.url("")); + let ctx = Context::builder() + .client(client) + .dry_run(true) + .no_confirm(true) + .build(); + + DeleteAlbum::new(Album { + id: Uuid::from_str(id).unwrap(), + name: String::from("My christmas holidays"), + assets_count: 473, + updated_at: DateTime::::from_str("2024-11-17T12:55:12Z").unwrap(), + }) + .execute(&ctx) + .await + .unwrap(); + + mock.assert_hits_async(0).await; + } +} diff --git a/src/actions/mod.rs b/src/actions/mod.rs index 6389237..6ba3fd6 100644 --- a/src/actions/mod.rs +++ b/src/actions/mod.rs @@ -1,5 +1,6 @@ pub mod action; pub mod confirm; +pub mod delete_album; pub mod fetch_album_assets; pub mod fetch_all_albums; pub mod fetch_all_libraries; diff --git a/src/args.rs b/src/args.rs index d070114..3be7512 100644 --- a/src/args.rs +++ b/src/args.rs @@ -78,6 +78,9 @@ pub(crate) enum Commands { #[derive(Serialize, Subcommand)] pub(crate) enum AlbumsCommands { + /// Delete all albums + #[serde(rename = "delete")] + Delete {}, /// List all albums #[serde(rename = "list")] List {}, diff --git a/src/commands/delete_albums.rs b/src/commands/delete_albums.rs new file mode 100644 index 0000000..41a254e --- /dev/null +++ b/src/commands/delete_albums.rs @@ -0,0 +1,29 @@ +use crate::{ + actions::{ + action::Action, + confirm::{Confirm, ConfirmResult}, + delete_album::DeleteAlbum, + fetch_all_albums::FetchAllAlbums, + }, + context::Context, +}; +use color_eyre::eyre::Result; +use log::info; + +pub async fn delete_albums(ctx: Context) -> Result<()> { + let albums = FetchAllAlbums::new(()).execute(&ctx).await?; + + if let ConfirmResult::Positive = Confirm::new(None).execute(&ctx).await? { + for album in &albums { + DeleteAlbum::new(album.clone()).execute(&ctx).await?; + } + + info!( + "Deleted {} albums{}", + albums.len(), + if ctx.dry_run { " (dry run)" } else { "" } + ); + } + + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 039ac33..d65cdbd 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,3 +1,4 @@ +pub mod delete_albums; pub mod delete_assets; pub mod list_albums; pub mod list_assets; diff --git a/src/main.rs b/src/main.rs index 19e4997..145b627 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use args::{AlbumsCommands, AssetsCommands, LibrariesCommands, PeopleCommands, Se use clap::Parser; use color_eyre::eyre::{Result, WrapErr}; use color_eyre::Section; +use commands::delete_albums::delete_albums; use commands::delete_assets::delete_assets; use commands::list_albums::list_albums; use commands::list_assets::list_assets; @@ -78,6 +79,7 @@ async fn main() -> Result<()> { match &args.command { Commands::Albums { albums_command } => match albums_command { + AlbumsCommands::Delete {} => delete_albums(ctx).await, AlbumsCommands::List {} => list_albums(ctx).await, }, Commands::Assets { assets_command } => match assets_command { diff --git a/src/models/album.rs b/src/models/album.rs index fe64982..f48b29d 100644 --- a/src/models/album.rs +++ b/src/models/album.rs @@ -1,4 +1,4 @@ -use chrono::{DateTime, NaiveDate, Utc}; +use chrono::{DateTime, Utc}; use uuid::Uuid; use crate::types::AlbumResponseDto;