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.

routes.rs 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. use chrono::prelude::Local;
  2. use serde::{Deserialize, Serialize};
  3. use tera::{Context, Tera};
  4. use tide::convert::json;
  5. use tide::http::mime;
  6. use tide::{Redirect, Request, Response, Result, StatusCode};
  7. use std::env;
  8. use crate::{fs, post::Post, util, State};
  9. #[derive(Debug, Serialize, Deserialize)]
  10. struct User {
  11. username: String,
  12. password: String,
  13. }
  14. pub async fn index(req: Request<State>) -> Result {
  15. let posts: Vec<Post> = fs::get_all_posts().await?;
  16. let mut context = Context::new();
  17. context.insert("posts", &posts);
  18. render_html_response("index.html", &context, req)
  19. }
  20. pub async fn single_post(req: Request<State>) -> Result {
  21. let mut context = Context::new();
  22. let slug = req.param("slug")?;
  23. let post = fs::get_one_post(slug).await?;
  24. context.insert("post", &post);
  25. render_html_response("single.html", &context, req)
  26. }
  27. pub async fn new_post(req: Request<State>) -> Result {
  28. let context = Context::new();
  29. render_html_response("new.html", &context, req)
  30. }
  31. pub async fn edit_post(req: Request<State>) -> Result {
  32. let mut context = Context::new();
  33. let slug = req.param("slug")?;
  34. let mut post = fs::get_one_post(slug).await?;
  35. post.body = post.body.replace("<br>", "\n");
  36. post.html = post.generate_html();
  37. context.insert("post", &post);
  38. render_html_response("edit.html", &context, req)
  39. }
  40. pub async fn create_post(mut req: Request<State>) -> Result {
  41. let mut post: Post = req.body_form().await?;
  42. post.date = Local::now().date().naive_local().to_string();
  43. post.body = post.body.trim().to_owned();
  44. post.html = post.generate_html();
  45. post.save().await?;
  46. Ok(Redirect::new("/").into())
  47. }
  48. pub async fn update_post(mut req: Request<State>) -> Result {
  49. let mut post: Post = req.body_form().await?;
  50. post.html = post.generate_html();
  51. post.save().await?;
  52. req.session_mut()
  53. .insert("flash_success", String::from("Post updated successfully"))?;
  54. redirect(&format!("/posts/{}", post.slug))
  55. }
  56. pub async fn delete_post(mut req: Request<State>) -> Result {
  57. let slug: String = req.param("slug")?;
  58. fs::delete_post(slug)?;
  59. req.session_mut()
  60. .insert("flash_success", String::from("Post deleted successfully"))?;
  61. render_json_response(json!({ "success": "true" }))
  62. }
  63. pub async fn preview_post(mut req: Request<State>) -> Result {
  64. let body: String = req.body_string().await?;
  65. let html = util::generate_html(&body);
  66. render_json_response(json!({ "body": html }))
  67. }
  68. pub async fn login_page(req: Request<State>) -> Result {
  69. render_html_response("login.html", &Context::new(), req)
  70. }
  71. pub async fn login(mut req: Request<State>) -> Result {
  72. let username = env::var("ADMIN_USERNAME")?;
  73. let password = env::var("ADMIN_PASSWORD")?;
  74. let user: User = req.body_form().await?;
  75. if user.username == username && user.password == password {
  76. req.session_mut().insert("logged_in", true)?;
  77. redirect("/")
  78. } else {
  79. req.session_mut().remove("logged_in");
  80. req.session_mut()
  81. .insert("flash_error", "Invalid credentials")?;
  82. let login_path = req.state().login_path.clone();
  83. redirect(&login_path)
  84. }
  85. }
  86. pub async fn logout(mut req: Request<State>) -> Result {
  87. req.session_mut().insert("logged_in", false)?;
  88. Ok(Redirect::new("/").into())
  89. }
  90. pub fn render_html_response(
  91. template: &str,
  92. context: &Context,
  93. req: Request<State>,
  94. ) -> Result<Response> {
  95. let mut context = context.clone();
  96. let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
  97. let login_path = &req.state().login_path;
  98. context.insert("logged_in", &logged_in);
  99. context.insert("login_path", login_path);
  100. context.extend(prepare_flash_messages(req));
  101. let html = render_template(template, &context)?;
  102. let res = Response::builder(StatusCode::Ok)
  103. .body(html)
  104. .content_type(mime::HTML)
  105. .build();
  106. Ok(res)
  107. }
  108. pub fn render_json_response(json: serde_json::Value) -> Result<Response> {
  109. let res = Response::builder(StatusCode::Ok)
  110. .body(json)
  111. .content_type(mime::JSON)
  112. .build();
  113. Ok(res)
  114. }
  115. fn redirect(path: &str) -> Result<Response> {
  116. Ok(Redirect::new(path).into())
  117. }
  118. pub fn render_template(template: &str, context: &Context) -> Result<String> {
  119. let tera = Tera::new("templates/**/*.html")?;
  120. let html = tera.render(template, &context)?;
  121. Ok(html)
  122. }
  123. fn prepare_flash_messages(mut req: Request<State>) -> Context {
  124. let mut context = Context::new();
  125. context.insert("flash_error", &false);
  126. context.insert("flash_success", &false);
  127. for key in vec!["flash_error", "flash_success"] {
  128. match req.session_mut().get::<String>(key) {
  129. Some(value) => {
  130. req.session_mut().remove(key);
  131. &context.insert(key, &value);
  132. }
  133. None => {}
  134. }
  135. }
  136. context
  137. }