macroblog.rs @ e964ec8f74b644d66ca166a7524adcc3a82709c9

feat: Move code to blog

- Move most logic of the blog to blog.rs, making it easier to test.
- Now the file contains the creation date of the blog post to be parsed.
- Add chrono to parse datetime, so later we can order by date.
- Refactor gitlab pipeline, move `before_script` to a proper place.
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 12003e91d5e52097ad7d82c92483fbf831351c0e..8cae0ac6163c17d90e604b08886035384d529660 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,14 +1,9 @@
-before_script:
-    - apt-get update -qy
-    - apt-get install -y ruby-dev
-    - gem install dpl
-
 stages:
     - test
     - production
 
 test:
-    image: rust:latest
+    image: rust:alpine
     stage: test
     script:
         - cargo install cargo2junit
@@ -25,6 +20,9 @@     image: ruby:latest
     needs:
       - test
     script:
+        - apt-get update -qy
+        - apt-get install -y ruby-dev
+        - gem install dpl
         - gem install faraday -v 1.8.0
         - dpl --provider=heroku --app=$HEROKU_APP --api-key=$HEROKU_API_KEY
     only:
diff --git a/Cargo.lock b/Cargo.lock
index b687dc4ba345533b859801322d8dd90f09f8eec1..0b23a345018c789378ffbafcdf6c790f9869fec3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -45,6 +45,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "libc",
+ "num-integer",
+ "num-traits",
+ "time",
+ "winapi",
+]
+
+[[package]]
 name = "cpufeatures"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -287,6 +300,7 @@ [[package]]
 name = "macroblog"
 version = "0.1.0"
 dependencies = [
+ "chrono",
  "hyper",
  "regex",
  "rust-embed",
@@ -310,7 +324,7 @@  "libc",
  "log",
  "miow",
  "ntapi",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
  "winapi",
 ]
 
