feat: add sort params to list/search, capo-aware GET /songs/{id}?apply_capo=true
This commit is contained in:
@@ -3,7 +3,7 @@ use axum::{
|
||||
http::StatusCode,
|
||||
Json,
|
||||
};
|
||||
use domain::RepositoryError;
|
||||
use domain::{ChordTransposer, RepositoryError, SortField, SortOrder};
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
@@ -11,6 +11,8 @@ use uuid::Uuid;
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListQuery {
|
||||
pub q: Option<String>,
|
||||
pub sort: Option<String>,
|
||||
pub order: Option<String>,
|
||||
}
|
||||
|
||||
use crate::routes::tabs::{AppState, ErrorResponse, ParseRequest, resolve_html};
|
||||
@@ -38,10 +40,19 @@ pub async fn list_songs(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Query(params): Query<ListQuery>,
|
||||
) -> Result<Json<Vec<domain::SongSummary>>, (StatusCode, Json<ErrorResponse>)> {
|
||||
let sort = match params.sort.as_deref() {
|
||||
Some("title") => SortField::Title,
|
||||
Some("artist") => SortField::Artist,
|
||||
_ => SortField::Date,
|
||||
};
|
||||
let order = match params.order.as_deref() {
|
||||
Some("asc") => SortOrder::Asc,
|
||||
_ => SortOrder::Desc,
|
||||
};
|
||||
let result = if let Some(q) = params.q.filter(|s| !s.is_empty()) {
|
||||
state.search.search(&q).await
|
||||
state.search.search(&q, sort, order).await
|
||||
} else {
|
||||
state.songs.list().await
|
||||
state.songs.list(sort, order).await
|
||||
};
|
||||
result
|
||||
.map(Json)
|
||||
@@ -80,19 +91,37 @@ pub async fn update_song(
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetSongQuery {
|
||||
pub apply_capo: Option<bool>,
|
||||
}
|
||||
|
||||
pub async fn get_song(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Path(id): Path<String>,
|
||||
Query(params): Query<GetSongQuery>,
|
||||
) -> Result<Json<domain::Song>, (StatusCode, Json<ErrorResponse>)> {
|
||||
let uuid = Uuid::parse_str(&id).map_err(|_| {
|
||||
(StatusCode::BAD_REQUEST, Json(ErrorResponse { error: "Invalid ID".into() }))
|
||||
})?;
|
||||
|
||||
match state.songs.get(uuid).await {
|
||||
Ok(Some(song)) => Ok(Json(song)),
|
||||
Ok(None) => Err((StatusCode::NOT_FOUND, Json(ErrorResponse { error: "Not found".into() }))),
|
||||
Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: e.to_string() }))),
|
||||
}
|
||||
let song = match state.songs.get(uuid).await {
|
||||
Ok(Some(s)) => s,
|
||||
Ok(None) => return Err((StatusCode::NOT_FOUND, Json(ErrorResponse { error: "Not found".into() }))),
|
||||
Err(e) => return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: e.to_string() }))),
|
||||
};
|
||||
|
||||
let song = if params.apply_capo.unwrap_or(false) {
|
||||
if let Some(capo) = song.meta.capo {
|
||||
ChordTransposer.transpose_song(&song, capo as i8)
|
||||
} else {
|
||||
song
|
||||
}
|
||||
} else {
|
||||
song
|
||||
};
|
||||
|
||||
Ok(Json(song))
|
||||
}
|
||||
|
||||
pub async fn delete_song(
|
||||
|
||||
Reference in New Issue
Block a user