From 56bc614db670f07711298f1d9f490eb02934c660 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Sun, 26 Oct 2025 16:43:01 -0400 Subject: [PATCH 1/6] tsk-218: Added empty file --- src/callers/queue/song.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/callers/queue/song.rs diff --git a/src/callers/queue/song.rs b/src/callers/queue/song.rs new file mode 100644 index 0000000..e69de29 -- 2.47.3 From 04dd4f89e41be288d5a04d3f7a749f9f5ad4f642 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Sun, 26 Oct 2025 17:19:33 -0400 Subject: [PATCH 2/6] tsk-218: Created song module in queue module --- src/callers/mod.rs | 10 - src/callers/queue/coverart.rs | 10 +- src/callers/queue/mod.rs | 14 ++ src/callers/queue/song.rs | 449 ++++++++++++++++++++++++++++++++++ src/callers/song.rs | 434 +------------------------------- src/main.rs | 51 ++-- 6 files changed, 497 insertions(+), 471 deletions(-) diff --git a/src/callers/mod.rs b/src/callers/mod.rs index df3666c..217840b 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -4,17 +4,7 @@ pub mod queue; pub mod song; pub mod endpoints { - pub const QUEUESONG: &str = "/api/v2/song/queue"; - pub const QUEUESONGLINKUSERID: &str = "/api/v2/song/queue/link"; - pub const QUEUESONGDATA: &str = "/api/v2/song/queue/{id}"; - pub const QUEUESONGUPDATE: &str = "/api/v2/song/queue/{id}"; - pub const NEXTQUEUESONG: &str = "/api/v2/song/queue/next"; pub const QUEUEMETADATA: &str = "/api/v2/song/metadata/queue"; - pub const QUEUECOVERART: &str = "/api/v2/coverart/queue"; - pub const QUEUECOVERARTDATA: &str = "/api/v2/coverart/queue/data/{id}"; - pub const QUEUECOVERARTLINK: &str = "/api/v2/coverart/queue/link"; - pub const QUEUESONGDATAWIPE: &str = "/api/v2/song/queue/data/wipe"; - pub const QUEUECOVERARTDATAWIPE: &str = "/api/v2/coverart/queue/data/wipe"; pub const CREATESONG: &str = "/api/v2/song"; pub const GETSONGS: &str = "/api/v2/song"; diff --git a/src/callers/queue/coverart.rs b/src/callers/queue/coverart.rs index 16ed258..22bf99b 100644 --- a/src/callers/queue/coverart.rs +++ b/src/callers/queue/coverart.rs @@ -125,7 +125,7 @@ pub mod endpoint { /// Endpoint to queue cover art #[utoipa::path( post, - path = super::super::super::endpoints::QUEUECOVERART, + path = super::super::endpoints::QUEUECOVERART, request_body( content = super::request::queue::Request, ), @@ -203,7 +203,7 @@ pub mod endpoint { /// Endpoint to link queued cover art #[utoipa::path( post, - path = super::super::super::endpoints::QUEUECOVERARTLINK, + path = super::super::endpoints::QUEUECOVERARTLINK, request_body( content = super::request::link::Request, description = "Linking queued cover art to queued song", @@ -244,7 +244,7 @@ pub mod endpoint { /// Endpoint to fetch cover art details #[utoipa::path( get, - path = super::super::super::endpoints::QUEUECOVERART, + path = super::super::endpoints::QUEUECOVERART, params( ("id" = uuid::Uuid, Path, description = "Queued cover art Id"), ("song_queue_id" = uuid::Uuid, Path, description = "Queued song Id") @@ -305,7 +305,7 @@ pub mod endpoint { /// Endpoint to fetch the queued cover art data #[utoipa::path( get, - path = super::super::super::endpoints::QUEUECOVERARTDATA, + path = super::super::endpoints::QUEUECOVERARTDATA, params(("id" = uuid::Uuid, Path, description = "Queued cover art Id")), responses( (status = 200, description = "Queued cover art data", body = Vec), @@ -343,7 +343,7 @@ pub mod endpoint { /// Endpoint to wipe data from the cover art queue #[utoipa::path( patch, - path = super::super::super::endpoints::QUEUECOVERARTDATAWIPE, + path = super::super::endpoints::QUEUECOVERARTDATAWIPE, request_body( content = super::request::wipe_data_from_coverart_queue::Request, description = "Data required to wipe the data from the cover art queue", diff --git a/src/callers/queue/mod.rs b/src/callers/queue/mod.rs index 165fc86..b47a5ca 100644 --- a/src/callers/queue/mod.rs +++ b/src/callers/queue/mod.rs @@ -1 +1,15 @@ pub mod coverart; +pub mod song; + +pub mod endpoints { + pub const QUEUESONG: &str = "/api/v2/song/queue"; + pub const QUEUESONGLINKUSERID: &str = "/api/v2/song/queue/link"; + pub const QUEUESONGDATA: &str = "/api/v2/song/queue/{id}"; + pub const QUEUESONGUPDATE: &str = "/api/v2/song/queue/{id}"; + pub const NEXTQUEUESONG: &str = "/api/v2/song/queue/next"; + pub const QUEUECOVERART: &str = "/api/v2/coverart/queue"; + pub const QUEUECOVERARTDATA: &str = "/api/v2/coverart/queue/data/{id}"; + pub const QUEUECOVERARTLINK: &str = "/api/v2/coverart/queue/link"; + pub const QUEUESONGDATAWIPE: &str = "/api/v2/song/queue/data/wipe"; + pub const QUEUECOVERARTDATAWIPE: &str = "/api/v2/coverart/queue/data/wipe"; +} diff --git a/src/callers/queue/song.rs b/src/callers/queue/song.rs index e69de29..d02df3c 100644 --- a/src/callers/queue/song.rs +++ b/src/callers/queue/song.rs @@ -0,0 +1,449 @@ +pub mod request { + + pub mod song_queue { + #[derive(utoipa::ToSchema)] + pub struct SongQueueRequest { + /// Filename + pub file: String, + #[schema(rename = "type")] + /// File type. Should be a file and not a value + pub file_type: String, + /// Raw data of the flac file + pub value: Vec, + } + } + + pub mod update_status { + #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Request { + pub id: uuid::Uuid, + pub status: String, + } + } + + pub mod wipe_data_from_song_queue { + #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Request { + pub song_queue_id: uuid::Uuid, + } + } + + pub mod link_user_id { + #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Request { + pub song_queue_id: uuid::Uuid, + pub user_id: uuid::Uuid, + } + } +} + + +pub mod response { + + pub mod song_queue { + /// Song queue response + #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + /// Id of the queued song + pub data: Vec, + } + } + + pub mod fetch_queue_song { + use serde::{Deserialize, Serialize}; + + #[derive(Default, Deserialize, Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + pub data: Vec, + } + } + + pub mod update_status { + #[derive(serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct ChangedStatus { + pub old_status: String, + pub new_status: String, + } + + #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + pub data: Vec, + } + } + + pub mod update_song_queue { + #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + pub data: Vec, + } + } + + pub mod wipe_data_from_song_queue { + #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + pub data: Vec, + } + } + + pub mod link_user_id { + #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + pub data: Vec, + } + } +} + + +pub mod endpoint { + use axum::response::IntoResponse; + + use crate::repo::queue as repo; + + /// Endpoint to queue a song. Starts the process and places the song in a queue + #[utoipa::path( + post, + path = super::super::endpoints::QUEUESONG, + request_body( + content = super::request::song_queue::SongQueueRequest, + description = "Multipart form data for uploading song", + content_type = "multipart/form-data" + ), + responses( + (status = 200, description = "Song queued", body = super::response::song_queue::Response) + ) + )] + pub async fn queue_song( + axum::Extension(pool): axum::Extension, + mut multipart: axum::extract::Multipart, + ) -> (axum::http::StatusCode, axum::Json) { + let mut results: Vec = Vec::new(); + let mut response = super::response::song_queue::Response::default(); + + while let Some(field) = multipart.next_field().await.unwrap() { + let name = field.name().unwrap().to_string(); + let file_name = field.file_name().unwrap().to_string(); + let content_type = field.content_type().unwrap().to_string(); + let data = field.bytes().await.unwrap(); + + println!( + "Received file '{}' (name = '{}', content-type = '{}', size = {})", + file_name, + name, + content_type, + data.len() + ); + + let raw_data: Vec = data.to_vec(); + let queue_repo = repo::song::insert( + &pool, + &raw_data, + &file_name, + &crate::repo::queue::song::status::PENDING.to_string(), + ) + .await + .unwrap(); + results.push(queue_repo); + } + + response.data = results; + response.message = if response.data.is_empty() { + String::from("Error") + } else { + String::from("Success") + }; + + (axum::http::StatusCode::OK, axum::Json(response)) + } + + /// Endpoint to link a user id to a queued song + #[utoipa::path( + patch, + path = super::super::endpoints::QUEUESONGLINKUSERID, + request_body( + content = super::request::link_user_id::Request, + description = "User Id and queued song id", + content_type = "application/json" + ), + responses( + (status = 200, description = "Queued song linked", body = super::response::link_user_id::Response), + (status = 400, description = "Linkage failed", body = super::response::link_user_id::Response) + ) + )] + pub async fn link_user_id( + axum::Extension(pool): axum::Extension, + axum::Json(payload): axum::Json, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::link_user_id::Response::default(); + + match repo::song::get_song_queue(&pool, &payload.song_queue_id).await { + Ok(song_queue) => { + match repo::song::link_user_id(&pool, &song_queue.id, &payload.user_id).await + { + Ok(user_id) => { + response.message = String::from(crate::callers::response::SUCCESSFUL); + response.data.push(user_id); + (axum::http::StatusCode::OK, axum::Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } + + /// Endpoint to fetch the next queued song as long as it is available + #[utoipa::path( + get, + path = super::super::endpoints::NEXTQUEUESONG, + responses( + (status = 200, description = "Queued song is present and available", body = super::response::fetch_queue_song::Response), + (status = 400, description = "Linkage failed", body = super::response::fetch_queue_song::Response) + ) + )] + pub async fn fetch_queue_song( + axum::Extension(pool): axum::Extension, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::fetch_queue_song::Response::default(); + + match repo::song::get_most_recent_and_update(&pool).await { + Ok(item) => { + response.message = String::from("Successful"); + response.data.push(item); + (axum::http::StatusCode::OK, axum::Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } + + // TODO: Rename + /// Endpoint to download the queued song + #[utoipa::path( + get, + path = super::super::endpoints::QUEUESONGDATA, + params(("id" = uuid::Uuid, Path, description = "Queued song Id")), + responses( + (status = 200, description = "Queued song linked", body = Vec), + (status = 400, description = "Linkage failed", body = Vec) + ) + )] + pub async fn download_queued_song( + axum::Extension(pool): axum::Extension, + axum::extract::Path(id): axum::extract::Path, + ) -> (axum::http::StatusCode, axum::response::Response) { + println!("Id: {id}"); + + match repo::song::get_data(&pool, &id).await { + Ok(data) => { + let by = axum::body::Bytes::from(data); + let mut response = by.into_response(); + let headers = response.headers_mut(); + headers.insert( + axum::http::header::CONTENT_TYPE, + "audio/flac".parse().unwrap(), + ); + headers.insert( + axum::http::header::CONTENT_DISPOSITION, + format!("attachment; filename=\"{id}.flac\"") + .parse() + .unwrap(), + ); + + (axum::http::StatusCode::OK, response) + } + Err(_err) => (axum::http::StatusCode::BAD_REQUEST, axum::response::Response::default()), + } + } + + /// Endpoint to update the status of a queued song + #[utoipa::path( + patch, + path = super::super::endpoints::QUEUESONG, + request_body( + content = super::request::update_status::Request, + description = "Update the status of a queued song", + content_type = "application/json" + ), + responses( + (status = 200, description = "Status has been updated", body = super::response::update_status::Response), + (status = 400, description = "Error updating status of queued song", body = super::response::update_status::Response) + ) + )] + pub async fn update_song_queue_status( + axum::Extension(pool): axum::Extension, + axum::Json(payload): axum::Json, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::update_status::Response::default(); + + if repo::song::status::is_valid(&payload.status).await { + let id = payload.id; + if !id.is_nil() { + match repo::song::get_status_of_song_queue(&pool, &id).await { + Ok(old) => { + match repo::song::update_song_queue_status( + &pool, + &payload.status, + &id, + ) + .await + { + Ok(new) => { + response.message = String::from("Successful"); + response + .data + .push(super::response::update_status::ChangedStatus { + old_status: old, + new_status: new, + }); + (axum::http::StatusCode::OK, axum::Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } else { + response.message = String::from("Id is nil"); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } else { + response.message = String::from("Status not valid"); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + + /// Endpoint to update the queued song data + #[utoipa::path( + patch, + path = super::super::endpoints::QUEUESONGUPDATE, + request_body( + content = super::request::song_queue::SongQueueRequest, + description = "Multipart form data for uploading song", + content_type = "multipart/form-data" + ), + params(("id" = uuid::Uuid, Path, description = "Queued song Id")), + responses( + (status = 200, description = "Queued song updated", body = super::response::update_song_queue::Response), + (status = 400, description = "Error updating queued song", body = super::response::update_song_queue::Response), + (status = 404, description = "Queued song not found", body = super::response::update_song_queue::Response) + ) + )] + pub async fn update_song_queue( + axum::extract::Path(id): axum::extract::Path, + axum::Extension(pool): axum::Extension, + mut multipart: axum::extract::Multipart, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::update_song_queue::Response::default(); + + if let Some(field) = multipart.next_field().await.unwrap() { + let name = field.name().unwrap().to_string(); + let file_name = field.file_name().unwrap().to_string(); + let content_type = match field.content_type() { + Some(ct) => ct.to_string(), + None => String::new(), + }; + + let data = field.bytes().await.unwrap(); + + println!( + "Received file '{}' (name = '{}', content-type = '{}', size = {})", + file_name, + name, + content_type, + data.len() + ); + + let raw_data: Vec = data.to_vec(); + match repo::song::update(&pool, &raw_data, &id).await { + Ok(_) => { + response.message = String::from("Successful"); + response.data.push(id); + (axum::http::StatusCode::OK, axum::Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } + } else { + response.message = String::from("No data provided"); + (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) + } + } + + /// Endpoint to wipe the data from a queued song + #[utoipa::path( + patch, + path = super::super::endpoints::QUEUESONGDATAWIPE, + request_body( + content = super::request::wipe_data_from_song_queue::Request, + description = "Pass the queued song Id to wipe the data", + content_type = "application/json" + ), + responses( + (status = 200, description = "Queued song data wiped", body = super::response::wipe_data_from_song_queue::Response), + (status = 404, description = "Queued song cannot be found", body = super::response::wipe_data_from_song_queue::Response) + ) + )] + pub async fn wipe_data_from_song_queue( + axum::Extension(pool): axum::Extension, + axum::Json(payload): axum::Json, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::wipe_data_from_song_queue::Response::default(); + let id = payload.song_queue_id; + + match repo::song::get_song_queue(&pool, &id).await { + Ok(song_queue) => match repo::song::wipe_data(&pool, &song_queue.id).await { + Ok(wiped_id) => { + response.message = String::from("Success"); + response.data.push(wiped_id); + + (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)) + } + } + } +} diff --git a/src/callers/song.rs b/src/callers/song.rs index 47c6389..ba740cc 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -1,32 +1,13 @@ -// TODO: Separate queue and song endpoints pub mod request { use serde::{Deserialize, Serialize}; + // TODO: Might not be used #[derive(Default, Deserialize, Serialize)] pub struct Request { pub message: String, } - pub mod song_queue { - #[derive(utoipa::ToSchema)] - pub struct SongQueueRequest { - /// Filename - pub file: String, - #[schema(rename = "type")] - /// File type. Should be a file and not a value - pub file_type: String, - /// Raw data of the flac file - pub value: Vec, - } - } - pub mod update_status { - #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Request { - pub id: uuid::Uuid, - pub status: String, - } - } pub mod create_metadata { #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] @@ -87,20 +68,6 @@ pub mod request { } } - pub mod wipe_data_from_song_queue { - #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Request { - pub song_queue_id: uuid::Uuid, - } - } - - pub mod link_user_id { - #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Request { - pub song_queue_id: uuid::Uuid, - pub user_id: uuid::Uuid, - } - } pub mod get_songs { #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] @@ -111,48 +78,6 @@ pub mod request { } pub mod response { - use serde::{Deserialize, Serialize}; - - /// Song queue response - #[derive(Default, Deserialize, Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - /// Id of the queued song - pub data: Vec, - } - - pub mod fetch_queue_song { - use serde::{Deserialize, Serialize}; - - #[derive(Default, Deserialize, Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - pub data: Vec, - } - } - - pub mod update_status { - #[derive(serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct ChangedStatus { - pub old_status: String, - pub new_status: String, - } - - #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - pub data: Vec, - } - } - - pub mod update_song_queue { - #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - pub data: Vec, - } - } - pub mod create_metadata { #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] pub struct Response { @@ -161,21 +86,6 @@ pub mod response { } } - pub mod wipe_data_from_song_queue { - #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - pub data: Vec, - } - } - - pub mod link_user_id { - #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - pub data: Vec, - } - } pub mod get_songs { #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] @@ -204,309 +114,12 @@ pub mod response { /// Module for song related endpoints pub mod endpoint { - use axum::{Json, http::StatusCode, response::IntoResponse}; + use axum::{Json, response::IntoResponse}; // use crate::callers::song::song_queue; use crate::repo; use crate::repo::queue as repo_queue; - /// Endpoint to queue a song. Starts the process and places the song in a queue - #[utoipa::path( - post, - path = super::super::endpoints::QUEUESONG, - request_body( - content = super::request::song_queue::SongQueueRequest, - description = "Multipart form data for uploading song", - content_type = "multipart/form-data" - ), - responses( - (status = 200, description = "Song queued", body = super::response::Response) - ) - )] - pub async fn queue_song( - axum::Extension(pool): axum::Extension, - mut multipart: axum::extract::Multipart, - ) -> (StatusCode, Json) { - let mut results: Vec = Vec::new(); - let mut response = super::response::Response::default(); - - while let Some(field) = multipart.next_field().await.unwrap() { - let name = field.name().unwrap().to_string(); - let file_name = field.file_name().unwrap().to_string(); - let content_type = field.content_type().unwrap().to_string(); - let data = field.bytes().await.unwrap(); - - println!( - "Received file '{}' (name = '{}', content-type = '{}', size = {})", - file_name, - name, - content_type, - data.len() - ); - - let raw_data: Vec = data.to_vec(); - let queue_repo = repo_queue::song::insert( - &pool, - &raw_data, - &file_name, - &repo::queue::song::status::PENDING.to_string(), - ) - .await - .unwrap(); - results.push(queue_repo); - } - - response.data = results; - response.message = if response.data.is_empty() { - String::from("Error") - } else { - String::from("Success") - }; - - (StatusCode::OK, Json(response)) - } - - /// Endpoint to link a user id to a queued song - #[utoipa::path( - patch, - path = super::super::endpoints::QUEUESONGLINKUSERID, - request_body( - content = super::request::link_user_id::Request, - description = "User Id and queued song id", - content_type = "application/json" - ), - responses( - (status = 200, description = "Queued song linked", body = super::response::link_user_id::Response), - (status = 400, description = "Linkage failed", body = super::response::link_user_id::Response) - ) - )] - pub async fn link_user_id( - axum::Extension(pool): axum::Extension, - axum::Json(payload): axum::Json, - ) -> ( - axum::http::StatusCode, - axum::Json, - ) { - let mut response = super::response::link_user_id::Response::default(); - - match repo_queue::song::get_song_queue(&pool, &payload.song_queue_id).await { - Ok(song_queue) => { - match repo_queue::song::link_user_id(&pool, &song_queue.id, &payload.user_id).await - { - Ok(user_id) => { - response.message = String::from(crate::callers::response::SUCCESSFUL); - response.data.push(user_id); - (axum::http::StatusCode::OK, axum::Json(response)) - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } - } - - /// Endpoint to fetch the next queued song as long as it is available - #[utoipa::path( - get, - path = super::super::endpoints::NEXTQUEUESONG, - responses( - (status = 200, description = "Queued song is present and available", body = super::response::fetch_queue_song::Response), - (status = 400, description = "Linkage failed", body = super::response::fetch_queue_song::Response) - ) - )] - pub async fn fetch_queue_song( - axum::Extension(pool): axum::Extension, - ) -> ( - StatusCode, - Json, - ) { - let mut response = super::response::fetch_queue_song::Response::default(); - - match repo_queue::song::get_most_recent_and_update(&pool).await { - Ok(item) => { - response.message = String::from("Successful"); - response.data.push(item); - (StatusCode::OK, Json(response)) - } - Err(err) => { - response.message = err.to_string(); - (StatusCode::BAD_REQUEST, Json(response)) - } - } - } - - // TODO: Rename - /// Endpoint to download the queued song - #[utoipa::path( - get, - path = super::super::endpoints::QUEUESONGDATA, - params(("id" = uuid::Uuid, Path, description = "Queued song Id")), - responses( - (status = 200, description = "Queued song linked", body = Vec), - (status = 400, description = "Linkage failed", body = Vec) - ) - )] - pub async fn download_queued_song( - axum::Extension(pool): axum::Extension, - axum::extract::Path(id): axum::extract::Path, - ) -> (StatusCode, axum::response::Response) { - println!("Id: {id}"); - - match repo_queue::song::get_data(&pool, &id).await { - Ok(data) => { - let by = axum::body::Bytes::from(data); - let mut response = by.into_response(); - let headers = response.headers_mut(); - headers.insert( - axum::http::header::CONTENT_TYPE, - "audio/flac".parse().unwrap(), - ); - headers.insert( - axum::http::header::CONTENT_DISPOSITION, - format!("attachment; filename=\"{id}.flac\"") - .parse() - .unwrap(), - ); - - (StatusCode::OK, response) - } - Err(_err) => (StatusCode::BAD_REQUEST, axum::response::Response::default()), - } - } - - /// Endpoint to update the status of a queued song - #[utoipa::path( - patch, - path = super::super::endpoints::QUEUESONG, - request_body( - content = super::request::update_status::Request, - description = "Update the status of a queued song", - content_type = "application/json" - ), - responses( - (status = 200, description = "Status has been updated", body = super::response::update_status::Response), - (status = 400, description = "Error updating status of queued song", body = super::response::update_status::Response) - ) - )] - pub async fn update_song_queue_status( - axum::Extension(pool): axum::Extension, - axum::Json(payload): axum::Json, - ) -> ( - axum::http::StatusCode, - axum::Json, - ) { - let mut response = super::response::update_status::Response::default(); - - if repo::queue::song::status::is_valid(&payload.status).await { - let id = payload.id; - if !id.is_nil() { - match repo::queue::song::get_status_of_song_queue(&pool, &id).await { - Ok(old) => { - match repo::queue::song::update_song_queue_status( - &pool, - &payload.status, - &id, - ) - .await - { - Ok(new) => { - response.message = String::from("Successful"); - response - .data - .push(super::response::update_status::ChangedStatus { - old_status: old, - new_status: new, - }); - (axum::http::StatusCode::OK, axum::Json(response)) - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } - } else { - response.message = String::from("Id is nil"); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } else { - response.message = String::from("Status not valid"); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } - - /// Endpoint to update the queued song data - #[utoipa::path( - patch, - path = super::super::endpoints::QUEUESONGUPDATE, - request_body( - content = super::request::song_queue::SongQueueRequest, - description = "Multipart form data for uploading song", - content_type = "multipart/form-data" - ), - params(("id" = uuid::Uuid, Path, description = "Queued song Id")), - responses( - (status = 200, description = "Queued song updated", body = super::response::update_song_queue::Response), - (status = 400, description = "Error updating queued song", body = super::response::update_song_queue::Response), - (status = 404, description = "Queued song not found", body = super::response::update_song_queue::Response) - ) - )] - pub async fn update_song_queue( - axum::extract::Path(id): axum::extract::Path, - axum::Extension(pool): axum::Extension, - mut multipart: axum::extract::Multipart, - ) -> ( - axum::http::StatusCode, - axum::Json, - ) { - let mut response = super::response::update_song_queue::Response::default(); - - if let Some(field) = multipart.next_field().await.unwrap() { - let name = field.name().unwrap().to_string(); - let file_name = field.file_name().unwrap().to_string(); - let content_type = match field.content_type() { - Some(ct) => ct.to_string(), - None => String::new(), - }; - - let data = field.bytes().await.unwrap(); - - println!( - "Received file '{}' (name = '{}', content-type = '{}', size = {})", - file_name, - name, - content_type, - data.len() - ); - - let raw_data: Vec = data.to_vec(); - match repo_queue::song::update(&pool, &raw_data, &id).await { - Ok(_) => { - response.message = String::from("Successful"); - response.data.push(id); - (axum::http::StatusCode::OK, axum::Json(response)) - } - Err(err) => { - response.message = err.to_string(); - (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) - } - } - } else { - response.message = String::from("No data provided"); - (axum::http::StatusCode::NOT_FOUND, axum::Json(response)) - } - } /// Endpoint to create song #[utoipa::path( @@ -591,49 +204,6 @@ pub mod endpoint { } } - /// Endpoint to wipe the data from a queued song - #[utoipa::path( - patch, - path = super::super::endpoints::QUEUESONGDATAWIPE, - request_body( - content = super::request::wipe_data_from_song_queue::Request, - description = "Pass the queued song Id to wipe the data", - content_type = "application/json" - ), - responses( - (status = 200, description = "Queued song data wiped", body = super::response::wipe_data_from_song_queue::Response), - (status = 404, description = "Queued song cannot be found", body = super::response::wipe_data_from_song_queue::Response) - ) - )] - pub async fn wipe_data_from_song_queue( - axum::Extension(pool): axum::Extension, - axum::Json(payload): axum::Json, - ) -> ( - axum::http::StatusCode, - axum::Json, - ) { - let mut response = super::response::wipe_data_from_song_queue::Response::default(); - let id = payload.song_queue_id; - - match repo_queue::song::get_song_queue(&pool, &id).await { - Ok(song_queue) => match repo_queue::song::wipe_data(&pool, &song_queue.id).await { - Ok(wiped_id) => { - response.message = String::from("Success"); - response.data.push(wiped_id); - - (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)) - } - } - } // Endpoint to get songs #[utoipa::path( diff --git a/src/main.rs b/src/main.rs index 603b214..2dadcb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,6 +55,7 @@ pub mod init { use crate::callers::coverart as coverart_caller; use crate::callers::metadata as metadata_caller; use crate::callers::queue::coverart as coverart_queue_callers; + use crate::callers::queue::song as song_queue_callers; use crate::callers::song as song_caller; use coverart_caller::endpoint as coverart_endpoints; use coverart_caller::response as coverart_responses; @@ -64,6 +65,8 @@ pub mod init { use metadata_caller::response as metadata_responses; use song_caller::endpoint as song_endpoints; use song_caller::response as song_responses; + use song_queue_callers::endpoint as song_queue_endpoints; + use song_queue_callers::response as song_queue_responses; mod cors { pub async fn configure_cors() -> tower_http::cors::CorsLayer { @@ -115,15 +118,15 @@ pub mod init { #[derive(utoipa::OpenApi)] #[openapi( - paths(song_endpoints::queue_song, song_endpoints::link_user_id, song_endpoints::fetch_queue_song, song_endpoints::download_queued_song, - song_endpoints::update_song_queue_status, song_endpoints::update_song_queue, song_endpoints::create_metadata, song_endpoints::wipe_data_from_song_queue, song_endpoints::get_songs, song_endpoints::get_all_songs, song_endpoints::stream_song, song_endpoints::download_song, + paths(song_queue_endpoints::queue_song, song_queue_endpoints::link_user_id, song_queue_endpoints::fetch_queue_song, song_queue_endpoints::download_queued_song, + song_queue_endpoints::update_song_queue_status, song_queue_endpoints::update_song_queue, song_endpoints::create_metadata, song_queue_endpoints::wipe_data_from_song_queue, song_endpoints::get_songs, song_endpoints::get_all_songs, song_endpoints::stream_song, song_endpoints::download_song, song_endpoints::delete_song, coverart_queue_endpoints::queue, coverart_queue_endpoints::link, coverart_queue_endpoints::fetch_coverart_no_data, coverart_queue_endpoints::fetch_coverart_with_data, coverart_endpoints::create_coverart, coverart_queue_endpoints::wipe_data_from_coverart_queue, coverart_endpoints::get_coverart, coverart_endpoints::download_coverart, metadata_endpoints::queue_metadata, metadata_endpoints::fetch_metadata), - components(schemas(song_responses::Response, song_responses::link_user_id::Response, song_responses::fetch_queue_song::Response, - song_responses::update_status::Response, song_responses::update_song_queue::Response, song_responses::create_metadata::Response, - song_responses::wipe_data_from_song_queue::Response, song_responses::get_songs::Response, song_responses::delete_song::Response, + components(schemas(song_queue_callers::response::song_queue::Response, song_queue_callers::response::link_user_id::Response, song_queue_callers::response::fetch_queue_song::Response, + song_queue_responses::update_status::Response, song_queue_callers::response::update_song_queue::Response, song_responses::create_metadata::Response, + song_queue_callers::response::wipe_data_from_song_queue::Response, song_responses::get_songs::Response, song_responses::delete_song::Response, coverart_queue_responses::queue::Response, coverart_queue_responses::link::Response, coverart_queue_responses::fetch_coverart_no_data::Response, coverart_queue_responses::fetch_coverart_with_data::Response, coverart_responses::create_coverart::Response, coverart_queue_responses::wipe_data_from_coverart_queue::Response, coverart_responses::get_coverart::Response, @@ -138,44 +141,44 @@ pub mod init { axum::Router::new() .route(crate::ROOT, get(crate::root)) .route( - crate::callers::endpoints::QUEUESONG, - post(crate::callers::song::endpoint::queue_song).route_layer( + crate::callers::queue::endpoints::QUEUESONG, + post(crate::callers::queue::song::endpoint::queue_song).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUESONG, - patch(crate::callers::song::endpoint::update_song_queue_status).route_layer( + crate::callers::queue::endpoints::QUEUESONG, + patch(crate::callers::queue::song::endpoint::update_song_queue_status).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUESONGLINKUSERID, - patch(crate::callers::song::endpoint::link_user_id).route_layer( + crate::callers::queue::endpoints::QUEUESONGLINKUSERID, + patch(crate::callers::queue::song::endpoint::link_user_id).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUESONGDATA, - get(crate::callers::song::endpoint::download_queued_song).route_layer( + crate::callers::queue::endpoints::QUEUESONGDATA, + get(crate::callers::queue::song::endpoint::download_queued_song).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::NEXTQUEUESONG, - get(crate::callers::song::endpoint::fetch_queue_song).route_layer( + crate::callers::queue::endpoints::NEXTQUEUESONG, + get(crate::callers::queue::song::endpoint::fetch_queue_song).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUESONGUPDATE, - patch(crate::callers::song::endpoint::update_song_queue).route_layer( + crate::callers::queue::endpoints::QUEUESONGUPDATE, + patch(crate::callers::queue::song::endpoint::update_song_queue).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUESONGDATAWIPE, - patch(crate::callers::song::endpoint::wipe_data_from_song_queue).route_layer( + crate::callers::queue::endpoints::QUEUESONGDATAWIPE, + patch(crate::callers::queue::song::endpoint::wipe_data_from_song_queue).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) @@ -192,32 +195,32 @@ pub mod init { ), ) .route( - crate::callers::endpoints::QUEUECOVERART, + crate::callers::queue::endpoints::QUEUECOVERART, post(crate::callers::queue::coverart::endpoint::queue).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUECOVERARTDATA, + crate::callers::queue::endpoints::QUEUECOVERARTDATA, get(crate::callers::queue::coverart::endpoint::fetch_coverart_with_data) .route_layer(axum::middleware::from_fn( crate::auth::auth::, )), ) .route( - crate::callers::endpoints::QUEUECOVERART, + crate::callers::queue::endpoints::QUEUECOVERART, get(crate::callers::queue::coverart::endpoint::fetch_coverart_no_data).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUECOVERARTLINK, + crate::callers::queue::endpoints::QUEUECOVERARTLINK, patch(crate::callers::queue::coverart::endpoint::link).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .route( - crate::callers::endpoints::QUEUECOVERARTDATAWIPE, + crate::callers::queue::endpoints::QUEUECOVERARTDATAWIPE, patch(crate::callers::queue::coverart::endpoint::wipe_data_from_coverart_queue) .route_layer(axum::middleware::from_fn( crate::auth::auth::, -- 2.47.3 From 389ed2264e65b320f288a22987e55598cc9b2b80 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Sun, 26 Oct 2025 17:19:48 -0400 Subject: [PATCH 3/6] tsk-218: Code formatting --- src/callers/queue/song.rs | 37 ++++++++++++++++++------------------- src/callers/song.rs | 6 ------ src/main.rs | 7 ++++--- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/callers/queue/song.rs b/src/callers/queue/song.rs index d02df3c..a483baf 100644 --- a/src/callers/queue/song.rs +++ b/src/callers/queue/song.rs @@ -37,17 +37,16 @@ pub mod request { } } - pub mod response { pub mod song_queue { - /// Song queue response - #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] - pub struct Response { - pub message: String, - /// Id of the queued song - pub data: Vec, - } + /// Song queue response + #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] + pub struct Response { + pub message: String, + /// Id of the queued song + pub data: Vec, + } } pub mod fetch_queue_song { @@ -99,7 +98,6 @@ pub mod response { } } - pub mod endpoint { use axum::response::IntoResponse; @@ -121,7 +119,10 @@ pub mod endpoint { pub async fn queue_song( axum::Extension(pool): axum::Extension, mut multipart: axum::extract::Multipart, - ) -> (axum::http::StatusCode, axum::Json) { + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { let mut results: Vec = Vec::new(); let mut response = super::response::song_queue::Response::default(); @@ -186,8 +187,7 @@ pub mod endpoint { match repo::song::get_song_queue(&pool, &payload.song_queue_id).await { Ok(song_queue) => { - match repo::song::link_user_id(&pool, &song_queue.id, &payload.user_id).await - { + match repo::song::link_user_id(&pool, &song_queue.id, &payload.user_id).await { Ok(user_id) => { response.message = String::from(crate::callers::response::SUCCESSFUL); response.data.push(user_id); @@ -271,7 +271,10 @@ pub mod endpoint { (axum::http::StatusCode::OK, response) } - Err(_err) => (axum::http::StatusCode::BAD_REQUEST, axum::response::Response::default()), + Err(_err) => ( + axum::http::StatusCode::BAD_REQUEST, + axum::response::Response::default(), + ), } } @@ -303,12 +306,8 @@ pub mod endpoint { if !id.is_nil() { match repo::song::get_status_of_song_queue(&pool, &id).await { Ok(old) => { - match repo::song::update_song_queue_status( - &pool, - &payload.status, - &id, - ) - .await + match repo::song::update_song_queue_status(&pool, &payload.status, &id) + .await { Ok(new) => { response.message = String::from("Successful"); diff --git a/src/callers/song.rs b/src/callers/song.rs index ba740cc..1da626b 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -7,8 +7,6 @@ pub mod request { pub message: String, } - - pub mod create_metadata { #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] pub struct Request { @@ -68,7 +66,6 @@ pub mod request { } } - pub mod get_songs { #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] pub struct Params { @@ -86,7 +83,6 @@ pub mod response { } } - pub mod get_songs { #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] pub struct Response { @@ -120,7 +116,6 @@ pub mod endpoint { use crate::repo; use crate::repo::queue as repo_queue; - /// Endpoint to create song #[utoipa::path( post, @@ -204,7 +199,6 @@ pub mod endpoint { } } - // Endpoint to get songs #[utoipa::path( get, diff --git a/src/main.rs b/src/main.rs index 2dadcb1..834d706 100644 --- a/src/main.rs +++ b/src/main.rs @@ -178,9 +178,10 @@ pub mod init { ) .route( crate::callers::queue::endpoints::QUEUESONGDATAWIPE, - patch(crate::callers::queue::song::endpoint::wipe_data_from_song_queue).route_layer( - axum::middleware::from_fn(crate::auth::auth::), - ), + patch(crate::callers::queue::song::endpoint::wipe_data_from_song_queue) + .route_layer(axum::middleware::from_fn( + crate::auth::auth::, + )), ) .route( crate::callers::endpoints::QUEUEMETADATA, -- 2.47.3 From 7b0073a6c833b28a8bc7ec2362cc2e656679bfee Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Sun, 26 Oct 2025 17:23:16 -0400 Subject: [PATCH 4/6] tsk-218: Version bump --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6f2bd0..b6f7f1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -834,7 +834,7 @@ dependencies = [ [[package]] name = "icarus" -version = "0.3.6" +version = "0.3.7" dependencies = [ "axum", "axum-extra", diff --git a/Cargo.toml b/Cargo.toml index 07511ee..55e5d40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "icarus" -version = "0.3.6" +version = "0.3.7" edition = "2024" rust-version = "1.90" -- 2.47.3 From b9a5adf8f7946b71c2409ca420f850d4e124d365 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Sun, 26 Oct 2025 17:29:00 -0400 Subject: [PATCH 5/6] tsk-218: Cleanup --- src/callers/queue/song.rs | 2 -- src/callers/song.rs | 9 --------- 2 files changed, 11 deletions(-) diff --git a/src/callers/queue/song.rs b/src/callers/queue/song.rs index a483baf..73c09c7 100644 --- a/src/callers/queue/song.rs +++ b/src/callers/queue/song.rs @@ -1,5 +1,4 @@ pub mod request { - pub mod song_queue { #[derive(utoipa::ToSchema)] pub struct SongQueueRequest { @@ -38,7 +37,6 @@ pub mod request { } pub mod response { - pub mod song_queue { /// Song queue response #[derive(Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] diff --git a/src/callers/song.rs b/src/callers/song.rs index 1da626b..0d8c605 100644 --- a/src/callers/song.rs +++ b/src/callers/song.rs @@ -1,12 +1,4 @@ pub mod request { - use serde::{Deserialize, Serialize}; - - // TODO: Might not be used - #[derive(Default, Deserialize, Serialize)] - pub struct Request { - pub message: String, - } - pub mod create_metadata { #[derive(Debug, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] pub struct Request { @@ -112,7 +104,6 @@ pub mod response { pub mod endpoint { use axum::{Json, response::IntoResponse}; - // use crate::callers::song::song_queue; use crate::repo; use crate::repo::queue as repo_queue; -- 2.47.3 From 149999a1d2d7def071104c625e13592dd231073d Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Sun, 26 Oct 2025 17:43:06 -0400 Subject: [PATCH 6/6] tsk-218: Test fixes --- src/main.rs | 110 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 42 deletions(-) diff --git a/src/main.rs b/src/main.rs index 834d706..1969bc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -475,7 +475,7 @@ mod tests { let body = MultipartBody::from(form); let req = axum::http::Request::builder() .method(axum::http::Method::POST) - .uri(crate::callers::endpoints::QUEUESONG) + .uri(crate::callers::queue::endpoints::QUEUESONG) .header(axum::http::header::CONTENT_TYPE, content_type) .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::from_stream(body)) @@ -495,7 +495,7 @@ mod tests { let req = axum::http::Request::builder() .method(axum::http::Method::PATCH) - .uri(crate::callers::endpoints::QUEUESONGLINKUSERID) + .uri(crate::callers::queue::endpoints::QUEUESONGLINKUSERID) .header(axum::http::header::CONTENT_TYPE, "application/json") .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::from(payload.to_string())) @@ -509,7 +509,7 @@ mod tests { ) -> Result { let fetch_req = axum::http::Request::builder() .method(axum::http::Method::GET) - .uri(crate::callers::endpoints::NEXTQUEUESONG) + .uri(crate::callers::queue::endpoints::NEXTQUEUESONG) .header(axum::http::header::CONTENT_TYPE, "application/json") .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::empty()) @@ -538,7 +538,7 @@ mod tests { app: &axum::Router, id: &uuid::Uuid, ) -> Result { - let raw_uri = String::from(crate::callers::endpoints::QUEUESONGDATA); + let raw_uri = String::from(crate::callers::queue::endpoints::QUEUESONGDATA); let end_index = raw_uri.len() - 4; let mut uri: String = (&raw_uri[..end_index]).to_string(); uri += &id.to_string(); @@ -565,7 +565,7 @@ mod tests { let req = axum::http::Request::builder() .method(axum::http::Method::POST) - .uri(crate::callers::endpoints::QUEUECOVERART) + .uri(crate::callers::queue::endpoints::QUEUECOVERART) .header(axum::http::header::CONTENT_TYPE, content_type) .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::from_stream(body)) @@ -604,7 +604,7 @@ mod tests { }); let req = axum::http::Request::builder() .method(axum::http::Method::PATCH) - .uri(crate::callers::endpoints::QUEUECOVERARTLINK) + .uri(crate::callers::queue::endpoints::QUEUECOVERARTLINK) .header(axum::http::header::CONTENT_TYPE, "application/json") .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::from(payload.to_string())) @@ -661,7 +661,7 @@ mod tests { let req = axum::http::Request::builder() .method(axum::http::Method::PATCH) - .uri(crate::callers::endpoints::QUEUESONG) + .uri(crate::callers::queue::endpoints::QUEUESONG) .header(axum::http::header::CONTENT_TYPE, "application/json") .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::from(payload.to_string())) @@ -676,7 +676,7 @@ mod tests { ) -> Result { let uri = format!( "{}?id={}", - crate::callers::endpoints::QUEUECOVERART, + crate::callers::queue::endpoints::QUEUECOVERART, coverart_queue_id ); @@ -698,9 +698,10 @@ mod tests { ) -> Result<(axum::response::Response, uuid::Uuid), std::convert::Infallible> { match super::song_queue_req(&app).await { Ok(response) => { - let resp = - super::get_resp_data::(response) - .await; + let resp = super::get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); let song_queue_id = resp.data[0]; @@ -711,7 +712,7 @@ mod tests { match super::song_queue_link_req(&app, &song_queue_id, &user_id).await { Ok(response) => { let resp = super::get_resp_data::< - crate::callers::song::response::link_user_id::Response, + crate::callers::queue::song::response::link_user_id::Response, >(response) .await; assert_eq!( @@ -723,7 +724,7 @@ mod tests { match super::queue_metadata_req(&app, &song_queue_id).await { Ok(response) => { let resp = super::get_resp_data::< - crate::callers::song::response::Response, + crate::callers::queue::song::response::song_queue::Response, >(response) .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); @@ -932,8 +933,10 @@ mod tests { // Send request match song_queue_req(&app).await { Ok(response) => { - let resp = - get_resp_data::(response).await; + let resp = get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); } @@ -966,8 +969,10 @@ mod tests { match song_queue_req(&app).await { Ok(response) => { - let resp = - get_resp_data::(response).await; + let resp = get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); @@ -978,7 +983,7 @@ mod tests { match song_queue_link_req(&app, &song_queue_id, &user_id).await { Ok(response) => { let resp = get_resp_data::< - crate::callers::song::response::link_user_id::Response, + crate::callers::queue::song::response::link_user_id::Response, >(response) .await; let collected_user_id = &resp.data[0]; @@ -1043,7 +1048,7 @@ mod tests { match update_song_queue_status_req(&app, &song_queue_id).await { Ok(response) => { let resp = get_resp_data::< - crate::callers::song::response::update_status::Response, + crate::callers::queue::song::response::update_status::Response, >(response) .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); @@ -1058,7 +1063,7 @@ mod tests { match fetch_queue_req(&app).await { Ok(response) => { let resp = get_resp_data::< - crate::callers::song::response::fetch_queue_song::Response, + crate::callers::queue::song::response::fetch_queue_song::Response, >(response) .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); @@ -1103,8 +1108,10 @@ mod tests { // Send request match song_queue_req(&app).await { Ok(response) => { - let resp = - get_resp_data::(response).await; + let resp = get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); @@ -1118,19 +1125,32 @@ mod tests { let temp_file = tempfile::tempdir().expect("Could not create test directory"); let test_dir = String::from(temp_file.path().to_str().unwrap()); - let new_file = format!("{}/new_file.flac", test_dir); - - let mut file = std::fs::File::create(&new_file).unwrap(); - file.write_all(&bytes).unwrap(); + let song = icarus_models::song::Song { + directory: test_dir, + filename: icarus_models::song::generate_filename( + icarus_models::types::MusicTypes::FlacExtension, + true, + ), + data: bytes.to_vec(), + ..Default::default() + }; + match song.save_to_filesystem() { + Ok(_) => {} + Err(err) => { + assert!(false, "Error: {err:?}") + } + } + let songpath = song.song_path().unwrap(); let mut form = MultipartForm::default(); - let _ = form.add_file("flac", new_file); + let _ = form.add_file("flac", &songpath); // Create request let content_type = form.content_type(); let body = MultipartBody::from(form); - let raw_uri = String::from(crate::callers::endpoints::QUEUESONGUPDATE); + let raw_uri = + String::from(crate::callers::queue::endpoints::QUEUESONGUPDATE); let end_index = raw_uri.len() - 5; let uri = format!( @@ -1157,7 +1177,7 @@ mod tests { { Ok(response) => { let resp = get_resp_data::< - crate::callers::song::response::update_song_queue::Response, + crate::callers::queue::song::response::update_song_queue::Response, >(response) .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); @@ -1213,8 +1233,10 @@ mod tests { // Send request match song_queue_req(&app).await { Ok(response) => { - let resp = - get_resp_data::(response).await; + let resp = get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); let id = resp.data[0]; @@ -1276,7 +1298,7 @@ mod tests { match update_song_queue_status_req(&app, &song_queue_id).await { Ok(response) => { let resp = get_resp_data::< - crate::callers::song::response::update_status::Response, + crate::callers::queue::song::response::update_status::Response, >(response) .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); @@ -1320,16 +1342,19 @@ mod tests { // Send request match song_queue_req(&app).await { Ok(response) => { - let resp = - get_resp_data::(response).await; + let resp = get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); match queue_metadata_req(&app, &resp.data[0]).await { Ok(response) => { - let resp = - get_resp_data::(response) - .await; + let resp = get_resp_data::< + crate::callers::queue::song::response::song_queue::Response, + >(response) + .await; assert_eq!(false, resp.data.is_empty(), "Should not be empty"); } Err(err) => { @@ -1605,8 +1630,9 @@ mod tests { "Should not be empty" ); - let raw_uri = - String::from(crate::callers::endpoints::QUEUECOVERARTDATA); + let raw_uri = String::from( + crate::callers::queue::endpoints::QUEUECOVERARTDATA, + ); let end_index = raw_uri.len() - 5; let uri = format!( "{}/{}", @@ -1890,7 +1916,7 @@ mod tests { .oneshot( axum::http::Request::builder() .method(axum::http::Method::PATCH) - .uri(crate::callers::endpoints::QUEUESONGDATAWIPE) + .uri(crate::callers::queue::endpoints::QUEUESONGDATAWIPE) .header(axum::http::header::CONTENT_TYPE, "application/json") .header(axum::http::header::AUTHORIZATION, bearer_auth().await) .body(axum::body::Body::from(payload.to_string())) @@ -1899,7 +1925,7 @@ mod tests { .await { Ok(response) => { - let resp = get_resp_data::(response).await; + let resp = get_resp_data::(response).await; assert_eq!( false, resp.data.is_empty(), @@ -2008,7 +2034,7 @@ mod tests { .oneshot( axum::http::Request::builder() .method(axum::http::Method::PATCH) - .uri(crate::callers::endpoints::QUEUECOVERARTDATAWIPE) + .uri(crate::callers::queue::endpoints::QUEUECOVERARTDATAWIPE) .header( axum::http::header::CONTENT_TYPE, "application/json", -- 2.47.3