From bd8bd674e47208f540674da60959a094e290eb2e Mon Sep 17 00:00:00 2001 From: Pierre Jarriges <pierre.jarriges@tutanota.com> Date: Thu, 29 Sep 2022 14:44:47 +0200 Subject: [PATCH] get page add page --- example.json | 4 +- src/main.rs | 4 +- src/service/admin.rs | 50 +++++++++-- src/website/page.rs | 4 + src/website/website.rs | 182 +++++++++++++++++++++++++++++++++-------- 5 files changed, 205 insertions(+), 39 deletions(-) diff --git a/example.json b/example.json index 5411f33..2a6360c 100644 --- a/example.json +++ b/example.json @@ -4,7 +4,9 @@ "metadata": { "title": "Hello Krustcea !", "description": "An example website", - "image": "https://example.com/images/ex_pic.png", + "image": [ + "https://example.com/images/ex_pic.png" + ], "css": [], "js": [], "url_slug": "", diff --git a/src/main.rs b/src/main.rs index ee1186c..b8d0cc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,7 +58,9 @@ async fn main() -> std::io::Result<()> { .service( web::scope("/auth") .wrap(AuthService {}) - .service(service::admin_workspace), + .service(service::admin_workspace) + .service(service::add_page) + .service(service::get_page_data), ), ) .service(service::files::favicon) diff --git a/src/service/admin.rs b/src/service/admin.rs index aa53c86..d10c659 100644 --- a/src/service/admin.rs +++ b/src/service/admin.rs @@ -1,13 +1,14 @@ +use crate::website::{Page, WebSite}; use crate::AppState; use actix_web::{ get, post, - web::{Data, Form}, - HttpRequest, HttpResponse, Responder, + web::{Data, Form, Json}, + HttpRequest, HttpResponse, }; use std::sync::RwLock; #[get("/workspace")] -async fn admin_workspace() -> impl Responder { +async fn admin_workspace() -> HttpResponse { // TODO return admin static web view with js application actix_web::HttpResponse::Ok().body("Welcome Admin") } @@ -23,7 +24,7 @@ async fn admin_authenticate( credentials: Form<Credentials>, app_state: Data<RwLock<AppState>>, req: HttpRequest, -) -> impl Responder { +) -> HttpResponse { let (admin_username, admin_pwd, cookie_name) = { let app_state = app_state .read() @@ -57,7 +58,7 @@ async fn admin_authenticate( } #[get("/login")] -pub async fn admin_login() -> impl Responder { +pub async fn admin_login() -> HttpResponse { // TODO create a module with built-in admin static views HttpResponse::Ok().body( " @@ -88,3 +89,42 @@ pub async fn admin_login() -> impl Responder { ", ) } + +#[derive(serde::Deserialize, Clone)] +pub struct AddPageData { + parent_page_id: usize, + new_page: Page, +} + +#[post("/add-page")] +pub async fn add_page( + website: Data<RwLock<WebSite>>, + add_page_data: Json<AddPageData>, +) -> HttpResponse { + match website + .write() + .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(), + Err(msg) => { + HttpResponse::BadRequest().body(format!("Error adding new page to website - {}", msg)) + } + } +} + +#[get("/page-data/{id}")] +pub async fn get_page_data( + website: Data<RwLock<WebSite>>, + id: actix_web::web::Path<usize>, +) -> HttpResponse { + let id = id.into_inner(); + match website + .read() + .expect("Couldn't acquire website read lock") + .get_page(id) + { + Some(page) => HttpResponse::Ok().json(page), + None => HttpResponse::NotFound().body(format!("Page with id {} was not found", id)), + } +} diff --git a/src/website/page.rs b/src/website/page.rs index 6559b01..cc95c88 100644 --- a/src/website/page.rs +++ b/src/website/page.rs @@ -318,6 +318,10 @@ impl Page { map } + + pub fn add_sub_page(&mut self, page: Page) { + self.sub_pages.push(page); + } } #[cfg(test)] diff --git a/src/website/website.rs b/src/website/website.rs index fc53a9b..3168dbf 100644 --- a/src/website/website.rs +++ b/src/website/website.rs @@ -115,47 +115,38 @@ impl WebSite { Ok(self.clone()) } - fn init_last_generated_page_id(&mut self) { - let mut ids = vec![self.root_page.get_id()]; - - fn collect_ids(p: &Page, ids: &mut Vec<usize>) { - for sp in p.sub_pages.iter() { - ids.push(sp.get_id()); - collect_ids(sp, ids); + pub fn get_all_pages_as_vec(&self) -> Vec<&Page> { + let mut pages = Vec::new(); + fn collect_pages<'a>(root: &'a Page, vec: &mut Vec<&'a Page>) { + vec.push(root); + for p in root.sub_pages.iter() { + collect_pages(p, vec); } } - - collect_ids(&self.root_page, &mut ids); - - self.last_generated_page_id = *ids.iter().max().unwrap(); + collect_pages(&self.root_page, &mut pages); + pages } - fn generate_pages_ids(&mut self) { - self.init_last_generated_page_id(); + fn max_page_id(&self) -> usize { + self.get_all_pages_as_vec() + .iter() + .map(|p| p.get_id()) + .max() + .unwrap() + } - fn generate_page_id(page: &mut Page, last_generated_page_id: &mut usize) { - if page.get_id() == 0 { - *last_generated_page_id += 1; - page.set_id(*last_generated_page_id); - } - } + fn generate_pages_ids<'a>(&'a mut self) { + self.last_generated_page_id = self.max_page_id(); - fn rec_gen_ids( - p: &mut Page, - gen_id: fn(&mut Page, &mut usize), - last_generated_page_id: &mut usize, - ) { - gen_id(p, last_generated_page_id); - for sp in p.sub_pages.iter_mut() { - rec_gen_ids(sp, gen_id, last_generated_page_id) + fn process_page(page: &mut Page, id: &mut usize) { + *id += 1; + page.set_id(*id); + for sp in page.sub_pages.iter_mut() { + process_page(sp, id); } } - rec_gen_ids( - &mut self.root_page, - generate_page_id, - &mut self.last_generated_page_id, - ); + process_page(&mut self.root_page, &mut self.last_generated_page_id); } pub fn save(&self, config: &AppConfig) -> std::io::Result<()> { @@ -172,4 +163,131 @@ impl WebSite { Ok(()) } + + fn find_page(page: &Page, match_id: usize) -> Option<&Page> { + if page.get_id() == match_id { + return Some(page); + } + for sp in page.sub_pages.iter() { + if let Some(page) = Self::find_page(sp, match_id) { + return Some(page); + }; + } + None + } + + fn find_page_mut(page: &mut Page, match_id: usize) -> Option<&mut Page> { + if page.get_id() == match_id { + return Some(page); + } + + for sp in page.sub_pages.iter_mut() { + if let Some(p) = Self::find_page_mut(sp, match_id) { + return Some(p); + }; + } + + None + } + + pub fn get_page(&self, id: usize) -> Option<&Page> { + Self::find_page(&self.root_page, id) + } + + pub fn add_page(&mut self, parent_page_id: usize, page: Page) -> Result<(), String> { + let id = self.last_generated_page_id + 1; + let parent_page = Self::find_page_mut(&mut self.root_page, parent_page_id); + match parent_page { + Some(pp) => { + let mut page = page; + page.set_id(id); + pp.add_sub_page(page); + } + None => { + return Err(format!( + "Parent page with id {} was not found", + parent_page_id + )) + } + } + + self.last_generated_page_id = id; + + Ok(()) + } +} + +#[cfg(test)] +mod test_website { + use super::*; + + fn test_website(pth: &PathBuf) -> WebSite { + WebSiteBuilder::testing(pth).build().unwrap() + } + + fn remove_test_dir(pth: &PathBuf) { + let _ = std::fs::remove_dir_all(pth); + } + + #[test] + fn test_pages_id() { + let test_dir = &PathBuf::from("./test"); + let ws = test_website(&test_dir); + + assert_eq!(ws.last_generated_page_id, 3); + assert_eq!(ws.max_page_id(), 3); + assert!(!ws.get_all_pages_as_vec().iter().any(|p| p.get_id() == 0)); + remove_test_dir(&test_dir); + } + + #[test] + fn test_get_page() { + let test_dir = &PathBuf::from("./test"); + let ws = test_website(&test_dir); + let page = ws.get_page(1); + assert!(page.is_some()); + let page = ws.get_page(2); + assert!(page.is_some()); + let page = ws.get_page(3); + assert!(page.is_some()); + let page = ws.get_page(4); + assert!(page.is_none()); + remove_test_dir(&test_dir); + } + + #[test] + fn test_add_page() { + let test_dir = &PathBuf::from("./test"); + let mut ws = test_website(&test_dir); + let test_new_page: &'static str = " +{ + \"template_name\": \"TEST TEMPLATE\", + \"metadata\": { + \"title\": \"Added page\", + \"description\": \"Added page descr\", + \"image\": [\"https://example.com/images/ex_pic.png\"], + \"css\": [], + \"js\": [], + \"url_slug\": \"\", + \"lang\": \"en\" + }, + \"body\": [ + { + \"tag\": \"h1\", + \"text\": \"Added page\" + } + ], + \"sub_pages\": [] +} + "; + + let new_page: Page = serde_json::from_str(test_new_page).unwrap(); + let added = ws.add_page(1, new_page); + assert!(added.is_ok()); + let retrieved = ws.get_page(4); + assert!(retrieved.is_some()); + let retrieved = retrieved.unwrap(); + assert_eq!(retrieved.metadata.title, "Added page"); + remove_test_dir(&test_dir); + } } -- GitLab