1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
use axum::{
extract::{Json, Path, State},
http::StatusCode,
response::{IntoResponse, Response},
routing::{delete, get, post},
Router,
};
use axum_extra::extract::Query;
use super::{
app::{self, DeleteError},
Channel, Id,
};
use crate::{
app::App, clock::RequestedAt, error::Internal, event::Sequence, login::Login,
message::app::SendError,
};
#[cfg(test)]
mod test;
pub fn router() -> Router<App> {
Router::new()
.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))
}
#[derive(Default, serde::Deserialize)]
struct ListQuery {
resume_point: Option<Sequence>,
}
async fn list(
State(app): State<App>,
_: Login,
Query(query): Query<ListQuery>,
) -> Result<Channels, Internal> {
let channels = app.channels().all(query.resume_point).await?;
let response = Channels(channels);
Ok(response)
}
struct Channels(Vec<Channel>);
impl IntoResponse for Channels {
fn into_response(self) -> Response {
let Self(channels) = self;
Json(channels).into_response()
}
}
#[derive(Clone, serde::Deserialize)]
struct CreateRequest {
name: String,
}
async fn on_create(
State(app): State<App>,
_: Login, // requires auth, but doesn't actually care who you are
RequestedAt(created_at): RequestedAt,
Json(form): Json<CreateRequest>,
) -> Result<Json<Channel>, CreateError> {
let channel = app
.channels()
.create(&form.name, &created_at)
.await
.map_err(CreateError)?;
Ok(Json(channel))
}
#[derive(Debug)]
struct CreateError(app::CreateError);
impl IntoResponse for CreateError {
fn into_response(self) -> Response {
let Self(error) = self;
match error {
duplicate @ app::CreateError::DuplicateName(_) => {
(StatusCode::BAD_REQUEST, duplicate.to_string()).into_response()
}
other => Internal::from(other).into_response(),
}
}
}
#[derive(Clone, serde::Deserialize)]
struct SendRequest {
message: String,
}
async fn on_send(
State(app): State<App>,
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, DeleteErrorResponse> {
app.channels().delete(&channel, &deleted_at).await?;
Ok(StatusCode::ACCEPTED)
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
struct DeleteErrorResponse(#[from] DeleteError);
impl IntoResponse for DeleteErrorResponse {
fn into_response(self) -> Response {
let Self(error) = self;
match error {
not_found @ DeleteError::NotFound(_) => {
(StatusCode::NOT_FOUND, not_found.to_string()).into_response()
}
other => Internal::from(other).into_response(),
}
}
}
|