implement bare basic functionality!!!

This commit is contained in:
Schrottkatze 2024-10-04 20:18:36 +02:00
parent 5f9bb732b8
commit ed87d3fb51
Signed by: schrottkatze
SSH key fingerprint: SHA256:hXb3t1vINBFCiDCmhRABHX5ocdbLiKyCdKI4HK2Rbbc
7 changed files with 238 additions and 13 deletions

View file

@ -4,14 +4,16 @@ version = "0.1.0"
edition = "2021"
[dependencies]
http = "1"
axum = { version = "0.7.5", features = [ "json", "macros" ] }
axum-macros = "0.4.1"
chrono = { version = "0.4", features = [ "serde" ] }
chrono-tz = "0.10.0"
maud = "0.26.0"
sqlx = { version = "0.8.2", features = ["postgres", "runtime-tokio", "tls-rustls-ring", "uuid" ] }
tokio = { version = "1.40.0", features = ["full"] }
sqlx = { version = "0.8.2", features = [ "postgres", "runtime-tokio", "tls-rustls-ring", "uuid", "chrono" ] }
tokio = { version = "1.40.0", features = [ "full" ] }
tokio-tungstenite = "0.24.0"
serde = { version = "1", features = ["derive"] }
serde = { version = "1", features = [ "derive" ] }
anyhow = "1"
uuid = { version = "1.10.0", features = ["serde"] }
uuid = { version = "1.10.0", features = [ "serde" ] }
rand = "0.8.5"

View file

@ -10,8 +10,10 @@ create table chats (
create table messages (
id uuid default (gen_random_uuid()) primary key,
timestamp timestamptz default (now()),
timestamp timestamptz not null default (now()),
chat_id uuid not null references chats(id),
content varchar(2000) not null,
from_admin boolean not null
)
);
insert into chats (url_path) values ('tstcht');

View file

@ -1,18 +1,28 @@
use axum::{
extract::{Path, State},
response::Html,
Json,
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};
use crate::{
model::{Chat, Message},
ADMIN_TOK,
};
pub async fn get(
Path(url_path): Path<String>,
headers: HeaderMap,
State(pool): State<Pool<Postgres>>,
) -> Json<Vec<Message>> {
) -> 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
@ -25,5 +35,74 @@ pub async fn get(
.fetch_all(&pool)
.await
.unwrap();
Json(messages)
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<String>,
headers: HeaderMap,
State(pool): State<Pool<Postgres>>,
Form(FormMessageBody { msgcontent: body }): Form<FormMessageBody>,
) -> 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,
}

View file

@ -17,7 +17,7 @@ async fn main() -> anyhow::Result<()> {
let app = Router::new()
.route("/", get(|| async { "<h1>gay</h1>" }))
.route("/:path", get(chat::get))
.route("/:path", get(chat::get).post(chat::post))
.with_state(pool.clone())
.nest("/stat", stat::router(pool.clone()))
.nest("/admin", admin::router(pool.clone()));

View file

@ -1,3 +1,4 @@
use chrono::{DateTime, FixedOffset, Local, Utc};
use serde::Serialize;
use sqlx::{prelude::FromRow, Decode, Encode};
use uuid::Uuid;
@ -15,6 +16,7 @@ pub struct Message {
// Uuid but sqlx doesnt impl serde traits for them
pub id: Uuid,
pub chat_id: Uuid,
pub timestamp: DateTime<Utc>,
pub content: String,
pub from_admin: bool,