use super::page::{Page, PageTemplate}; use crate::app::AppConfig; use crate::static_files::StaticFilesManager; use serde::ser::{SerializeStruct, Serializer}; use serde::{Deserialize, Serialize}; use std::io::prelude::*; use std::path::PathBuf; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct WebSiteBuilder { root_page: Page, #[serde(default = "Vec::new")] assets_index: Vec<String>, templates: Vec<PageTemplate>, } #[derive(Debug, Clone)] pub struct WebSite { root_page: Page, pub static_files_manager: StaticFilesManager, templates: Vec<PageTemplate>, } impl Serialize for WebSite { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut state = serializer.serialize_struct("WebSite", 3)?; state.serialize_field("root_page", &self.root_page)?; state.serialize_field("templates", &self.templates)?; state.serialize_field("assets_index", &self.static_files_manager.index)?; state.end() } } impl WebSiteBuilder { pub fn from_json(json: &str) -> Self { serde_json::from_str(json).unwrap() } pub fn with_static_files_manager( &mut self, static_files_manager: StaticFilesManager, ) -> WebSite { WebSite { root_page: self.root_page.clone(), static_files_manager: { let mut static_files_manager = static_files_manager; static_files_manager.add_assets_pathes(&self.assets_index); static_files_manager }, templates: self.templates.clone(), } } #[cfg(test)] pub fn testing(test_dir: &PathBuf) -> WebSite { Self::from_json(crate::testing::TEST_JSON_WEBSITE) .with_static_files_manager(StaticFilesManager::testing_new(test_dir).unwrap()) } fn blank_website_template() -> PathBuf { std::env::current_dir() .unwrap() .join("templates") .join("new_website.json") } pub fn load(config: &AppConfig) -> Self { let file_path = match &config.load { Some(pth) => pth.clone(), None => { if let Some(loaded) = Self::try_load_from_existing_file(config) { return loaded; } Self::blank_website_template() } }; Self::from_json(&std::fs::read_to_string(file_path).unwrap()) } fn try_load_from_existing_file(config: &AppConfig) -> Option<Self> { let website_file_path = config.storage_dir.join("website.json"); if website_file_path.exists() { match &std::fs::read_to_string(&website_file_path) { Ok(json) => return Some(Self::from_json(&json)), Err(_) => return None, } } None } } impl WebSite { pub fn build(&mut self) -> Result<Self, String> { if let Err(err) = self.root_page.build( &self.templates, PathBuf::from("/"), &self.static_files_manager, ) { return Err(err); }; Ok(self.clone()) } pub fn save(&self, config: &AppConfig) -> std::io::Result<()> { let save_json = serde_json::to_string(self).unwrap(); let json_path = config.storage_dir.join("website.json"); let mut f = std::fs::OpenOptions::new() .write(true) .create(true) .truncate(true) .open(&json_path)?; f.write_all(save_json.as_bytes())?; f.flush()?; Ok(()) } }