Create metadata #133
@@ -1,4 +1,5 @@
|
|||||||
SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
|
SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
|
||||||
|
ROOT_DIRECTORY=/home/icarus/mydata
|
||||||
POSTGRES_MAIN_USER=icarus
|
POSTGRES_MAIN_USER=icarus
|
||||||
POSTGRES_MAIN_PASSWORD=password
|
POSTGRES_MAIN_PASSWORD=password
|
||||||
POSTGRES_MAIN_DB=icarus_db
|
POSTGRES_MAIN_DB=icarus_db
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
env:
|
env:
|
||||||
|
ROOT_DIRECTORY: "/tmp"
|
||||||
DATABASE_URL: "postgres://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}"
|
DATABASE_URL: "postgres://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}"
|
||||||
run: cargo test --verbose
|
run: cargo test --verbose
|
||||||
|
|
||||||
|
|||||||
@@ -26,3 +26,26 @@ CREATE TABLE IF NOT EXISTS "coverartQueue" (
|
|||||||
|
|
||||||
-- Create an index for better query performance
|
-- Create an index for better query performance
|
||||||
CREATE INDEX metadata_queue_data_metadata ON "metadataQueue" USING gin (metadata);
|
CREATE INDEX metadata_queue_data_metadata ON "metadataQueue" USING gin (metadata);
|
||||||
|
|
||||||
|
-- Table to store a song's info
|
||||||
|
CREATE TABLE IF NOT EXISTS "song" (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
artist TEXT NOT NULL,
|
||||||
|
album_artist TEXT NOT NULL,
|
||||||
|
album TEXT NOT NULL,
|
||||||
|
genre TEXT NOT NULL,
|
||||||
|
-- TODO: Address discrepancy of date and year at some point
|
||||||
|
-- date TEXT NOT NULL,
|
||||||
|
year INT NOT NULL,
|
||||||
|
track SMALLINT NOT NULL,
|
||||||
|
disc SMALLINT NOT NULL,
|
||||||
|
track_count SMALLINT NOT NULL,
|
||||||
|
disc_count SMALLINT NOT NULL,
|
||||||
|
duration INT NOT NULL,
|
||||||
|
audio_type TEXT NOT NULL,
|
||||||
|
date_created timestamptz DEFAULT now(),
|
||||||
|
filename TEXT NOT NULL,
|
||||||
|
directory TEXT NOT NULL,
|
||||||
|
user_id UUID NULL
|
||||||
|
);
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ pub mod endpoints {
|
|||||||
pub const QUEUECOVERART: &str = "/api/v2/coverart/queue";
|
pub const QUEUECOVERART: &str = "/api/v2/coverart/queue";
|
||||||
pub const QUEUECOVERARTDATA: &str = "/api/v2/coverart/queue/data";
|
pub const QUEUECOVERARTDATA: &str = "/api/v2/coverart/queue/data";
|
||||||
pub const QUEUECOVERARTLINK: &str = "/api/v2/coverart/queue/link";
|
pub const QUEUECOVERARTLINK: &str = "/api/v2/coverart/queue/link";
|
||||||
|
|
||||||
|
pub const CREATESONG: &str = "/api/v2/song";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,69 @@ pub mod request {
|
|||||||
pub status: String,
|
pub status: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod create_metadata {
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct Request {
|
||||||
|
pub title: String,
|
||||||
|
pub artist: String,
|
||||||
|
pub album_artist: String,
|
||||||
|
pub album: String,
|
||||||
|
pub genre: String,
|
||||||
|
pub date: String,
|
||||||
|
pub track: i32,
|
||||||
|
pub disc: i32,
|
||||||
|
pub track_count: i32,
|
||||||
|
pub disc_count: i32,
|
||||||
|
pub duration: i32,
|
||||||
|
pub audio_type: String,
|
||||||
|
pub user_id: uuid::Uuid,
|
||||||
|
pub song_queue_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
!self.title.is_empty()
|
||||||
|
|| !self.artist.is_empty()
|
||||||
|
|| !self.album_artist.is_empty()
|
||||||
|
|| !self.album.is_empty()
|
||||||
|
|| !self.genre.is_empty()
|
||||||
|
|| !self.date.is_empty()
|
||||||
|
|| self.track > 0
|
||||||
|
|| self.disc > 0
|
||||||
|
|| self.track_count > 0
|
||||||
|
|| self.disc_count > 0
|
||||||
|
|| self.duration > 0
|
||||||
|
|| !self.audio_type.is_empty()
|
||||||
|
|| !self.user_id.is_nil()
|
||||||
|
|| !self.song_queue_id.is_nil()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_song(&self) -> icarus_models::song::Song {
|
||||||
|
icarus_models::song::Song {
|
||||||
|
id: uuid::Uuid::nil(),
|
||||||
|
title: self.title.clone(),
|
||||||
|
artist: self.artist.clone(),
|
||||||
|
album_artist: self.album_artist.clone(),
|
||||||
|
album: self.album.clone(),
|
||||||
|
genre: self.genre.clone(),
|
||||||
|
year: self.date[..3].parse().unwrap(),
|
||||||
|
track: self.track,
|
||||||
|
disc: self.disc,
|
||||||
|
track_count: self.track_count,
|
||||||
|
disc_count: self.disc_count,
|
||||||
|
duration: self.duration,
|
||||||
|
audio_type: self.audio_type.clone(),
|
||||||
|
user_id: self.user_id,
|
||||||
|
// TODO: Change the type of this in icarus_models lib
|
||||||
|
date_created: String::new(),
|
||||||
|
filename: String::new(),
|
||||||
|
data: Vec::new(),
|
||||||
|
directory: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod response {
|
pub mod response {
|
||||||
@@ -55,8 +118,18 @@ pub mod response {
|
|||||||
pub data: Vec<Vec<u8>>,
|
pub data: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod create_metadata {
|
||||||
|
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct Response {
|
||||||
|
pub message: String,
|
||||||
|
pub data: Vec<icarus_models::song::Song>,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Might make a distinction between year and date in a song's tag at some point
|
||||||
|
|
||||||
pub mod status {
|
pub mod status {
|
||||||
pub const PENDING: &str = "pending";
|
pub const PENDING: &str = "pending";
|
||||||
pub const PROCESSING: &str = "processing";
|
pub const PROCESSING: &str = "processing";
|
||||||
@@ -67,6 +140,60 @@ pub mod status {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod song_db {
|
||||||
|
use sqlx::Row;
|
||||||
|
|
||||||
|
// TODO: Change first parameter of return value from string to a time type
|
||||||
|
pub async fn insert(
|
||||||
|
pool: &sqlx::PgPool,
|
||||||
|
song: &icarus_models::song::Song,
|
||||||
|
) -> Result<(String, uuid::Uuid), sqlx::Error> {
|
||||||
|
let result = sqlx::query(
|
||||||
|
r#"
|
||||||
|
INSERT INTO "song" (title, artist, album_artist, album, genre, year, track, disc, track_count, disc_count, duration, audio_type, filename, directory, user_id)
|
||||||
|
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) RETURNING date_created, id;
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
.bind(&song.title)
|
||||||
|
.bind(&song.artist)
|
||||||
|
.bind(&song.album_artist)
|
||||||
|
.bind(&song.album)
|
||||||
|
.bind(&song.genre)
|
||||||
|
.bind(song.year)
|
||||||
|
.bind(song.track)
|
||||||
|
.bind(song.disc)
|
||||||
|
.bind(song.track_count)
|
||||||
|
.bind(song.disc_count)
|
||||||
|
.bind(song.duration)
|
||||||
|
.bind(&song.audio_type)
|
||||||
|
.bind(&song.filename)
|
||||||
|
.bind(&song.directory)
|
||||||
|
.bind(song.user_id)
|
||||||
|
.fetch_one(pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
eprintln!("Error inserting query: {:?}", e);
|
||||||
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(row) => {
|
||||||
|
let id: uuid::Uuid = row
|
||||||
|
.try_get("id")
|
||||||
|
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||||
|
.unwrap();
|
||||||
|
let date_created_time: time::OffsetDateTime = row
|
||||||
|
.try_get("date_created")
|
||||||
|
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||||
|
.unwrap();
|
||||||
|
let date_created = date_created_time.to_string();
|
||||||
|
|
||||||
|
Ok((date_created, id))
|
||||||
|
}
|
||||||
|
Err(_) => Err(sqlx::Error::RowNotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod song_queue {
|
mod song_queue {
|
||||||
use sqlx::Row;
|
use sqlx::Row;
|
||||||
|
|
||||||
@@ -289,6 +416,7 @@ pub mod endpoint {
|
|||||||
data.len()
|
data.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Remove this
|
||||||
// Save the file to disk
|
// Save the file to disk
|
||||||
let mut file = std::fs::File::create(&file_name).unwrap();
|
let mut file = std::fs::File::create(&file_name).unwrap();
|
||||||
file.write_all(&data).unwrap();
|
file.write_all(&data).unwrap();
|
||||||
@@ -456,4 +584,59 @@ pub mod endpoint {
|
|||||||
(axum::http::StatusCode::NOT_FOUND, axum::Json(response))
|
(axum::http::StatusCode::NOT_FOUND, axum::Json(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_metadata(
|
||||||
|
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||||
|
axum::Json(payload): axum::Json<super::request::create_metadata::Request>,
|
||||||
|
) -> (
|
||||||
|
axum::http::StatusCode,
|
||||||
|
axum::Json<super::response::create_metadata::Response>,
|
||||||
|
) {
|
||||||
|
let mut response = super::response::create_metadata::Response::default();
|
||||||
|
|
||||||
|
if payload.is_valid() {
|
||||||
|
let mut song = payload.to_song();
|
||||||
|
song.filename =
|
||||||
|
song.generate_filename(icarus_models::types::MusicTypes::FlacExtension, true);
|
||||||
|
song.directory = crate::environment::get_root_directory().await.unwrap();
|
||||||
|
|
||||||
|
match song_queue::get_data(&pool, &payload.song_queue_id).await {
|
||||||
|
Ok(data) => {
|
||||||
|
song.data = data;
|
||||||
|
let dir = std::path::Path::new(&song.directory);
|
||||||
|
let save_path = dir.join(&song.filename);
|
||||||
|
|
||||||
|
let mut file = std::fs::File::create(&save_path).unwrap();
|
||||||
|
file.write_all(&song.data).unwrap();
|
||||||
|
|
||||||
|
match song.song_path() {
|
||||||
|
Ok(_) => match super::song_db::insert(&pool, &song).await {
|
||||||
|
Ok((date_created, id)) => {
|
||||||
|
song.id = id;
|
||||||
|
song.date_created = date_created;
|
||||||
|
response.data.push(song);
|
||||||
|
|
||||||
|
(axum::http::StatusCode::OK, axum::Json(response))
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
response.message = format!("{:?} song {:?}", err.to_string(), song);
|
||||||
|
(axum::http::StatusCode::BAD_REQUEST, 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("Request body is not valid");
|
||||||
|
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
pub async fn get_db_url() -> String {
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
std::env::var(crate::keys::DBURL).expect(crate::keys::error::ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_root_directory() -> Result<String, std::env::VarError> {
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
std::env::var(crate::keys::ROOT_DIRECTORY)
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
pub const DBURL: &str = "DATABASE_URL";
|
||||||
|
pub const ROOT_DIRECTORY: &str = "ROOT_DIRECTORY";
|
||||||
|
|
||||||
|
pub mod error {
|
||||||
|
pub const ERROR: &str = "DATABASE_URL must be set in .env";
|
||||||
|
}
|
||||||
+170
-59
@@ -1,24 +1,17 @@
|
|||||||
pub mod callers;
|
pub mod callers;
|
||||||
|
pub mod environment;
|
||||||
|
pub mod keys;
|
||||||
|
|
||||||
pub mod db {
|
pub mod db {
|
||||||
|
|
||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
use std::env;
|
|
||||||
|
|
||||||
pub mod connection_settings {
|
pub mod connection_settings {
|
||||||
pub const MAXCONN: u32 = 10;
|
pub const MAXCONN: u32 = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod keys {
|
|
||||||
pub const DBURL: &str = "DATABASE_URL";
|
|
||||||
|
|
||||||
pub mod error {
|
|
||||||
pub const ERROR: &str = "DATABASE_URL must be set in .env";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
|
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
|
||||||
let database_url = get_db_url().await;
|
let database_url = crate::environment::get_db_url().await;
|
||||||
println!("Database url: {:?}", database_url);
|
println!("Database url: {:?}", database_url);
|
||||||
|
|
||||||
PgPoolOptions::new()
|
PgPoolOptions::new()
|
||||||
@@ -27,11 +20,6 @@ pub mod db {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_db_url() -> String {
|
|
||||||
dotenvy::dotenv().ok();
|
|
||||||
env::var(keys::DBURL).expect(keys::error::ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn migrations(pool: &sqlx::PgPool) {
|
pub async fn migrations(pool: &sqlx::PgPool) {
|
||||||
// Run migrations using the sqlx::migrate! macro
|
// Run migrations using the sqlx::migrate! macro
|
||||||
// Assumes your migrations are in a ./migrations folder relative to Cargo.toml
|
// Assumes your migrations are in a ./migrations folder relative to Cargo.toml
|
||||||
@@ -109,6 +97,10 @@ pub mod init {
|
|||||||
crate::callers::endpoints::QUEUECOVERARTLINK,
|
crate::callers::endpoints::QUEUECOVERARTLINK,
|
||||||
patch(crate::callers::coverart::endpoint::link),
|
patch(crate::callers::coverart::endpoint::link),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
crate::callers::endpoints::CREATESONG,
|
||||||
|
post(crate::callers::song::endpoint::create_metadata),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn app() -> axum::Router {
|
pub async fn app() -> axum::Router {
|
||||||
@@ -125,18 +117,23 @@ pub mod init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move elsewhere
|
||||||
fn get_full() -> String {
|
fn get_full() -> String {
|
||||||
get_address() + ":" + &get_port()
|
get_address() + ":" + &get_port()
|
||||||
}
|
}
|
||||||
|
// TODO: Move elsewhere
|
||||||
fn get_address() -> String {
|
fn get_address() -> String {
|
||||||
String::from("0.0.0.0")
|
String::from("0.0.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move elsewhere
|
||||||
fn get_port() -> String {
|
fn get_port() -> String {
|
||||||
String::from("3000")
|
String::from("3000")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move elsewhere
|
||||||
pub const ROOT: &str = "/";
|
pub const ROOT: &str = "/";
|
||||||
|
// TODO: Move elsewhere
|
||||||
// basic handler that responds with a static string
|
// basic handler that responds with a static string
|
||||||
pub async fn root() -> &'static str {
|
pub async fn root() -> &'static str {
|
||||||
"Hello, World!"
|
"Hello, World!"
|
||||||
@@ -157,13 +154,13 @@ mod tests {
|
|||||||
mod db_mgr {
|
mod db_mgr {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::db;
|
use crate::keys;
|
||||||
|
|
||||||
pub const LIMIT: usize = 6;
|
pub const LIMIT: usize = 6;
|
||||||
|
|
||||||
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
|
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
let tm_db_url = std::env::var(db::keys::DBURL).expect("DATABASE_URL must be present");
|
let tm_db_url = crate::environment::get_db_url().await;
|
||||||
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
|
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
|
||||||
sqlx::PgPool::connect_with(tm_options).await
|
sqlx::PgPool::connect_with(tm_options).await
|
||||||
}
|
}
|
||||||
@@ -176,8 +173,7 @@ mod tests {
|
|||||||
|
|
||||||
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
|
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
let db_url =
|
let db_url = crate::environment::get_db_url().await;
|
||||||
std::env::var(db::keys::DBURL).expect("DATABASE_URL must be set for tests");
|
|
||||||
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
|
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
|
||||||
sqlx::PgPool::connect_with(options).await
|
sqlx::PgPool::connect_with(options).await
|
||||||
}
|
}
|
||||||
@@ -206,7 +202,7 @@ mod tests {
|
|||||||
pub fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
|
pub fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
|
||||||
dotenvy::dotenv().ok(); // Load .env file if it exists
|
dotenvy::dotenv().ok(); // Load .env file if it exists
|
||||||
|
|
||||||
match std::env::var(db::keys::DBURL) {
|
match std::env::var(keys::DBURL) {
|
||||||
Ok(database_url) => {
|
Ok(database_url) => {
|
||||||
let parsed_url = url::Url::parse(&database_url)?;
|
let parsed_url = url::Url::parse(&database_url)?;
|
||||||
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
|
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
|
||||||
@@ -273,6 +269,22 @@ mod tests {
|
|||||||
app.clone().oneshot(fetch_req).await
|
app.clone().oneshot(fetch_req).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_metadata_queue_req(
|
||||||
|
app: &axum::Router,
|
||||||
|
id: &uuid::Uuid,
|
||||||
|
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||||
|
let uri = format!("{}?id={}", crate::callers::endpoints::QUEUEMETADATA, id);
|
||||||
|
|
||||||
|
let req = 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();
|
||||||
|
|
||||||
|
app.clone().oneshot(req).await
|
||||||
|
}
|
||||||
|
|
||||||
async fn fetch_queue_data_req(
|
async fn fetch_queue_data_req(
|
||||||
app: &axum::Router,
|
app: &axum::Router,
|
||||||
id: &uuid::Uuid,
|
id: &uuid::Uuid,
|
||||||
@@ -312,6 +324,22 @@ mod tests {
|
|||||||
app.clone().oneshot(req).await
|
app.clone().oneshot(req).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn queue_metadata_req(
|
||||||
|
app: &axum::Router,
|
||||||
|
id: &uuid::Uuid,
|
||||||
|
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||||
|
let payload = payload_data(&id).await;
|
||||||
|
|
||||||
|
let req = axum::http::Request::builder()
|
||||||
|
.method(axum::http::Method::POST)
|
||||||
|
.uri(crate::callers::endpoints::QUEUEMETADATA)
|
||||||
|
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||||
|
.body(axum::body::Body::from(payload.to_string()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
app.clone().oneshot(req).await
|
||||||
|
}
|
||||||
|
|
||||||
async fn coverart_queue_song_queue_link_req(
|
async fn coverart_queue_song_queue_link_req(
|
||||||
app: &axum::Router,
|
app: &axum::Router,
|
||||||
coverart_id: &uuid::Uuid,
|
coverart_id: &uuid::Uuid,
|
||||||
@@ -540,20 +568,8 @@ mod tests {
|
|||||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||||
let new_payload = payload_data(&resp.data[0]).await;
|
|
||||||
|
|
||||||
match app
|
match queue_metadata_req(&app, &resp.data[0]).await {
|
||||||
.clone()
|
|
||||||
.oneshot(
|
|
||||||
axum::http::Request::builder()
|
|
||||||
.method(axum::http::Method::POST)
|
|
||||||
.uri(crate::callers::endpoints::QUEUEMETADATA)
|
|
||||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
|
||||||
.body(axum::body::Body::from(new_payload.to_string()))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
let resp =
|
let resp =
|
||||||
get_resp_data::<crate::callers::song::response::Response>(response)
|
get_resp_data::<crate::callers::song::response::Response>(response)
|
||||||
@@ -599,20 +615,8 @@ mod tests {
|
|||||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||||
let new_payload = payload_data(&resp.data[0]).await;
|
|
||||||
|
|
||||||
match app
|
match queue_metadata_req(&app, &resp.data[0]).await {
|
||||||
.clone()
|
|
||||||
.oneshot(
|
|
||||||
axum::http::Request::builder()
|
|
||||||
.method(axum::http::Method::POST)
|
|
||||||
.uri(crate::callers::endpoints::QUEUEMETADATA)
|
|
||||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
|
||||||
.body(axum::body::Body::from(new_payload.to_string()))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
let resp =
|
let resp =
|
||||||
get_resp_data::<crate::callers::song::response::Response>(response)
|
get_resp_data::<crate::callers::song::response::Response>(response)
|
||||||
@@ -620,20 +624,8 @@ mod tests {
|
|||||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||||
|
|
||||||
let id = resp.data[0];
|
let id = resp.data[0];
|
||||||
let uri = format!("{}?id={}", crate::callers::endpoints::QUEUEMETADATA, id);
|
|
||||||
|
|
||||||
match app
|
match fetch_metadata_queue_req(&app, &id).await {
|
||||||
.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) => {
|
Ok(response) => {
|
||||||
let resp = get_resp_data::<
|
let resp = get_resp_data::<
|
||||||
crate::callers::metadata::response::fetch_metadata::Response,
|
crate::callers::metadata::response::fetch_metadata::Response,
|
||||||
@@ -1199,4 +1191,123 @@ mod tests {
|
|||||||
|
|
||||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_create_song() {
|
||||||
|
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||||
|
let db_name = db_mgr::generate_db_name().await;
|
||||||
|
|
||||||
|
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Success");
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
assert!(false, "Error: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||||
|
db::migrations(&pool).await;
|
||||||
|
|
||||||
|
let app = init::app(pool).await;
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
match song_queue_req(&app).await {
|
||||||
|
Ok(response) => {
|
||||||
|
let resp =
|
||||||
|
get_resp_data::<crate::callers::song::response::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::<crate::callers::song::response::Response>(response)
|
||||||
|
.await;
|
||||||
|
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||||
|
|
||||||
|
let id = resp.data[0];
|
||||||
|
|
||||||
|
match fetch_metadata_queue_req(&app, &id).await {
|
||||||
|
Ok(response) => {
|
||||||
|
let resp = get_resp_data::<
|
||||||
|
crate::callers::metadata::response::fetch_metadata::Response,
|
||||||
|
>(response)
|
||||||
|
.await;
|
||||||
|
assert_eq!(false, resp.data.is_empty(), "Data should not be empty");
|
||||||
|
let song_q_id = resp.data[0].song_queue_id;
|
||||||
|
|
||||||
|
let payload = serde_json::json!({
|
||||||
|
"title": "Power of Soul",
|
||||||
|
"artist": "Jimmi Hendrix",
|
||||||
|
"album_artist": "Jimmi Hendrix",
|
||||||
|
"album": "Machine Gun",
|
||||||
|
"genre": "Psychadelic Rock",
|
||||||
|
"date": "2016-01-01",
|
||||||
|
"track": 1,
|
||||||
|
"disc": 1,
|
||||||
|
"track_count": 11,
|
||||||
|
"disc_count": 1,
|
||||||
|
"duration": 330,
|
||||||
|
"audio_type": "flac",
|
||||||
|
"user_id": "d6e159c1-9648-4c85-81e5-52f502ff53e4",
|
||||||
|
"song_queue_id": song_q_id
|
||||||
|
});
|
||||||
|
|
||||||
|
eprintln!("Payload: {:?}", payload);
|
||||||
|
|
||||||
|
match app
|
||||||
|
.clone()
|
||||||
|
.oneshot(
|
||||||
|
axum::http::Request::builder()
|
||||||
|
.method(axum::http::Method::POST)
|
||||||
|
.uri(crate::callers::endpoints::CREATESONG)
|
||||||
|
.header(
|
||||||
|
axum::http::header::CONTENT_TYPE,
|
||||||
|
"application/json",
|
||||||
|
)
|
||||||
|
.body(axum::body::Body::from(payload.to_string()))
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
let resp = get_resp_data::<crate::callers::song::response::create_metadata::Response>(response).await;
|
||||||
|
assert_eq!(
|
||||||
|
false,
|
||||||
|
resp.data.is_empty(),
|
||||||
|
"No songs found, Response {:?}",
|
||||||
|
resp
|
||||||
|
);
|
||||||
|
let song = &resp.data[0];
|
||||||
|
let song_id = song.id;
|
||||||
|
assert_eq!(
|
||||||
|
false,
|
||||||
|
song_id.is_nil(),
|
||||||
|
"Song id should not be nil {:?}",
|
||||||
|
song
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
assert!(false, "Error: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
assert!(false, "Error: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
assert!(false, "Error: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
assert!(false, "Error: {:?}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user