diff options
author | tempest <git@ashen.earth> | 2025-04-15 00:08:12 -0600 |
---|---|---|
committer | tempest <git@ashen.earth> | 2025-04-15 00:08:12 -0600 |
commit | b856f12cf422b96c37c12df3d7829e4d15ef4453 (patch) | |
tree | 4547df3ec3d347715292a860a5a63207fe428de3 /src/data/page.rs | |
parent | 128cc42557c8d7da46c63a40ea4469ed0eb7f26d (diff) |
Can find content data
Diffstat (limited to 'src/data/page.rs')
-rw-r--r-- | src/data/page.rs | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/data/page.rs b/src/data/page.rs new file mode 100644 index 0000000..6d0b802 --- /dev/null +++ b/src/data/page.rs @@ -0,0 +1,151 @@ +use std::{ + collections::HashMap, + fs::{self, File}, + io::{BufRead, BufReader}, + path::Path, +}; + +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use super::PageUuid; + +#[derive(Clone, Deserialize, Serialize, Debug)] +pub struct Page { + pub uuid: PageUuid, + pub author: Uuid, + pub title: String, + pub current_version: DateTime<Utc>, + pub prev_versions: Vec<DateTime<Utc>>, + content_offset: usize, +} + +pub struct Pages { + pub pages: HashMap<PageUuid, Page>, +} + +const METADATA_DIVIDER: &'static str = "<!-- trans rights ~ath&+ -->"; + +#[cfg(feature = "ssr")] +impl Pages { + pub fn init(pages_dir: &Path) -> Result<Self, String> { + // Read dir + let page_dirs = fs::read_dir(&pages_dir) + .map_err(|_| "Could not open pages data directory".to_string())?; + + // Parse each + let pages = page_dirs + .map(|dir_entry| -> Result<Page, String> { + let page_dir_path = dir_entry.as_ref().unwrap().path(); + + Pages::read_page(&page_dir_path) + }) + .collect::<Result<Vec<Page>, String>>()?; + + // Build lookup + Ok(Self { + pages: pages + .into_iter() + .map(|page| (page.uuid.clone(), page)) + .collect::<HashMap<_, _>>(), + }) + } + + fn read_page(page_dir: &Path) -> Result<Page, String> { + let current_page = page_dir + .join("current") + .canonicalize() + .map_err(|_| "Could not canonicalize page location".to_string())?; + + let mut reader = BufReader::new( + File::open(¤t_page).map_err(|_| "Could not open page file".to_string())?, + ); + let page_uuid = PageUuid( + Uuid::try_parse( + &page_dir + .file_name() + .ok_or("Could not read page directory".to_string())? + .to_str() + .unwrap(), + ) + .map_err(|_| "Could not parse page UUID".to_string())?, + ); + + let mut metadata_string = String::new(); + let mut current_line = String::new(); + let mut content_offset = 0; + 'readloop: while let Ok(size) = reader.read_line(&mut current_line) { + content_offset += size; + if size == 0 { + return Err("Page file is invalid".to_string()); + } + + if current_line.trim() == METADATA_DIVIDER { + break 'readloop; + } + + metadata_string.push_str(¤t_line); + current_line.truncate(0); + } + + #[derive(Deserialize)] + struct PageMetadata { + title: String, + author: String, + prev_versions: Option<Vec<String>>, + } + + let metadata: PageMetadata = toml::from_str(&metadata_string).map_err(|err| { + println!("{err:?}"); + "Page metadata is invalid".to_string() + })?; + let current_version = DateTime::parse_from_rfc3339( + current_page + .file_name() + .unwrap() + .to_str() + .unwrap() + .replace("_", ":") + .as_str(), + ) + .map_err(|_| "Invalid date format".to_string())? + .to_utc(); + let prev_versions = metadata + .prev_versions + .unwrap_or(Vec::new()) + .iter() + .filter_map(|str| { + DateTime::parse_from_rfc3339(str.replace("_", ":").as_str()) + .ok() + .map(|timestamp| timestamp.to_utc()) + }) + .collect::<Vec<_>>(); + + Ok(Page { + uuid: page_uuid, + author: Uuid::try_parse(&metadata.author) + .map_err(|_| "Could not parse author UUID".to_string())?, + title: metadata.title, + current_version, + prev_versions, + content_offset, + }) + } + + pub fn get_page(&self, uuid: PageUuid) -> Option<Page> { + todo!() + } + + pub fn create_page(&self, page: Page) { + todo!() + } + + pub fn update_page(&self, page: Page) { + todo!() + } + + pub fn delete_page(&self, uuid: PageUuid) -> Result<(), String> { + todo!() + } +} |