//! 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, Json(SetStatusForm { status }): Json, ) -> 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>, (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") }