use chrono::Utc; use rss::{ChannelBuilder, Guid, Item, ItemBuilder}; use std::env; use std::fs::File; use std::fs::OpenOptions; use std::io::prelude::*; use std::path::PathBuf; use uuid::Uuid; use crate::structures::*; pub fn write_feed(lang: &str) { // Path to atom feed let mut path = PathBuf::new(); path.push("static"); path.push(lang); path.push("rss.xml"); let file = match File::create(path) { Err(why) => panic!("couldn't create feed: {}", why), Ok(file) => file, }; let recipes = db_get_all_recipes(); let mut feed_items: Vec = Vec::new(); for i in recipes { feed_items.push( ItemBuilder::default() .title(i.name) .link(format!("/{}", &i.shortcode)) .guid(Guid { value: i.id.as_simple().to_string(), permalink: false, }) .pub_date(i.posted_date.to_string()) .build(), ); } let channel = ChannelBuilder::default() .title("Catgirl Cooking") .link("https://catgirl.cooking") .description("New recipes for catgirl.cooking") .last_build_date(Utc::now().to_string()) .items(feed_items) .build(); match channel.write_to(file) { Ok(_) => println!("wrote feed to file"), Err(e) => panic!("couldn't write feed to file: {}", e), } } pub fn write_html(html: String, lang: &str, shortcode: Option<&str>) { // Create a path to write the file to let mut path = PathBuf::new(); path.push("static"); // base path for web content path.push(lang); // not really that useful right now match shortcode { // If there's a shortcode (for a recipe), use that path Some(short) => { path.push(short); path.push("index.html"); } None => path.push("index.html"), // Otherwise just write to the main index } // If the directory doesn't exist, create it let prefix = path.parent().unwrap(); std::fs::create_dir_all(prefix).unwrap(); // Open file in write-only mode let mut file = match OpenOptions::new().write(true).create(true).open(&path) { Err(why) => panic!("couldn't create file: {}", why), Ok(file) => file, }; // Write the HTML to file match file.write_all(html.as_bytes()) { Err(why) => panic!("couldn't write to file: {}", why), Ok(_) => println!("successfully wrote to file"), } } pub fn open_database(keyspace: &str) -> Option { let db: sled::Db; let key = "HOME"; let database_path = match env::var(key) { Ok(val) => { let mut tmp_path = PathBuf::new(); tmp_path.push(val); tmp_path.push(".local/share/catgirl-cooking"); tmp_path.push("database"); tmp_path } Err(e) => { panic!("failed to get key: {}", e); } }; match sled::open(database_path) { Ok(database) => db = database, Err(error) => { println!("error in opening database: {}", error); return None; } } let database: Option = match db.open_tree(keyspace) { Ok(tree) => Some(tree), Err(e) => { println!("error in opening Tree: {}", e); None } }; return database; } pub fn db_insert_recipe(recipe: Recipe) { let db = match open_database("recipes") { Some(database) => database, None => panic!(), }; let bytes; match bincode::serialize(&recipe) { Ok(result) => bytes = result, Err(error) => panic!("could not serialize recipe: {}", error), } match db.insert(recipe.id.as_simple().to_string(), bytes) { Ok(_) => println!("inserted recipe"), Err(error) => panic!("failed to insert recipe: {}", error), } db.flush().unwrap(); } pub fn db_get_recipe(id: Uuid) -> Recipe { let db = match open_database("recipes") { Some(database) => database, None => panic!(), }; let db_entry = match db.get(id.as_simple().to_string()) { Ok(entry) => entry, Err(error) => panic!("failed to get recipe: {}", error), }; if let Some(entry) = db_entry { let read_entry = match bincode::deserialize(&entry) { Ok(entry) => entry, Err(error) => panic!("failed to deserialize entry: {}", error), }; return read_entry; } else { panic!("failed to find entry"); } } pub fn db_get_all_recipes() -> Vec { let db = match open_database("recipes") { Some(database) => database, None => panic!(), }; let first_key = match db.first() { Ok(pair) => match pair { Some(key) => key.0, None => panic!("error getting first key"), }, Err(error) => panic!("error getting first key: {}", error), }; let mut recipes_list: Vec = Vec::new(); let mut iter = db.range(first_key..); loop { match iter.next() { Some(x) => { let read_entry; match bincode::deserialize(&x.unwrap().1) { Ok(result) => read_entry = result, Err(error) => panic!("failed to deserialize entry: {}", error), } recipes_list.push(read_entry); } None => break, } } return recipes_list; } pub fn db_get_last_recipe() -> Recipe { let db = match open_database("recipes") { Some(database) => database, None => panic!(), }; let last_key = match db.last() { Ok(pair) => match pair { Some(key) => key.0, None => panic!("error getting first key"), }, Err(error) => panic!("error getting first key: {}", error), }; let read_entry; match bincode::deserialize(&last_key) { Ok(result) => read_entry = result, Err(error) => panic!("faled to deserialize entry: {}", error), } return read_entry; }