Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. use std::env;
  2. use std::ffi::OsStr;
  3. use std::fs::{read_dir, File};
  4. use std::io::prelude::*;
  5. use std::io::{Error, ErrorKind};
  6. use std::path::PathBuf;
  7. use async_std::fs::read_to_string;
  8. use chrono::prelude::Local;
  9. use dotenv;
  10. use serde::{Deserialize, Serialize};
  11. use serde_json;
  12. use tera::{Context, Tera};
  13. use tide::utils::After;
  14. use tide::{Body, Response, StatusCode};
  15. use uuid::Uuid;
  16. #[derive(Debug, Serialize, Deserialize)]
  17. struct Post {
  18. id: String,
  19. title: String,
  20. body: String,
  21. date: String,
  22. }
  23. impl Post {
  24. fn save(&mut self) -> std::io::Result<()> {
  25. let mut path: PathBuf = get_posts_directory()?;
  26. let filename = format!("{}.json", self.id);
  27. path = path.join(&filename);
  28. let mut file = File::create(&path)?;
  29. file.write_all(serde_json::to_string(&self)?.as_bytes())?;
  30. Ok(())
  31. }
  32. }
  33. fn get_posts_directory() -> Result<PathBuf, Error> {
  34. match env::var("POSTS_DIR") {
  35. Ok(dir) => Ok(dir.into()),
  36. Err(_) => Err(Error::new(
  37. ErrorKind::Other,
  38. "Posts directory environment variable not set",
  39. )),
  40. }
  41. }
  42. async fn read_all_posts() -> Result<Vec<Post>, Error> {
  43. let path = match get_posts_directory() {
  44. Ok(p) => Ok(p),
  45. Err(_) => Err(Error::new(ErrorKind::Other, "POSTS_DIR variable is not set"))
  46. }?;
  47. let mut posts: Vec<Post> = vec![];
  48. let files = match read_dir(path) {
  49. Ok(f) => Ok(f),
  50. Err(_) => Err(Error::new(ErrorKind::Other, "Posts directory does not exist"))
  51. }?;
  52. for file in files {
  53. let file = file?;
  54. if let Some("json") = file.path().extension().and_then(OsStr::to_str) {
  55. let contents = match read_to_string(file.path()).await {
  56. Ok(c) => Ok(c),
  57. Err(_) => Err(Error::new(ErrorKind::Other, format!("Error reading post {:?}", file.path())))
  58. }?;
  59. let mut post: Post = match serde_json::from_str(&contents) {
  60. Ok(p) => Ok(p),
  61. Err(_) => Err(Error::new(ErrorKind::Other, format!("Error deserializing post")))
  62. }?;
  63. post.body = post.body.replace("\n", "<br>");
  64. posts.push(post);
  65. }
  66. }
  67. Ok(posts)
  68. }
  69. #[async_std::main]
  70. async fn main() -> std::io::Result<()> {
  71. dotenv::dotenv().ok();
  72. tide::log::start();
  73. let mut app = tide::new();
  74. app.with(After(|mut res: Response| async {
  75. if let Some(err) = res.downcast_error::<async_std::io::Error>() {
  76. let tera = Tera::new("templates/**/*.html")?;
  77. let mut context = Context::new();
  78. context.insert("error", &err.to_string());
  79. let html = tera.render("error.html", &context)?;
  80. res.set_body(html);
  81. res.set_status(StatusCode::InternalServerError);
  82. }
  83. Ok(res)
  84. }));
  85. app.with(After(|mut res: Response| async {
  86. res.set_content_type(tide::http::mime::HTML);
  87. Ok(res)
  88. }));
  89. app.at("/").get(|_| async {
  90. let tera = Tera::new("templates/**/*.html")?;
  91. let posts = read_all_posts().await?;
  92. let mut context = Context::new();
  93. context.insert("posts", &posts);
  94. let html = tera.render("index.html", &context)?;
  95. Ok(Body::from_string(html))
  96. });
  97. app.at("/posts")
  98. .post(|mut req: tide::Request<()>| async move {
  99. let mut post: Post = req.body_form().await?;
  100. post.id = Uuid::new_v4().to_string();
  101. post.date = Local::now().date().naive_local().to_string();
  102. post.body = post.body.trim().to_owned();
  103. post.save()?;
  104. Ok(tide::Redirect::new("/"))
  105. });
  106. app.listen("127.0.0.1:8080").await?;
  107. Ok(())
  108. }