summaryrefslogtreecommitdiff
path: root/src/index
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-09-18 22:49:38 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-09-20 16:42:44 -0400
commit22348bfa35f009e62abe2f30863e0434079a1fe2 (patch)
treec5b5b5e660a1ee2a05785f4669102c1023b6e7b0 /src/index
parentaafdeb9ffaf9a993ca4462b3422667e04469b2e3 (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.rs36
-rw-r--r--src/index/mod.rs3
-rw-r--r--src/index/routes.rs82
-rw-r--r--src/index/templates.rs127
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" }
- }
- }
- }
-}