use markdown::Options; use rand::seq::SliceRandom; use rust_embed::RustEmbed; use std::collections::{HashMap, VecDeque}; use super::prop_structs::{PoemDatabase, PoemStruct}; #[derive(RustEmbed)] #[folder = "data/other"] struct OtherData; #[derive(RustEmbed)] #[folder = "data/poems"] pub struct Poems; impl PoemDatabase { pub fn new() -> PoemDatabase { PoemDatabase { poem_list: Vec::<(String, String)>::new(), poem_hashmap: HashMap::::new(), } } // There's no need to actually make a database yet, but maybe in the future... pub async fn build_poem_database(&mut self) { for p in Poems::iter() { let filename = p.to_string(); let poem_content = Poems::get(&filename).expect("Found poem {filename:?}"); let mut poem_to_str = std::str::from_utf8(poem_content.data.as_ref()) .expect("Poem is valid UT8.") .lines(); let poem_title = poem_to_str.next().expect("No title specified."); let poem_content = poem_to_str.into_iter().collect::>().join("\n"); let poem_title_to_html_string = markdown::to_html_with_options(poem_title, &Options::gfm()).unwrap(); let poem_content_to_html_string = markdown::to_html_with_options(poem_content.as_str(), &Options::gfm()).unwrap(); let mut split_filename = filename.trim_end_matches(".md").split("_"); let creation_date = split_filename.next().expect("Obtained creation date"); let slug = split_filename.next().expect("Obtained slug"); self.poem_list .push((creation_date.to_string(), slug.to_string())); let poem_struct = PoemStruct { title: poem_title_to_html_string.to_string(), content: poem_content_to_html_string, creation_date: creation_date.to_string(), }; self.poem_hashmap.insert(slug.to_string(), poem_struct); } self.poem_list.sort_by_key(|k| k.0.clone()) } pub fn get_poem(&self, slug: String) -> PoemStruct { self.poem_hashmap .get(slug.as_str()) .expect("Grabbed poem from database") .clone() } pub fn get_poem_list(&self) -> Vec<(String, String)> { self.poem_list .iter() .map(|s| { ( s.1.clone(), self.poem_hashmap .get(&s.1) .expect("Got poemstruct from database") .title .clone(), ) }) .collect::>() .clone() } pub fn get_oldest_entry(&self, current: String) -> String { let mut poem_list = VecDeque::from_iter(self.poem_list.iter()); let oldest = poem_list .pop_front() .expect("There is an entry in this list of poems.") .1 .clone(); if current == oldest { return format!("/poems/{current}#"); } format!("/poems/{oldest}") } pub fn get_latest_entry(&self, current: String) -> String { let mut poem_list = self.poem_list.clone(); let latest = poem_list .pop() .expect("There is an entry in this list of poems.") .1 .clone(); if current == latest { return format!("/poems/{current}#"); } format!("/poems/{latest}") } pub fn get_previous_entry(&self, current: String) -> String { let poem_list = self.poem_list.clone(); match poem_list.iter().enumerate().find_map(|(index, p)| { if p.1 == current { if index != 0 { Some(poem_list[index - 1].1.clone()) } else { None } } else { None } }) { Some(entry) => format!("/poems/{entry}"), None => format!("/poems/{current}"), } } pub fn get_next_entry(&self, current: String) -> String { let poem_list = self.poem_list.clone(); match poem_list.iter().enumerate().find_map(|(index, p)| { if p.1 == current { if index != poem_list.len() - 1 { Some(poem_list[index + 1].1.clone()) } else { None } } else { None } }) { Some(entry) => format!("/poems/{entry}"), None => format!("/poems/{current}"), } } pub fn get_random_entry(&self) -> String { let poem_list = self.poem_list.clone(); let mut rng = rand::thread_rng(); let random_entry = poem_list .choose(&mut rng) .expect("Got a valid entry") .1 .clone(); format!("/poems/{random_entry}") } } pub fn get_homepage_paragraph() -> String { let homepage_paragraph_content = OtherData::get("homepage.md").expect("Found homepage paragraph."); let homepage_paragraph_to_string = std::str::from_utf8(homepage_paragraph_content.data.as_ref()) .expect("Homepage file is valid UTF-8"); let test = markdown::to_html_with_options(homepage_paragraph_to_string, &Options::gfm()).unwrap(); test }