use axum::{
extract::{Path, State},
routing::get,
Json, Router,
};
use reposix_core::RecordStatus;
use rusqlite::params;
use serde::Serialize;
use crate::{error::ApiError, routes::issues, AppState};
const ALL_STATUSES: [RecordStatus; 5] = [
RecordStatus::Open,
RecordStatus::InProgress,
RecordStatus::InReview,
RecordStatus::Done,
RecordStatus::WontFix,
];
pub fn router(state: AppState) -> Router {
Router::new()
.route(
"/projects/{slug}/issues/{id}/transitions",
get(get_transitions),
)
.with_state(state)
}
#[derive(Debug, Serialize)]
struct TransitionsResponse {
current_state: String,
available: Vec<String>,
}
#[allow(clippy::unused_async)]
async fn get_transitions(
State(state): State<AppState>,
Path((slug, id)): Path<(String, u64)>,
) -> Result<Json<TransitionsResponse>, ApiError> {
#[allow(clippy::cast_possible_wrap)]
let id_signed = id as i64;
let current_raw: String = {
let conn = state.db.lock();
match conn.query_row(
"SELECT status FROM issues WHERE project = ?1 AND id = ?2",
params![slug, id_signed],
|r| r.get::<_, String>(0),
) {
Ok(s) => s,
Err(rusqlite::Error::QueryReturnedNoRows) => return Err(ApiError::NotFound),
Err(e) => return Err(ApiError::Db(e)),
}
};
let current = issues::parse_status_shared(¤t_raw)?;
let available: Vec<String> = ALL_STATUSES
.iter()
.filter(|s| **s as u8 != current as u8)
.map(|s| s.as_str().to_owned())
.collect();
Ok(Json(TransitionsResponse {
current_state: current.as_str().to_owned(),
available,
}))
}