aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel A. Giovanini <mail@gabrielgio.me>2022-06-11 00:00:27 +0200
committerGabriel A. Giovanini <mail@gabrielgio.me>2022-06-11 00:00:27 +0200
commit4fb323f69c11557a51c7da0b2031029f63edf789 (patch)
tree0d08ce52abbe0c5d123b4051f50ec5bc386652ae
parent0e147a780e74b54afbd56ff7438077d855d5c1c2 (diff)
downloadmacroblog.rs-4fb323f69c11557a51c7da0b2031029f63edf789.tar.gz
macroblog.rs-4fb323f69c11557a51c7da0b2031029f63edf789.tar.bz2
macroblog.rs-4fb323f69c11557a51c7da0b2031029f63edf789.zip
feat: Handle 404 result
Now gracefully handle 404, so instead of just panic now it will return a proper http 404 response.
-rw-r--r--README.md2
-rw-r--r--src/assets.rs49
-rw-r--r--src/bin/actix.rs9
-rw-r--r--src/blog.rs63
-rw-r--r--src/lib.rs1
-rw-r--r--src/router.rs14
-rw-r--r--tests/test_blog.rs3
-rw-r--r--tests/test_router.rs19
8 files changed, 99 insertions, 61 deletions
diff --git a/README.md b/README.md
index 59cf13b..2a9d334 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
After reading [this
article](https://www.andreinc.net/2022/04/10/a-blog-that-is-a-single-executable-binary)
by Andrei Ciobanu it sparkled in me to do the same thing but with rust.
-It is going to be a bit bigger than micro though ;)
+It is going to be a bit bigger than micro ;)
To achieve that I'll be using the following:
diff --git a/src/assets.rs b/src/assets.rs
new file mode 100644
index 0000000..2c39d1b
--- /dev/null
+++ b/src/assets.rs
@@ -0,0 +1,49 @@
+use chrono::NaiveDate;
+use regex::Regex;
+use rust_embed::RustEmbed;
+use sailfish::TemplateOnce;
+use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
+use std::str;
+
+pub const BLOG_REGEX: &str = r"(?P<date>[\d]{4}-[\d]{2}-[\d]{2})(?P<title>[a-zA-Z0-9-_]*)";
+
+#[derive(RustEmbed)]
+#[folder = "content/posts/"]
+pub struct PostAsset;
+
+#[derive(TemplateOnce)]
+#[template(path = "index.html")]
+pub struct IndexTemplate {
+ pub posts: Vec<BlogEntry>,
+}
+
+#[derive(TemplateOnce)]
+#[template(path = "post.html")]
+pub struct PostTemplate {
+ pub content: String,
+ pub title: String,
+ pub date: String,
+}
+
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+pub struct BlogEntry {
+ pub title: String,
+ pub datetime: NaiveDate,
+ pub file: String,
+}
+
+impl BlogEntry {
+ pub fn new(path: &String) -> BlogEntry {
+ let re = Regex::new(BLOG_REGEX).unwrap();
+ let caps = re.captures(path).unwrap();
+ let date = &caps["date"];
+ let title = str::replace(&caps["title"], "_", " ");
+
+ BlogEntry {
+ title: String::from(title),
+ file: String::from(path),
+ datetime: NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap(),
+ }
+ }
+
+}
diff --git a/src/bin/actix.rs b/src/bin/actix.rs
index 3f00f36..101fe2e 100644
--- a/src/bin/actix.rs
+++ b/src/bin/actix.rs
@@ -1,6 +1,7 @@
use actix_web::{get, web, middleware, App, HttpResponse, HttpServer, Responder, http::header::ContentType};
use macroblog::blog::{render_index_page, render_post_page};
-use std::{env};
+use macroblog::router::blog_post_exists;
+use std::env;
#[get("/")]
async fn index() -> impl Responder {
@@ -14,6 +15,12 @@ async fn index() -> impl Responder {
#[get("/posts/{name}")]
async fn posts(name: web::Path<String>) -> impl Responder {
+
+ if !blog_post_exists(&name) {
+ return HttpResponse::NotFound()
+ .body("Not Found".to_string());
+ }
+
let body = render_post_page(&name);
HttpResponse::Ok()
diff --git a/src/blog.rs b/src/blog.rs
index c877303..eaa314a 100644
--- a/src/blog.rs
+++ b/src/blog.rs
@@ -1,62 +1,18 @@
-use chrono::NaiveDate;
use pulldown_cmark::{html, Options, Parser};
-use regex::Regex;
-use rust_embed::RustEmbed;
use sailfish::TemplateOnce;
-use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
use std::str;
+use crate::assets::{BlogEntry, PostAsset, IndexTemplate, PostTemplate};
-const BLOG_REGEX: &str = r"(?P<date>[\d]{4}-[\d]{2}-[\d]{2})(?P<title>[a-zA-Z0-9-_]*)";
-#[derive(RustEmbed)]
-#[folder = "content/posts/"]
-struct PostAsset;
+pub fn read_assets() -> Vec<BlogEntry> {
+ let mut entries: Vec<BlogEntry> = PostAsset::iter()
+ .map(|e| format!("{}", e))
+ .map(|e| BlogEntry::new(&e))
+ .collect();
-#[derive(TemplateOnce)]
-#[template(path = "index.html")]
-struct IndexTemplate {
- posts: Vec<BlogEntry>,
-}
-
-#[derive(TemplateOnce)]
-#[template(path = "post.html")]
-struct PostTemplate {
- content: String,
- title: String,
- date: String,
-}
-
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct BlogEntry {
- pub title: String,
- pub datetime: NaiveDate,
- pub file: String,
-}
-
-impl BlogEntry {
- pub fn new(path: &String) -> BlogEntry {
- let re = Regex::new(BLOG_REGEX).unwrap();
- let caps = re.captures(path).unwrap();
- let date = &caps["date"];
- let title = str::replace(&caps["title"], "_", " ");
+ entries.sort_by(|a, b| b.datetime.cmp(&a.datetime));
- BlogEntry {
- title: String::from(title),
- file: String::from(path),
- datetime: NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap(),
- }
- }
-
- pub fn read_assets() -> Vec<BlogEntry> {
- let mut entries: Vec<BlogEntry> = PostAsset::iter()
- .map(|e| format!("{}", e))
- .map(|e| BlogEntry::new(&e))
- .collect();
-
- entries.sort_by(|a, b| b.datetime.cmp(&a.datetime));
-
- entries
- }
+ entries
}
fn get_file_content(path: &str) -> String {
@@ -68,6 +24,7 @@ fn get_file_content(path: &str) -> String {
return html_output.to_string();
}
+
pub fn render_post_page(path: &String) -> String {
let blog = BlogEntry::new(path);
@@ -82,7 +39,7 @@ pub fn render_post_page(path: &String) -> String {
pub fn render_index_page() -> String {
IndexTemplate {
- posts: BlogEntry::read_assets(),
+ posts: read_assets(),
}
.render_once()
.unwrap()
diff --git a/src/lib.rs b/src/lib.rs
index 0c69888..90ddff2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,2 +1,3 @@
pub mod blog;
pub mod router;
+pub mod assets;
diff --git a/src/router.rs b/src/router.rs
index 35fdf3e..c196ab8 100644
--- a/src/router.rs
+++ b/src/router.rs
@@ -1,3 +1,6 @@
+use std::borrow::Borrow;
+
+use crate::assets::PostAsset;
use regex::Regex;
const ACTION_REGEX: &str = r"/{0,1}(?P<action>\w*)/(?P<id>.+)";
@@ -8,6 +11,10 @@ pub enum Router {
Post { page: String },
}
+pub fn blog_post_exists(name: &str) -> bool {
+ PostAsset::iter().any(|x| name.eq(&x.to_string()))
+}
+
impl Router {
pub fn new(path: &str) -> Router {
let re = Regex::new(ACTION_REGEX).unwrap();
@@ -17,6 +24,13 @@ impl Router {
None => "index",
};
+
+ // this 7 means the "/posts/" from the full path
+ let trimmed_path: String = path.chars().skip(7).collect();
+ if action.eq("posts") && !blog_post_exists(&trimmed_path) {
+ return Router::NotFound;
+ }
+
match action {
"posts" => Router::Post {
page: caps.unwrap()["id"].to_string(),
diff --git a/tests/test_blog.rs b/tests/test_blog.rs
index b72f800..6cd3249 100644
--- a/tests/test_blog.rs
+++ b/tests/test_blog.rs
@@ -1,4 +1,5 @@
use macroblog::blog::*;
+use macroblog::assets::*;
use chrono::NaiveDate;
@@ -17,7 +18,7 @@ fn test_create_blog_entry() {
#[test]
fn test_read_assets() {
// This test meant to test if all files are parsed correctly
- let assets = BlogEntry::read_assets();
+ let assets = read_assets();
assert!(assets.iter().count() > 1)
}
diff --git a/tests/test_router.rs b/tests/test_router.rs
index 7ebe019..cfd4c32 100644
--- a/tests/test_router.rs
+++ b/tests/test_router.rs
@@ -1,11 +1,11 @@
-use macroblog::router::{Router};
+use macroblog::router::Router;
#[test]
fn test_router_new_posts() {
- match Router::new("/posts/k8s.html") {
+ match Router::new("/posts/2021-12-26Enable_NFS_on_K3S.md") {
Router::NotFound => assert!(false, "Wrong type parse"),
Router::Index => assert!(false, "Wrong type parse"),
- Router::Post { page } => assert_eq!(page, "k8s.html".to_string())
+ Router::Post { page } => assert_eq!(page, "2021-12-26Enable_NFS_on_K3S.md".to_string()),
};
}
@@ -14,7 +14,7 @@ fn test_router_new_index() {
match Router::new("/") {
Router::Index => assert!(true),
Router::NotFound => assert!(false, "Wrong type parse"),
- Router::Post { page: _ } => assert!(false, "Wrong type parse")
+ Router::Post { page: _ } => assert!(false, "Wrong type parse"),
};
}
@@ -23,6 +23,15 @@ fn test_router_new_not_found() {
match Router::new("/not_found") {
Router::NotFound => assert!(true),
Router::Index => assert!(false, "Wrong type parse"),
- Router::Post { page: _ } => assert!(false, "Wrong type parse")
+ Router::Post { page: _ } => assert!(false, "Wrong type parse"),
+ };
+}
+
+#[test]
+fn test_router_new_not_found_matching_regex() {
+ match Router::new("/posts/2021-12-03Enable_NFS_on_K3S.html") {
+ Router::NotFound => assert!(true),
+ Router::Index => assert!(false, "Wrong type parse"),
+ Router::Post { page: _ } => assert!(false, "Wrong type parse"),
};
}