diff --git a/src/captcha.rs b/src/captcha.rs
index b5a1f63..b1105f2 100644
--- a/src/captcha.rs
+++ b/src/captcha.rs
@@ -7,7 +7,7 @@ use captcha::filters::{Grid, Noise, Wave};
use captcha::Captcha;
use std::path::Path;
-use crate::structures::{CaptchaAnswer};
+use crate::structures::CaptchaAnswer;
use rocket::{form::Form, http::Cookie, http::CookieJar};
// Create a new captcha image
@@ -42,9 +42,10 @@ pub fn return_captcha(cookies: &CookieJar<'_>) -> File {
let file = File::open(&("/tmp/captcha".to_owned() + &captcha_text + ".png")); // Open the captcha image file
info!("created new captcha {}", captcha_text); // Print the captcha text
- cookies.add_private(Cookie::new( // Set the token as a private cookie
+ cookies.add_private(Cookie::new(
+ // Set the token as a private cookie
"token", // Add a cookie to store the captcha answer
- captcha_text
+ captcha_text,
));
return file.unwrap(); // Return the captcha image
diff --git a/src/io.rs b/src/io.rs
index 902c618..f30f184 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -1,11 +1,11 @@
+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 std::env;
use uuid::Uuid;
-use chrono::Utc;
-use rss::{ChannelBuilder, ItemBuilder, Item, Guid};
use crate::structures::*;
@@ -24,14 +24,17 @@ pub fn write_feed(lang: &str) {
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());
+ 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()
@@ -53,11 +56,12 @@ pub fn write_html(html: String, lang: &str, shortcode: Option<&str>) {
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
+ 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
}
@@ -66,10 +70,7 @@ pub fn write_html(html: String, lang: &str, shortcode: Option<&str>) {
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) {
+ let mut file = match OpenOptions::new().write(true).create(true).open(&path) {
Err(why) => panic!("couldn't create file: {}", why),
Ok(file) => file,
};
@@ -91,7 +92,7 @@ pub fn open_database(keyspace: &str) -> Option {
tmp_path.push(".local/share/catgirl-cooking");
tmp_path.push("database");
tmp_path
- },
+ }
Err(e) => {
panic!("failed to get key: {}", e);
}
@@ -107,7 +108,10 @@ pub fn open_database(keyspace: &str) -> Option {
let database: Option = match db.open_tree(keyspace) {
Ok(tree) => Some(tree),
- Err(e) => { println!("error in opening Tree: {}", e); None },
+ Err(e) => {
+ println!("error in opening Tree: {}", e);
+ None
+ }
};
return database;
}
@@ -139,8 +143,8 @@ pub fn db_get_recipe(id: Uuid) -> Recipe {
};
let db_entry = match db.get(id.as_simple().to_string()) {
- Ok(entry) => entry,
- Err(error) => panic!("failed to get recipe: {}", error),
+ Ok(entry) => entry,
+ Err(error) => panic!("failed to get recipe: {}", error),
};
if let Some(entry) = db_entry {
@@ -159,12 +163,12 @@ pub fn db_get_all_recipes() -> Vec {
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),
};
@@ -180,7 +184,7 @@ pub fn db_get_all_recipes() -> Vec {
Err(error) => panic!("failed to deserialize entry: {}", error),
}
recipes_list.push(read_entry);
- },
+ }
None => break,
}
}
@@ -193,12 +197,12 @@ pub fn db_get_last_recipe() -> Recipe {
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),
};
@@ -209,4 +213,4 @@ pub fn db_get_last_recipe() -> Recipe {
}
return read_entry;
-}
+}
diff --git a/src/main.rs b/src/main.rs
index 096978d..424009c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,20 +1,20 @@
-use build_html::{self, Html, HtmlContainer, ContainerType, Container};
+use build_html::{self, Container, ContainerType, Html, HtmlContainer};
use uuid::Uuid;
-mod structures;
-mod io;
-mod tests;
-mod networking;
mod captcha;
+mod io;
+mod networking;
+mod structures;
+mod tests;
#[macro_use]
extern crate rocket;
use rocket::fairing::{Fairing, Info, Kind};
-use rocket::{http::Header, Request, Response};
use rocket::fs::FileServer;
+use rocket::{http::Header, Request, Response};
-use crate::networking::*;
use crate::captcha::*;
+use crate::networking::*;
fn construct_main_page() {
// Create the footer
@@ -29,11 +29,12 @@ fn construct_main_page() {
// Create (test) lists of tags & recipes
let tags: Vec<&str> = vec!["breakfast", "apples", "cheese", "vegan", "vegetarian"];
let recipes = io::db_get_all_recipes();
-
+
// Create HTML string of tags
let mut tags_html = String::new(); // Create custom html string for tags
tags_html.push_str(r#"
Tags: "#); // Begin paragraph element
- for x in tags { // Go through the list of tags
+ for x in tags {
+ // Go through the list of tags
tags_html.push_str(format!("{},", x, x).as_str()); // Append the tags as a link
}
tags_html.push_str(r#"
"#); // End the paragraph
@@ -52,8 +53,14 @@ fn construct_main_page() {
.with_head_link("favicon.ico", "icon") // Favicon
.with_stylesheet("style.css") // Link stylesheet
.with_meta(vec![("charset", "UTF-8")])
- .with_meta(vec![("name", "viewport"), ("content", "width=device-width, initial-scale=1")]) // Display stuff
- .with_meta(vec![("name", "description"), ("content", structures::DESCRIPTION)]) // Add the description
+ .with_meta(vec![
+ ("name", "viewport"),
+ ("content", "width=device-width, initial-scale=1"),
+ ]) // Display stuff
+ .with_meta(vec![
+ ("name", "description"),
+ ("content", structures::DESCRIPTION),
+ ]) // Add the description
.with_title(structures::TITLE)
.with_header(1, structures::HEADER)
.with_raw(r#"
"#)
@@ -81,7 +88,7 @@ fn rebuild() {
#[launch]
fn rocket() -> _ {
rebuild();
-
+
// Launch rocket
let _config = sled::Config::default()
.use_compression(true)
@@ -90,12 +97,7 @@ fn rocket() -> _ {
rocket::build()
.mount(
"/api",
- routes![
- test,
- return_captcha,
- check_captcha,
- new_recipe
- ],
+ routes![test, return_captcha, check_captcha, new_recipe],
)
.mount("/", FileServer::from("static/en/"))
}
diff --git a/src/networking.rs b/src/networking.rs
index 3b52dec..1e1de2d 100644
--- a/src/networking.rs
+++ b/src/networking.rs
@@ -1,5 +1,5 @@
-use rocket::form::Form;
use crate::structures::{RecipeForm, Tag};
+use rocket::form::Form;
#[get("/test")]
pub fn test() -> String {
@@ -10,15 +10,12 @@ pub fn parse_tags(tags: String) -> Vec {
let split: Vec<&str> = tags.split(",").collect();
let mut tags_vec: Vec = Vec::new();
for i in split {
- tags_vec.push(Tag::new(i
- .replace(" ", "")
- .replace("#", "")));
+ tags_vec.push(Tag::new(i.replace(" ", "").replace("#", "")));
}
return tags_vec;
}
#[post("/new-recipe", data = "")]
pub fn new_recipe(recipe: Form) -> String {
-
return recipe.recipe_name.to_owned();
}
diff --git a/src/structures.rs b/src/structures.rs
index cfca03a..50715ec 100644
--- a/src/structures.rs
+++ b/src/structures.rs
@@ -1,9 +1,9 @@
-use uuid::Uuid;
+use build_html::{self, Container, ContainerType, Html, HtmlContainer, HtmlPage};
use chrono::prelude::*;
-use serde_derive::{Deserialize, Serialize};
-use build_html::{self, Html, HtmlContainer, ContainerType, Container, HtmlPage};
-use std::fmt;
use rocket::form::Form;
+use serde_derive::{Deserialize, Serialize};
+use std::fmt;
+use uuid::Uuid;
use crate::io::write_html;
@@ -121,25 +121,29 @@ pub struct RecipeForm {
#[derive(Debug, Serialize, Deserialize)]
pub struct Recipe {
- pub id: Uuid, // Unique recipe ID
+ pub id: Uuid, // Unique recipe ID
pub name: String, // Full recipe name
pub shortcode: String,
pub prep_time: (i32, TimeUnits), // Preparation time: (value, units)
pub cooking_time: (i32, TimeUnits), // Cooking time: (value, units)
- pub servings: u8, // How many servinge the recipe makes
+ pub servings: u8, // How many servinge the recipe makes
pub ingredients: Vec<(i32, MeasurementUnits, String)>, // Vector of ingredients: (value, units, name)
pub directions: Vec<(u16, String)>, // List of instructions: (step #, details)
- pub attribution: String, // Author name
- pub posted_date: DateTime, // Date the recipe was first posted
+ pub attribution: String, // Author name
+ pub posted_date: DateTime, // Date the recipe was first posted
pub edited_date: Option>, // Date the recipe was last edited
- pub tags: Option>, // List of tags
+ pub tags: Option>, // List of tags
}
impl Recipe {
pub fn example(name: &str, time: i32, directions: Vec<&str>, ingredients: Vec<&str>) -> Recipe {
let mut ingredients_list: Vec<(i32, MeasurementUnits, String)> = Vec::new();
for i in 0..ingredients.len() {
- ingredients_list.push((i.try_into().unwrap(), MeasurementUnits::Litres, ingredients[i].to_string()));
+ ingredients_list.push((
+ i.try_into().unwrap(),
+ MeasurementUnits::Litres,
+ ingredients[i].to_string(),
+ ));
}
let mut directions_list: Vec<(u16, String)> = Vec::new();
@@ -163,7 +167,16 @@ impl Recipe {
}
}
- pub fn new(name: String, prep_time: (i32, TimeUnits), cooking_time: (i32, TimeUnits), servings: u8, ingredients: Vec<(i32, MeasurementUnits, String)>, directions: Vec, attribution: String, tags: Option>) -> Recipe {
+ pub fn new(
+ name: String,
+ prep_time: (i32, TimeUnits),
+ cooking_time: (i32, TimeUnits),
+ servings: u8,
+ ingredients: Vec<(i32, MeasurementUnits, String)>,
+ directions: Vec,
+ attribution: String,
+ tags: Option>,
+ ) -> Recipe {
let mut directions_list: Vec<(u16, String)> = Vec::new();
for i in 0..directions.len() {
directions_list.push((i.try_into().unwrap(), directions[i].to_string()));
@@ -198,21 +211,27 @@ impl Recipe {
// Metadata
let meta = Container::new(ContainerType::UnorderedList)
.with_attributes(vec![("class", "recipe")])
- .with_paragraph(format!("⏲️ Preparation time: {} {}", &self.prep_time.0, &self.prep_time.1))
- .with_paragraph(format!("🍳 Cooking time: {} {}", &self.cooking_time.0, &self.cooking_time.1))
+ .with_paragraph(format!(
+ "⏲️ Preparation time: {} {}",
+ &self.prep_time.0, &self.prep_time.1
+ ))
+ .with_paragraph(format!(
+ "🍳 Cooking time: {} {}",
+ &self.cooking_time.0, &self.cooking_time.1
+ ))
.with_paragraph(format!("🍽️ Servings: {}", &self.servings));
// Ingredients
- let mut ingredients_container = Container::new(ContainerType::UnorderedList)
- .with_attributes(vec![("class", "recipe")]);
+ let mut ingredients_container =
+ Container::new(ContainerType::UnorderedList).with_attributes(vec![("class", "recipe")]);
for i in &self.ingredients {
let ingredient = format!("{} {} {}", &i.0, &i.1, &i.2);
ingredients_container.add_paragraph(ingredient);
}
// Directions
- let mut directions_container = Container::new(ContainerType::OrderedList)
- .with_attributes(vec![("class", "recipe")]);
+ let mut directions_container =
+ Container::new(ContainerType::OrderedList).with_attributes(vec![("class", "recipe")]);
for n in &self.directions {
directions_container.add_paragraph(&n.1);
}
@@ -223,16 +242,20 @@ impl Recipe {
match &self.tags {
Some(list) => {
for x in 0..list.len() {
- if x != list.len()-1 {
- tags_html.push_str(format!("#{},", list[x].1, list[x].1).as_str());
+ if x != list.len() - 1 {
+ tags_html.push_str(
+ format!("#{},", list[x].1, list[x].1).as_str(),
+ );
} else {
- tags_html.push_str(format!("#{}", list[x].1, list[x].1).as_str());
+ tags_html.push_str(
+ format!("#{}", list[x].1, list[x].1).as_str(),
+ );
}
}
- },
+ }
None => {
tags_html.push_str(r#"no tags!! :o"#);
- },
+ }
}
tags_html.push_str(r#"
"#);
@@ -243,8 +266,9 @@ impl Recipe {
"Last edited on: {}-{}-{}
",
date.year(),
date.month(),
- date.day())
- },
+ date.day()
+ )
+ }
None => "No edits
".to_string(),
};
@@ -253,7 +277,10 @@ impl Recipe {
.with_head_link("/favicon.ico", "icon") // Favicon
.with_stylesheet("/style.css") // Link stylesheet
.with_meta(vec![("charset", "UTF-8")])
- .with_meta(vec![("name", "viewport"), ("content", "width=device-width, initial-scale=1")]) // Display stuff
+ .with_meta(vec![
+ ("name", "viewport"),
+ ("content", "width=device-width, initial-scale=1"),
+ ]) // Display stuff
.with_meta(vec![("name", "description"), ("content", DESCRIPTION)]) // Add the description
.with_title(TITLE)
.with_header(1, &self.name)
@@ -270,12 +297,13 @@ impl Recipe {
"Recipe added on: {}-{}-{}
",
&self.posted_date.year(),
&self.posted_date.month(),
- &self.posted_date.day()))
+ &self.posted_date.day()
+ ))
.with_raw(edit_date)
.with_container(footer);
write_html(recipe_page.to_html_string(), "en", Some(&self.shortcode));
- }
+ }
}
pub fn construct_shortcode(full_name: String) -> String {
diff --git a/src/tests.rs b/src/tests.rs
index 9eed194..1cd1978 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -1,8 +1,8 @@
#[cfg(test)]
mod tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.
+ use crate::networking::parse_tags;
use crate::structures::*;
- use crate::networking::{parse_tags};
#[test]
fn test_tag_new() {
@@ -11,25 +11,38 @@ mod tests {
#[test]
fn test_tag_from_string() {
- assert_eq!(Tag::from_string("#test".to_string()), Tag('#', "test".to_string()));
+ assert_eq!(
+ Tag::from_string("#test".to_string()),
+ Tag('#', "test".to_string())
+ );
}
#[test]
fn test_tag_to_string() {
- assert_eq!(Tag('#', "test".to_string()).to_string(), "#test".to_string());
+ assert_eq!(
+ Tag('#', "test".to_string()).to_string(),
+ "#test".to_string()
+ );
}
#[test]
fn test_shortcode_conversion() {
- assert_eq!(construct_shortcode("Test SHORtcode".to_string()), "test-shortcode".to_string());
+ assert_eq!(
+ construct_shortcode("Test SHORtcode".to_string()),
+ "test-shortcode".to_string()
+ );
}
#[test]
fn test_parse_tags() {
- assert_eq!(parse_tags("one,TWO ,tHRee, #four".to_string()), vec![
- Tag('#',"one".to_string()),
- Tag('#',"two".to_string()),
- Tag('#',"three".to_string()),
- Tag('#',"four".to_string())]);
+ assert_eq!(
+ parse_tags("one,TWO ,tHRee, #four".to_string()),
+ vec![
+ Tag('#', "one".to_string()),
+ Tag('#', "two".to_string()),
+ Tag('#', "three".to_string()),
+ Tag('#', "four".to_string())
+ ]
+ );
}
}