diff --git a/src/main.rs b/src/main.rs index 976144819d6df23875539d9d50664b54e5c37426..2b314144ebc12410a71a55b6cbee438975048a45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,7 +63,9 @@ async fn main() -> std::io::Result<()> { .service(service::get_page_data) .service(service::update_page) .service(service::files::post_files) - .service(service::files::delete_static_file), + .service(service::files::delete_static_file) + .service(service::add_template) + .service(service::update_template), ), ) .service(service::files::favicon) diff --git a/src/service/website.rs b/src/service/website.rs index a7242a3b5a8cb3736e56159123f3d90d44206f01..1c5f1da042dedbccb475bb47f3d314762da26807 100644 --- a/src/service/website.rs +++ b/src/service/website.rs @@ -1,4 +1,4 @@ -use crate::website::{Page, WebSite}; +use crate::website::{Page, PageTemplate, WebSite}; use actix_web::{ get, post, put, web::{Data, Json}, @@ -23,7 +23,7 @@ pub async fn add_page( .expect("Couldn't acquire website write lock") .add_page(add_page_data.parent_page_id, add_page_data.new_page.clone()) { - Ok(()) => HttpResponse::Ok().finish(), + Ok(()) => HttpResponse::Created().finish(), Err(msg) => { HttpResponse::BadRequest().body(format!("Error adding new page to website - {}", msg)) } @@ -53,11 +53,11 @@ pub async fn update_page( updated_page: Json<Page>, ) -> HttpResponse { let id = id.into_inner(); - let updated_page = updated_page.into_inner(); + match website .write() .expect("Couldn't acquire website write lock") - .update_page(id, updated_page) + .update_page(id, updated_page.into_inner()) { Ok(page) => HttpResponse::Ok().json(page), Err(msg) => { @@ -65,3 +65,46 @@ pub async fn update_page( } } } + +#[post("/add-template")] +pub async fn add_template( + website: Data<RwLock<WebSite>>, + new_template: Json<PageTemplate>, +) -> HttpResponse { + match website + .write() + .expect("Couldn't acquire website write lock") + .add_template(new_template.into_inner()) + { + Ok(template) => HttpResponse::Created().json(template), + Err(msg) => HttpResponse::BadRequest().body(format!("Error adding new template {}", msg)), + } +} + +#[post("/update-template")] +pub async fn update_template( + website: Data<RwLock<WebSite>>, + updated_template: Json<PageTemplate>, +) -> HttpResponse { + let updated = { + let mut ws = website + .write() + .expect("Couldn't acquire website write lock"); + match ws.update_template(updated_template.into_inner()) { + Ok(template) => template.clone(), + Err(msg) => { + return HttpResponse::BadRequest().body(format!("Error updating template {}", msg)) + } + } + }; + + WebSite::update_page_rec_after_template_update( + &mut website + .write() + .expect("Couldn't acquire website write lock") + .root_page, + &updated, + ); + + HttpResponse::Ok().json(updated) +} diff --git a/src/website/mod.rs b/src/website/mod.rs index c1c6ad901df80cf18aef76011857b658ab59c3cf..19c8a3fe3d294136b4e906832a6bb4896409b663 100644 --- a/src/website/mod.rs +++ b/src/website/mod.rs @@ -3,5 +3,5 @@ mod html; mod page; mod website; -pub use page::Page; +pub use page::*; pub use website::*; diff --git a/src/website/page.rs b/src/website/page.rs index cc95c8857eb642b9b806b7aab59d5cc91f97da0b..34fc43b977e954cd77affb61ff7b3ac006f4c0a1 100644 --- a/src/website/page.rs +++ b/src/website/page.rs @@ -249,6 +249,17 @@ impl Page { Ok(()) } + pub fn update_template(&mut self, template: &PageTemplate) { + self.template = Some(template.clone()); + self.template_name = template.name.to_owned(); + } + + pub fn update_template_if_same_name(&mut self, template: &PageTemplate) { + if self.template_name.eq(&template.name) { + self.update_template(template); + } + } + pub fn set_template(&mut self, template: PageTemplate) { self.template = Some(template); } @@ -286,6 +297,7 @@ impl Page { .find(|t| t.name == self.template_name) .expect("Page template not found") } + fn write_to_static_file( &self, url: &PathBuf, diff --git a/src/website/website.rs b/src/website/website.rs index 2de39e99cd48f4341b02f34380f20b20ca4a09e8..946c180a32717c12e8a40db0358038918131ce22 100644 --- a/src/website/website.rs +++ b/src/website/website.rs @@ -19,7 +19,7 @@ pub struct WebSiteBuilder(WebSiteData); #[derive(Debug, Clone)] pub struct WebSite { last_generated_page_id: usize, - root_page: Page, + pub root_page: Page, pub static_files_manager: StaticFilesManager, templates: Vec<PageTemplate>, } @@ -229,6 +229,83 @@ impl WebSite { None => Err(format!("Page with id {} was not found", id)), } } + + fn validate_add_template(&self, template: &PageTemplate) -> Result<(), String> { + if !self.get_template(&template.name).is_none() { + return Err(format!( + "A template named \"{}\" already exists", + template.name + )); + } + + if PageTemplate::get_page_body_placeholder(&mut template.clone().contents).is_err() { + return Err(format!( + "Page body container was not found in template named \"{}\"", + template.name + )); + } + + Ok(()) + } + + fn validate_update_template(&self, template: &PageTemplate) -> Result<(), String> { + if self.get_template(&template.name).is_none() { + return Err(format!( + "Templated named \"{}\" was not found.", + template.name + )); + } + + if PageTemplate::get_page_body_placeholder(&mut template.clone().contents).is_err() { + return Err(format!( + "Page body container was not found in template named \"{}\"", + template.name + )); + } + + Ok(()) + } + + fn get_template(&self, name: &String) -> Option<&PageTemplate> { + self.templates.iter().find(|t| t.name.eq(name)) + } + + fn get_template_mut(&mut self, name: &String) -> Option<&mut PageTemplate> { + self.templates.iter_mut().find(|t| t.name.eq(name)) + } + + pub fn add_template(&mut self, new_template: PageTemplate) -> Result<&PageTemplate, String> { + match self.validate_add_template(&new_template) { + Ok(()) => { + let name = new_template.name.to_owned(); + self.templates.push(new_template); + Ok(self.get_template(&name).unwrap()) + } + Err(msg) => Err(msg), + } + } + + pub fn update_template( + &mut self, + updated_template: PageTemplate, + ) -> Result<&PageTemplate, String> { + match self.validate_update_template(&updated_template) { + Ok(()) => { + let template = self.get_template_mut(&updated_template.name).unwrap(); + *template = updated_template; + + Ok(template) + } + Err(msg) => Err(msg), + } + } + + pub fn update_page_rec_after_template_update(page: &mut Page, template: &PageTemplate) { + page.update_template_if_same_name(template); + for sp in page.sub_pages.iter_mut() { + Self::update_page_rec_after_template_update(sp, template); + } + } } #[cfg(test)] @@ -320,4 +397,79 @@ mod test_website { remove_test_dir(&test_dir); } + + #[test] + fn add_template() { + let test_template: &'static str = " +{ + \"name\": \"TEST ADD TEMPLATE\", + \"layout\": {}, + \"contents\": [ + { + \"tag\": \"div\", + \"attrs\": { + \"class\": \"page-template\" + }, + \"contents\": [ + { + \"tag\": \"header\", + \"contents\": [ + { + \"tag\": \"nav\" + } + ] + }, + { + \"tag\": \"div\", + \"attrs\": { + \"id\": \"page-body\" + } + }, + { + \"tag\": \"footer\" + } + ] + } + ] +} + "; + + let test_dir = PathBuf::from("./test"); + let mut ws = test_website(&test_dir); + + let new_template: PageTemplate = serde_json::from_str(test_template).unwrap(); + + let add_template_res = ws.add_template(new_template); + assert!(add_template_res.is_ok()); + + let added_template = add_template_res.unwrap(); + assert_eq!(added_template.name, "TEST ADD TEMPLATE"); + + remove_test_dir(&test_dir); + } + + #[test] + fn test_update_template() { + let test_dir = PathBuf::from("./test"); + let ws = test_website(&test_dir); + let (updated, mut ws) = { + let mut ws = ws; + let mut template = ws + .get_template(&"TEST TEMPLATE".to_string()) + .unwrap() + .clone(); + + template.contents[0].tag = "changed_tag".to_owned(); + + let updated = ws.update_template(template).unwrap(); + assert_eq!(updated.contents[0].tag, "changed_tag"); + (updated.clone(), ws) + }; + + WebSite::update_page_rec_after_template_update(&mut ws.root_page, &updated); + for p in ws.get_all_pages_as_vec() { + assert_eq!(p.template.as_ref().unwrap().contents[0].tag, "changed_tag"); + } + remove_test_dir(&test_dir); + } }