use chrono::{Local, NaiveDateTime}; use crypto::digest::Digest; use crypto::sha2::Sha256; use diesel::pg::PgConnection as PGC; use diesel::prelude::*; use syntect::highlighting::ThemeSet; use syntect::html::highlighted_html_for_string; use syntect::parsing::SyntaxSet; use crate::schema::snippets; use crate::schema::snippets::columns::uuid; #[derive(Queryable, Serialize, Deserialize)] pub struct Snippet { pub id: i32, pub title: String, pub body: String, pub created_at: Option, pub filetype: Option, pub formatted_body: String, pub uuid: String, } #[derive(Serialize, Deserialize)] pub struct ApiSnippet { pub title: String, pub body: String, pub filetype: Option, } #[derive(Insertable, AsChangeset)] #[table_name = "snippets"] pub struct InsertableSnippet { pub title: String, pub body: String, pub filetype: Option, pub formatted_body: String, pub uuid: String, } fn format_snippet(filetype: Option, body: String) -> String { filetype.map_or( format!("
\n{}\n
", body), |filetype| { let ps = SyntaxSet::load_defaults_newlines(); let ts = ThemeSet::load_defaults(); ps.find_syntax_by_extension(&filetype).map_or( format!("
\n{}\n
", body), |syntax| { let content = htmlescape::decode_html(&body).expect("Invalid HTML"); highlighted_html_for_string( &content, &ps, &syntax, &ts.themes["Solarized (light)"], ) }, ) }, ) } fn generate_uuid(snippet: &ApiSnippet) -> String { let current_timestamp = Local::now().to_string(); let mut hasher = Sha256::new(); hasher.input_str(&format!( "{}{}{}", snippet.title, snippet.body, current_timestamp )); hasher.result_str().to_string() } pub fn get(connection: &PGC, snippet_uuid: &str) -> QueryResult { snippets::table .filter(uuid.eq(snippet_uuid)) .first(connection) } pub fn insert(snippet: ApiSnippet, connection: &PGC) -> QueryResult { let body = htmlescape::encode_minimal(&snippet.body.clone()); let formatted_snippet = InsertableSnippet { filetype: snippet.filetype.clone(), title: snippet.title.clone(), body: body.clone(), uuid: generate_uuid(&snippet), formatted_body: format_snippet(snippet.filetype, body), }; diesel::insert_into(snippets::table) .values(formatted_snippet) .get_result(connection) } #[cfg(test)] mod tests { use super::*; #[test] fn identical_snippets_have_different_uuids() { let snippet = ApiSnippet { title: String::from("Hello world"), body: String::from("Hello world"), filetype: None, }; let uuid1 = generate_uuid(&snippet); let uuid2 = generate_uuid(&snippet); assert!(uuid1 != uuid2); } }