Add page resolver
This commit is contained in:
parent
78cb11b54a
commit
37d6c3cd4d
6 changed files with 150 additions and 14 deletions
|
@ -1,4 +1,4 @@
|
||||||
*:80 {
|
127.0.0.1 {
|
||||||
route /favicon.ico {
|
route /favicon.ico {
|
||||||
file_server {
|
file_server {
|
||||||
root ./static
|
root ./static
|
||||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use axum::{Router, routing::get};
|
use axum::{Router, routing::get};
|
||||||
use log::info;
|
use log::info;
|
||||||
use sea_orm::{Database, DatabaseConnection};
|
use sea_orm::{Database, DatabaseConnection, ConnectOptions};
|
||||||
|
|
||||||
mod routes;
|
mod routes;
|
||||||
mod entities;
|
mod entities;
|
||||||
|
@ -11,7 +11,9 @@ mod block_types;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
env::set_var("RUST_LOG", "info");
|
if env::var("RUST_LOG").is_err() {
|
||||||
|
env::set_var("RUST_LOG", "info");
|
||||||
|
}
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
|
@ -26,7 +28,10 @@ async fn main() {
|
||||||
|
|
||||||
info!("Connecting to the database...");
|
info!("Connecting to the database...");
|
||||||
|
|
||||||
let db_conn = Database::connect(db_url)
|
let mut db_opt = ConnectOptions::new(db_url);
|
||||||
|
db_opt.sqlx_logging_level(log::LevelFilter::Debug);
|
||||||
|
|
||||||
|
let db_conn = Database::connect(db_opt)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to connect to the database! HALTING");
|
.expect("Failed to connect to the database! HALTING");
|
||||||
//Migrator::up(&db_conn, None).await.expect("Failed to run migrations! HALTING");
|
//Migrator::up(&db_conn, None).await.expect("Failed to run migrations! HALTING");
|
||||||
|
@ -37,6 +42,8 @@ async fn main() {
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(routes::root))
|
.route("/", get(routes::root))
|
||||||
|
.route("/post/:slug", get(not_implemented))
|
||||||
|
.route("/:slug", get(routes::page_resolver::resolver))
|
||||||
.with_state(app_state);
|
.with_state(app_state);
|
||||||
|
|
||||||
info!("Attempting to bind to address...");
|
info!("Attempting to bind to address...");
|
||||||
|
@ -48,13 +55,14 @@ async fn main() {
|
||||||
match bind {
|
match bind {
|
||||||
Ok(bind) => {
|
Ok(bind) => {
|
||||||
info!("Binded to address successfully!");
|
info!("Binded to address successfully!");
|
||||||
info!("Started!");
|
info!("Listening for connections...");
|
||||||
bind.serve(app.into_make_service())
|
match bind.serve(app.into_make_service()).await {
|
||||||
.await
|
Err(e) => panic!("Failed to start server! HALTING {}", e),
|
||||||
.unwrap();
|
_ => (),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
panic!("Failed to bind! HALTING")
|
panic!("Failed to bind! HALTING {}", e)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,3 +71,7 @@ async fn main() {
|
||||||
struct AppState {
|
struct AppState {
|
||||||
db_conn: DatabaseConnection,
|
db_conn: DatabaseConnection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn not_implemented() -> &'static str {
|
||||||
|
"Not Implemented"
|
||||||
|
}
|
|
@ -1,9 +1,41 @@
|
||||||
|
pub(crate) mod page_resolver;
|
||||||
|
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use crate::{block_types::BlockTypes, AppState};
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "page.html")]
|
||||||
|
pub(crate) struct PageTemplate {
|
||||||
|
title: String,
|
||||||
|
description: Option<String>,
|
||||||
|
show_title: bool,
|
||||||
|
content_blocks: Vec<BlockTypes>,
|
||||||
|
year: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "post.html")]
|
||||||
|
pub(crate) struct PostTemplate {
|
||||||
|
title: String,
|
||||||
|
summary: Option<String>,
|
||||||
|
publish_date: String,
|
||||||
|
last_updated: Option<String>,
|
||||||
|
content_blocks: Vec<BlockTypes>,
|
||||||
|
year: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "notfound.html")]
|
||||||
|
pub(crate) struct NotFoundTemplate {
|
||||||
|
slug: String,
|
||||||
|
year: String
|
||||||
|
}
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use crate::block_types;
|
use crate::block_types;
|
||||||
use crate::{block_types::BlockTypes, AppState};
|
|
||||||
use crate::entities::{prelude::*, *};
|
use crate::entities::{prelude::*, *};
|
||||||
use sea_orm::*;
|
use sea_orm::*;
|
||||||
|
|
||||||
|
@ -36,7 +68,6 @@ pub(crate) async fn root(
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get home page blocks! HALTING");
|
.expect("Failed to get home page blocks! HALTING");
|
||||||
|
|
||||||
// TODO: should move this into its own func, it'll be reused a bit
|
|
||||||
let content_blocks: Vec<BlockTypes> = blocks.into_iter().map(|f|
|
let content_blocks: Vec<BlockTypes> = blocks.into_iter().map(|f|
|
||||||
match f.r#type.as_str() {
|
match f.r#type.as_str() {
|
||||||
"HR" => BlockTypes::HR,
|
"HR" => BlockTypes::HR,
|
||||||
|
|
67
src/routes/page_resolver.rs
Normal file
67
src/routes/page_resolver.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use askama_axum::IntoResponse;
|
||||||
|
use axum::extract::{State, Path};
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use log::{warn, error};
|
||||||
|
|
||||||
|
use crate::block_types;
|
||||||
|
use crate::{block_types::BlockTypes, AppState};
|
||||||
|
use crate::entities::{prelude::*, *};
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
|
use super::{PageTemplate, NotFoundTemplate};
|
||||||
|
|
||||||
|
pub(crate) async fn resolver(
|
||||||
|
Path(slug): Path<String>,
|
||||||
|
state: State<AppState>
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let page_search: Result<Option<page::Model>, DbErr> = Page::find()
|
||||||
|
.filter(page::Column::Slug.eq(&slug))
|
||||||
|
.one(&state.db_conn)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let page_meta: page::Model = match page_search {
|
||||||
|
Ok(page_result) => {
|
||||||
|
match page_result {
|
||||||
|
Some(page_result) => page_result,
|
||||||
|
None => return (StatusCode::NOT_FOUND, NotFoundTemplate { slug, year: "2023".to_owned() }).into_response(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, ()).into_response();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let blocks: Vec<page_block::Model> = page_meta.find_related(PageBlock)
|
||||||
|
.order_by_asc(page_block::Column::Order)
|
||||||
|
.all(&state.db_conn)
|
||||||
|
.await
|
||||||
|
.expect("Failed to get home page blocks! HALTING");
|
||||||
|
|
||||||
|
let content_blocks: Vec<BlockTypes> = blocks.into_iter().map(|f|
|
||||||
|
match f.r#type.as_str() {
|
||||||
|
"HR" => BlockTypes::HR,
|
||||||
|
"PARAGRAPH" => BlockTypes::PARAGRAPH { text: f.content },
|
||||||
|
"MARKDOWN" => BlockTypes::MARKDOWN { content: f.content },
|
||||||
|
"HEADER" => {
|
||||||
|
let deserde: block_types::Header = serde_json::from_str(&f.content.as_str()).expect("Incorrect HEADER formatting");
|
||||||
|
|
||||||
|
BlockTypes::HEADER { text: deserde.text, size: deserde.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
warn!("Unsupported block type! ({})", f.r#type.as_str());
|
||||||
|
BlockTypes::UNSUPPORTED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
).collect();
|
||||||
|
|
||||||
|
(StatusCode::FOUND, PageTemplate {
|
||||||
|
title: page_meta.clone().title,
|
||||||
|
description: page_meta.clone().description,
|
||||||
|
show_title: page_meta.clone().show_title,
|
||||||
|
content_blocks,
|
||||||
|
year: "2023".to_string()
|
||||||
|
}).into_response()
|
||||||
|
}
|
15
templates/notfound.html
Normal file
15
templates/notfound.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}404{% endblock %}
|
||||||
|
|
||||||
|
{% block description %}
|
||||||
|
This page wasn't found!
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Page not found!</h1>
|
||||||
|
|
||||||
|
<p><code>{{ slug }}</code> was not found! Would you like to go <a href="/">home</a>?</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -27,8 +27,19 @@
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{% for block in blocks %}
|
{% for content_block in content_blocks %}
|
||||||
<p>block is real</p>
|
{% match content_block %}
|
||||||
|
{% when BlockTypes::HR %}
|
||||||
|
<hr />
|
||||||
|
{% when BlockTypes::PARAGRAPH { text } %}
|
||||||
|
<p>{{ text }}</p>
|
||||||
|
{% when BlockTypes::MARKDOWN { content } %}
|
||||||
|
{{ content|markdown }}
|
||||||
|
{% when BlockTypes::HEADER { text, size } %}
|
||||||
|
<h{{size}}>{{text}}</h{{size}}>
|
||||||
|
{% when BlockTypes::UNSUPPORTED %}
|
||||||
|
<b>UNSUPPORTED block type here!</b>
|
||||||
|
{% endmatch %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
Reference in a new issue