217 lines
6.0 KiB
Rust
217 lines
6.0 KiB
Rust
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<Item> = 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<sled::Tree> {
|
|
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<sled::Tree> = 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<Recipe> {
|
|
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<Recipe> = 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;
|
|
}
|