agadir 0.1.0

Blogging over the terminal
Documentation
use std::{
    fs::{self, File},
    io::Read,
    path::PathBuf,
};

use chrono::NaiveDate;
use ratatui::text::Text;
use tracing::error;

use crate::formatter::Formatter;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone)]
pub struct Post<'a> {
    pub title: Text<'a>,
    pub created_at: NaiveDate,
    pub modified_at: NaiveDate,
    pub content: Text<'a>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MetaData {
    pub title: String,
    pub created_at: String,
    pub modified_at: String,
}

pub fn load_posts(path: PathBuf, formatter: Formatter<'_>) -> Vec<Post<'static>> {
    let mut posts: Vec<Post> = Vec::new();

    for entry in fs::read_dir(path).unwrap() {
        let entry = entry.unwrap();

        if entry.file_name() == "assets" {
            continue;
        }

        let path = entry.path();

        let mut buf = String::new();
        let Ok(mut file) = File::open(path.clone()) else {
            error!("{}", format!("Can not open the file {:?}", path.clone()));
            continue;
        };
        if file.read_to_string(&mut buf).is_err() {
            error!("{}", format!("Can not read the file {:?}", path.clone()));
            continue;
        }

        if let Some(text) = buf.clone().strip_prefix("---\n") {
            if let Some(index) = text.find("---\n") {
                let metadata = &text[..index];
                let file_name = path.file_name().unwrap().to_str().unwrap();

                let metadata = match serde_yaml::from_str::<MetaData>(metadata) {
                    Ok(v) => v,
                    Err(e) => {
                        error!(
                            "{}",
                            format!(
                                "Can not parse the metadata from the file `{}`: {}",
                                file_name, e
                            ),
                        );
                        continue;
                    }
                };

                let title = Text::from(metadata.title);

                let Ok(created_at) = NaiveDate::parse_from_str(&metadata.created_at, "%d/%m/%Y")
                else {
                    error!(
                            "{}",
                            format!("`created_at` field from the file `{}` is not in the right format `%d/%m/%Y`", file_name),
                        );
                    continue;
                };

                let Ok(modified_at) = NaiveDate::parse_from_str(&metadata.modified_at, "%d/%m/%Y")
                else {
                    error!(
                            "{}",
                            format!("`modified_at` field from the file `{}` is not in the right format `%d/%m/%Y`", file_name),
                        );
                    continue;
                };

                let content = formatter.format(&text[index + 5..]);

                let post = Post {
                    title,
                    created_at,
                    modified_at,
                    content,
                };

                posts.push(post.clone());
            }
        }
    }

    posts
}