The backend of a gist server written in Rust
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

snippet.rs 2.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. use chrono::NaiveDateTime;
  2. use crypto::digest::Digest;
  3. use crypto::sha2::Sha256;
  4. use diesel::pg::PgConnection as PGC;
  5. use diesel::prelude::*;
  6. use syntect::highlighting::ThemeSet;
  7. use syntect::html::highlighted_html_for_string;
  8. use syntect::parsing::SyntaxSet;
  9. use crate::schema::snippets;
  10. use crate::schema::snippets::columns::uuid;
  11. #[derive(Queryable, Serialize, Deserialize)]
  12. pub struct Snippet {
  13. pub id: i32,
  14. pub title: String,
  15. pub body: String,
  16. pub created_at: Option<NaiveDateTime>,
  17. pub filetype: Option<String>,
  18. pub formatted_body: String,
  19. pub uuid: String,
  20. }
  21. #[derive(Serialize, Deserialize)]
  22. pub struct ApiSnippet {
  23. pub title: String,
  24. pub body: String,
  25. pub filetype: Option<String>,
  26. }
  27. #[derive(Insertable, AsChangeset)]
  28. #[table_name = "snippets"]
  29. pub struct InsertableSnippet {
  30. pub title: String,
  31. pub body: String,
  32. pub filetype: Option<String>,
  33. pub formatted_body: String,
  34. pub uuid: String,
  35. }
  36. fn format_snippet(filetype: Option<String>, body: String) -> String {
  37. filetype.map_or(
  38. format!("<pre class='plaintext'>\n{}\n</pre>", body),
  39. |filetype| {
  40. let ps = SyntaxSet::load_defaults_newlines();
  41. let ts = ThemeSet::load_defaults();
  42. ps.find_syntax_by_extension(&filetype).map_or(
  43. format!("<pre class='plaintext'>\n{}\n</pre>", body),
  44. |syntax| {
  45. highlighted_html_for_string(
  46. &htmlescape::decode_html(&body).expect("Invalid HTML"),
  47. &ps,
  48. syntax,
  49. &ts.themes["Solarized (light)"],
  50. )
  51. },
  52. )
  53. },
  54. )
  55. }
  56. fn generate_uuid(snippet: &ApiSnippet) -> String {
  57. let mut hasher = Sha256::new();
  58. hasher.input_str(&format!("{}{}", snippet.title, snippet.body));
  59. hasher.result_str().to_string()
  60. }
  61. pub fn get(connection: &PGC, snippet_uuid: &str) -> QueryResult<Snippet> {
  62. snippets::table
  63. .filter(uuid.eq(snippet_uuid))
  64. .first(connection)
  65. }
  66. pub fn insert(snippet: ApiSnippet, connection: &PGC) -> QueryResult<Snippet> {
  67. let body = htmlescape::encode_minimal(&snippet.body.clone());
  68. let formatted_snippet = InsertableSnippet {
  69. filetype: snippet.filetype.clone(),
  70. title: snippet.title.clone(),
  71. body: body.clone(),
  72. uuid: generate_uuid(&snippet),
  73. formatted_body: format_snippet(snippet.filetype, body),
  74. };
  75. diesel::insert_into(snippets::table)
  76. .values(formatted_snippet)
  77. .get_result(connection)
  78. }