Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
website.rs 4.75 KiB
Newer Older
peterrabbit's avatar
peterrabbit committed
use crate::app_state::AppConfig;
peterrabbit's avatar
peterrabbit committed
use regex::{Captures, Regex};
peterrabbit's avatar
peterrabbit committed
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
peterrabbit's avatar
peterrabbit committed
use std::path::PathBuf;
peterrabbit's avatar
peterrabbit committed

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PageData {
    pub title: String,
    pub lang: String,
    pub description: String,
    pub slug: String,
    pub html_body: String,
peterrabbit's avatar
peterrabbit committed
    pub css_src: Option<String>,
    pub js_src: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlDoc(String);

impl HtmlDoc {
peterrabbit's avatar
peterrabbit committed
    fn load_template() -> String {
        std::fs::read_to_string(
peterrabbit's avatar
peterrabbit committed
            std::env::current_dir()
                .unwrap()
                .join("templates")
                .join("html_doc.html"),
        )
peterrabbit's avatar
peterrabbit committed
        .expect("Missing html_doc template")
    }
peterrabbit's avatar
peterrabbit committed

peterrabbit's avatar
peterrabbit committed
    pub fn from_page_data(page_data: &PageData) -> Self {
peterrabbit's avatar
peterrabbit committed
        let re = Regex::new(r#"\{[a-z]+\}"#).unwrap();

peterrabbit's avatar
peterrabbit committed
        let html = re
            .replace_all(&HtmlDoc::load_template(), |captures: &Captures| {
peterrabbit's avatar
peterrabbit committed
                let placeholder = captures.iter().next().unwrap().unwrap().as_str();
                let placeholder = placeholder[1..placeholder.len() - 1].to_owned();
                page_data.field_from_str_key(placeholder)
            })
            .to_string();

peterrabbit's avatar
peterrabbit committed
        HtmlDoc(html)
peterrabbit's avatar
peterrabbit committed
    }

    pub fn to_string(&self) -> String {
        self.0.clone()
    }
peterrabbit's avatar
peterrabbit committed
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WebPage {
    pub page_data: PageData,
peterrabbit's avatar
peterrabbit committed
    pub html_doc: HtmlDoc,
peterrabbit's avatar
peterrabbit committed
}

impl PageData {
    pub fn to_web_page(&self) -> WebPage {
        WebPage {
            page_data: self.clone(),
peterrabbit's avatar
peterrabbit committed
            html_doc: HtmlDoc::from_page_data(&self),
        }
    }

    pub fn field_from_str_key(&self, key: String) -> String {
        match &key[..] {
            "title" => self.title.to_owned(),
            "lang" => self.lang.to_owned(),
            "description" => self.description.to_owned(),
            "slug" => self.slug.to_owned(),
            "body" => self.html_body.to_owned(),
            "css" => self.css_src.as_ref().unwrap_or(&String::new()).to_owned(),
            "js" => self.js_src.as_ref().unwrap_or(&String::new()).to_owned(),
            _ => String::new(),
peterrabbit's avatar
peterrabbit committed
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PagesTree {
    pub page_data: PageData,
    pub sub_pages: Option<Vec<PagesTree>>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WebSite {
    pages_tree: PagesTree,
peterrabbit's avatar
peterrabbit committed
    pages_index_by_url: HashMap<PathBuf, WebPage>,
peterrabbit's avatar
peterrabbit committed
}

impl WebSite {
    pub fn new(pages_tree: PagesTree) -> Self {
        let mut pages_index_by_url = HashMap::new();
peterrabbit's avatar
peterrabbit committed
        WebSite::create_index_by_url(&mut pages_index_by_url, &pages_tree, PathBuf::from("/"));
peterrabbit's avatar
peterrabbit committed

        WebSite {
            pages_tree,
            pages_index_by_url,
        }
    }

peterrabbit's avatar
peterrabbit committed
    pub fn from_json_str(json: &str) -> Self {
        WebSite::new(serde_json::from_str(json).unwrap())
    }

peterrabbit's avatar
peterrabbit committed
    pub fn load(config: &AppConfig) -> WebSite {
        let file_path = match &config.load {
            None => std::env::current_dir()
                .unwrap()
                .join("templates")
                .join("new_website.json"),
            Some(pth) => pth.clone(),
        };

        WebSite::from_json_str(&std::fs::read_to_string(file_path).unwrap())
    }

peterrabbit's avatar
peterrabbit committed
    fn create_index_by_url(
peterrabbit's avatar
peterrabbit committed
        index: &mut HashMap<PathBuf, WebPage>,
peterrabbit's avatar
peterrabbit committed
        pages_tree: &PagesTree,
peterrabbit's avatar
peterrabbit committed
        from_url: PathBuf,
peterrabbit's avatar
peterrabbit committed
    ) {
        let page_data = pages_tree.page_data.clone();
peterrabbit's avatar
peterrabbit committed
        let url = from_url.join(&page_data.slug);
peterrabbit's avatar
peterrabbit committed

peterrabbit's avatar
peterrabbit committed
        index.insert(url.clone(), page_data.to_web_page());
peterrabbit's avatar
peterrabbit committed

        if let Some(sub_pages) = &pages_tree.sub_pages {
            for pt in sub_pages {
peterrabbit's avatar
peterrabbit committed
                WebSite::create_index_by_url(index, pt, url.clone());
peterrabbit's avatar
peterrabbit committed
    pub fn get_page_by_url(&self, url: &PathBuf) -> Option<&WebPage> {
        self.pages_index_by_url.get(&PathBuf::from("/").join(url))
peterrabbit's avatar
peterrabbit committed
    }
}

#[cfg(test)]
mod test_website {
    use super::*;
    use crate::testing::TEST_JSON_WEBSITE;
peterrabbit's avatar
peterrabbit committed

    #[test]
    fn test_index_pages_by_slug() {
        let website = WebSite::from_json_str(TEST_JSON_WEBSITE);
peterrabbit's avatar
peterrabbit committed
        let root_page = website.get_page_by_url(&PathBuf::from("/"));
peterrabbit's avatar
peterrabbit committed
        assert!(root_page.is_some());
        let root_page = root_page.unwrap();
        assert_eq!(root_page.page_data.html_body, "<h1>Test Website</h1>");

peterrabbit's avatar
peterrabbit committed
        let sub_page = website.get_page_by_url(&PathBuf::from("subpage"));
peterrabbit's avatar
peterrabbit committed
        assert!(sub_page.is_some());
        let sub_page = sub_page.unwrap();
        assert_eq!(sub_page.page_data.html_body, "<h1>A sub page</h1>");
peterrabbit's avatar
peterrabbit committed

        let nested_page = website.get_page_by_url(&PathBuf::from("subpage/nested"));
        assert!(nested_page.is_some());
        let nested_page = nested_page.unwrap();
        assert_eq!(nested_page.page_data.html_body, "<h1>Nested page</h1>");
peterrabbit's avatar
peterrabbit committed
    }
}