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.
  1diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
  2index 12003e91d5e52097ad7d82c92483fbf831351c0e..8cae0ac6163c17d90e604b08886035384d529660 100644
  3--- a/.gitlab-ci.yml
  4+++ b/.gitlab-ci.yml
  5@@ -1,14 +1,9 @@
  6-before_script:
  7-    - apt-get update -qy
  8-    - apt-get install -y ruby-dev
  9-    - gem install dpl
 10-
 11 stages:
 12     - test
 13     - production
 14 
 15 test:
 16-    image: rust:latest
 17+    image: rust:alpine
 18     stage: test
 19     script:
 20         - cargo install cargo2junit
 21@@ -25,6 +20,9 @@     image: ruby:latest
 22     needs:
 23       - test
 24     script:
 25+        - apt-get update -qy
 26+        - apt-get install -y ruby-dev
 27+        - gem install dpl
 28         - gem install faraday -v 1.8.0
 29         - dpl --provider=heroku --app=$HEROKU_APP --api-key=$HEROKU_API_KEY
 30     only:
 31diff --git a/Cargo.lock b/Cargo.lock
 32index b687dc4ba345533b859801322d8dd90f09f8eec1..0b23a345018c789378ffbafcdf6c790f9869fec3 100644
 33--- a/Cargo.lock
 34+++ b/Cargo.lock
 35@@ -45,6 +45,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 36 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 37 
 38 [[package]]
 39+name = "chrono"
 40+version = "0.4.19"
 41+source = "registry+https://github.com/rust-lang/crates.io-index"
 42+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
 43+dependencies = [
 44+ "libc",
 45+ "num-integer",
 46+ "num-traits",
 47+ "time",
 48+ "winapi",
 49+]
 50+
 51+[[package]]
 52 name = "cpufeatures"
 53 version = "0.2.2"
 54 source = "registry+https://github.com/rust-lang/crates.io-index"
 55@@ -287,6 +300,7 @@ [[package]]
 56 name = "macroblog"
 57 version = "0.1.0"
 58 dependencies = [
 59+ "chrono",
 60  "hyper",
 61  "regex",
 62  "rust-embed",
 63@@ -310,7 +324,7 @@  "libc",
 64  "log",
 65  "miow",
 66  "ntapi",
 67- "wasi",
 68+ "wasi 0.11.0+wasi-snapshot-preview1",
 69  "winapi",
 70 ]
 71 
 72@@ -333,6 +347,25 @@  "winapi",
 73 ]
 74 
 75 [[package]]
 76+name = "num-integer"
 77+version = "0.1.45"
 78+source = "registry+https://github.com/rust-lang/crates.io-index"
 79+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
 80+dependencies = [
 81+ "autocfg",
 82+ "num-traits",
 83+]
 84+
 85+[[package]]
 86+name = "num-traits"
 87+version = "0.2.15"
 88+source = "registry+https://github.com/rust-lang/crates.io-index"
 89+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
 90+dependencies = [
 91+ "autocfg",
 92+]
 93+
 94+[[package]]
 95 name = "num_cpus"
 96 version = "1.13.1"
 97 source = "registry+https://github.com/rust-lang/crates.io-index"
 98@@ -602,6 +635,17 @@  "unicode-xid",
 99 ]
