Forráskód Böngészése

Improve articles listing and add displaying article support.

Alexandre Leblanc 3 éve
szülő
commit
7035a46450
4 módosított fájl, 120 hozzáadás és 26 törlés
  1. 67 0
      Cargo.lock
  2. 3 1
      Cargo.toml
  3. 24 0
      src/articles_repository.rs
  4. 26 25
      src/main.rs

+ 67 - 0
Cargo.lock

@@ -471,6 +471,15 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.7"
@@ -769,6 +778,18 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "pulldown-cmark"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
+dependencies = [
+ "bitflags",
+ "getopts",
+ "memchr",
+ "unicase",
+]
+
 [[package]]
 name = "quote"
 version = "1.0.20"
@@ -849,6 +870,15 @@ version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
 
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
 [[package]]
 name = "scopeguard"
 version = "1.1.0"
@@ -1046,6 +1076,15 @@ version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
 
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.8"
@@ -1067,6 +1106,12 @@ dependencies = [
  "tinyvec",
 ]
 
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
 [[package]]
 name = "url"
 version = "2.2.2"
@@ -1087,6 +1132,8 @@ dependencies = [
  "chrono",
  "fern",
  "log",
+ "pulldown-cmark",
+ "walkdir",
 ]
 
 [[package]]
@@ -1095,6 +1142,17 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
 [[package]]
 name = "wasi"
 version = "0.10.0+wasi-snapshot-preview1"
@@ -1123,6 +1181,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"

+ 3 - 1
Cargo.toml

@@ -9,4 +9,6 @@ description = "Blog engine running on version control system to store articles"
 actix-web = "4"
 log = "0.4"
 fern = "0.6"
-chrono = "0.4"
+chrono = "0.4"
+walkdir = "2.3.2"
+pulldown-cmark = "0.9"

+ 24 - 0
src/articles_repository.rs

@@ -0,0 +1,24 @@
+use std::io::Error;
+use std::{fs, io};
+
+use walkdir::WalkDir;
+
+pub trait ArticlesRepository {
+    fn get_directory_listing(&self, path: &str) -> Vec<String>;
+}
+
+pub struct FsRepository {}
+
+impl ArticlesRepository for FsRepository {
+    fn get_directory_listing(&self, path: &str) -> Vec<String> {
+        WalkDir::new(path)
+            .follow_links(true)
+            .into_iter()
+            .filter_map(|entry| entry.ok())
+            .filter(|entry| {
+                entry.file_name().to_string_lossy().ends_with(".md") && entry.file_type().is_file()
+            })
+            .map(|entry| entry.path().to_str().unwrap().to_string())
+            .collect::<Vec<String>>()
+    }
+}

+ 26 - 25
src/main.rs

@@ -1,3 +1,4 @@
+mod articles_repository;
 mod config;
 mod vcs;
 
@@ -7,28 +8,16 @@ use actix_web::middleware::Logger;
 use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
 use fern;
 use log::error;
-use std::{env, io};
+use std::{env, fs, io};
 
+use articles_repository::{ArticlesRepository, FsRepository};
 use config::Configuration;
-
-fn get_directory_listing(path: &str) -> Result<Vec<String>, io::Error>
-{
-    match std::fs::read_dir(path) {
-        Ok(files) => {
-            Ok(files
-                .into_iter()
-                .filter(|dir| dir.as_ref().unwrap().path().starts_with("./."))
-                .map(|dir| dir.as_ref().unwrap().path().to_str().unwrap().to_owned())
-                .collect::<Vec<String>>())
-        },
-        Err(error) => {
-            Err(error)
-        }
-    }
-}
+use pulldown_cmark::{html, Options, Parser};
 
 #[get("")]
 async fn show_articles_list() -> impl Responder {
+    let repo: FsRepository = FsRepository {};
+
     const CONTENT_FOLDER: &str = "./content";
     let estimated_path: String = env::current_dir()
         .unwrap_or_default()
@@ -38,20 +27,32 @@ async fn show_articles_list() -> impl Responder {
 
     log::trace!("Estimated content repository: {estimated_path}/{CONTENT_FOLDER}");
 
-    let paths = match get_directory_listing(&CONTENT_FOLDER) {
-        Ok(list) => list.join("\n"),
-        Err(error) => {
-            error!("Couldn't list articles from path. Error: {error}");
-            String::new()
-        }
-    };
+    let paths = repo.get_directory_listing(&CONTENT_FOLDER).join("\n");
 
     HttpResponse::Ok().body(format!("List of articles:\r\n{paths}"))
 }
 
 #[get("/{path:.+}")]
 async fn show_article(path: web::Path<(String,)>) -> impl Responder {
-    HttpResponse::Ok().body(format!("Specific article: {}", path.into_inner().0))
+    let p = &path.0;
+    let file = fs::read_to_string(p.as_str());
+
+    match file {
+        Ok(content) => {
+            log::trace!("Opening article located {}", p.as_str());
+            let mut options = Options::empty();
+            options.insert(Options::ENABLE_STRIKETHROUGH);
+            let parser = Parser::new_ext(content.as_str(), options);
+            let mut html_output = String::new();
+            html::push_html(&mut html_output, parser);
+
+            HttpResponse::Ok().body(html_output)
+        }
+        Err(error) => {
+            log::error!("Article located at path {} was not found.", p.as_str());
+            HttpResponse::NotFound().finish()
+        }
+    }
 }
 
 #[actix_web::main]