diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2024-09-18 22:49:38 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2024-09-20 16:42:44 -0400 |
| commit | 22348bfa35f009e62abe2f30863e0434079a1fe2 (patch) | |
| tree | c5b5b5e660a1ee2a05785f4669102c1023b6e7b0 /src/index | |
| parent | aafdeb9ffaf9a993ca4462b3422667e04469b2e3 (diff) | |
Remove the HTML client, and expose a JSON API.
This API structure fell out of a conversation with Kit. Described loosely:
kit: ok
kit: Here's what I'm picturing in a client
kit: list channels, make-new-channel, zero to one active channels, post-to-active.
kit: login/sign-up, logout
owen: you will likely also want "am I logged in" here
kit: sure, whoami
Diffstat (limited to 'src/index')
| -rw-r--r-- | src/index/app.rs | 36 | ||||
| -rw-r--r-- | src/index/mod.rs | 3 | ||||
| -rw-r--r-- | src/index/routes.rs | 82 | ||||
| -rw-r--r-- | src/index/templates.rs | 127 |
4 files changed, 0 insertions, 248 deletions
diff --git a/src/index/app.rs b/src/index/app.rs deleted file mode 100644 index 4f234ee..0000000 --- a/src/index/app.rs +++ /dev/null @@ -1,36 +0,0 @@ -use sqlx::sqlite::SqlitePool; - -use crate::repo::{ - channel::{self, Channel, Provider as _}, - error::NotFound as _, -}; - -pub struct Index<'a> { - db: &'a SqlitePool, -} - -impl<'a> Index<'a> { - pub const fn new(db: &'a SqlitePool) -> Self { - Self { db } - } - - pub async fn channel(&self, channel: &channel::Id) -> Result<Channel, Error> { - let mut tx = self.db.begin().await?; - let channel = tx - .channels() - .by_id(channel) - .await - .not_found(|| Error::ChannelNotFound(channel.clone()))?; - tx.commit().await?; - - Ok(channel) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("channel {0} not found")] - ChannelNotFound(channel::Id), - #[error(transparent)] - DatabaseError(#[from] sqlx::Error), -} diff --git a/src/index/mod.rs b/src/index/mod.rs deleted file mode 100644 index 0d89a50..0000000 --- a/src/index/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod app; -pub mod routes; -mod templates; diff --git a/src/index/routes.rs b/src/index/routes.rs deleted file mode 100644 index 37f6dc9..0000000 --- a/src/index/routes.rs +++ /dev/null @@ -1,82 +0,0 @@ -use axum::{ - extract::{Path, State}, - http::{header, StatusCode}, - response::{IntoResponse, Response}, - routing::get, - Router, -}; -use maud::Markup; - -use super::{app, templates}; -use crate::{ - app::App, - error::InternalError, - repo::{channel, login::Login}, -}; - -async fn index(State(app): State<App>, login: Option<Login>) -> Result<Markup, InternalError> { - match login { - None => Ok(templates::unauthenticated()), - Some(login) => index_authenticated(app, login).await, - } -} - -async fn index_authenticated(app: App, login: Login) -> Result<Markup, InternalError> { - let channels = app.channels().all().await?; - - Ok(templates::authenticated(login, &channels)) -} - -#[derive(rust_embed::Embed)] -#[folder = "js"] -struct Js; - -async fn js(Path(path): Path<String>) -> impl IntoResponse { - let mime = mime_guess::from_path(&path).first_or_octet_stream(); - - match Js::get(&path) { - Some(file) => ( - StatusCode::OK, - [(header::CONTENT_TYPE, mime.as_ref())], - file.data, - ) - .into_response(), - None => (StatusCode::NOT_FOUND, "").into_response(), - } -} - -async fn channel( - State(app): State<App>, - _: Login, - Path(channel): Path<channel::Id>, -) -> Result<Markup, ChannelError> { - let channel = app - .index() - .channel(&channel) - .await - // impl From would work here, but it'd take more code. - .map_err(ChannelError)?; - Ok(templates::channel(&channel)) -} - -#[derive(Debug)] -struct ChannelError(app::Error); - -impl IntoResponse for ChannelError { - fn into_response(self) -> Response { - let Self(error) = self; - match error { - not_found @ app::Error::ChannelNotFound(_) => { - (StatusCode::NOT_FOUND, not_found.to_string()).into_response() - } - app::Error::DatabaseError(error) => InternalError::from(error).into_response(), - } - } -} - -pub fn router() -> Router<App> { - Router::new() - .route("/", get(index)) - .route("/js/*path", get(js)) - .route("/:channel", get(channel)) -} diff --git a/src/index/templates.rs b/src/index/templates.rs deleted file mode 100644 index d56972c..0000000 --- a/src/index/templates.rs +++ /dev/null @@ -1,127 +0,0 @@ -use maud::{html, Markup, DOCTYPE}; - -use crate::repo::{channel::Channel, login::Login}; - -pub fn authenticated<'c>(login: Login, channels: impl IntoIterator<Item = &'c Channel>) -> Markup { - html! { - (DOCTYPE) - head { - title { "hi" } - } - body { - section { - (channel_list(channels)) - (create_channel()) - } - section { - (logout_form(&login.name)) - } - } - } -} - -fn channel_list<'c>(channels: impl IntoIterator<Item = &'c Channel>) -> Markup { - html! { - ul { - @for channel in channels { - (channel_list_entry(&channel)) - } - } - } -} - -fn channel_list_entry(channel: &Channel) -> Markup { - html! { - li { - a href=(format!("/{}", channel.id)) { - (channel.name) " (" (channel.id) ")" - } - } - } -} - -fn create_channel() -> Markup { - html! { - form action="/create" method="post" { - label { - "name" - input name="name" type="text" {} - } - button { - "start channel" - } - } - } -} - -fn logout_form(name: &str) -> Markup { - html! { - form action="/logout" method="post" { - button { "bye, " (name) } - } - } -} - -pub fn unauthenticated() -> Markup { - html! { - (DOCTYPE) - head { - title { "hi" } - } - body { - (login_form()) - } - } -} - -fn login_form() -> Markup { - html! { - form action="/login" method="post" { - label { - "login" - input name="name" type="text" {} - } - label { - "password" - input name="password" type="password" {} - } - button { "hi" } - } - } -} - -pub fn channel(channel: &Channel) -> Markup { - html! { - (DOCTYPE) - head { - title { "hi - " (channel.name) } - script src="/js/channel.js" {} - template id="message" { - p { - span.sender { "(sender)" } - ": " - span.message { "(message)" } - " (at " - span.sent_at { "(sent_at)" } - ")" } - } - meta name="channel" content=(channel.id) {} - link rel="events" href=(format!("/events?channel={}", channel.id)) {} - } - body { - section class="messages" {} - section { - form action=(format!("/{}/send", channel.id)) method="post" { - label { - "message" - input name="message" type="text" autofocus {} - } - button { "send" } - } - } - section { - a href="/" { "back" } - } - } - } -} |
