use axum::{ extract::{FromRef, Path, State}, http::{ header::{ACCEPT, CONTENT_TYPE}, HeaderMap, HeaderValue, StatusCode, }, response::{Html, IntoResponse, Redirect}, Form, Json, }; use maud::{html, Render}; use serde::{Deserialize, Serialize}; use sqlx::{Pool, Postgres}; use uuid::Uuid; use crate::{ model::{Chat, Message}, ADMIN_TOK, }; pub async fn get( Path(url_path): Path, headers: HeaderMap, State(pool): State>, ) -> impl IntoResponse { println!("headers: {headers:#?}"); let chat = sqlx::query_as!(Chat, r#"select * from chats where url_path = $1"#, url_path) .fetch_one(&pool) .await .unwrap(); let messages = sqlx::query_as!( Message, r#"select * from messages where chat_id = $1"#, chat.id ) .fetch_all(&pool) .await .unwrap(); if Some(&HeaderValue::from_static("application/json")) == headers.get(ACCEPT) { Json(messages).into_response() } else { Html( html! { main { div #history { @for msg in &messages { div.message.(if msg.from_admin { "from_admin" } else { "from_user" }) { p { (msg.content) "(" (msg.timestamp) ")" } } } } form #send method="post"{ textarea #msgcontent name="msgcontent" rows="1" cols="80" {} button type="submit" { "Send!" } } } } .into_string(), ) .into_response() } } // TODO: // - validation of msg length // - fix terrible returns lmao pub async fn post( Path(url_path): Path, headers: HeaderMap, State(pool): State>, Form(FormMessageBody { msgcontent: body }): Form, ) -> impl IntoResponse { let chat = sqlx::query_as!(Chat, r#"select * from chats where url_path = $1"#, url_path) .fetch_one(&pool) .await .unwrap(); if body.len() > 2000 { return StatusCode::BAD_REQUEST.into_response(); } if headers.get("x-admin-tok") == Some(&HeaderValue::from_static(ADMIN_TOK)) { sqlx::query!( r#"insert into messages (chat_id, content, from_admin) values ($1, $2, true);"#, chat.id, body ) .execute(&pool) .await .unwrap(); StatusCode::OK.into_response() } else { sqlx::query!( r#"insert into messages (chat_id, content, from_admin) values ($1, $2, false);"#, chat.id, body ) .execute(&pool) .await .unwrap(); Redirect::to(&format!("/{url_path}")).into_response() } } #[derive(Debug, Serialize, Deserialize)] pub struct FormMessageBody { msgcontent: String, }