diff options
| author | Kit La Touche <kit@transneptune.net> | 2024-10-03 23:30:42 -0400 |
|---|---|---|
| committer | Kit La Touche <kit@transneptune.net> | 2024-10-03 23:30:42 -0400 |
| commit | d50b1b56c011c03c7d8a95242af404b727e91a80 (patch) | |
| tree | efe3408f6a8ef669981826d1a29d16a24b460d89 /src/channel/routes.rs | |
| parent | 30c13478d61065a512f5bc8824fecbf2ee6afc81 (diff) | |
| parent | 7f12fd41c2941a55a6437f24e4f780104a718790 (diff) | |
Merge branch 'main' into feature-frontend
Diffstat (limited to 'src/channel/routes.rs')
| -rw-r--r-- | src/channel/routes.rs | 122 |
1 files changed, 104 insertions, 18 deletions
diff --git a/src/channel/routes.rs b/src/channel/routes.rs index 1f8db5a..23c0602 100644 --- a/src/channel/routes.rs +++ b/src/channel/routes.rs @@ -2,20 +2,19 @@ use axum::{ extract::{Json, Path, State}, http::StatusCode, response::{IntoResponse, Response}, - routing::{get, post}, + routing::{delete, get, post}, Router, }; +use axum_extra::extract::Query; -use super::app; +use super::{app, Channel, Id}; use crate::{ app::App, clock::RequestedAt, error::Internal, - events::app::EventsError, - repo::{ - channel::{self, Channel}, - login::Login, - }, + event::{Instant, Sequence}, + login::Login, + message::{self, app::SendError}, }; #[cfg(test)] @@ -26,10 +25,21 @@ pub fn router() -> Router<App> { .route("/api/channels", get(list)) .route("/api/channels", post(on_create)) .route("/api/channels/:channel", post(on_send)) + .route("/api/channels/:channel", delete(on_delete)) + .route("/api/channels/:channel/messages", get(messages)) } -async fn list(State(app): State<App>, _: Login) -> Result<Channels, Internal> { - let channels = app.channels().all().await?; +#[derive(Default, serde::Deserialize)] +struct ResumeQuery { + resume_point: Option<Sequence>, +} + +async fn list( + State(app): State<App>, + _: Login, + Query(query): Query<ResumeQuery>, +) -> Result<Channels, Internal> { + let channels = app.channels().all(query.resume_point).await?; let response = Channels(channels); Ok(response) @@ -86,31 +96,107 @@ struct SendRequest { async fn on_send( State(app): State<App>, - Path(channel): Path<channel::Id>, + Path(channel): Path<Id>, RequestedAt(sent_at): RequestedAt, login: Login, Json(request): Json<SendRequest>, +) -> Result<StatusCode, SendErrorResponse> { + app.messages() + .send(&channel, &login, &sent_at, &request.message) + .await?; + + Ok(StatusCode::ACCEPTED) +} + +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +struct SendErrorResponse(#[from] SendError); + +impl IntoResponse for SendErrorResponse { + fn into_response(self) -> Response { + let Self(error) = self; + match error { + not_found @ SendError::ChannelNotFound(_) => { + (StatusCode::NOT_FOUND, not_found.to_string()).into_response() + } + other => Internal::from(other).into_response(), + } + } +} + +async fn on_delete( + State(app): State<App>, + Path(channel): Path<Id>, + RequestedAt(deleted_at): RequestedAt, + _: Login, ) -> Result<StatusCode, ErrorResponse> { - app.events() - .send(&login, &channel, &request.message, &sent_at) - .await - // Could impl `From` here, but it's more code and this is used once. - .map_err(ErrorResponse)?; + app.channels().delete(&channel, &deleted_at).await?; Ok(StatusCode::ACCEPTED) } -#[derive(Debug)] -struct ErrorResponse(EventsError); +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +struct ErrorResponse(#[from] app::Error); impl IntoResponse for ErrorResponse { fn into_response(self) -> Response { let Self(error) = self; match error { - not_found @ EventsError::ChannelNotFound(_) => { + not_found @ app::Error::NotFound(_) => { (StatusCode::NOT_FOUND, not_found.to_string()).into_response() } other => Internal::from(other).into_response(), } } } + +async fn messages( + State(app): State<App>, + Path(channel): Path<Id>, + _: Login, + Query(query): Query<ResumeQuery>, +) -> Result<Messages, ErrorResponse> { + let messages = app + .channels() + .messages(&channel, query.resume_point) + .await?; + let response = Messages( + messages + .into_iter() + .map(|message| MessageView { + sent: message.sent, + sender: message.sender, + message: MessageInner { + id: message.id, + body: message.body, + }, + }) + .collect(), + ); + + Ok(response) +} + +struct Messages(Vec<MessageView>); + +#[derive(serde::Serialize)] +struct MessageView { + #[serde(flatten)] + sent: Instant, + sender: Login, + message: MessageInner, +} + +#[derive(serde::Serialize)] +struct MessageInner { + id: message::Id, + body: String, +} + +impl IntoResponse for Messages { + fn into_response(self) -> Response { + let Self(messages) = self; + Json(messages).into_response() + } +} |
