diff --git a/example.json b/example.json index 28042f411c7ad834eb447b8431dcb7efdfcffbb6..eb31b637426279b15d23335c61a7394798168dac 100644 --- a/example.json +++ b/example.json @@ -6,7 +6,8 @@ "description": "A website for Pijar", "image": "https://pijar.com/static/images/pijar_pic.png", "css": [], - "js": [] + "js": [], + "url_slug": "" }, "body": [ { @@ -30,7 +31,8 @@ } ] } - ] + ], + "sub_pages": [] }, "assets_index": { "images": [ diff --git a/model.dia b/model.dia index 597d424aac6e8a01527dacf244a11593bfc25138..6a0f8a70ac906e294656c8f730efb72eb6e387cd 100644 Binary files a/model.dia and b/model.dia differ diff --git a/src/app/args.rs b/src/app/args.rs new file mode 100644 index 0000000000000000000000000000000000000000..5deb639699e514f77384732bb7d6fa87ce8ac32a --- /dev/null +++ b/src/app/args.rs @@ -0,0 +1,26 @@ +use std::path::PathBuf; +use structopt::StructOpt; + +#[derive(Clone, StructOpt)] +pub struct AppArgs { + #[structopt(short = "c", long = "ctx", default_value = "debug")] + pub context: String, + + #[structopt(short = "d", long = "dir")] + pub app_storage_root: Option<PathBuf>, + + #[structopt(long)] + pub load: Option<PathBuf>, + + #[structopt(short, long, default_value = "localhost")] + pub host: String, + + #[structopt(short, long, default_value = "8080")] + pub port: u16, + + #[structopt(long = "ptls", default_value = "8443")] + pub port_tls: u16, + + #[structopt(long = "certs_dir", default_value = "/etc/letsencrypt/live")] + pub ssl_certs_dir: PathBuf, +} diff --git a/src/app_state.rs b/src/app/config.rs similarity index 65% rename from src/app_state.rs rename to src/app/config.rs index 9cd3f677f9ce359e6426560aca90046b95f5e999..42ce77848de5707a0e0386bcb28a3281a5906607 100644 --- a/src/app_state.rs +++ b/src/app/config.rs @@ -1,3 +1,4 @@ +use crate::app::AppArgs; use std::path::PathBuf; use structopt::StructOpt; @@ -7,30 +8,6 @@ pub enum AppContext { Production, } -#[derive(Clone, StructOpt)] -pub struct AppArgs { - #[structopt(short = "c", long = "ctx", default_value = "debug")] - pub context: String, - - #[structopt(short = "d", long = "dir")] - pub app_storage_root: Option<PathBuf>, - - #[structopt(long)] - pub load: Option<PathBuf>, - - #[structopt(short, long, default_value = "localhost")] - pub host: String, - - #[structopt(short, long, default_value = "8080")] - pub port: u16, - - #[structopt(long = "ptls", default_value = "8443")] - pub port_tls: u16, - - #[structopt(long = "certs_dir", default_value = "/etc/letsencrypt/live")] - pub ssl_certs_dir: PathBuf, -} - #[derive(Clone)] pub struct AppConfig { pub exec_path: PathBuf, @@ -91,23 +68,3 @@ impl AppConfig { } } } - -#[derive(Clone)] -pub struct AppState { - pub config: AppConfig, - pub preferences: AppPreference, - // authentication - // ... -} - -#[derive(Clone)] -pub struct AppPreference {} - -impl AppState { - pub fn new() -> Self { - AppState { - config: AppConfig::new(), - preferences: AppPreference {}, - } - } -} diff --git a/src/app/mod.rs b/src/app/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..e5bee9e4394401f26dfebbea5a6874ed924469c0 --- /dev/null +++ b/src/app/mod.rs @@ -0,0 +1,8 @@ +mod args; +mod config; +mod preferences; +mod state; +pub use args::*; +pub use config::*; +pub use preferences::*; +pub use state::*; diff --git a/src/app/preferences.rs b/src/app/preferences.rs new file mode 100644 index 0000000000000000000000000000000000000000..f097a658ef456d5f8d55e62499a90bf57ccc000f --- /dev/null +++ b/src/app/preferences.rs @@ -0,0 +1,2 @@ +#[derive(Clone)] +pub struct AppPreferences {} diff --git a/src/app/state.rs b/src/app/state.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d0dc75548ddbf3cc1fe0fed60a191b53af49768 --- /dev/null +++ b/src/app/state.rs @@ -0,0 +1,18 @@ +use crate::app::{AppConfig, AppPreferences}; + +#[derive(Clone)] +pub struct AppState { + pub config: AppConfig, + pub preferences: AppPreferences, + // authentication + // ... +} + +impl AppState { + pub fn new() -> Self { + AppState { + config: AppConfig::new(), + preferences: AppPreferences {}, + } + } +} diff --git a/src/main.rs b/src/main.rs index 1bd17254117dc4c20f4f1dbf45fd91b54af36052..c996be1f4371e3176c8f9ae649df1fb4db869b53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -mod app_state; +mod app; mod service; mod static_files; mod testing; @@ -6,7 +6,7 @@ mod tls_config; mod website; use actix_web::{App, HttpServer}; use actix_web_lab::middleware::RedirectHttps; -use app_state::AppState; +use app::AppState; use static_files::StaticFilesManager; use tls_config::tls_config; use website::WebSite; diff --git a/src/service.rs b/src/service/mod.rs similarity index 100% rename from src/service.rs rename to src/service/mod.rs diff --git a/src/static_files.rs b/src/static_files.rs index c4fbab6dd5d9e12d2babda955b05a58ffddd794d..4da405f36f67b5cfbac8679c84163147fa28c859 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -1,4 +1,4 @@ -use crate::app_state::AppState; +use crate::app::AppState; use std::path::{Path, PathBuf}; pub struct StaticFilesManager { diff --git a/src/tls_config.rs b/src/tls_config.rs index 61c23e834292fb988c87fdedf362cb88f7b3db56..b69f528a9c815460aee666b15dd4d0c50b5b6300 100644 --- a/src/tls_config.rs +++ b/src/tls_config.rs @@ -1,4 +1,4 @@ -use crate::app_state::AppConfig; +use crate::app::AppConfig; pub fn tls_config(app_config: &AppConfig) -> rustls::ServerConfig { let certs_dir = app_config.ssl_certs_dir.clone(); diff --git a/src/website/html.rs b/src/website/html.rs new file mode 100644 index 0000000000000000000000000000000000000000..9385527ab52b428fa313ab6d25cc15249d5ecd58 --- /dev/null +++ b/src/website/html.rs @@ -0,0 +1,46 @@ +use crate::website::page::PageData; +use regex::{Captures, Regex}; +use serde::{Deserialize, Serialize}; + +pub const HTML_DOC_TEMPLATE: &'static str = " +<html lang='{lang}'> +<head> + <meta charset='UTF-8'> + <meta http-equiv='X-UA-Compatible' content='IE=edge'> + <meta name='viewport' content='width=device-width, initial-scale=1.0'> + <meta name='description' content='{description}'> + <title>{title}</title> + <link rel='stylesheet' href='{css}'> +</head> + +<body> + {body} +</body> + +<script src='{js}'></script> + +</html> +"; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct HtmlDoc(String); + +impl HtmlDoc { + pub fn from_page_data(page_data: &PageData) -> 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) + }) + .to_string(); + + HtmlDoc(html) + } + + pub fn to_string(&self) -> String { + self.0.clone() + } +} diff --git a/src/website/mod.rs b/src/website/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..fcd415f3f758b45a0e5beb732b55fe40f845fcc3 --- /dev/null +++ b/src/website/mod.rs @@ -0,0 +1,5 @@ +mod html; +mod page; +mod website; + +pub use website::*; diff --git a/src/website/page.rs b/src/website/page.rs new file mode 100644 index 0000000000000000000000000000000000000000..4f38e7a9cbcdd0321f948fe899d74000edeadc8d --- /dev/null +++ b/src/website/page.rs @@ -0,0 +1,47 @@ +use crate::website::html::HtmlDoc; +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>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct WebPage { + pub page_data: PageData, + pub html_doc: HtmlDoc, +} + +impl PageData { + pub fn to_web_page(&self) -> WebPage { + WebPage { + page_data: self.clone(), + 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(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PagesTree { + pub page_data: PageData, + pub sub_pages: Option<Vec<PagesTree>>, +} diff --git a/src/website.rs b/src/website/website.rs similarity index 53% rename from src/website.rs rename to src/website/website.rs index c65d5c57cc5002b4c474cb079be4bb3b369ddf00..6a6cb1f8d665c336760c3ac7e77191bc2804f1f8 100644 --- a/src/website.rs +++ b/src/website/website.rs @@ -1,87 +1,9 @@ -use crate::app_state::AppConfig; -use regex::{Captures, Regex}; +use crate::app::AppConfig; +use crate::website::page::{PagesTree, WebPage}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; -#[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>, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct HtmlDoc(String); - -impl HtmlDoc { - fn load_template() -> String { - std::fs::read_to_string( - std::env::current_dir() - .unwrap() - .join("templates") - .join("html_doc.html"), - ) - .expect("Missing html_doc template") - } - - pub fn from_page_data(page_data: &PageData) -> Self { - let re = Regex::new(r#"\{[a-z]+\}"#).unwrap(); - - let html = re - .replace_all(&HtmlDoc::load_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) - }) - .to_string(); - - HtmlDoc(html) - } - - pub fn to_string(&self) -> String { - self.0.clone() - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct WebPage { - pub page_data: PageData, - pub html_doc: HtmlDoc, -} - -impl PageData { - pub fn to_web_page(&self) -> WebPage { - WebPage { - page_data: self.clone(), - 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(), - } - } -} - -#[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, diff --git a/templates/html_doc.html b/templates/html_doc.html deleted file mode 100644 index e8568983f7381e625c8a362998d811e2cf4fabb3..0000000000000000000000000000000000000000 --- a/templates/html_doc.html +++ /dev/null @@ -1,17 +0,0 @@ -<html lang="{lang}"> - -<head> - <meta charset="UTF-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="description" content="{description}"> - <title>{title}</title> - <link rel="stylesheet" href="{css}"> -</head> - -<body> - {body} -</body> -<script src="{js}"></script> - -</html> \ No newline at end of file diff --git a/templates/new_website.json b/templates/new_website.json index 92a78fa0bb711d3ca85824202be08689a336ee56..c6c845b183ec34d9d3fb805cb176ac14d07b0163 100644 --- a/templates/new_website.json +++ b/templates/new_website.json @@ -6,35 +6,5 @@ "description": "A new website", "html_body": "<h1>New Website</h1>" }, - "sub_pages": [ - { - "page_data": { - "title": "A sub page", - "lang": "en", - "slug": "subpage", - "description": "A sub page of the new web site", - "html_body": "<h1>A sub page</h1>" - } - }, - { - "page_data": { - "title": "Some other page", - "lang": "en", - "slug": "otherpage", - "description": "Some other page of the new web site", - "html_body": "<h1>Another page</h1>" - }, - "sub_pages": [ - { - "page_data": { - "title": "A sub page of the other page", - "lang": "en", - "slug": "othersubpage", - "description": "A sub page of the other page of the new web site", - "html_body": "<h1>A subpage</h1>" - } - } - ] - } - ] + "sub_pages": [] } \ No newline at end of file