add root template
This commit is contained in:
parent
eb1bb7309a
commit
26de7b3cc4
10 changed files with 141 additions and 21 deletions
|
@ -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()
|
||||
|
|
22
src/main.rs
22
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<Arc<AppState>>) -> 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();
|
||||
}
|
||||
|
|
|
@ -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<Utc>,
|
||||
pub last_active: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum Role {
|
||||
Viewer = 1,
|
||||
Editor = 2,
|
||||
Manager = 3,
|
||||
Admin = 4,
|
||||
}
|
||||
|
||||
impl Serialize for Role {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(match self {
|
||||
Role::Viewer => "viwer",
|
||||
Role::Editor => "editor",
|
||||
Role::Manager => "manager",
|
||||
Role::Admin => "admin",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
9
src/pages/index.rs
Normal file
9
src/pages/index.rs
Normal file
|
@ -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<Arc<AppState>>) -> impl IntoResponse {
|
||||
Page::new(state.hbs.render::<PageData>("index.hbs", &Default::default()))
|
||||
}
|
2
src/pages/mod.rs
Normal file
2
src/pages/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod index;
|
||||
pub mod user;
|
40
src/pages/user/mod.rs
Normal file
40
src/pages/user/mod.rs
Normal file
|
@ -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<Arc<AppState>>,
|
||||
Path(user_id): Path<i32>,
|
||||
) -> 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::<PageData>("error.hbs", &Default::default()),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Page::new(
|
||||
state
|
||||
.hbs
|
||||
.render("error.hbs", &PageData { user: Some(user) }),
|
||||
)
|
||||
}
|
|
@ -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<Handlebars<'static>> {
|
|||
|
||||
Ok(hbs)
|
||||
}
|
||||
|
||||
pub struct Page(Result<String, RenderError>);
|
||||
|
||||
impl Page {
|
||||
pub fn new(res: Result<String, RenderError>) -> 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<User>,
|
||||
}
|
||||
|
|
5
templates/error.hbs
Normal file
5
templates/error.hbs
Normal file
|
@ -0,0 +1,5 @@
|
|||
{{#*inline "page"}}
|
||||
<h1>Error</h1>
|
||||
<p>An internal error occurred. Sorry :(</p>
|
||||
{{/inline}}
|
||||
{{> root.hbs}}
|
5
templates/index.hbs
Normal file
5
templates/index.hbs
Normal file
|
@ -0,0 +1,5 @@
|
|||
{{#*inline "page"}}
|
||||
<h1>board!</h1>
|
||||
<p>this will be a site eventually</p>
|
||||
{{/inline}}
|
||||
{{> root.hbs}}
|
|
@ -6,6 +6,6 @@
|
|||
<title>imgboard</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello world!!!</h1>
|
||||
{{> page}}
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue