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 5.69 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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::*;
        const JSON_TEMPLATE: &'static str = "
    {
        \"page_data\": {
            \"title\": \"Test Website\",
            \"slug\": \"\",
            \"lang\": \"en\",
            \"description\": \"A test website\",
            \"html_body\": \"<h1>Test Website</h1>\"
        },
        \"sub_pages\": [
            {
                \"page_data\": {
                    \"title\": \"A sub page\",
                    \"slug\": \"subpage\",
                    \"lang\": \"en\",
                    \"description\": \"A sub page of the testing web site\",
                    \"html_body\": \"<h1>A sub page</h1>\"
                },
                \"sub_pages\": [
                    {
                        \"page_data\": {
    
    peterrabbit's avatar
    peterrabbit committed
                            \"title\": \"Nested page\",
    
    peterrabbit's avatar
    peterrabbit committed
                            \"lang\": \"en\",
    
    peterrabbit's avatar
    peterrabbit committed
                            \"slug\": \"nested\",
                            \"description\": \"Nested testing page\",
                            \"html_body\": \"<h1>Nested page</h1>\"
    
    peterrabbit's avatar
    peterrabbit committed
                        } 
                    }
                ]
            }
        ]
    }
            ";
    
        #[test]
        fn test_index_pages_by_slug() {
    
    peterrabbit's avatar
    peterrabbit committed
            let website = WebSite::from_json_str(JSON_TEMPLATE);
            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
        }
    }