From d2da92336fb109600e59c9ed1e4976ebf891d82c Mon Sep 17 00:00:00 2001 From: Fuwn Date: Sun, 12 Jun 2022 02:32:47 -0700 Subject: feat(blog): sub-blog configuration --- content/pages/blog/programming_languages/Forth.gmi | 6 - content/pages/blog/programming_languages/Go.gmi | 6 - content/pages/blog/programming_languages/OCaml.gmi | 6 - content/pages/blog/programming_languages/Rust.gmi | 6 - content/pages/blog/programming_languages/blog.json | 25 ++ content/pages/blog/projects/GemRest.gmi | 8 - content/pages/blog/projects/blog.json | 11 + src/modules/blog.rs | 22 ++ src/modules/blog/config.rs | 59 +++++ src/modules/blog/module.rs | 290 +++++++++++++++++++++ src/modules/mod.rs | 6 +- src/modules/multi_blog.rs | 184 ------------- 12 files changed, 410 insertions(+), 219 deletions(-) create mode 100644 content/pages/blog/programming_languages/blog.json create mode 100644 content/pages/blog/projects/blog.json create mode 100644 src/modules/blog.rs create mode 100644 src/modules/blog/config.rs create mode 100644 src/modules/blog/module.rs delete mode 100644 src/modules/multi_blog.rs diff --git a/content/pages/blog/programming_languages/Forth.gmi b/content/pages/blog/programming_languages/Forth.gmi index 88a5b3b..788b5dc 100644 --- a/content/pages/blog/programming_languages/Forth.gmi +++ b/content/pages/blog/programming_languages/Forth.gmi @@ -1,9 +1,3 @@ -# Forth - -Author: Fuwn -Created: 2022. 04. 21. -Last Modified: 2022. 04. 21. - ## Resources => http://www.forth.org/ Forth Interest Group Home Page diff --git a/content/pages/blog/programming_languages/Go.gmi b/content/pages/blog/programming_languages/Go.gmi index dd319a7..1f2e8b2 100644 --- a/content/pages/blog/programming_languages/Go.gmi +++ b/content/pages/blog/programming_languages/Go.gmi @@ -1,9 +1,3 @@ -# Go - -Author: Fuwn -Created: 2021. 07. 19. -Last Modified: 2021. 07. 20. - Golang... Go is quite a funny language to me. I have a hard time taking it seriously, not because of the name, but because of the way it handles. Don't get me wrong, Go is a great tool to have under your belt, but it just feels very... "childish" ... to ME. Other than the weird chills I get whilst working with it (I just had to get that off my back, for the record), I think Go is a pretty nifty language. Go has the "I can do anything! just not very well..." [0] feeling to it, and it is very much true! I don't write software in Go because it "fast!" or "great on memory!", I write software in Go because it "fast! ...", "to write in!". diff --git a/content/pages/blog/programming_languages/OCaml.gmi b/content/pages/blog/programming_languages/OCaml.gmi index 1b72d82..15c6ce7 100644 --- a/content/pages/blog/programming_languages/OCaml.gmi +++ b/content/pages/blog/programming_languages/OCaml.gmi @@ -1,9 +1,3 @@ -# OCaml - -Author: Fuwn -Created: 2021. 07. 23. -Last Modified: 2021. 07. 23. - ## Resources => https://www2.lib.uchicago.edu/keith/ocaml-class/why.html OCaml for the Skeptical diff --git a/content/pages/blog/programming_languages/Rust.gmi b/content/pages/blog/programming_languages/Rust.gmi index f996660..32b798f 100644 --- a/content/pages/blog/programming_languages/Rust.gmi +++ b/content/pages/blog/programming_languages/Rust.gmi @@ -1,9 +1,3 @@ -# Rust - -Author: Fuwn -Created: 2021. 07. 23. -Last Modified: 2021. 07. 23. - ## Resources => https://ceronman.com/2021/07/22/my-experience-crafting-an-interpreter-with-rust/ My experience crafting an interpreter with Rust \ No newline at end of file diff --git a/content/pages/blog/programming_languages/blog.json b/content/pages/blog/programming_languages/blog.json new file mode 100644 index 0000000..a35f9f4 --- /dev/null +++ b/content/pages/blog/programming_languages/blog.json @@ -0,0 +1,25 @@ +{ + "description": "Thoughts and Resources of the Programming Languages Fuwn Uses", + "posts": { + "Go": { + "author": "Fuwn", + "created": "2021. 07. 19.", + "last_modified": "2021. 07. 20." + }, + "Forth": { + "author": "Fuwn", + "created": "2022. 04. 21.", + "last_modified": "2022. 04. 21." + }, + "OCaml": { + "author": "Fuwn", + "created": "2021. 07. 23.", + "last_modified": "2021. 07. 23." + }, + "Rust": { + "author": "Fuwn", + "created": "2021. 07. 23.", + "last_modified": "2021. 07. 23." + } + } +} diff --git a/content/pages/blog/projects/GemRest.gmi b/content/pages/blog/projects/GemRest.gmi index 2e2a6d3..ef14bf0 100644 --- a/content/pages/blog/projects/GemRest.gmi +++ b/content/pages/blog/projects/GemRest.gmi @@ -1,11 +1,3 @@ -# GemRest - -Author: Fuwn -Created: 2022. 06. 11. -Last Modified: 2022. 06. 11. - -Simple solutions designed for the Gemini protocol; so you can rest easy by letting us handle the hassle. - => https://github.com/gemrest GitHub => https://gem.rest/ Website => gemini://gem.rest/ Gemini Capsule diff --git a/content/pages/blog/projects/blog.json b/content/pages/blog/projects/blog.json new file mode 100644 index 0000000..fca7c63 --- /dev/null +++ b/content/pages/blog/projects/blog.json @@ -0,0 +1,11 @@ +{ + "description": "Details and Resources for a Few of Fuwn’s Projects", + "posts": { + "GemRest": { + "description": "Simple solutions designed for the Gemini protocol; so you can rest easy by letting us handle the hassle.", + "author": "Fuwn", + "created": "2022. 06. 11.", + "last_modified": "2022. 06. 11." + } + } +} diff --git a/src/modules/blog.rs b/src/modules/blog.rs new file mode 100644 index 0000000..4672ec2 --- /dev/null +++ b/src/modules/blog.rs @@ -0,0 +1,22 @@ +// This file is part of Locus . +// Copyright (C) 2022-2022 Fuwn +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// Copyright (C) 2022-2022 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +mod config; +mod module; + +pub use module::module; diff --git a/src/modules/blog/config.rs b/src/modules/blog/config.rs new file mode 100644 index 0000000..34d9373 --- /dev/null +++ b/src/modules/blog/config.rs @@ -0,0 +1,59 @@ +// This file is part of Locus . +// Copyright (C) 2022-2022 Fuwn +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// Copyright (C) 2022-2022 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct Entry { + description: Option, + author: Option, + created: Option, + last_modified: Option, + name: Option, +} +impl Entry { + pub const fn description(&self) -> &Option { &self.description } + + pub const fn author(&self) -> &Option { &self.author } + + pub const fn name(&self) -> &Option { &self.name } + + pub const fn created(&self) -> &Option { &self.created } + + pub const fn last_modified(&self) -> &Option { &self.last_modified } +} + +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct Blog { + name: Option, + description: Option, + posts: Option>, +} +impl Blog { + pub const fn description(&self) -> &Option { &self.description } + + pub const fn name(&self) -> &Option { &self.name } + + pub const fn posts(&self) -> &Option> { &self.posts } + + pub fn from_string(string: &str) -> serde_json::Result { + serde_json::from_str(string) + } +} diff --git a/src/modules/blog/module.rs b/src/modules/blog/module.rs new file mode 100644 index 0000000..c6e904d --- /dev/null +++ b/src/modules/blog/module.rs @@ -0,0 +1,290 @@ +// This file is part of Locus . +// Copyright (C) 2022-2022 Fuwn +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// Copyright (C) 2022-2022 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +use std::{ + collections::HashMap, + fs::{self, read_dir}, + io::Read, +}; + +use crate::{modules::blog::config::Blog, route::track_mount, success}; + +#[allow(clippy::too_many_lines)] +pub fn module(router: &mut windmark::Router) { + let paths = read_dir("content/pages/blog").unwrap(); + let mut blogs: HashMap> = HashMap::new(); + + for path in paths { + let blog = path.unwrap().path().display().to_string(); + let blog_paths = read_dir(&blog).unwrap(); + let mut entries: HashMap<_, String> = HashMap::new(); + + blog_paths + .map(|e| e.unwrap().path().display().to_string()) + .for_each(|file| { + let mut contents = String::new(); + + fs::File::open(&file) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); + + entries.insert( + file.replace(&blog, "").replace(".gmi", "").replace( + { + #[cfg(windows)] + { + '\\' + } + + #[cfg(unix)] + { + '/' + } + }, + "", + ), + contents, + ); + }); + + blogs.insert( + blog + .replace( + { + #[cfg(windows)] + { + "content/pages/blog\\" + } + + #[cfg(unix)] + { + "content/pages/blog/" + } + }, + "", + ) + .split('_') + .map(|s| { + // https://gist.github.com/jpastuszek/2704f3c5a3864b05c48ee688d0fd21d7 + let mut c = s.chars(); + + match c.next() { + None => String::new(), + Some(f) => + f.to_uppercase() + .chain(c.flat_map(char::to_lowercase)) + .collect(), + } + }) + .collect::>() + .join(" "), + entries, + ); + } + + let blog_clone = blogs.clone(); + + track_mount( + router, + "/blog", + "Fuwn's blogs", + Box::new(move |context| { + success!( + &format!( + "# BLOGS ({})\n\n{}", + blog_clone.len(), + blog_clone + .iter() + .map(|(title, entries)| (title.clone(), entries.clone())) + .collect::>() + .into_iter() + .map(|(title, entries)| { + let config: Option = + entries.get("blog.json").and_then(|content| { + if let Ok(config) = Blog::from_string(content) { + Some(config) + } else { + None + } + }); + let name = config + .clone() + .unwrap_or_default() + .name() + .clone() + .unwrap_or_else(|| title.clone()); + let description = config + .unwrap_or_default() + .description() + .clone() + .unwrap_or_else(|| "One of Fuwn's blogs".to_string()); + + format!( + "=> {} {} ― {}", + format_args!( + "/blog/{}", + name.replace(' ', "_").to_lowercase(), + ), + name, + description + ) + }) + .collect::>() + .join("\n") + ), + context + ) + }), + ); + + for (blog, mut entries) in blogs { + let fixed_blog_name = blog.replace(' ', "_").to_lowercase(); + let fixed_blog_name_clone = fixed_blog_name.clone(); + let config: Option = + entries.remove_entry("blog.json").and_then(|(_, content)| { + if let Ok(config) = Blog::from_string(&content) { + Some(config) + } else { + None + } + }); + let entries_clone = entries.clone(); + let name = config + .clone() + .unwrap_or_default() + .name() + .clone() + .unwrap_or_else(|| blog.clone()); + let description = config + .clone() + .unwrap_or_default() + .description() + .clone() + .unwrap_or_else(|| "One of Fuwn's blogs".to_string()); + let config_clone = config.clone(); + + track_mount( + router, + &format!("/blog/{}", fixed_blog_name), + &format!("{} ― {}", name, description), + Box::new(move |context| { + success!( + &format!( + "# {} ({})\n\n{}\n\n{}", + blog.to_uppercase(), + entries_clone.len(), + description, + entries_clone + .iter() + .map(|(title, _)| title.clone()) + .collect::>() + .into_iter() + .map(|title| { + format!( + "=> {} {}{}", + format_args!( + "/blog/{}/{}", + fixed_blog_name_clone, + title.to_lowercase() + ), + title, + { + let post = config_clone + .clone() + .unwrap_or_default() + .posts() + .clone() + .and_then(|posts| posts.get(&title).cloned()) + .unwrap_or_default() + .description() + .clone() + .unwrap_or_else(|| "".to_string()); + + if post.is_empty() { + "".to_string() + } else { + format!(" ― {}", post) + } + } + ) + }) + .collect::>() + .join("\n") + ), + context + ) + }), + ); + + for (title, contents) in entries { + let header = if let Ok(header) = construct_header(&config, &title) { + header + } else { + "".to_string() + }; + + track_mount( + router, + &format!("/blog/{}/{}", fixed_blog_name, title.to_lowercase()), + &format!("{}, {} ― An entry to one of Fuwn's blogs", name, title), + Box::new(move |context| { + success!(format!("{}\n{}", header, contents), context) + }), + ); + } + } +} + +fn construct_header(config: &Option, name: &str) -> Result { + let post = + if let Some(posts) = config.clone().unwrap_or_default().posts().clone() { + if let Some(post) = posts.get(name) { + post.clone() + } else { + return Err(()); + } + } else { + return Err(()); + }; + + Ok(format!( + "# {}\n\n{}{}{}{}", + post.name().clone().unwrap_or_else(|| name.to_string()), + if post.author().is_some() { + format!("Author: {}\n", post.author().clone().unwrap()) + } else { + "".to_string() + }, + if post.created().is_some() { + format!("Created: {}\n", post.created().clone().unwrap()) + } else { + "".to_string() + }, + if post.last_modified().is_some() { + format!("Last Modified: {}\n", post.last_modified().clone().unwrap()) + } else { + "".to_string() + }, + if post.description().is_some() { + format!("\n{}\n", post.description().clone().unwrap()) + } else { + "".to_string() + }, + )) +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 4b67961..79025ae 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -16,7 +16,7 @@ // Copyright (C) 2022-2022 Fuwn // SPDX-License-Identifier: GPL-3.0-only -mod multi_blog; +mod blog; mod random; mod remarks; mod robots; @@ -28,7 +28,7 @@ mod uptime; pub fn module(router: &mut windmark::Router) { crate::statelesses!( - router, uptime, sitemap, search, remarks, multi_blog, random, r#static, - router, robots, + router, uptime, sitemap, search, remarks, blog, random, r#static, router, + robots, ); } diff --git a/src/modules/multi_blog.rs b/src/modules/multi_blog.rs deleted file mode 100644 index 4dda4b0..0000000 --- a/src/modules/multi_blog.rs +++ /dev/null @@ -1,184 +0,0 @@ -// This file is part of Locus . -// Copyright (C) 2022-2022 Fuwn -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 3. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// Copyright (C) 2022-2022 Fuwn -// SPDX-License-Identifier: GPL-3.0-only - -use std::{ - collections::HashMap, - fs::{self, read_dir}, - io::Read, -}; - -use crate::{route::track_mount, success}; - -#[allow(clippy::too_many_lines)] -pub fn module(router: &mut windmark::Router) { - let paths = read_dir("content/pages/blog").unwrap(); - let mut blogs: HashMap> = HashMap::new(); - - for path in paths { - let blog = path.unwrap().path().display().to_string(); - let blog_paths = read_dir(&blog).unwrap(); - let mut entries: HashMap<_, String> = HashMap::new(); - - blog_paths - .map(|e| e.unwrap().path().display().to_string()) - .for_each(|file| { - let mut contents = String::new(); - - fs::File::open(&file) - .unwrap() - .read_to_string(&mut contents) - .unwrap(); - - entries.insert( - file.replace(&blog, "").replace(".gmi", "").replace( - { - #[cfg(windows)] - { - '\\' - } - - #[cfg(unix)] - { - '/' - } - }, - "", - ), - contents, - ); - }); - - blogs.insert( - blog - .replace( - { - #[cfg(windows)] - { - "content/pages/blog\\" - } - - #[cfg(unix)] - { - "content/pages/blog/" - } - }, - "", - ) - .split('_') - .map(|s| { - // https://gist.github.com/jpastuszek/2704f3c5a3864b05c48ee688d0fd21d7 - let mut c = s.chars(); - - match c.next() { - None => String::new(), - Some(f) => - f.to_uppercase() - .chain(c.flat_map(char::to_lowercase)) - .collect(), - } - }) - .collect::>() - .join(" "), - entries, - ); - } - - let blog_clone = blogs.clone(); - - track_mount( - router, - "/blog", - "Fuwn's blogs", - Box::new(move |context| { - success!( - &format!( - "# BLOGS ({})\n\n{}", - blog_clone.len(), - blog_clone - .iter() - .map(|(title, _)| title.clone()) - .collect::>() - .into_iter() - .map(|i| { - format!( - "=> {} {}", - format_args!("/blog/{}", i.replace(' ', "_").to_lowercase(),), - i - ) - }) - .collect::>() - .join("\n") - ), - context - ) - }), - ); - - for (blog, entries) in blogs { - let fixed_blog_name = blog.replace(' ', "_").to_lowercase(); - let entries_clone = entries.clone(); - let fixed_blog_name_clone = fixed_blog_name.clone(); - let blog_clone = blog.clone(); - - track_mount( - router, - &format!("/blog/{}", fixed_blog_name), - &format!("{} ― One of Fuwn's blogs", &blog), - Box::new(move |context| { - success!( - &format!( - "# {} ({})\n\n{}", - blog.to_uppercase(), - entries_clone.len(), - entries_clone - .iter() - .map(|(title, _)| title.clone()) - .collect::>() - .into_iter() - .map(|i| { - format!( - "=> {} {}", - format_args!( - "/blog/{}/{}", - fixed_blog_name_clone, - i.to_lowercase() - ), - i - ) - }) - .collect::>() - .join("\n") - ), - context - ) - }), - ); - - for (title, contents) in entries { - track_mount( - router, - &format!("/blog/{}/{}", fixed_blog_name, title.to_lowercase()), - &format!( - "{}, {} ― An entry to one of Fuwn's blogs", - blog_clone, title - ), - Box::new(move |context| success!(contents, context)), - ); - } - } -} -- cgit v1.2.3