From 4d30f027afcc7744571bd7d23cd1d258ac3562a4 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 14:51:31 -0400 Subject: [PATCH 01/13] Added initial code for delete song endpoint --- src/callers/song.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/callers/song.rs b/src/callers/song.rs index 6d8d6e9..8752936 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -173,6 +173,14 @@ pub mod response { pub data: Vec, } } + + pub mod delete_song { + #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] + pub struct Response { + pub message: String, + pub data: Vec + } + } } // TODO: Might make a distinction between year and date in a song's tag at some point @@ -336,6 +344,102 @@ pub mod song_db { Err(_) => Err(sqlx::Error::RowNotFound), } } + + pub async fn delete_song(pool: &sqlx::PgPool, id: &uuid::Uuid) -> Result { + let result = sqlx::query( + // icarus_models::song::Song, + r#" + DELETE FROM "song" + WHERE id = $1 + RETURNING id, title, artist, album_artist, genre, year, disc, track_count, disc_count, duration, audio_type, date_created, filename, directory, user_id + "#, + ) + .bind(id) + .fetch_one(pool) + .await + .map_err(|e| { + eprintln!("Error deleting data: {e:?}") + }); + + match result { + Ok(row) => { + let date_created_time: time::OffsetDateTime = row + .try_get("date_created") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(); + + Ok(icarus_models::song::Song { + id: row + .try_get("id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + title: row + .try_get("title") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + artist: row + .try_get("artist") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + album_artist: row + .try_get("album_artist") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + album: row + .try_get("album") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + genre: row + .try_get("genre") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + year: row + .try_get("year") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + track: row + .try_get("track") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + disc: row + .try_get("disc") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + track_count: row + .try_get("track_count") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + disc_count: row + .try_get("disc_count") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + duration: row + .try_get("duration") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + audio_type: row + .try_get("audio_type") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + filename: row + .try_get("filename") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + directory: row + .try_get("directory") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + date_created: date_created_time.to_string(), + user_id: row + .try_get("user_id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + data: Vec::new(), + }) + } + Err(_) => Err(sqlx::Error::RowNotFound), + } + } } mod song_queue { @@ -1094,4 +1198,38 @@ pub mod endpoint { ), } } + + pub async fn delete_song(axum::Extension(pool): axum::Extension, axum::extract::Path(id): axum::extract::Path) + -> (axum::http::StatusCode, axum::Json) { + let mut response = super::response::delete_song::Response::default(); + + match super::song_db::get_song(&pool, &id).await { + Ok(song) => match song.song_path() { + Ok(song_path) => match super::song_db::delete_song(&pool, &id).await { + Ok(deleted_song) => match std::fs::remove_file(song_path) { + Ok(result) => { + response.data.push(deleted_song); + (axum::http::StatusCode::OK, axum::Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } + } + } } -- 2.47.3 From 89fcb5f4f6f22508ef2c9ecaae9bb95e48d22828 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 16:00:48 -0400 Subject: [PATCH 02/13] Saving changes --- src/callers/coverart.rs | 71 +++++++++++++++++++++++++++++++++++++++++ src/callers/song.rs | 41 ++++++++++++++++-------- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/callers/coverart.rs b/src/callers/coverart.rs index 3818f57..633af52 100644 --- a/src/callers/coverart.rs +++ b/src/callers/coverart.rs @@ -376,6 +376,77 @@ pub mod cov_db { Err(_) => Err(sqlx::Error::RowNotFound), } } + + pub async fn get_coverart_with_song_id( + pool: &sqlx::PgPool, + song_id: &uuid::Uuid, + ) -> Result { + let result = sqlx::query( + r#" + SELECT id, title, path, song_id FROM "coverart" WHERE song_id = $1; + "#, + ) + .bind(song_id) + .fetch_one(pool) + .await + .map_err(|e| { + eprintln!("Error querying data: {e:?}"); + }); + + match result { + Ok(row) => Ok(icarus_models::coverart::CoverArt { + id: row + .try_get("id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + title: row + .try_get("title") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + path: row + .try_get("path") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + data: Vec::new(), + song_id: row + .try_get("song_id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + }), + Err(_) => Err(sqlx::Error::RowNotFound), + } + } + + pub async fn delete_coverart(pool: &sqlx::PgPool, id: &uuid::Uuid) -> Result { + let result = sqlx::query( + r#" + DELETE FROM "coverrt" + WHERE id = $1 + RETURNING id, title, path, song_id + "# + ) + .bind(id) + .fetch_one(pool) + .await + .map_err(|e| { + eprintln!("Error deleting data: {e:?}"); + }); + + match result { + Ok(row) => { + Ok(icarus_models::coverart::CoverArt { + id: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + title: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + path: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + song_id: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + data: Vec::new(), + }) + } + Err(_err) => { + Err(sqlx::Error::RowNotFound) + } + } + } } pub mod endpoint { diff --git a/src/callers/song.rs b/src/callers/song.rs index 8752936..26eb931 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -1204,21 +1204,34 @@ pub mod endpoint { let mut response = super::response::delete_song::Response::default(); match super::song_db::get_song(&pool, &id).await { - Ok(song) => match song.song_path() { - Ok(song_path) => match super::song_db::delete_song(&pool, &id).await { - Ok(deleted_song) => match std::fs::remove_file(song_path) { - Ok(result) => { - response.data.push(deleted_song); - (axum::http::StatusCode::OK, axum::Json(response)) + Ok(song) => match super::super::coverart::cov_db::get_coverart_with_song_id(&pool, &song.id).await { + Ok(coverart) => { + let coverart_path = std::path::Path::new(&coverart.path); + if coverart_path.exists() { + match song.song_path() { + Ok(song_path) => match super::song_db::delete_song(&pool, &song.id).await { + Ok(deleted_song) => match super::super::coverart::cov_db::delete_coverart(&pool, &coverart.id).await { + Ok(deleted_coverart) => { + } + Err(err) => { + } + } + } + + } + Err(err) => { + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } + } + Err(err) => { + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) - } - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } else { + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } Err(err) => { -- 2.47.3 From 016cfab506569ff37e27a1649c0e160c36bd3e7b Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 16:09:17 -0400 Subject: [PATCH 03/13] More changes --- src/callers/song.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/callers/song.rs b/src/callers/song.rs index 26eb931..176f664 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -178,7 +178,7 @@ pub mod response { #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] pub struct Response { pub message: String, - pub data: Vec + pub data: Vec<(icarus_models::song::Song, icarus_models::coverart::CoverArt)> } } } @@ -1211,17 +1211,31 @@ pub mod endpoint { match song.song_path() { Ok(song_path) => match super::song_db::delete_song(&pool, &song.id).await { Ok(deleted_song) => match super::super::coverart::cov_db::delete_coverart(&pool, &coverart.id).await { - Ok(deleted_coverart) => { + Ok(deleted_coverart) => match std::fs::remove_file(song_path) { + Ok(_) => match std::fs::remove_file(&coverart.path) { + Ok(_) => { + response.data.push((deleted_song, deleted_coverart)); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } + Err(err) => { + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } + } + Err(err) => { + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } } - Err(err) => { - } - } - } + Err(err) => { + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } } Err(err) => { - response.message = String::from("Could not locate coverart on the filesystem"); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + response.message = String::from("Could not locate coverart on the filesystem"); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } Err(err) => { -- 2.47.3 From 87907ce5e7ed9f889fcbaa824ef5d891aad73f91 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 16:11:38 -0400 Subject: [PATCH 04/13] Made delete song endpoint available --- src/callers/mod.rs | 1 + src/main.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/callers/mod.rs b/src/callers/mod.rs index 3c6b223..cadc8ac 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -19,6 +19,7 @@ pub mod endpoints { pub const GETSONGS: &str = "/api/v2/song"; pub const STREAMSONG: &str = "/api/v2/song/stream/{id}"; pub const DOWNLOADSONG: &str = "/api/v2/song/download/{id}"; + pub const DELETESONG: &str = "/api/v2/song/{id}"; pub const CREATECOVERART: &str = "/api/v2/coverart"; pub const GETCOVERART: &str = "/api/v2/coverart"; pub const DOWNLOADCOVERART: &str = "/api/v2/coverart/download/{id}"; diff --git a/src/main.rs b/src/main.rs index e1c8186..48447b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ async fn main() { } pub mod init { - use axum::routing::{get, patch, post}; + use axum::routing::{delete, get, patch, post}; use std::time::Duration; use tower_http::timeout::TimeoutLayer; @@ -135,6 +135,7 @@ pub mod init { crate::callers::endpoints::DOWNLOADSONG, get(crate::callers::song::endpoint::download_song), ) + .route(crate::callers::endpoints::DELETESONG, delete(crate::callers::song::endpoint::delete_song)) } pub async fn app() -> axum::Router { -- 2.47.3 From db1db67fee4ef6e47f42108db9f675631077b75d Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:14:29 -0400 Subject: [PATCH 05/13] Response change --- src/callers/song.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/callers/song.rs b/src/callers/song.rs index 176f664..46c4284 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -175,10 +175,16 @@ pub mod response { } pub mod delete_song { + #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] + pub struct SongAndCoverArt { + pub song: icarus_models::song::Song, + pub coverart: icarus_models::coverart::CoverArt + } + #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] pub struct Response { pub message: String, - pub data: Vec<(icarus_models::song::Song, icarus_models::coverart::CoverArt)> + pub data: Vec, } } } @@ -1214,32 +1220,33 @@ pub mod endpoint { Ok(deleted_coverart) => match std::fs::remove_file(song_path) { Ok(_) => match std::fs::remove_file(&coverart.path) { Ok(_) => { - response.data.push((deleted_song, deleted_coverart)); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + response.message = String::from(super::super::response::SUCCESSFUL); + response.data.push(super::response::delete_song::SongAndCoverArt{ song: deleted_song, coverart: deleted_coverart }); + (axum::http::StatusCode::OK, axum::Json(response)) } Err(err) => { - response.message = String::from("Could not locate coverart on the filesystem"); + response.message = err.to_string(); (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } Err(err) => { - response.message = String::from("Could not locate coverart on the filesystem"); + response.message = err.to_string(); (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } Err(err) => { - response.message = String::from("Could not locate coverart on the filesystem"); + response.message = err.to_string(); (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } Err(err) => { - response.message = String::from("Could not locate coverart on the filesystem"); + response.message = err.to_string(); (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } Err(err) => { - response.message = String::from("Could not locate coverart on the filesystem"); + response.message = err.to_string(); (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } } -- 2.47.3 From 936728509801073a0a6e115d944b4215410d7464 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:20:36 -0400 Subject: [PATCH 06/13] Added test function --- src/main.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/main.rs b/src/main.rs index 48447b9..f385cd4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2122,5 +2122,62 @@ mod tests { let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await; } + + #[tokio::test] + async fn test_delete_song() { + let tm_pool = super::db_mgr::get_pool().await.unwrap(); + let db_name = super::db_mgr::generate_db_name().await; + + match super::db_mgr::create_database(&tm_pool, &db_name).await { + Ok(_) => { + println!("Success"); + } + Err(err) => { + assert!(false, "Error: {:?}", err); + } + } + + let pool = super::db_mgr::connect_to_db(&db_name).await.unwrap(); + super::db_mgr::migrations(&pool).await; + + let app = super::init::app(pool).await; + + let id = test_data::song_id().await.unwrap(); + + let uri = + super::format_url_with_value(crate::callers::endpoints::DOWNLOADSONG, &id).await; + + /* + match app + .clone() + .oneshot( + axum::http::Request::builder() + .method(axum::http::Method::GET) + .uri(&uri) + .body(axum::body::Body::empty()) + .unwrap(), + ) + .await + { + Ok(response) => { + let e = response.into_body(); + let mut data = e.into_data_stream(); + while let Some(chunk) = data.next().await { + match chunk { + Ok(_data) => {} + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + } + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + */ + + let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await; + } } } -- 2.47.3 From a452f85c384fd7ee1d99525d3b443eb5a326bd19 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:39:21 -0400 Subject: [PATCH 07/13] Changes to code Fixing errors --- src/callers/coverart.rs | 2 +- src/callers/song.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/callers/coverart.rs b/src/callers/coverart.rs index 633af52..4e7a155 100644 --- a/src/callers/coverart.rs +++ b/src/callers/coverart.rs @@ -420,7 +420,7 @@ pub mod cov_db { pub async fn delete_coverart(pool: &sqlx::PgPool, id: &uuid::Uuid) -> Result { let result = sqlx::query( r#" - DELETE FROM "coverrt" + DELETE FROM "coverart" WHERE id = $1 RETURNING id, title, path, song_id "# diff --git a/src/callers/song.rs b/src/callers/song.rs index 46c4284..ba14736 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -357,7 +357,7 @@ pub mod song_db { r#" DELETE FROM "song" WHERE id = $1 - RETURNING id, title, artist, album_artist, genre, year, disc, track_count, disc_count, duration, audio_type, date_created, filename, directory, user_id + RETURNING id, title, artist, album, album_artist, genre, year, disc, track, track_count, disc_count, duration, audio_type, date_created, filename, directory, user_id "#, ) .bind(id) -- 2.47.3 From a10c92d754e443bce9c763d17d5b91068db65112 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:40:11 -0400 Subject: [PATCH 08/13] How did I miss this? --- src/callers/coverart.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callers/coverart.rs b/src/callers/coverart.rs index 4e7a155..8102cc1 100644 --- a/src/callers/coverart.rs +++ b/src/callers/coverart.rs @@ -436,9 +436,9 @@ pub mod cov_db { Ok(row) => { Ok(icarus_models::coverart::CoverArt { id: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - title: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - path: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - song_id: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + title: row.try_get("title").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + path: row.try_get("path").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), + song_id: row.try_get("song_id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), data: Vec::new(), }) } -- 2.47.3 From 7096172d98d0d45cd880663eb8f266624d0b7ffc Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:41:30 -0400 Subject: [PATCH 09/13] Got the test working --- src/main.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index f385cd4..c5a5cf1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2145,14 +2145,13 @@ mod tests { let id = test_data::song_id().await.unwrap(); let uri = - super::format_url_with_value(crate::callers::endpoints::DOWNLOADSONG, &id).await; + super::format_url_with_value(crate::callers::endpoints::DELETESONG, &id).await; - /* match app .clone() .oneshot( axum::http::Request::builder() - .method(axum::http::Method::GET) + .method(axum::http::Method::DELETE) .uri(&uri) .body(axum::body::Body::empty()) .unwrap(), @@ -2160,8 +2159,13 @@ mod tests { .await { Ok(response) => { - let e = response.into_body(); - let mut data = e.into_data_stream(); + let resp = super::get_resp_data::(response).await; + assert_eq!(false, resp.data.is_empty(), "Response has no data"); + let song_and_coverart = &resp.data[0]; + assert_eq!(id, song_and_coverart.song.id, "Song Ids do not match {id:?} {:?}", song_and_coverart.song.id); + // let e = response.into_body(); + // let mut data = e.into_data_stream(); + /* while let Some(chunk) = data.next().await { match chunk { Ok(_data) => {} @@ -2170,12 +2174,12 @@ mod tests { } } } + */ } Err(err) => { assert!(false, "Error: {err:?}"); } } - */ let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await; } -- 2.47.3 From f00b69f83a229d0855998260f570c78e33428434 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:43:50 -0400 Subject: [PATCH 10/13] Code cleanup and formatting --- src/callers/coverart.rs | 53 +++++++++++------- src/callers/song.rs | 118 ++++++++++++++++++++++++++-------------- src/main.rs | 29 +++++----- 3 files changed, 124 insertions(+), 76 deletions(-) diff --git a/src/callers/coverart.rs b/src/callers/coverart.rs index 8102cc1..a2b2aa0 100644 --- a/src/callers/coverart.rs +++ b/src/callers/coverart.rs @@ -417,34 +417,45 @@ pub mod cov_db { } } - pub async fn delete_coverart(pool: &sqlx::PgPool, id: &uuid::Uuid) -> Result { + pub async fn delete_coverart( + pool: &sqlx::PgPool, + id: &uuid::Uuid, + ) -> Result { let result = sqlx::query( r#" DELETE FROM "coverart" WHERE id = $1 RETURNING id, title, path, song_id - "# - ) - .bind(id) - .fetch_one(pool) - .await - .map_err(|e| { - eprintln!("Error deleting data: {e:?}"); - }); + "#, + ) + .bind(id) + .fetch_one(pool) + .await + .map_err(|e| { + eprintln!("Error deleting data: {e:?}"); + }); match result { - Ok(row) => { - Ok(icarus_models::coverart::CoverArt { - id: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - title: row.try_get("title").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - path: row.try_get("path").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - song_id: row.try_get("song_id").map_err(|_e| sqlx::Error::RowNotFound).unwrap(), - data: Vec::new(), - }) - } - Err(_err) => { - Err(sqlx::Error::RowNotFound) - } + Ok(row) => Ok(icarus_models::coverart::CoverArt { + id: row + .try_get("id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + title: row + .try_get("title") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + path: row + .try_get("path") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + song_id: row + .try_get("song_id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(), + data: Vec::new(), + }), + Err(_err) => Err(sqlx::Error::RowNotFound), } } } diff --git a/src/callers/song.rs b/src/callers/song.rs index ba14736..fcdcfd6 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -178,7 +178,7 @@ pub mod response { #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] pub struct SongAndCoverArt { pub song: icarus_models::song::Song, - pub coverart: icarus_models::coverart::CoverArt + pub coverart: icarus_models::coverart::CoverArt, } #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] @@ -351,7 +351,10 @@ pub mod song_db { } } - pub async fn delete_song(pool: &sqlx::PgPool, id: &uuid::Uuid) -> Result { + pub async fn delete_song( + pool: &sqlx::PgPool, + id: &uuid::Uuid, + ) -> Result { let result = sqlx::query( // icarus_models::song::Song, r#" @@ -1205,59 +1208,94 @@ pub mod endpoint { } } - pub async fn delete_song(axum::Extension(pool): axum::Extension, axum::extract::Path(id): axum::extract::Path) - -> (axum::http::StatusCode, axum::Json) { + pub async fn delete_song( + axum::Extension(pool): axum::Extension, + axum::extract::Path(id): axum::extract::Path, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { let mut response = super::response::delete_song::Response::default(); match super::song_db::get_song(&pool, &id).await { - Ok(song) => match super::super::coverart::cov_db::get_coverart_with_song_id(&pool, &song.id).await { - Ok(coverart) => { - let coverart_path = std::path::Path::new(&coverart.path); - if coverart_path.exists() { - match song.song_path() { - Ok(song_path) => match super::song_db::delete_song(&pool, &song.id).await { - Ok(deleted_song) => match super::super::coverart::cov_db::delete_coverart(&pool, &coverart.id).await { - Ok(deleted_coverart) => match std::fs::remove_file(song_path) { - Ok(_) => match std::fs::remove_file(&coverart.path) { - Ok(_) => { - response.message = String::from(super::super::response::SUCCESSFUL); - response.data.push(super::response::delete_song::SongAndCoverArt{ song: deleted_song, coverart: deleted_coverart }); - (axum::http::StatusCode::OK, axum::Json(response)) - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + Ok(song) => { + match super::super::coverart::cov_db::get_coverart_with_song_id(&pool, &song.id) + .await + { + Ok(coverart) => { + let coverart_path = std::path::Path::new(&coverart.path); + if coverart_path.exists() { + match song.song_path() { + Ok(song_path) => { + match super::song_db::delete_song(&pool, &song.id).await { + Ok(deleted_song) => { + match super::super::coverart::cov_db::delete_coverart( + &pool, + &coverart.id, + ) + .await + { + Ok(deleted_coverart) => { + match std::fs::remove_file(song_path) { + Ok(_) => match std::fs::remove_file( + &coverart.path, + ) { + Ok(_) => { + response.message = String::from(super::super::response::SUCCESSFUL); + response.data.push(super::response::delete_song::SongAndCoverArt{ song: deleted_song, coverart: deleted_coverart }); + ( + axum::http::StatusCode::OK, + axum::Json(response), + ) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } + }, + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } + } + } + + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + } } } Err(err) => { response.message = err.to_string(); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response), + ) } } - - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) - } } Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) + response.message = err.to_string(); + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response), + ) } } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) - } + } else { + response.message = + String::from("Could not locate coverart on the filesystem"); + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response), + ) } - } else { - response.message = String::from("Could not locate coverart on the filesystem"); - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response)) } - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } } } Err(err) => { diff --git a/src/main.rs b/src/main.rs index c5a5cf1..bbdbe0d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,7 +135,10 @@ pub mod init { crate::callers::endpoints::DOWNLOADSONG, get(crate::callers::song::endpoint::download_song), ) - .route(crate::callers::endpoints::DELETESONG, delete(crate::callers::song::endpoint::delete_song)) + .route( + crate::callers::endpoints::DELETESONG, + delete(crate::callers::song::endpoint::delete_song), + ) } pub async fn app() -> axum::Router { @@ -2159,22 +2162,18 @@ mod tests { .await { Ok(response) => { - let resp = super::get_resp_data::(response).await; + let resp = super::get_resp_data::< + crate::callers::song::response::delete_song::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Response has no data"); + let song_and_coverart = &resp.data[0]; - assert_eq!(id, song_and_coverart.song.id, "Song Ids do not match {id:?} {:?}", song_and_coverart.song.id); - // let e = response.into_body(); - // let mut data = e.into_data_stream(); - /* - while let Some(chunk) = data.next().await { - match chunk { - Ok(_data) => {} - Err(err) => { - assert!(false, "Error: {err:?}"); - } - } - } - */ + assert_eq!( + id, song_and_coverart.song.id, + "Song Ids do not match {id:?} {:?}", + song_and_coverart.song.id + ); } Err(err) => { assert!(false, "Error: {err:?}"); -- 2.47.3 From cce98042bfd5e526cab4ecdb6f3f283e86703c2e Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 20:44:38 -0400 Subject: [PATCH 11/13] Version bump --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b76cb8f..623c074 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "icarus" -version = "0.1.98" +version = "0.1.99" dependencies = [ "axum", "common-multipart-rfc7578", diff --git a/Cargo.toml b/Cargo.toml index 1c63dbb..244a60c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "icarus" -version = "0.1.98" +version = "0.1.99" edition = "2024" rust-version = "1.88" -- 2.47.3 From 58e7bdb104703e1633deda0cfbbf25bc4f02583d Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 21:27:22 -0400 Subject: [PATCH 12/13] Code changes --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index bbdbe0d..8e9340f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1839,7 +1839,7 @@ mod tests { let _ = db_mgr::drop_database(&tm_pool, &db_name).await; } - pub mod after_song_queue { + pub mod zzz_after_song_queue { use futures::StreamExt; use tower::ServiceExt; @@ -2127,7 +2127,7 @@ mod tests { } #[tokio::test] - async fn test_delete_song() { + async fn test_last_delete_song() { let tm_pool = super::db_mgr::get_pool().await.unwrap(); let db_name = super::db_mgr::generate_db_name().await; -- 2.47.3 From 507d1b3ef20249909a144e2086a5712a5ca102d9 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 29 Jul 2025 21:30:25 -0400 Subject: [PATCH 13/13] Workflow change --- .github/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 74b4171..d13914b 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -68,7 +68,7 @@ jobs: env: ROOT_DIRECTORY: "/tmp" DATABASE_URL: "postgres://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}" - run: cargo test --verbose + run: cargo test --verbose -- --test-threads=1 - name: Run clippy run: cargo clippy -- -D warnings -- 2.47.3