aboutsummaryrefslogtreecommitdiffstats
path: root/src/blog.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2024-01-31 17:54:14 +0000
committerLibravatar cel 🌸 <cel@blos.sm>2024-01-31 17:54:14 +0000
commitb78d026c242e8d95e611e050afd5b72eb562d56d (patch)
tree00bf948afb9d4563b5ea506a8983b57a9293c7d5 /src/blog.rs
parentbea1a0e0c81e78133bb534c744ee858b6b1ad200 (diff)
downloadblossom-b78d026c242e8d95e611e050afd5b72eb562d56d.tar.gz
blossom-b78d026c242e8d95e611e050afd5b72eb562d56d.tar.bz2
blossom-b78d026c242e8d95e611e050afd5b72eb562d56d.zip
genericise articles
Diffstat (limited to 'src/blog.rs')
-rw-r--r--src/blog.rs146
1 files changed, 30 insertions, 116 deletions
diff --git a/src/blog.rs b/src/blog.rs
index 22cee05..0e757d5 100644
--- a/src/blog.rs
+++ b/src/blog.rs
@@ -7,12 +7,13 @@ use tokio::{fs, io::AsyncReadExt};
use chrono::{DateTime, Utc};
use crate::{
+ article::Article,
error::BlossomError,
posts::{Post, PostType},
Result,
};
-static ARTICLES_DIR: &str = "./articles";
+static DIRECTORY: &str = "./articles";
#[derive(Clone)]
pub struct Blogpost {
@@ -32,6 +33,32 @@ pub struct BlogpostMetadata {
tags: Vec<String>,
}
+impl Article for Blogpost {
+ type Metadata = BlogpostMetadata;
+
+ type Article = Blogpost;
+
+ fn directory() -> &'static str {
+ DIRECTORY
+ }
+
+ fn new(file_name: String, metadata: Self::Metadata, content: String) -> Result<Self::Article> {
+ let updated_at = if let Some(updated_at) = metadata.updated_at {
+ Some(updated_at.parse::<DateTime<Utc>>()?)
+ } else {
+ None
+ };
+ Ok(Blogpost {
+ file_name,
+ title: metadata.title,
+ published_at: metadata.published_at.parse::<DateTime<Utc>>()?,
+ updated_at,
+ tags: metadata.tags,
+ content,
+ })
+ }
+}
+
impl Post for Blogpost {
fn id(&self) -> &str {
&self.file_name
@@ -45,12 +72,8 @@ impl Post for Blogpost {
&self.published_at
}
- fn updated_at(&self) -> &DateTime<Utc> {
- if let Some(updated_at) = &self.updated_at {
- updated_at
- } else {
- &self.published_at
- }
+ fn updated_at(&self) -> Option<&DateTime<Utc>> {
+ self.updated_at.as_ref()
}
fn tags(&self) -> &Vec<String> {
@@ -74,113 +97,4 @@ impl Blogpost {
pub fn file_name(&self) -> &str {
&self.file_name
}
-
- async fn from_path(path: impl AsRef<Path>) -> Result<Self> {
- let mut file = fs::File::open(&path).await?;
- let mut buf = String::new();
- file.read_to_string(&mut buf).await?;
- let parse_options = ParseOptions {
- constructs: Constructs {
- frontmatter: true,
- ..Constructs::gfm()
- },
- ..ParseOptions::default()
- };
- let metadata: BlogpostMetadata = markdown::to_mdast(&buf, &parse_options)
- .unwrap()
- .try_into()?;
- let file_name = path
- .as_ref()
- .file_name()
- .ok_or(BlossomError::NotAFile)?
- .to_string_lossy();
- let file_name = file_name[..file_name.len() - 3].to_owned();
- let updated_at = if let Some(updated_at) = metadata.updated_at {
- Some(updated_at.parse::<DateTime<Utc>>()?)
- } else {
- None
- };
- // TODO: cache render only when needed
- let options = Options {
- parse: parse_options,
- compile: CompileOptions {
- gfm_task_list_item_checkable: true,
- allow_dangerous_html: true,
- ..CompileOptions::default()
- },
- };
- let content = markdown::to_html_with_options(&buf, &options).unwrap();
- Ok(Self {
- file_name,
- title: metadata.title,
- published_at: metadata.published_at.parse::<DateTime<Utc>>()?,
- updated_at,
- tags: metadata.tags,
- content,
- })
- }
-
- // async fn render(&mut self) -> Result<String> {
- // let path = Path::new(ARTICLES_DIR)
- // .join(&self.file_name)
- // .with_extension("md");
- // // TODO: remove unwraps when file read failure
- // let mut file = fs::File::open(&path).await.unwrap();
- // let mut buf = String::new();
- // file.read_to_string(&mut buf).await.unwrap();
- // let parse_options = ParseOptions {
- // constructs: Constructs {
- // frontmatter: true,
- // ..Constructs::gfm()
- // },
- // ..ParseOptions::default()
- // };
- // let options = Options {
- // parse: parse_options,
- // compile: CompileOptions {
- // gfm_task_list_item_checkable: true,
- // allow_dangerous_html: true,
- // ..CompileOptions::default()
- // },
- // };
- // let content = markdown::to_html_with_options(&buf, &options).unwrap();
- // Ok(content)
- // }
-}
-
-impl TryFrom<Node> for BlogpostMetadata {
- type Error = BlossomError;
-
- fn try_from(tree: Node) -> std::prelude::v1::Result<Self, Self::Error> {
- let children = tree.children();
- if let Some(children) = children {
- if let Some(toml) = children.into_iter().find_map(|el| match el {
- Node::Toml(toml) => Some(&toml.value),
- _ => None,
- }) {
- return Ok(toml::from_str(toml)?);
- };
- }
- Err(BlossomError::NoMetadata)
- }
-}
-
-pub async fn get_blogposts() -> Result<Vec<Blogpost>> {
- let mut blogposts: Vec<Blogpost> = Vec::new();
- let mut articles_dir = fs::read_dir(ARTICLES_DIR).await?;
- while let Some(entry) = articles_dir.next_entry().await? {
- let blogpost = Blogpost::from_path(entry.path()).await?;
- blogposts.push(blogpost);
- }
- blogposts.sort_by_key(|post| post.published_at);
- blogposts.reverse();
- Ok(blogposts)
-}
-
-pub async fn get_blogpost(file_name: &str) -> Result<Blogpost> {
- let path = Path::new(ARTICLES_DIR)
- .join(Path::new(file_name))
- .with_extension("md");
- println!("{:?}", path);
- Blogpost::from_path(path).await
}