From c0676f8f867e9e9453bda878e8110f2ca5db1f80 Mon Sep 17 00:00:00 2001 From: peterrabbit <peterrabbit@msi.home> Date: Mon, 22 Aug 2022 16:25:19 +0200 Subject: [PATCH] wip model structure --- model.dia | Bin 3619 -> 3662 bytes src/service/page.rs | 2 +- src/website/css.rs | 5 +++ src/website/html.rs | 21 +++++---- src/website/item.rs | 17 ++++++++ src/website/mod.rs | 2 + src/website/page.rs | 84 ++++++++++++++++++++++-------------- src/website/website.rs | 96 ++++++++++++++++++++--------------------- 8 files changed, 136 insertions(+), 91 deletions(-) create mode 100644 src/website/css.rs create mode 100644 src/website/item.rs diff --git a/model.dia b/model.dia index 6a0f8a70ac906e294656c8f730efb72eb6e387cd..2c33574f1873a2c4abcc01875ba5adff2d75df05 100644 GIT binary patch delta 3523 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 delta 3508 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 Jo8F+M`45+@;+6ma diff --git a/src/service/page.rs b/src/service/page.rs index 197a50e..7a5ddea 100644 --- a/src/service/page.rs +++ b/src/service/page.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; pub async fn page(website: web::Data<WebSite>, pth: web::Path<PathBuf>) -> impl Responder { let pth = pth.into_inner(); match website.get_page_by_url(&pth) { - Some(page) => HttpResponse::Ok().body(page.html_doc.to_string()), + Some(page) => HttpResponse::Ok().body(page.html.to_string()), None => HttpResponse::NotFound().body(format!("Not found {}", pth.display())), } } diff --git a/src/website/css.rs b/src/website/css.rs new file mode 100644 index 0000000..27a5b58 --- /dev/null +++ b/src/website/css.rs @@ -0,0 +1,5 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct StyleSheet(pub HashMap<String, String>); diff --git a/src/website/html.rs b/src/website/html.rs index 9385527..447612a 100644 --- a/src/website/html.rs +++ b/src/website/html.rs @@ -1,8 +1,11 @@ -use crate::website::page::PageData; +use super::page::Page; use regex::{Captures, Regex}; use serde::{Deserialize, Serialize}; -pub const HTML_DOC_TEMPLATE: &'static str = " +// const CSS_LINK_FRAGMENT: &'static str = "<link rel='stylesheet' href='{url}'>"; +// const SCRIPT_FRAGMENT: &'static str = "<script src='{url}'></script>"; + +const HTML_DOC_TEMPLATE: &'static str = " <html lang='{lang}'> <head> <meta charset='UTF-8'> @@ -10,14 +13,14 @@ pub const HTML_DOC_TEMPLATE: &'static str = " <meta name='viewport' content='width=device-width, initial-scale=1.0'> <meta name='description' content='{description}'> <title>{title}</title> - <link rel='stylesheet' href='{css}'> + {css} </head> <body> {body} </body> -<script src='{js}'></script> +{js} </html> "; @@ -26,21 +29,23 @@ pub const HTML_DOC_TEMPLATE: &'static str = " pub struct HtmlDoc(String); impl HtmlDoc { - pub fn from_page_data(page_data: &PageData) -> Self { + pub fn from_page(page: &Page) -> Self { let re = Regex::new(r#"\{[a-z]+\}"#).unwrap(); let html = re .replace_all(HTML_DOC_TEMPLATE, |captures: &Captures| { 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) + page.text_from_key(placeholder) }) .to_string(); HtmlDoc(html) } +} - pub fn to_string(&self) -> String { - self.0.clone() +impl std::fmt::Display for HtmlDoc { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) } } diff --git a/src/website/item.rs b/src/website/item.rs new file mode 100644 index 0000000..9c0ca17 --- /dev/null +++ b/src/website/item.rs @@ -0,0 +1,17 @@ +use super::css::StyleSheet; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Item { + contents: Vec<ItemContent>, + layout: StyleSheet, +} + +impl std::fmt::Display for Item { + fn fmt(&self, _f: &mut std::fmt::Formatter) -> std::fmt::Result { + unimplemented!() + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ItemContent {} diff --git a/src/website/mod.rs b/src/website/mod.rs index fcd415f..3f286a7 100644 --- a/src/website/mod.rs +++ b/src/website/mod.rs @@ -1,4 +1,6 @@ +mod css; mod html; +mod item; mod page; mod website; diff --git a/src/website/page.rs b/src/website/page.rs index 4f38e7a..28362f1 100644 --- a/src/website/page.rs +++ b/src/website/page.rs @@ -1,47 +1,67 @@ -use crate::website::html::HtmlDoc; +use super::css::StyleSheet; +use super::html::HtmlDoc; +use super::item::*; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PageData { - pub title: String, - pub lang: String, - pub description: String, - pub slug: String, - pub html_body: String, - pub css_src: Option<String>, - pub js_src: Option<String>, +pub struct Page { + template: PageTemplate, + body: PageBody, + pub metadata: PageMetadata, + pub sub_pages: Vec<Page>, + pub html: HtmlDoc, } #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct WebPage { - pub page_data: PageData, - pub html_doc: HtmlDoc, +pub struct PageTemplate { + layout: StyleSheet, + name: String, + fixed_contents: Vec<ItemContent>, } -impl PageData { - pub fn to_web_page(&self) -> WebPage { - WebPage { - page_data: self.clone(), - html_doc: HtmlDoc::from_page_data(&self), - } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PageBody(Vec<Item>); + +impl std::fmt::Display for PageBody { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{}", + &self + .0 + .iter() + .map(|i| i.to_string()) + .collect::<Vec<String>>() + .join("") + ) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PageMetadata { + pub title: String, + pub lang: String, + pub description: String, + pub url_slug: String, + pub css_src: Vec<String>, + pub js_src: Vec<String>, +} + +impl Page { + pub fn build_html(&mut self) { + self.html = HtmlDoc::from_page(self); } - pub fn field_from_str_key(&self, key: String) -> String { + pub fn text_from_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(), + "title" => self.metadata.title.to_owned(), + "lang" => self.metadata.lang.to_owned(), + "description" => self.metadata.description.to_owned(), + "slug" => self.metadata.url_slug.to_owned(), + "body" => self.body.to_string(), + // "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(), } } } - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PagesTree { - pub page_data: PageData, - pub sub_pages: Option<Vec<PagesTree>>, -} diff --git a/src/website/website.rs b/src/website/website.rs index 6a6cb1f..18e7d70 100644 --- a/src/website/website.rs +++ b/src/website/website.rs @@ -1,28 +1,27 @@ use crate::app::AppConfig; -use crate::website::page::{PagesTree, WebPage}; +use crate::website::page::{Page, PageTemplate}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct WebSite { - pages_tree: PagesTree, - pages_index_by_url: HashMap<PathBuf, WebPage>, + root_page: Page, + assets_index: Vec<String>, + templates: Vec<PageTemplate>, + pages_index: HashMap<PathBuf, Page>, } impl WebSite { - pub fn new(pages_tree: PagesTree) -> Self { - let mut pages_index_by_url = HashMap::new(); - WebSite::create_index_by_url(&mut pages_index_by_url, &pages_tree, PathBuf::from("/")); - - WebSite { - pages_tree, - pages_index_by_url, + pub fn from_json(json: &str) -> Self { + let mut obj: Self = serde_json::from_str(json).unwrap(); + obj.build_assets_index(); + obj.build_pages_index(obj.root_page.clone(), PathBuf::from("/")); + obj.root_page.build_html(); + for p in obj.root_page.sub_pages.iter_mut() { + p.build_html(); } - } - - pub fn from_json_str(json: &str) -> Self { - WebSite::new(serde_json::from_str(json).unwrap()) + obj } pub fn load(config: &AppConfig) -> WebSite { @@ -34,52 +33,49 @@ impl WebSite { Some(pth) => pth.clone(), }; - WebSite::from_json_str(&std::fs::read_to_string(file_path).unwrap()) + WebSite::from_json(&std::fs::read_to_string(file_path).unwrap()) } - fn create_index_by_url( - index: &mut HashMap<PathBuf, WebPage>, - pages_tree: &PagesTree, - from_url: PathBuf, - ) { - let page_data = pages_tree.page_data.clone(); - let url = from_url.join(&page_data.slug); + fn build_pages_index(&mut self, root_page: Page, from_url: PathBuf) { + let url = from_url.join(&root_page.metadata.url_slug); - index.insert(url.clone(), page_data.to_web_page()); + self.pages_index.insert(url.clone(), root_page.clone()); - if let Some(sub_pages) = &pages_tree.sub_pages { - for pt in sub_pages { - WebSite::create_index_by_url(index, pt, url.clone()); - } + for p in root_page.sub_pages { + self.build_pages_index(p, url.clone()); } } - pub fn get_page_by_url(&self, url: &PathBuf) -> Option<&WebPage> { - self.pages_index_by_url.get(&PathBuf::from("/").join(url)) + fn build_assets_index(&mut self) { + unimplemented!(); + } + + pub fn get_page_by_url(&self, url: &PathBuf) -> Option<&Page> { + self.pages_index.get(&PathBuf::from("/").join(url)) } } -#[cfg(test)] -mod test_website { - use super::*; - use crate::testing::TEST_JSON_WEBSITE; +// #[cfg(test)] +// mod test_website { +// use super::*; +// use crate::testing::TEST_JSON_WEBSITE; - #[test] - fn test_index_pages_by_slug() { - let website = WebSite::from_json_str(TEST_JSON_WEBSITE); - let root_page = website.get_page_by_url(&PathBuf::from("/")); - assert!(root_page.is_some()); - let root_page = root_page.unwrap(); - assert_eq!(root_page.page_data.html_body, "<h1>Test Website</h1>"); +// #[test] +// fn test_index_pages_by_slug() { +// let website = WebSite::from_json(TEST_JSON_WEBSITE); +// let root_page = website.get_page_by_url(&PathBuf::from("/")); +// assert!(root_page.is_some()); +// let root_page = root_page.unwrap(); +// assert_eq!(root_page.page_data.html_body, "<h1>Test Website</h1>"); - let sub_page = website.get_page_by_url(&PathBuf::from("subpage")); - assert!(sub_page.is_some()); - let sub_page = sub_page.unwrap(); - assert_eq!(sub_page.page_data.html_body, "<h1>A sub page</h1>"); +// let sub_page = website.get_page_by_url(&PathBuf::from("subpage")); +// assert!(sub_page.is_some()); +// let sub_page = sub_page.unwrap(); +// assert_eq!(sub_page.page_data.html_body, "<h1>A sub page</h1>"); - 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>"); - } -} +// 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>"); +// } +// } -- GitLab