Browse Source

Refactor routes into module

master
Dylan Baker 3 years ago
parent
commit
1afc7f3c60
5 changed files with 168 additions and 111 deletions
  1. 11
    95
      src/main.rs
  2. 119
    0
      src/routes.rs
  3. 32
    0
      templates/components.html
  4. 5
    0
      templates/edit.html
  5. 1
    16
      templates/index.html

+ 11
- 95
src/main.rs View File

@@ -1,19 +1,17 @@
1
-use std::env;
2 1
 use std::fs::File;
3 2
 use std::io::prelude::*;
4 3
 use std::io::{Error, ErrorKind};
5 4
 use std::path::PathBuf;
6 5
 
7
-use chrono::prelude::Local;
8 6
 use dotenv;
9 7
 use serde::{Deserialize, Serialize};
10 8
 use serde_json;
11
-use tera::{Context, Tera};
9
+use tera::Context;
12 10
 use tide::utils::After;
13
-use tide::{Body, Response, StatusCode};
14
-use uuid::Uuid;
11
+use tide::{Response, StatusCode};
15 12
 
16 13
 mod fs;
14
+mod routes;
17 15
 
18 16
 #[derive(Debug, Serialize, Deserialize)]
19 17
 pub struct Post {
@@ -23,12 +21,6 @@ pub struct Post {
23 21
     date: String,
24 22
 }
25 23
 
26
-#[derive(Debug, Serialize, Deserialize)]
27
-struct User {
28
-    username: String,
29
-    password: String,
30
-}
31
-
32 24
 impl Post {
33 25
     async fn save(&mut self) -> std::io::Result<()> {
34 26
         let mut path: PathBuf = fs::get_posts_directory_path().await?;
@@ -52,12 +44,6 @@ impl Post {
52 44
     }
53 45
 }
54 46
 
55
-fn render(template: &str, context: &Context) -> Result<Body, tide::Error> {
56
-    let tera = Tera::new("templates/**/*.html")?;
57
-    let html = tera.render(template, &context)?;
58
-    Ok(Body::from_string(html))
59
-}
60
-
61 47
 #[async_std::main]
62 48
 async fn main() -> std::io::Result<()> {
63 49
     dotenv::dotenv().ok();
@@ -75,13 +61,13 @@ async fn main() -> std::io::Result<()> {
75 61
                 } else {
76 62
                     StatusCode::InternalServerError
77 63
                 };
78
-                res.set_body(render("error.html", &context)?);
64
+                res.set_body(routes::render_template("error.html", &context)?);
79 65
                 res.set_status(status);
80 66
             }
81 67
             None => match res.status() {
82 68
                 StatusCode::NotFound => {
83 69
                     context.insert("error", "Page not found");
84
-                    res.set_body(render("error.html", &context)?);
70
+                    res.set_body(routes::render_template("error.html", &context)?);
85 71
                 }
86 72
                 _ => {}
87 73
             },
@@ -105,82 +91,12 @@ async fn main() -> std::io::Result<()> {
105 91
             .as_bytes(),
106 92
     ));
107 93
 
108
-    app.at("/").get(|req: tide::Request<()>| async move {
109
-        let posts: Vec<Post> = fs::get_all_posts().await?;
110
-        let mut context = Context::new();
111
-        context.insert("posts", &posts);
112
-        let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
113
-        context.insert("logged_in", &logged_in);
114
-        render("index.html", &context)
115
-    });
116
-
117
-    app.at("/posts")
118
-        .post(|mut req: tide::Request<()>| async move {
119
-            let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
120
-            if !logged_in {
121
-                Ok(tide::Redirect::new("/login"))
122
-            } else {
123
-                let mut post: Post = req.body_form().await?;
124
-                post.id = Uuid::new_v4().to_string();
125
-                post.date = Local::now().date().naive_local().to_string();
126
-                post.body = post.body.trim().to_owned();
127
-                post.save().await?;
128
-                Ok(tide::Redirect::new("/"))
129
-            }
130
-        });
131
-
132
-    app.at("/posts/:id")
133
-        .get(|req: tide::Request<()>| async move {
134
-            let mut context = Context::new();
135
-            let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
136
-            context.insert("logged_in", &logged_in);
137
-            let post_id = req.param("id")?;
138
-            let post = fs::get_one_post(post_id).await?;
139
-            context.insert("post", &post);
140
-            render("single.html", &context)
141
-        });
142
-
143
-    app.at("/login")
144
-        .get(|mut req: tide::Request<()>| async move {
145
-            let mut context = Context::new();
146
-            let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
147
-            context.insert("logged_in", &logged_in);
148
-            match req.session_mut().get::<String>("flash_error") {
149
-                Some(error) => {
150
-                    req.session_mut().remove("flash_error");
151
-                    &context.insert("error", &error);
152
-                }
153
-                None => {}
154
-            }
155
-            render("login.html", &context)
156
-        })
157
-        .post(|mut req: tide::Request<()>| async move {
158
-            let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
159
-            if logged_in {
160
-                return Ok(tide::Redirect::new("/"));
161
-            }
162
-
163
-            let username = env::var("ADMIN_USERNAME")?;
164
-            let password = env::var("ADMIN_PASSWORD")?;
165
-            let user: User = req.body_form().await?;
166
-            if user.username == username && user.password == password {
167
-                req.session_mut().remove("logged_in");
168
-                req.session_mut().insert("logged_in", true)?;
169
-                Ok(tide::Redirect::new("/"))
170
-            } else {
171
-                req.session_mut().remove("logged_in");
172
-                req.session_mut()
173
-                    .insert("flash_error", "Invalid credentials")?;
174
-                Ok(tide::Redirect::new("/login"))
175
-            }
176
-        });
177
-
178
-    app.at("/logout")
179
-        .post(|mut req: tide::Request<()>| async move {
180
-            req.session_mut().remove("logged_in");
181
-            req.session_mut().insert("logged_in", false)?;
182
-            Ok(tide::Redirect::new("/"))
183
-        });
94
+    app.at("/").get(routes::index);
95
+    app.at("/posts").post(routes::create_post);
96
+    app.at("/posts/:id").get(routes::single_post);
97
+    app.at("/posts/:id/edit").get(routes::edit_post);
98
+    app.at("/login").get(routes::login_page).post(routes::login);
99
+    app.at("/logout").post(routes::logout);
184 100
 
185 101
     app.listen("127.0.0.1:8080").await?;
186 102
 

+ 119
- 0
src/routes.rs View File

@@ -0,0 +1,119 @@
1
+use chrono::prelude::Local;
2
+use serde::{Deserialize, Serialize};
3
+use tera::{Context, Tera};
4
+use tide::http::mime;
5
+use tide::{Request, Response, Result, StatusCode};
6
+use uuid::Uuid;
7
+
8
+use std::env;
9
+
10
+use crate::{fs, Post};
11
+
12
+#[derive(Debug, Serialize, Deserialize)]
13
+struct User {
14
+    username: String,
15
+    password: String,
16
+}
17
+
18
+pub async fn index(req: Request<()>) -> Result {
19
+    let posts: Vec<Post> = fs::get_all_posts().await?;
20
+    let mut context = Context::new();
21
+    context.insert("posts", &posts);
22
+    let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
23
+    context.insert("logged_in", &logged_in);
24
+    render_response("index.html", &context)
25
+}
26
+
27
+pub async fn create_post(mut req: Request<()>) -> Result {
28
+    let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
29
+    if !logged_in {
30
+        Ok(tide::Redirect::new("/login").into())
31
+    } else {
32
+        let mut post: Post = req.body_form().await?;
33
+        post.id = Uuid::new_v4().to_string();
34
+        post.date = Local::now().date().naive_local().to_string();
35
+        post.body = post.body.trim().to_owned();
36
+        post.save().await?;
37
+        Ok(tide::Redirect::new("/").into())
38
+    }
39
+}
40
+
41
+pub async fn single_post(req: Request<()>) -> Result {
42
+    let mut context = Context::new();
43
+    let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
44
+    context.insert("logged_in", &logged_in);
45
+    let post_id = req.param("id")?;
46
+    let post = fs::get_one_post(post_id).await?;
47
+    context.insert("post", &post);
48
+    render_response("single.html", &context)
49
+}
50
+
51
+pub async fn edit_post(req: Request<()>) -> Result {
52
+    let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
53
+    if !logged_in {
54
+        Ok(tide::Redirect::new("/login").into())
55
+    } else {
56
+        let mut context = Context::new();
57
+        context.insert("logged_in", &logged_in);
58
+        let post_id = req.param("id")?;
59
+        let mut post = fs::get_one_post(post_id).await?;
60
+        post.body = post.body.replace("<br>", "\n");
61
+        context.insert("post", &post);
62
+        render_response("edit.html", &context)
63
+    }
64
+}
65
+
66
+pub async fn login_page(mut req: Request<()>) -> Result {
67
+    let mut context = Context::new();
68
+    let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
69
+    context.insert("logged_in", &logged_in);
70
+    match req.session_mut().get::<String>("flash_error") {
71
+        Some(error) => {
72
+            req.session_mut().remove("flash_error");
73
+            &context.insert("error", &error);
74
+        }
75
+        None => {}
76
+    }
77
+    render_response("login.html", &context)
78
+}
79
+
80
+pub async fn login(mut req: Request<()>) -> Result {
81
+    let logged_in: bool = req.session().get("logged_in").unwrap_or(false);
82
+    if logged_in {
83
+        return Ok(tide::Redirect::new("/").into());
84
+    }
85
+
86
+    let username = env::var("ADMIN_USERNAME")?;
87
+    let password = env::var("ADMIN_PASSWORD")?;
88
+    let user: User = req.body_form().await?;
89
+    if user.username == username && user.password == password {
90
+        req.session_mut().remove("logged_in");
91
+        req.session_mut().insert("logged_in", true)?;
92
+        Ok(tide::Redirect::new("/").into())
93
+    } else {
94
+        req.session_mut().remove("logged_in");
95
+        req.session_mut()
96
+            .insert("flash_error", "Invalid credentials")?;
97
+        Ok(tide::Redirect::new("/login").into())
98
+    }
99
+}
100
+
101
+pub async fn logout(mut req: Request<()>) -> Result {
102
+    req.session_mut().remove("logged_in");
103
+    req.session_mut().insert("logged_in", false)?;
104
+    Ok(tide::Redirect::new("/").into())
105
+}
106
+
107
+pub fn render_response(template: &str, context: &Context) -> Result<Response> {
108
+    let html = render_template(template, context)?;
109
+    let mut res = Response::new(StatusCode::Ok);
110
+    res.set_body(html);
111
+    res.set_content_type(mime::HTML);
112
+    Ok(res)
113
+}
114
+
115
+pub fn render_template(template: &str, context: &Context) -> Result<String> {
116
+    let tera = Tera::new("templates/**/*.html")?;
117
+    let html = tera.render(template, &context)?;
118
+    Ok(html)
119
+}

+ 32
- 0
templates/components.html View File

@@ -16,4 +16,36 @@
16 16
     {{ post.body | safe }}
17 17
   </div>
18 18
 </div>
19
+{% endmacro %} {% macro form(post=false, action, method) %}
20
+<form class="form" method="{{ method }}" action="{{ action }}">
21
+  <input
22
+    type="hidden"
23
+    name="id"
24
+    value="{% if post %}{{ post.id }}{% endif %}"
25
+  />
26
+  <input
27
+    type="hidden"
28
+    name="date"
29
+    value="{% if post %}{{ post.date }}{% endif %}"
30
+  />
31
+  <div class="form__field">
32
+    <label for="title" class="form__label">Title</label>
33
+    <input
34
+      class="form__text-field"
35
+      type="text"
36
+      name="title"
37
+      required
38
+      value="{% if post %}{{ post.title }}{% endif %}"
39
+    />
40
+  </div>
41
+  <div class="form__field">
42
+    <label for="body" class="form__label">Body</label>
43
+    <textarea class="form__textarea" name="body" required>
44
+{% if post %}{{ post.body }}{% endif %}</textarea
45
+    >
46
+  </div>
47
+  <div class="form__field">
48
+    <input class="btn" type="submit" value="Post" />
49
+  </div>
50
+</form>
19 51
 {% endmacro %}

+ 5
- 0
templates/edit.html View File

@@ -0,0 +1,5 @@
1
+{% extends "layout.html" %} {% block content %}
2
+<div class="posts">
3
+  {{ components::form(post=post, action="/posts/{{ post.id }}", method="PUT") }}
4
+</div>
5
+{% endblock %}

+ 1
- 16
templates/index.html View File

@@ -1,21 +1,6 @@
1 1
 {% extends "layout.html" %} {% block content %} {% if logged_in %}
2 2
 <h1 class="heading">New Post</h1>
3
-<form class="form" method="POST" action="/posts">
4
-  <input type="hidden" name="id" />
5
-  <input type="hidden" name="date" />
6
-  <div class="form__field">
7
-    <label for="title" class="form__label">Title</label>
8
-    <input class="form__text-field" type="text" name="title" required />
9
-  </div>
10
-  <div class="form__field">
11
-    <label for="body" class="form__label">Body</label>
12
-    <textarea class="form__textarea" name="body" required></textarea>
13
-  </div>
14
-  <div class="form__field">
15
-    <input class="btn" type="submit" value="Post" />
16
-  </div>
17
-</form>
18
-{% endif %}
3
+{{ components::form(action="/posts", method="POST") }} {% endif %}
19 4
 
20 5
 <div class="posts">
21 6
   {% for post in posts %} {{ components::post(post=post, type="index") }} {%

Loading…
Cancel
Save