From a8603361c02c8bc4b3e67f4f041bd50d5d0eb20f Mon Sep 17 00:00:00 2001 From: KD Date: Sat, 26 Jul 2025 14:12:03 -0400 Subject: [PATCH] Get coverart (#163) * Added initial code to get coverart endpoint * Test migration cleanup * Updated icarus_models * Made endpoint evailable * Added test * Version bump * Code formatting --- Cargo.lock | 6 +- Cargo.toml | 4 +- src/callers/coverart.rs | 83 +++++++++++++++++++++++++ src/callers/mod.rs | 1 + src/main.rs | 66 ++++++++++++++++++++ test_migrations/20250725213944_init.sql | 4 -- 6 files changed, 155 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 306c757..be020e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -752,7 +752,7 @@ dependencies = [ [[package]] name = "icarus" -version = "0.1.94" +version = "0.1.95" dependencies = [ "axum", "common-multipart-rfc7578", @@ -793,8 +793,8 @@ dependencies = [ [[package]] name = "icarus_models" -version = "0.4.5" -source = "git+ssh://git@git.kundeng.us/phoenix/icarus_models.git?tag=v0.4.5-devel-655d05dabb-111#655d05dabbdadb9b28940564a1eb82470aa4f166" +version = "0.5.1" +source = "git+ssh://git@git.kundeng.us/phoenix/icarus_models.git?tag=v0.5.1-devel-1c5de9dc26-111#1c5de9dc26099ac5f21e1dc7a1f7d0dbb892b34b" dependencies = [ "rand 0.9.1", "serde", diff --git a/Cargo.toml b/Cargo.toml index 80dff0f..fd0eb73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "icarus" -version = "0.1.94" +version = "0.1.95" edition = "2024" rust-version = "1.88" @@ -18,7 +18,7 @@ uuid = { version = "1.17.0", features = ["v4", "serde"] } sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] } time = { version = "0.3.41", features = ["formatting", "macros", "parsing", "serde"] } icarus_meta = { git = "ssh://git@git.kundeng.us/phoenix/icarus_meta.git", tag = "v0.3.0-devel-f4b71de969-680" } -icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.4.5-devel-655d05dabb-111" } +icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.5.1-devel-1c5de9dc26-111" } icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.3.0-devel-d73fba9899-006" } [dev-dependencies] diff --git a/src/callers/coverart.rs b/src/callers/coverart.rs index 8bbcd49..31f8045 100644 --- a/src/callers/coverart.rs +++ b/src/callers/coverart.rs @@ -45,6 +45,13 @@ pub mod request { pub coverart_queue_id: uuid::Uuid, } } + + pub mod get_coverart { + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Params { + pub id: Option, + } + } } pub mod response { @@ -99,6 +106,14 @@ pub mod response { pub data: Vec, } } + + pub mod get_coverart { + #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] + pub struct Response { + pub message: String, + pub data: Vec, + } + } } pub mod db { @@ -321,6 +336,46 @@ pub mod cov_db { Err(_err) => Err(sqlx::Error::RowNotFound), } } + + pub async fn get_coverart( + pool: &sqlx::PgPool, + id: &uuid::Uuid, + ) -> Result { + let result = sqlx::query( + r#" + SELECT id, title, path, song_id FROM "coverart" WHERE id = $1; + "#, + ) + .bind(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 mod endpoint { @@ -560,4 +615,32 @@ pub mod endpoint { } } } + + pub async fn get_coverart( + axum::Extension(pool): axum::Extension, + axum::extract::Query(params): axum::extract::Query, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::get_coverart::Response::default(); + + match params.id { + Some(id) => match super::cov_db::get_coverart(&pool, &id).await { + Ok(coverart) => { + response.data.push(coverart); + response.message = String::from(super::super::response::SUCCESSFUL); + (axum::http::StatusCode::OK, axum::Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + }, + None => { + response.message = String::from("Invalid parameters"); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } } diff --git a/src/callers/mod.rs b/src/callers/mod.rs index 6e31042..d81789b 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -18,6 +18,7 @@ pub mod endpoints { pub const CREATESONG: &str = "/api/v2/song"; pub const GETSONGS: &str = "/api/v2/song"; pub const CREATECOVERART: &str = "/api/v2/coverart"; + pub const GETCOVERART: &str = "/api/v2/coverart"; } pub mod response { diff --git a/src/main.rs b/src/main.rs index a122e09..4e8798e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -119,6 +119,10 @@ pub mod init { crate::callers::endpoints::GETSONGS, get(crate::callers::song::endpoint::get_songs), ) + .route( + crate::callers::endpoints::GETCOVERART, + get(crate::callers::coverart::endpoint::get_coverart), + ) } pub async fn app() -> axum::Router { @@ -1877,5 +1881,67 @@ mod tests { let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await; } + + #[tokio::test] + async fn test_get_coverart() { + 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 mut id = uuid::Uuid::nil(); + + match uuid::Uuid::parse_str("996122cd-5ae9-4013-9934-60768d3006ed") { + Ok(val) => { + id = val; + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + }; + + let uri = format!("{}?id={id}", crate::callers::endpoints::GETCOVERART); + + match app + .clone() + .oneshot( + axum::http::Request::builder() + .method(axum::http::Method::GET) + .uri(uri) + .header(axum::http::header::CONTENT_TYPE, "application/json") + .body(axum::body::Body::empty()) + .unwrap(), + ) + .await + { + Ok(response) => { + let resp = super::get_resp_data::< + crate::callers::coverart::response::get_coverart::Response, + >(response) + .await; + assert_eq!(false, resp.data.is_empty(), "Should not be empty"); + + let coverart = resp.data[0].clone(); + assert_eq!(id, coverart.id, "Id does not match {coverart:?}"); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + + let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await; + } } } diff --git a/test_migrations/20250725213944_init.sql b/test_migrations/20250725213944_init.sql index 0c78fc4..358829e 100644 --- a/test_migrations/20250725213944_init.sql +++ b/test_migrations/20250725213944_init.sql @@ -56,7 +56,3 @@ CREATE TABLE IF NOT EXISTS "coverart" ( path TEXT NOT NULL, song_id UUID NOT NULL ); - --- Might not to disable constraints on fields --- INSERT INTO "song" (id, title, artist, album_artist, album, genre, year, track, disc, track_count, disc_count, duration, audio_type, date_created, filename, directory, user_id) VALUES('44cf7940-34ff-489f-9124-d0ec90a55af9', 'Hypocrite Like The Rest', 'Kuoth', 'Kuoth', 'I', 'Alternative Hip-Hop', 2020, 1, 1, 9, 1, 139, 'flac', '2020-01-01 13:00:00-05', 'track01.flac', 'tests/I', '47491f9b-725a-4ba4-b9a5-711e1be46670'); --- Re-enable the constraints on the fields