cargagep-v2/src/api/bikes.rs
2026-08-24 12:00:58 +02:00

66 lines
1.9 KiB
Rust

//! Read-only view of the fleet, used by the reservation form to show which
//! cargo bikes can be picked.
use aide::{
axum::{
ApiRouter,
routing::{get_with, put_with},
},
transform::TransformOperation,
};
use axum::{Json, extract::Path, http::StatusCode};
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
api::helpers::{IdPath, admin, admin_desc, unexpected_error},
core::{
controller::{AnonAppController, AppController},
models::bike::{Bike, BikeStatus},
},
};
pub fn routes() -> ApiRouter {
ApiRouter::new()
.api_route("/", get_with(get_bikes, get_bikes_docs))
.api_route("/{id}/status", put_with(set_status, set_status_docs))
}
#[derive(Debug, Deserialize, JsonSchema)]
struct SetStatusForm {
status: BikeStatus,
}
/// Takes a bike in or out of the fleet. Deleting is not offered: a bike that
/// has been booked must stay, for the history.
#[axum::debug_handler]
async fn set_status(
ac: AppController,
Path(IdPath { id }): Path<IdPath>,
Json(SetStatusForm { status }): Json<SetStatusForm>,
) -> Result<(), (StatusCode, String)> {
match admin(ac)?.set_bike_status(id, status).await {
Ok(()) => Ok(()),
Err(err) if err.is_not_found() => Err((StatusCode::NOT_FOUND, "No such bike".to_owned())),
Err(err) => unexpected_error("set_bike_status", err),
}
}
fn set_status_docs(op: TransformOperation) -> TransformOperation {
op.tag("Bikes")
.summary("Put a bike in or out of service")
.response_with::<403, (), _>(admin_desc)
.response::<404, ()>()
}
#[axum::debug_handler]
async fn get_bikes(aac: AnonAppController) -> Result<Json<Vec<Bike>>, (StatusCode, String)> {
match aac.get_bikes().await {
Ok(bikes) => Ok(Json(bikes)),
Err(err) => unexpected_error("get_bikes", err),
}
}
fn get_bikes_docs(op: TransformOperation) -> TransformOperation {
op.tag("Bikes").summary("Get the fleet")
}