diff options
Diffstat (limited to 'src/channel/routes')
| -rw-r--r-- | src/channel/routes/channel/delete.rs | 39 | ||||
| -rw-r--r-- | src/channel/routes/channel/mod.rs | 9 | ||||
| -rw-r--r-- | src/channel/routes/channel/post.rs | 47 | ||||
| -rw-r--r-- | src/channel/routes/channel/test.rs (renamed from src/channel/routes/test/on_send.rs) | 12 | ||||
| -rw-r--r-- | src/channel/routes/mod.rs | 19 | ||||
| -rw-r--r-- | src/channel/routes/post.rs | 49 | ||||
| -rw-r--r-- | src/channel/routes/test.rs (renamed from src/channel/routes/test/on_create.rs) | 37 | ||||
| -rw-r--r-- | src/channel/routes/test/mod.rs | 2 |
8 files changed, 185 insertions, 29 deletions
diff --git a/src/channel/routes/channel/delete.rs b/src/channel/routes/channel/delete.rs new file mode 100644 index 0000000..efac0c0 --- /dev/null +++ b/src/channel/routes/channel/delete.rs @@ -0,0 +1,39 @@ +use axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Response}, +}; + +use crate::{ + app::App, + channel::app, + clock::RequestedAt, + error::{Internal, NotFound}, + login::Login, +}; + +pub async fn handler( + State(app): State<App>, + Path(channel): Path<super::PathInfo>, + RequestedAt(deleted_at): RequestedAt, + _: Login, +) -> Result<StatusCode, Error> { + app.channels().delete(&channel, &deleted_at).await?; + + Ok(StatusCode::ACCEPTED) +} + +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct Error(#[from] pub app::Error); + +impl IntoResponse for Error { + fn into_response(self) -> Response { + let Self(error) = self; + #[allow(clippy::match_wildcard_for_single_variants)] + match error { + app::Error::NotFound(_) => NotFound(error).into_response(), + other => Internal::from(other).into_response(), + } + } +} diff --git a/src/channel/routes/channel/mod.rs b/src/channel/routes/channel/mod.rs new file mode 100644 index 0000000..31a9142 --- /dev/null +++ b/src/channel/routes/channel/mod.rs @@ -0,0 +1,9 @@ +use crate::channel::Id; + +pub mod delete; +pub mod post; + +#[cfg(test)] +mod test; + +type PathInfo = Id; diff --git a/src/channel/routes/channel/post.rs b/src/channel/routes/channel/post.rs new file mode 100644 index 0000000..a71a3a0 --- /dev/null +++ b/src/channel/routes/channel/post.rs @@ -0,0 +1,47 @@ +use axum::{ + extract::{Json, Path, State}, + http::StatusCode, + response::{IntoResponse, Response}, +}; + +use crate::{ + app::App, + clock::RequestedAt, + error::{Internal, NotFound}, + login::Login, + message::app::SendError, +}; + +pub async fn handler( + State(app): State<App>, + Path(channel): Path<super::PathInfo>, + RequestedAt(sent_at): RequestedAt, + login: Login, + Json(request): Json<Request>, +) -> Result<StatusCode, Error> { + app.messages() + .send(&channel, &login, &sent_at, &request.body) + .await?; + + Ok(StatusCode::ACCEPTED) +} + +#[derive(serde::Deserialize)] +pub struct Request { + pub body: String, +} + +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct Error(#[from] pub SendError); + +impl IntoResponse for Error { + fn into_response(self) -> Response { + let Self(error) = self; + #[allow(clippy::match_wildcard_for_single_variants)] + match error { + SendError::ChannelNotFound(_) => NotFound(error).into_response(), + other => Internal::from(other).into_response(), + } + } +} diff --git a/src/channel/routes/test/on_send.rs b/src/channel/routes/channel/test.rs index 293cc56..bc02b20 100644 --- a/src/channel/routes/test/on_send.rs +++ b/src/channel/routes/channel/test.rs @@ -1,9 +1,9 @@ use axum::extract::{Json, Path, State}; use futures::stream::StreamExt; +use super::post; use crate::{ channel, - channel::routes, event::{self, Sequenced}, message::{self, app::SendError}, test::fixtures::{self, future::Immediately as _}, @@ -25,14 +25,14 @@ async fn messages_in_order() { ]; for (sent_at, body) in &requests { - let request = routes::SendRequest { body: body.clone() }; + let request = post::Request { body: body.clone() }; - routes::on_send( + post::handler( State(app.clone()), Path(channel.id.clone()), sent_at.clone(), sender.clone(), - Json(request.clone()), + Json(request), ) .await .expect("sending to a valid channel"); @@ -72,10 +72,10 @@ async fn nonexistent_channel() { let sent_at = fixtures::now(); let channel = channel::Id::generate(); - let request = routes::SendRequest { + let request = post::Request { body: fixtures::message::propose(), }; - let routes::SendErrorResponse(error) = routes::on_send( + let post::Error(error) = post::handler( State(app), Path(channel.clone()), sent_at, diff --git a/src/channel/routes/mod.rs b/src/channel/routes/mod.rs new file mode 100644 index 0000000..696bd72 --- /dev/null +++ b/src/channel/routes/mod.rs @@ -0,0 +1,19 @@ +use axum::{ + routing::{delete, post}, + Router, +}; + +use crate::app::App; + +mod channel; +mod post; + +#[cfg(test)] +mod test; + +pub fn router() -> Router<App> { + Router::new() + .route("/api/channels", post(post::handler)) + .route("/api/channels/:channel", post(channel::post::handler)) + .route("/api/channels/:channel", delete(channel::delete::handler)) +} diff --git a/src/channel/routes/post.rs b/src/channel/routes/post.rs new file mode 100644 index 0000000..d694f8b --- /dev/null +++ b/src/channel/routes/post.rs @@ -0,0 +1,49 @@ +use axum::{ + extract::{Json, State}, + http::StatusCode, + response::{self, IntoResponse}, +}; + +use crate::{ + app::App, + channel::{app, Channel}, + clock::RequestedAt, + error::Internal, + login::Login, +}; + +pub async fn handler( + State(app): State<App>, + _: Login, // requires auth, but doesn't actually care who you are + RequestedAt(created_at): RequestedAt, + Json(request): Json<Request>, +) -> Result<Json<Channel>, Error> { + let channel = app + .channels() + .create(&request.name, &created_at) + .await + .map_err(Error)?; + + Ok(Json(channel)) +} + +#[derive(serde::Deserialize)] +pub struct Request { + pub name: String, +} + +#[derive(Debug)] +pub struct Error(pub app::CreateError); + +impl IntoResponse for Error { + fn into_response(self) -> response::Response { + let Self(error) = self; + #[allow(clippy::match_wildcard_for_single_variants)] + match error { + app::CreateError::DuplicateName(_) => { + (StatusCode::CONFLICT, error.to_string()).into_response() + } + other => Internal::from(other).into_response(), + } + } +} diff --git a/src/channel/routes/test/on_create.rs b/src/channel/routes/test.rs index eeecc7f..81f1465 100644 --- a/src/channel/routes/test/on_create.rs +++ b/src/channel/routes/test.rs @@ -1,8 +1,9 @@ use axum::extract::{Json, State}; use futures::stream::StreamExt as _; +use super::post; use crate::{ - channel::{self, app, routes}, + channel::{self, app}, event, test::fixtures::{self, future::Immediately as _}, }; @@ -17,19 +18,15 @@ async fn new_channel() { // Call the endpoint let name = fixtures::channel::propose(); - let request = routes::CreateRequest { name }; - let Json(response_channel) = routes::on_create( - State(app.clone()), - creator, - fixtures::now(), - Json(request.clone()), - ) - .await - .expect("new channel in an empty app"); + let request = post::Request { name: name.clone() }; + let Json(response_channel) = + post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + .await + .expect("new channel in an empty app"); // Verify the structure of the response - assert_eq!(request.name, response_channel.name); + assert_eq!(name, response_channel.name); // Verify the semantics @@ -69,20 +66,18 @@ async fn duplicate_name() { // Call the endpoint - let request = routes::CreateRequest { name: channel.name }; - let routes::CreateError(error) = routes::on_create( - State(app.clone()), - creator, - fixtures::now(), - Json(request.clone()), - ) - .await - .expect_err("duplicate channel name"); + let request = post::Request { + name: channel.name.clone(), + }; + let post::Error(error) = + post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + .await + .expect_err("duplicate channel name should fail the request"); // Verify the structure of the response assert!(matches!( error, - app::CreateError::DuplicateName(name) if request.name == name + app::CreateError::DuplicateName(name) if channel.name == name )); } diff --git a/src/channel/routes/test/mod.rs b/src/channel/routes/test/mod.rs deleted file mode 100644 index 3e5aa17..0000000 --- a/src/channel/routes/test/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod on_create; -mod on_send; |
