use axum::{ extract::{Form, Path, State}, http::StatusCode, response::{IntoResponse, Redirect, Response}, routing::post, Router, }; use super::app::EventsError; use crate::{ app::App, clock::RequestedAt, error::InternalError, repo::{channel, login::Login}, }; pub fn router() -> Router { Router::new() .route("/create", post(on_create)) .route("/:channel/send", post(on_send)) } #[derive(serde::Deserialize)] struct CreateRequest { name: String, } async fn on_create( State(app): State, _: Login, // requires auth, but doesn't actually care who you are Form(form): Form, ) -> Result { app.channels().create(&form.name).await?; Ok(Redirect::to("/")) } #[derive(serde::Deserialize)] struct SendRequest { message: String, } async fn on_send( Path(channel): Path, RequestedAt(sent_at): RequestedAt, State(app): State, login: Login, Form(form): Form, ) -> Result { app.channels() .send(&login, &channel, &form.message, &sent_at) .await // Could impl `From` here, but it's more code and this is used once. .map_err(ErrorResponse)?; Ok(Redirect::to(&format!("/{}", channel))) } struct ErrorResponse(EventsError); impl IntoResponse for ErrorResponse { fn into_response(self) -> Response { let Self(error) = self; match error { not_found @ EventsError::ChannelNotFound(_) => { (StatusCode::NOT_FOUND, not_found.to_string()).into_response() } EventsError::DatabaseError(error) => InternalError::from(error).into_response(), } } }