@@ -333,6 +347,25 @@  "winapi",
 ]
 
 [[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
 name = "num_cpus"
 version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -602,6 +635,17 @@  "unicode-xid",
 ]
 
 [[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi 0.10.0+wasi-snapshot-preview1",
+ "winapi",
+]
+
+[[package]]
 name = "tokio"
 version = "1.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -737,6 +781,12 @@ dependencies = [
  "log",
  "try-lock",
 ]
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
 
 [[package]]
 name = "wasi"
diff --git a/Cargo.toml b/Cargo.toml
index de00d117e0465b66e6fd3f2616ffb608e3a6b7b6..a241371df453dc2b6745ca43f8fc86ceecfd30a2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,7 +8,8 @@ sailfish = "0.4.0"
 hyper = { version = "0.14", features = ["full"] }
 tokio = { version = "1", features = ["full"] }
 regex = "1.5"
-rust-embed="6.4.0"
+rust-embed = "6.4.0"
+chrono = "0.4"
 
 [profile.release]
 opt-level = 'z'
@@ -18,5 +19,5 @@ panic = 'abort'
 strip = true
 
 [lib]
-name="router"
-path="src/router.rs"
+name="macroblog"
+path="src/lib.rs"
diff --git a/content/posts/Enable_NFS_on_K3S.html b/content/posts/2021-12-26Enable_NFS_on_K3S.html
rename from content/posts/Enable_NFS_on_K3S.html
rename to content/posts/2021-12-26Enable_NFS_on_K3S.html
diff --git a/content/posts/Friz.box_turned_off_DHCP.html b/content/posts/2020-07-14Friz_box_turned_off_DHCP.html
rename from content/posts/Friz.box_turned_off_DHCP.html
rename to content/posts/2020-07-14Friz_box_turned_off_DHCP.html
diff --git a/content/posts/K8S_private_gitlab_registry_using_podman.html b/content/posts/2021-12-26K8S_private_gitlab_registry_using_podman.html
rename from content/posts/K8S_private_gitlab_registry_using_podman.html
rename to content/posts/2021-12-26K8S_private_gitlab_registry_using_podman.html
diff --git a/src/blog.rs b/src/blog.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6c190a9ed1fc5adb26f9929c8bf5ca2f0665136b
--- /dev/null
+++ b/src/blog.rs
@@ -0,0 +1,74 @@
+use rust_embed::RustEmbed;
+use sailfish::TemplateOnce;
+use chrono::NaiveDate;
+use regex::{Regex};
+use std::str;
+
+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;
+
+
+#[derive(TemplateOnce)]
+#[template(path = "index.html")]
+struct IndexTemplate {
+    posts: Vec<BlogEntry>,
+}
+
+#[derive(TemplateOnce)]
+#[template(path = "post.html")]
+struct PostTemplate {
+    content: String,
+}
+
+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()
+        }
+    }
+
+    pub fn read_assets() -> Vec<BlogEntry> {
+        PostAsset::iter()
+            .map(|e| format!("{}", e))
+            .map(|e| BlogEntry::new(&e))
+            .collect()
+    }
+}
+
+fn get_file_content(path: &str) -> String {
+    let buffer = PostAsset::get(path)
+        .unwrap()
+        .data
+        .into_owned();
+
+    return String::from_utf8(buffer).unwrap();
+}
+
+
+pub fn render_post_page(path: &String) -> String {
+    PostTemplate { content: get_file_content(path) }
+        .render_once()
+        .unwrap()
+}
+
+pub fn render_index_page() -> String {
+    IndexTemplate { posts: BlogEntry::read_assets() }
+        .render_once()
+        .unwrap()
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0c698884bb717efdd6fb15fbe9d622e170a3d0c7
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod blog;
+pub mod router;
diff --git a/src/main.rs b/src/main.rs
index 63a5386ecff2059e8fefcbbcce7d74f4a38c2124..ed347135f021e81ec594c03a3b9266779fff82bd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,60 +1,11 @@
-pub mod router;
 
 use std::convert::Infallible;
-use rust_embed::RustEmbed;
-use std::{env, str};
+use std::{env};
 use std::net::SocketAddr;
 use hyper::{Body, Request, Response, Server};
 use hyper::service::{make_service_fn, service_fn};
-use sailfish::TemplateOnce;
-use ::router::Router;
-
-struct PostEntry {
-    title: String,
-    file: String,
-}
-
-#[derive(TemplateOnce)]
-#[template(path = "index.html")]
-struct IndexTemplate {
-    posts: Vec<PostEntry>,
-}
-
-#[derive(TemplateOnce)]
-#[template(path = "post.html")]
-struct PostTemplate {
-    content: String,
-}
-
-#[derive(RustEmbed)]
-#[folder = "content/posts/"]
-struct PostAsset;
-
-
-fn get_file_content(path: &str) -> String {
-    let buffer = PostAsset::get(path)
-        .unwrap()
-        .data
-        .into_owned();
-
-    return String::from_utf8(buffer).unwrap();
-}
-
-fn get_post_entry(path: &String) -> PostEntry {
-    let sub_title = str::replace(path, "_", " ");
-    let title = str::replace(sub_title.as_str(), ".html", "");
-    PostEntry {
-        title: String::from(title),
-        file: String::from(path),
-    }
-}
-
-fn get_post_title() -> Vec<PostEntry> {
-    PostAsset::iter()
-        .map(|e| format!("{}", e))
-        .map(|e| get_post_entry(&e))
-        .collect()
-}
+use macroblog::router::Router;
+use macroblog::blog::{render_index_page, render_post_page};
 
 
 async fn not_found() -> Result<Response<Body>, Infallible> {
@@ -67,10 +18,7 @@ }
 
 
 async fn index() -> Result<Response<Body>, Infallible> {
-    let files = get_post_title();
-    let body = IndexTemplate { posts: files }
-        .render_once()
-        .unwrap();
+    let body = render_index_page();
 
     let resp: Response<Body> = Response::builder()
         .status(200)
@@ -83,9 +31,7 @@ }
 
 
 async fn post(path: &String) -> Result<Response<Body>, Infallible> {
-    let body = PostTemplate { content: get_file_content(path) }
-        .render_once()
-        .unwrap();
+    let body = render_post_page(path);
 
     let resp: Response<Body> = Response::builder()
         .status(200)
diff --git a/tests/test_blog.rs b/tests/test_blog.rs
new file mode 100644
index 0000000000000000000000000000000000000000..31d572595116f4fd3c078eb07360904c1f9e5fbb
--- /dev/null
+++ b/tests/test_blog.rs
@@ -0,0 +1,36 @@
+use macroblog::blog::*;
+
+use chrono::NaiveDate;
+
+
+#[test]
+fn test_create_blog_entry() {
+    let asset_filename = String::from("2021-12-03Enable_NFS_on_K3S.html");
+    let post_date = NaiveDate::from_ymd(2021, 12, 03);
+
+    let blog_entry = BlogEntry::new(&asset_filename);
+
+    assert_eq!(blog_entry.title, "Enable NFS on K3S");
+    assert_eq!(blog_entry.datetime, post_date);
+}
+
+#[test]
+fn test_read_assets() {
+    // This test meant to test if all files are parsed correctly
+    let assets = BlogEntry::read_assets();
+    assert!(assets.iter().count() > 1)
+}
+
+#[test]
+fn test_render_post_page() {
+    let path = &String::from("2020-07-14Friz_box_turned_off_DHCP.html");
+    let page = render_post_page(path);
+    assert!(!page.is_empty());
+}
+
+
+#[test]
+fn test_render_index_page() {
+    let page = render_index_page();
+    assert!(!page.is_empty());
+}
diff --git a/tests/test_router.rs b/tests/test_router.rs
index 0158d782b5eb5b06f948be3b48417943a44180e6..7ebe0196cbedddd7831d3a0ded8e62282997c056 100644
--- a/tests/test_router.rs
+++ b/tests/test_router.rs
@@ -1,4 +1,4 @@
-use router::{Router};
+use macroblog::router::{Router};
 
 #[test]
 fn test_router_new_posts() {