From 26de7b3cc4140c35775297759e3cc9b3ef71346d Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 19 Oct 2023 02:54:47 +0200 Subject: [PATCH] add root template --- migrations/20231018134946_init.sql | 1 + src/main.rs | 22 +++++----------- src/model/user.rs | 38 +++++++++++++++++++++++++++- src/pages/index.rs | 9 +++++++ src/pages/mod.rs | 2 ++ src/pages/user/mod.rs | 40 ++++++++++++++++++++++++++++++ src/templates.rs | 36 +++++++++++++++++++++++++-- templates/error.hbs | 5 ++++ templates/index.hbs | 5 ++++ templates/root.hbs | 4 +-- 10 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 src/pages/index.rs create mode 100644 src/pages/mod.rs create mode 100644 src/pages/user/mod.rs create mode 100644 templates/error.hbs create mode 100644 templates/index.hbs diff --git a/migrations/20231018134946_init.sql b/migrations/20231018134946_init.sql index 2aeb942..9ed5b85 100644 --- a/migrations/20231018134946_init.sql +++ b/migrations/20231018134946_init.sql @@ -2,6 +2,7 @@ CREATE TABLE users ( id SERIAL PRIMARY KEY, username TEXT NOT NULL UNIQUE, password TEXT NOT NULL, + role INTEGER NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), last_active TIMESTAMPTZ NOT NULL DEFAULT now() diff --git a/src/main.rs b/src/main.rs index 35fc4be..2641775 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,27 @@ pub mod config; pub mod model; +pub mod pages; pub mod state; pub mod templates; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; -use axum::extract::State; -use axum::http::{header, StatusCode}; -use axum::response::IntoResponse; use axum::{routing::get, Router}; use clap::Parser; use eyre::{Result, WrapErr}; use sqlx::migrate; use sqlx::postgres::PgPoolOptions; use tower_http::trace::TraceLayer; -use tracing::{debug, error, info}; +use tracing::{debug, info}; use crate::config::Config; use crate::state::AppState; use crate::templates::handlebars; +use crate::pages::index::index; +use crate::pages::user::get_user; + #[tokio::main] async fn main() -> Result<()> { dotenvy::dotenv().ok(); @@ -51,6 +52,7 @@ async fn main() -> Result<()> { let app = Router::new() .route("/", get(index)) + .route("/users/:id", get(get_user)) .layer(TraceLayer::new_for_http()) .with_state(state); @@ -62,15 +64,3 @@ async fn main() -> Result<()> { .await .wrap_err("running server") } - -async fn index(State(state): State>) -> impl IntoResponse { - let out = match state.hbs.render("root.hbs", &16) { - Ok(s) => s, - Err(err) => { - error!("Rendering index page: {}", err); - return (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response(); - } - }; - - return ([(header::CONTENT_TYPE, "text/html")], out).into_response(); -} diff --git a/src/model/user.rs b/src/model/user.rs index c020ced..c0ed2ca 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -1,12 +1,48 @@ use chrono::{DateTime, Utc}; -use serde::Serialize; +use serde::{Serialize, Serializer}; #[derive(Debug, Serialize)] pub struct User { pub id: i32, pub username: String, pub password: String, + pub role: Role, pub created_at: DateTime, pub last_active: DateTime, } + +#[derive(sqlx::Type, Debug)] +#[repr(i32)] +pub enum Role { + Viewer = 1, + Editor = 2, + Manager = 3, + Admin = 4, +} + +impl Serialize for Role { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(match self { + Role::Viewer => "viwer", + Role::Editor => "editor", + Role::Manager => "manager", + Role::Admin => "admin", + }) + } +} + +impl From for Role { + fn from(value: i32) -> Self { + match value { + 1 => Self::Viewer, + 2 => Self::Editor, + 3 => Self::Manager, + 4 => Self::Admin, + _ => unreachable!("Role should never be outside 1-4") + } + } +} diff --git a/src/pages/index.rs b/src/pages/index.rs new file mode 100644 index 0000000..610eebf --- /dev/null +++ b/src/pages/index.rs @@ -0,0 +1,9 @@ +use std::sync::Arc; + +use axum::{extract::State, response::IntoResponse}; + +use crate::{state::AppState, templates::{Page, PageData}}; + +pub async fn index(State(state): State>) -> impl IntoResponse { + Page::new(state.hbs.render::("index.hbs", &Default::default())) +} diff --git a/src/pages/mod.rs b/src/pages/mod.rs new file mode 100644 index 0000000..7835bce --- /dev/null +++ b/src/pages/mod.rs @@ -0,0 +1,2 @@ +pub mod index; +pub mod user; diff --git a/src/pages/user/mod.rs b/src/pages/user/mod.rs new file mode 100644 index 0000000..dfb2745 --- /dev/null +++ b/src/pages/user/mod.rs @@ -0,0 +1,40 @@ +use std::sync::Arc; + +use axum::{ + extract::{Path, State}, + response::IntoResponse, +}; +use sqlx::query_as; +use tracing::error; + +use crate::{ + model::user::User, + state::AppState, + templates::{Page, PageData}, +}; + +pub async fn get_user( + State(state): State>, + Path(user_id): Path, +) -> impl IntoResponse { + let user = match query_as!(User, r#"SELECT * FROM users WHERE id = $1"#, user_id) + .fetch_one(&state.pool) + .await + { + Ok(user) => user, + Err(why) => { + error!("Getting user: {}", why); + return Page::new( + state + .hbs + .render::("error.hbs", &Default::default()), + ); + } + }; + + Page::new( + state + .hbs + .render("error.hbs", &PageData { user: Some(user) }), + ) +} diff --git a/src/templates.rs b/src/templates.rs index 95f13a1..34a944c 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -1,7 +1,14 @@ +use axum::{ + http::{header, StatusCode}, + response::IntoResponse, +}; use eyre::{Context, Result}; -use handlebars::Handlebars; +use handlebars::{Handlebars, RenderError}; use rust_embed::RustEmbed; -use tracing::info; +use serde::Serialize; +use tracing::{error, info}; + +use crate::model::user::User; #[derive(RustEmbed)] #[folder = "templates/"] @@ -23,3 +30,28 @@ pub fn handlebars(dev_mode: bool) -> Result> { Ok(hbs) } + +pub struct Page(Result); + +impl Page { + pub fn new(res: Result) -> Self { + Self(res) + } +} + +impl IntoResponse for Page { + fn into_response(self) -> axum::response::Response { + match self.0 { + Ok(s) => ([(header::CONTENT_TYPE, "text/html; charset=utf-8")], s).into_response(), + Err(why) => { + error!("Error rendering page: {}", why); + (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response() + } + } + } +} + +#[derive(Debug, Default, Serialize)] +pub struct PageData { + pub user: Option, +} diff --git a/templates/error.hbs b/templates/error.hbs new file mode 100644 index 0000000..83575f2 --- /dev/null +++ b/templates/error.hbs @@ -0,0 +1,5 @@ +{{#*inline "page"}} +

Error

+

An internal error occurred. Sorry :(

+{{/inline}} +{{> root.hbs}} diff --git a/templates/index.hbs b/templates/index.hbs new file mode 100644 index 0000000..9bdec24 --- /dev/null +++ b/templates/index.hbs @@ -0,0 +1,5 @@ +{{#*inline "page"}} +

board!

+

this will be a site eventually

+{{/inline}} +{{> root.hbs}} diff --git a/templates/root.hbs b/templates/root.hbs index f0f25da..20bdac4 100644 --- a/templates/root.hbs +++ b/templates/root.hbs @@ -6,6 +6,6 @@ imgboard -

Hello world!!!

+ {{> page}} - \ No newline at end of file +