Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

main.rs 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. use std::env;
  2. use std::fs::File;
  3. use std::io::prelude::*;
  4. use std::io::{Error, ErrorKind};
  5. use std::path::PathBuf;
  6. use chrono::prelude::Local;
  7. use dotenv;
  8. use serde::{Deserialize, Serialize};
  9. use serde_json;
  10. use tera::{Context, Tera};
  11. use tide::utils::After;
  12. use tide::{Body, Response, StatusCode};
  13. use uuid::Uuid;
  14. mod fs;
  15. #[derive(Debug, Serialize, Deserialize)]
  16. pub struct Post {
  17. id: String,
  18. title: String,
  19. body: String,
  20. date: String,
  21. }
  22. #[derive(Debug, Serialize, Deserialize)]
  23. struct User {
  24. username: String,
  25. password: String,
  26. }
  27. impl Post {
  28. async fn save(&mut self) -> std::io::Result<()> {
  29. let mut path: PathBuf = fs::get_posts_directory_path().await?;
  30. let filename = format!("{}.json", self.id);
  31. path = path.join(&filename);
  32. let mut file = File::create(&path)?;
  33. file.write_all(serde_json::to_string(&self)?.as_bytes())?;
  34. Ok(())
  35. }
  36. fn from_str(blob: &str) -> Result<Post, Error> {
  37. let mut post: Post = match serde_json::from_str(blob) {
  38. Ok(p) => Ok(p),
  39. Err(_) => Err(Error::new(
  40. ErrorKind::Other,
  41. format!("Error deserializing post"),
  42. )),
  43. }?;
  44. post.body = post.body.replace("\n", "<br>");
  45. Ok(post)
  46. }
  47. }
  48. fn render(template: &str, context: &Context) -> Result<Body, tide::Error> {
  49. let tera = Tera::new("templates/**/*.html")?;
  50. let html = tera.render(template, &context)?;
  51. Ok(Body::from_string(html))
  52. }
  53. #[async_std::main]
  54. async fn main() -> std::io::Result<()> {
  55. dotenv::dotenv().ok();
  56. tide::log::start();
  57. let mut app = tide::new();
  58. app.with(After(|mut res: Response| async {
  59. let mut context = Context::new();
  60. match res.downcast_error::<async_std::io::Error>() {
  61. Some(e) => {
  62. context.insert("error", &e.to_string());
  63. let status = if let ErrorKind::NotFound = e.kind() {
  64. StatusCode::NotFound
  65. } else {
  66. StatusCode::InternalServerError
  67. };
  68. res.set_body(render("error.html", &context)?);
  69. res.set_status(status);
  70. }
  71. None => match res.status() {
  72. StatusCode::NotFound => {
  73. context.insert("error", "Page not found");
  74. res.set_body(render("error.html", &context)?);
  75. }
  76. _ => {}
  77. },
  78. };
  79. Ok(res)
  80. }));
  81. app.with(After(|mut res: Response| async {
  82. res.set_content_type(tide::http::mime::HTML);
  83. Ok(res)
  84. }));
  85. app.with(tide::sessions::SessionMiddleware::new(
  86. tide::sessions::MemoryStore::new(),
  87. std::env::var("TIDE_SECRET")
  88. .expect(
  89. "Please provide a TIDE_SECRET value of at \
  90. least 32 bytes in order to run this example",
  91. )
  92. .as_bytes(),
  93. ));
  94. app.at("/").get(|req: tide::Request<()>| async move {
  95. let posts: Vec<Post> = fs::get_all_posts().await?;
  96. let mut context = Context::new();
  97. context.insert("posts", &posts);
  98. let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
  99. context.insert("logged_in", &logged_in);
  100. render("index.html", &context)
  101. });
  102. app.at("/posts")
  103. .post(|mut req: tide::Request<()>| async move {
  104. let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
  105. if !logged_in {
  106. Ok(tide::Redirect::new("/login"))
  107. } else {
  108. let mut post: Post = req.body_form().await?;
  109. post.id = Uuid::new_v4().to_string();
  110. post.date = Local::now().date().naive_local().to_string();
  111. post.body = post.body.trim().to_owned();
  112. post.save().await?;
  113. Ok(tide::Redirect::new("/"))
  114. }
  115. });
  116. app.at("/posts/:id")
  117. .get(|req: tide::Request<()>| async move {
  118. let mut context = Context::new();
  119. let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
  120. context.insert("logged_in", &logged_in);
  121. let post_id = req.param("id")?;
  122. let post = fs::get_one_post(post_id).await?;
  123. context.insert("post", &post);
  124. render("single.html", &context)
  125. });
  126. app.at("/login")
  127. .get(|mut req: tide::Request<()>| async move {
  128. let mut context = Context::new();
  129. let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
  130. context.insert("logged_in", &logged_in);
  131. match req.session_mut().get::<String>("flash_error") {
  132. Some(error) => {
  133. req.session_mut().remove("flash_error");
  134. &context.insert("error", &error);
  135. }
  136. None => {}
  137. }
  138. render("login.html", &context)
  139. })
  140. .post(|mut req: tide::Request<()>| async move {
  141. let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
  142. if logged_in {
  143. return Ok(tide::Redirect::new("/"));
  144. }
  145. let username = env::var("ADMIN_USERNAME")?;
  146. let password = env::var("ADMIN_PASSWORD")?;
  147. let user: User = req.body_form().await?;
  148. if user.username == username && user.password == password {
  149. req.session_mut().remove("logged_in");
  150. req.session_mut().insert("logged_in", true)?;
  151. Ok(tide::Redirect::new("/"))
  152. } else {
  153. req.session_mut().remove("logged_in");
  154. req.session_mut()
  155. .insert("flash_error", "Invalid credentials")?;
  156. Ok(tide::Redirect::new("/login"))
  157. }
  158. });
  159. app.at("/logout")
  160. .post(|mut req: tide::Request<()>| async move {
  161. req.session_mut().remove("logged_in");
  162. req.session_mut().insert("logged_in", false)?;
  163. Ok(tide::Redirect::new("/"))
  164. });
  165. app.listen("127.0.0.1:8080").await?;
  166. Ok(())
  167. }