100 
101 [[package]]
102+name = "time"
103+version = "0.1.44"
104+source = "registry+https://github.com/rust-lang/crates.io-index"
105+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
106+dependencies = [
107+ "libc",
108+ "wasi 0.10.0+wasi-snapshot-preview1",
109+ "winapi",
110+]
111+
112+[[package]]
113 name = "tokio"
114 version = "1.18.1"
115 source = "registry+https://github.com/rust-lang/crates.io-index"
116@@ -737,6 +781,12 @@ dependencies = [
117  "log",
118  "try-lock",
119 ]
120+
121+[[package]]
122+name = "wasi"
123+version = "0.10.0+wasi-snapshot-preview1"
124+source = "registry+https://github.com/rust-lang/crates.io-index"
125+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
126 
127 [[package]]
128 name = "wasi"
129diff --git a/Cargo.toml b/Cargo.toml
130index de00d117e0465b66e6fd3f2616ffb608e3a6b7b6..a241371df453dc2b6745ca43f8fc86ceecfd30a2 100644
131--- a/Cargo.toml
132+++ b/Cargo.toml
133@@ -8,7 +8,8 @@ sailfish = "0.4.0"
134 hyper = { version = "0.14", features = ["full"] }
135 tokio = { version = "1", features = ["full"] }
136 regex = "1.5"
137-rust-embed="6.4.0"
138+rust-embed = "6.4.0"
139+chrono = "0.4"
140 
141 [profile.release]
142 opt-level = 'z'
143@@ -18,5 +19,5 @@ panic = 'abort'
144 strip = true
145 
146 [lib]
147-name="router"
148-path="src/router.rs"
149+name="macroblog"
150+path="src/lib.rs"
151diff --git a/content/posts/Enable_NFS_on_K3S.html b/content/posts/2021-12-26Enable_NFS_on_K3S.html
152rename from content/posts/Enable_NFS_on_K3S.html
153rename to content/posts/2021-12-26Enable_NFS_on_K3S.html
154diff --git a/content/posts/Friz.box_turned_off_DHCP.html b/content/posts/2020-07-14Friz_box_turned_off_DHCP.html
155rename from content/posts/Friz.box_turned_off_DHCP.html
156rename to content/posts/2020-07-14Friz_box_turned_off_DHCP.html
157diff --git a/content/posts/K8S_private_gitlab_registry_using_podman.html b/content/posts/2021-12-26K8S_private_gitlab_registry_using_podman.html
158rename from content/posts/K8S_private_gitlab_registry_using_podman.html
159rename to content/posts/2021-12-26K8S_private_gitlab_registry_using_podman.html
160diff --git a/src/blog.rs b/src/blog.rs
161new file mode 100644
162index 0000000000000000000000000000000000000000..6c190a9ed1fc5adb26f9929c8bf5ca2f0665136b
163--- /dev/null
164+++ b/src/blog.rs
165@@ -0,0 +1,74 @@
166+use rust_embed::RustEmbed;
167+use sailfish::TemplateOnce;
168+use chrono::NaiveDate;
169+use regex::{Regex};
170+use std::str;
171+
172+const BLOG_REGEX: &str = r"(?P<date>[\d]{4}-[\d]{2}-[\d]{2})(?P<title>[a-zA-Z0-9_]*)";
173+
174+#[derive(RustEmbed)]
175+#[folder = "content/posts/"]
176+struct PostAsset;
177+
178+
179+#[derive(TemplateOnce)]
180+#[template(path = "index.html")]
181+struct IndexTemplate {
182+    posts: Vec<BlogEntry>,
183+}
184+
185+#[derive(TemplateOnce)]
186+#[template(path = "post.html")]
187+struct PostTemplate {
188+    content: String,
189+}
190+
191+pub struct BlogEntry {
192+    pub title: String,
193+    pub datetime: NaiveDate,
194+    pub file: String,
195+}
196+
197+impl BlogEntry {
198+    pub fn new(path: &String) -> BlogEntry {
199+        let re = Regex::new(BLOG_REGEX).unwrap();
200+        let caps = re.captures(path).unwrap();
201+        let date = &caps["date"];
202+        let title = str::replace(&caps["title"], "_", " ");
203+
204+        BlogEntry {
205+            title: String::from(title),
206+            file: String::from(path),
207+            datetime: NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap()
208+        }
209+    }
210+
211+    pub fn read_assets() -> Vec<BlogEntry> {
212+        PostAsset::iter()
213+            .map(|e| format!("{}", e))
214+            .map(|e| BlogEntry::new(&e))
215+            .collect()
216+    }
217+}
218+
219+fn get_file_content(path: &str) -> String {
220+    let buffer = PostAsset::get(path)
221+        .unwrap()
222+        .data
223+        .into_owned();
224+
225+    return String::from_utf8(buffer).unwrap();
226+}
227+
228+
229+pub fn render_post_page(path: &String) -> String {
230+    PostTemplate { content: get_file_content(path) }
231+        .render_once()
232+        .unwrap()
233+}
234+
235+pub fn render_index_page() -> String {
236+    IndexTemplate { posts: BlogEntry::read_assets() }
237+        .render_once()
238+        .unwrap()
239+}
240diff --git a/src/lib.rs b/src/lib.rs
241new file mode 100644
242index 0000000000000000000000000000000000000000..0c698884bb717efdd6fb15fbe9d622e170a3d0c7
243--- /dev/null
244+++ b/src/lib.rs
245@@ -0,0 +1,2 @@
246+pub mod blog;
247+pub mod router;
248diff --git a/src/main.rs b/src/main.rs
249index 63a5386ecff2059e8fefcbbcce7d74f4a38c2124..ed347135f021e81ec594c03a3b9266779fff82bd 100644
250--- a/src/main.rs
251+++ b/src/main.rs
252@@ -1,60 +1,11 @@
253-pub mod router;
254 
255 use std::convert::Infallible;
256-use rust_embed::RustEmbed;
257-use std::{env, str};
258+use std::{env};
259 use std::net::SocketAddr;
260 use hyper::{Body, Request, Response, Server};
261 use hyper::service::{make_service_fn, service_fn};
262-use sailfish::TemplateOnce;
263-use ::router::Router;
264-
265-struct PostEntry {
266-    title: String,
267-    file: String,
268-}
269-
270-#[derive(TemplateOnce)]
271-#[template(path = "index.html")]
272-struct IndexTemplate {
273-    posts: Vec<PostEntry>,
274-}
275-
276-#[derive(TemplateOnce)]
277-#[template(path = "post.html")]
278-struct PostTemplate {
279-    content: String,
280-}
281-
282-#[derive(RustEmbed)]
283-#[folder = "content/posts/"]
284-struct PostAsset;
285-
286-
287-fn get_file_content(path: &str) -> String {
288-    let buffer = PostAsset::get(path)
289-        .unwrap()
290-        .data
291-        .into_owned();
292-
293-    return String::from_utf8(buffer).unwrap();
294-}
295-
296-fn get_post_entry(path: &String) -> PostEntry {
297-    let sub_title = str::replace(path, "_", " ");
298-    let title = str::replace(sub_title.as_str(), ".html", "");
299-    PostEntry {
300-        title: String::from(title),
301-        file: String::from(path),
302-    }
303-}
304-
305-fn get_post_title() -> Vec<PostEntry> {
306-    PostAsset::iter()
307-        .map(|e| format!("{}", e))
308-        .map(|e| get_post_entry(&e))
309-        .collect()
310-}
311+use macroblog::router::Router;
312+use macroblog::blog::{render_index_page, render_post_page};
313 
314 
315 async fn not_found() -> Result<Response<Body>, Infallible> {
316@@ -67,10 +18,7 @@ }
317 
318 
319 async fn index() -> Result<Response<Body>, Infallible> {
320-    let files = get_post_title();
321-    let body = IndexTemplate { posts: files }
322-        .render_once()
323-        .unwrap();
324+    let body = render_index_page();
325 
326     let resp: Response<Body> = Response::builder()
327         .status(200)
328@@ -83,9 +31,7 @@ }
329 
330 
331 async fn post(path: &String) -> Result<Response<Body>, Infallible> {
332-    let body = PostTemplate { content: get_file_content(path) }
333-        .render_once()
334-        .unwrap();
335+    let body = render_post_page(path);
336 
337     let resp: Response<Body> = Response::builder()
338         .status(200)
339diff --git a/tests/test_blog.rs b/tests/test_blog.rs
340new file mode 100644
341index 0000000000000000000000000000000000000000..31d572595116f4fd3c078eb07360904c1f9e5fbb
342--- /dev/null
343+++ b/tests/test_blog.rs
344@@ -0,0 +1,36 @@
345+use macroblog::blog::*;
346+
347+use chrono::NaiveDate;
348+
349+
350+#[test]
351+fn test_create_blog_entry() {
352+    let asset_filename = String::from("2021-12-03Enable_NFS_on_K3S.html");
353+    let post_date = NaiveDate::from_ymd(2021, 12, 03);
354+
355+    let blog_entry = BlogEntry::new(&asset_filename);
356+
357+    assert_eq!(blog_entry.title, "Enable NFS on K3S");
358+    assert_eq!(blog_entry.datetime, post_date);
359+}
360+
361+#[test]
362+fn test_read_assets() {
363+    // This test meant to test if all files are parsed correctly
364+    let assets = BlogEntry::read_assets();
365+    assert!(assets.iter().count() > 1)
366+}
367+
368+#[test]
369+fn test_render_post_page() {
370+    let path = &String::from("2020-07-14Friz_box_turned_off_DHCP.html");
371+    let page = render_post_page(path);
372+    assert!(!page.is_empty());
373+}
374+
375+
376+#[test]
377+fn test_render_index_page() {
378+    let page = render_index_page();
379+    assert!(!page.is_empty());
380+}
381diff --git a/tests/test_router.rs b/tests/test_router.rs
382index 0158d782b5eb5b06f948be3b48417943a44180e6..7ebe0196cbedddd7831d3a0ded8e62282997c056 100644
383--- a/tests/test_router.rs
384+++ b/tests/test_router.rs
385@@ -1,4 +1,4 @@
386-use router::{Router};
387+use macroblog::router::{Router};
388 
389 #[test]
390 fn test_router_new_posts() {