Add command to delete albums #27

Merged
kernald merged 1 commit from delete-albums into main 2024-11-24 12:03:56 +11:00
7 changed files with 152 additions and 1 deletions

115
src/actions/delete_album.rs Normal file
View file

@ -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<Self::Output> {
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::<Utc>::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::<Utc>::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::<Utc>::from_str("2024-11-17T12:55:12Z").unwrap(),
})
.execute(&ctx)
.await
.unwrap();
mock.assert_hits_async(0).await;
}
}

View file

@ -1,5 +1,6 @@
pub mod action; pub mod action;
pub mod confirm; pub mod confirm;
pub mod delete_album;
pub mod fetch_album_assets; pub mod fetch_album_assets;
pub mod fetch_all_albums; pub mod fetch_all_albums;
pub mod fetch_all_libraries; pub mod fetch_all_libraries;

View file

@ -78,6 +78,9 @@ pub(crate) enum Commands {
#[derive(Serialize, Subcommand)] #[derive(Serialize, Subcommand)]
pub(crate) enum AlbumsCommands { pub(crate) enum AlbumsCommands {
/// Delete all albums
#[serde(rename = "delete")]
Delete {},
/// List all albums /// List all albums
#[serde(rename = "list")] #[serde(rename = "list")]
List {}, List {},

View file

@ -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(())
}

View file

@ -1,3 +1,4 @@
pub mod delete_albums;
pub mod delete_assets; pub mod delete_assets;
pub mod list_albums; pub mod list_albums;
pub mod list_assets; pub mod list_assets;

View file

@ -13,6 +13,7 @@ use args::{AlbumsCommands, AssetsCommands, LibrariesCommands, PeopleCommands, Se
use clap::Parser; use clap::Parser;
use color_eyre::eyre::{Result, WrapErr}; use color_eyre::eyre::{Result, WrapErr};
use color_eyre::Section; use color_eyre::Section;
use commands::delete_albums::delete_albums;
use commands::delete_assets::delete_assets; use commands::delete_assets::delete_assets;
use commands::list_albums::list_albums; use commands::list_albums::list_albums;
use commands::list_assets::list_assets; use commands::list_assets::list_assets;
@ -78,6 +79,7 @@ async fn main() -> Result<()> {
match &args.command { match &args.command {
Commands::Albums { albums_command } => match albums_command { Commands::Albums { albums_command } => match albums_command {
AlbumsCommands::Delete {} => delete_albums(ctx).await,
AlbumsCommands::List {} => list_albums(ctx).await, AlbumsCommands::List {} => list_albums(ctx).await,
}, },
Commands::Assets { assets_command } => match assets_command { Commands::Assets { assets_command } => match assets_command {

View file

@ -1,4 +1,4 @@
use chrono::{DateTime, NaiveDate, Utc}; use chrono::{DateTime, Utc};
use uuid::Uuid; use uuid::Uuid;
use crate::types::AlbumResponseDto; use crate::types::AlbumResponseDto;