Browse Source

Use slugs instead of UUIDs

master
Dylan Baker 3 years ago
parent
commit
1c3547718f
10 changed files with 35 additions and 29 deletions
  1. 0
    1
      Cargo.lock
  2. 0
    1
      Cargo.toml
  3. 5
    5
      oslo-lib/src/fs.rs
  4. 2
    2
      oslo-lib/src/lib.rs
  5. 1
    1
      oslo-lib/src/post.rs
  6. 7
    9
      oslo-lib/src/routes.rs
  7. 2
    2
      static/script.js
  8. 2
    2
      static/style.css
  9. 15
    5
      templates/components.html
  10. 1
    1
      templates/edit.html

+ 0
- 1
Cargo.lock View File

1003
  "tera",
1003
  "tera",
1004
  "tide 0.13.0",
1004
  "tide 0.13.0",
1005
  "tide-tera",
1005
  "tide-tera",
1006
- "uuid",
1007
 ]
1006
 ]
1008
 
1007
 
1009
 [[package]]
1008
 [[package]]

+ 0
- 1
Cargo.toml View File

17
 tera = "1.5.0"
17
 tera = "1.5.0"
18
 tide = "0.13.0"
18
 tide = "0.13.0"
19
 tide-tera = "0.1.1"
19
 tide-tera = "0.1.1"
20
-uuid = { version = "0.4", features = ["serde", "v4"] }
21
 oslo-lib = { path = "oslo-lib" }
20
 oslo-lib = { path = "oslo-lib" }

+ 5
- 5
oslo-lib/src/fs.rs View File

25
     Ok(posts)
25
     Ok(posts)
26
 }
26
 }
27
 
27
 
28
-pub async fn get_one_post(post_id: String) -> Result<Post, Error> {
28
+pub async fn get_one_post(slug: String) -> Result<Post, Error> {
29
     let posts_dir = get_posts_directory_path()?;
29
     let posts_dir = get_posts_directory_path()?;
30
-    let path = posts_dir.join(format!("{}.json", post_id));
30
+    let path = posts_dir.join(format!("{}.json", slug));
31
     let contents = read_post_from_disk(&path).await?;
31
     let contents = read_post_from_disk(&path).await?;
32
     let post = Post::from_str(&contents)?;
32
     let post = Post::from_str(&contents)?;
33
 
33
 
34
     Ok(post)
34
     Ok(post)
35
 }
35
 }
36
 
36
 
37
-pub fn delete_post(post_id: String) -> Result<(), Error> {
37
+pub fn delete_post(slug: String) -> Result<(), Error> {
38
     let posts_dir = get_posts_directory_path()?;
38
     let posts_dir = get_posts_directory_path()?;
39
-    let path = posts_dir.join(format!("{}.json", post_id));
39
+    let path = posts_dir.join(format!("{}.json", slug));
40
     std::fs::remove_file(path)?;
40
     std::fs::remove_file(path)?;
41
     Ok(())
41
     Ok(())
42
 }
42
 }
56
 
56
 
57
 pub fn write_post_to_disk(post: &Post) -> Result<(), Error> {
57
 pub fn write_post_to_disk(post: &Post) -> Result<(), Error> {
58
     let mut path: PathBuf = get_posts_directory_path()?;
58
     let mut path: PathBuf = get_posts_directory_path()?;
59
-    let filename = format!("{}.json", post.id);
59
+    let filename = format!("{}.json", post.slug);
60
     path = path.join(&filename);
60
     path = path.join(&filename);
61
     let mut file = File::create(&path)?;
61
     let mut file = File::create(&path)?;
62
     file.write_all(serde_json::to_string(&post)?.as_bytes())?;
62
     file.write_all(serde_json::to_string(&post)?.as_bytes())?;

+ 2
- 2
oslo-lib/src/lib.rs View File

34
     app.at("/posts/new")
34
     app.at("/posts/new")
35
         .with(require_auth)
35
         .with(require_auth)
36
         .get(routes::new_post);
36
         .get(routes::new_post);
37
-    app.at("/posts/:id")
37
+    app.at("/posts/:slug")
38
         .get(routes::single_post)
38
         .get(routes::single_post)
39
         .post(routes::update_post)
39
         .post(routes::update_post)
40
         .delete(routes::delete_post);
40
         .delete(routes::delete_post);
41
-    app.at("/posts/:id/edit")
41
+    app.at("/posts/:slug/edit")
42
         .with(require_auth)
42
         .with(require_auth)
43
         .get(routes::edit_post);
43
         .get(routes::edit_post);
44
     app.at(&login_path)
44
     app.at(&login_path)

+ 1
- 1
oslo-lib/src/post.rs View File

6
 
6
 
7
 #[derive(Debug, Serialize, Deserialize)]
7
 #[derive(Debug, Serialize, Deserialize)]
8
 pub struct Post {
8
 pub struct Post {
9
-    pub id: String,
10
     pub title: String,
9
     pub title: String,
10
+    pub slug: String,
11
     pub body: String,
11
     pub body: String,
12
     pub html: String,
12
     pub html: String,
13
     pub date: String,
13
     pub date: String,

+ 7
- 9
oslo-lib/src/routes.rs View File

4
 use tide::convert::json;
4
 use tide::convert::json;
5
 use tide::http::mime;
5
 use tide::http::mime;
6
 use tide::{Redirect, Request, Response, Result, StatusCode};
6
 use tide::{Redirect, Request, Response, Result, StatusCode};
7
-use uuid::Uuid;
8
 
7
 
9
 use std::env;
8
 use std::env;
10
 
9
 
25
 
24
 
26
 pub async fn single_post(req: Request<State>) -> Result {
25
 pub async fn single_post(req: Request<State>) -> Result {
27
     let mut context = Context::new();
26
     let mut context = Context::new();
28
-    let post_id = req.param("id")?;
29
-    let post = fs::get_one_post(post_id).await?;
27
+    let slug = req.param("slug")?;
28
+    let post = fs::get_one_post(slug).await?;
30
     context.insert("post", &post);
29
     context.insert("post", &post);
31
     render_html_response("single.html", &context, req)
30
     render_html_response("single.html", &context, req)
32
 }
31
 }
38
 
37
 
39
 pub async fn edit_post(req: Request<State>) -> Result {
38
 pub async fn edit_post(req: Request<State>) -> Result {
40
     let mut context = Context::new();
39
     let mut context = Context::new();
41
-    let post_id = req.param("id")?;
42
-    let mut post = fs::get_one_post(post_id).await?;
40
+    let slug = req.param("slug")?;
41
+    let mut post = fs::get_one_post(slug).await?;
43
     post.body = post.body.replace("<br>", "\n");
42
     post.body = post.body.replace("<br>", "\n");
44
     post.html = post.generate_html();
43
     post.html = post.generate_html();
45
     context.insert("post", &post);
44
     context.insert("post", &post);
48
 
47
 
49
 pub async fn create_post(mut req: Request<State>) -> Result {
48
 pub async fn create_post(mut req: Request<State>) -> Result {
50
     let mut post: Post = req.body_form().await?;
49
     let mut post: Post = req.body_form().await?;
51
-    post.id = Uuid::new_v4().to_string();
52
     post.date = Local::now().date().naive_local().to_string();
50
     post.date = Local::now().date().naive_local().to_string();
53
     post.body = post.body.trim().to_owned();
51
     post.body = post.body.trim().to_owned();
54
     post.html = post.generate_html();
52
     post.html = post.generate_html();
62
     post.save().await?;
60
     post.save().await?;
63
     req.session_mut()
61
     req.session_mut()
64
         .insert("flash_success", String::from("Post updated successfully"))?;
62
         .insert("flash_success", String::from("Post updated successfully"))?;
65
-    redirect(&format!("/posts/{}", post.id))
63
+    redirect(&format!("/posts/{}", post.slug))
66
 }
64
 }
67
 
65
 
68
 pub async fn delete_post(mut req: Request<State>) -> Result {
66
 pub async fn delete_post(mut req: Request<State>) -> Result {
69
-    let id: String = req.param("id")?;
70
-    fs::delete_post(id)?;
67
+    let slug: String = req.param("slug")?;
68
+    fs::delete_post(slug)?;
71
     req.session_mut()
69
     req.session_mut()
72
         .insert("flash_success", String::from("Post deleted successfully"))?;
70
         .insert("flash_success", String::from("Post deleted successfully"))?;
73
     render_json_response(json!({ "success": "true" }))
71
     render_json_response(json!({ "success": "true" }))

+ 2
- 2
static/script.js View File

23
 document.querySelectorAll('[data-delete]').forEach((el) => {
23
 document.querySelectorAll('[data-delete]').forEach((el) => {
24
   el.addEventListener('click', (e) => {
24
   el.addEventListener('click', (e) => {
25
     if (confirm('Are you sure? This cannot be undone.')) {
25
     if (confirm('Are you sure? This cannot be undone.')) {
26
-      let postId = e.target.dataset.delete;
27
-      fetch(`/posts/${postId}`, {
26
+      let slug = e.target.dataset.delete;
27
+      fetch(`/posts/${slug}`, {
28
         method: 'DELETE',
28
         method: 'DELETE',
29
       }).then((r) => {
29
       }).then((r) => {
30
         r.json().then((data) => {
30
         r.json().then((data) => {

+ 2
- 2
static/style.css View File

122
   resize: vertical;
122
   resize: vertical;
123
 }
123
 }
124
 
124
 
125
-.post:not(:last-child) {
126
-  margin: 3em 0;
125
+.post {
126
+  margin: 1em 0;
127
 }
127
 }
128
 
128
 
129
 .post__heading {
129
 .post__heading {

+ 15
- 5
templates/components.html View File

1
 {% macro post(post, type) %}
1
 {% macro post(post, type) %}
2
   <div class="post">
2
   <div class="post">
3
-    
3
+
4
       <div class="post__heading">
4
       <div class="post__heading">
5
         <div class="post__title">
5
         <div class="post__title">
6
           <span class="post__date">:: {{ post.date }} //</span>
6
           <span class="post__date">:: {{ post.date }} //</span>
7
-          <a class="post__link" href="/posts/{{ post.id }}">
7
+          <a class="post__link" href="/posts/{{ post.slug }}">
8
             {{ post.title }}
8
             {{ post.title }}
9
           </a>
9
           </a>
10
         </div>
10
         </div>
11
         {% if logged_in %}
11
         {% if logged_in %}
12
           <div class="post__meta">
12
           <div class="post__meta">
13
-            <a class="post__link" href="/posts/{{ post.id }}/edit">edit</a>
14
-            <span class="post__link danger" data-delete="{{ post.id }}">delete</span>          
13
+            <a class="post__link" href="/posts/{{ post.slug }}/edit">edit</a>
14
+            <span class="post__link danger" data-delete="{{ post.slug }}">delete</span>
15
           </div>
15
           </div>
16
         {% endif %}
16
         {% endif %}
17
       </div>
17
       </div>
29
     <input
29
     <input
30
       type="hidden"
30
       type="hidden"
31
       name="id"
31
       name="id"
32
-      value="{% if post %}{{ post.id }}{% endif %}"
32
+      value="{% if post %}{{ post.slug }}{% endif %}"
33
     />
33
     />
34
     <input
34
     <input
35
       type="hidden"
35
       type="hidden"
47
         value="{% if post %}{{ post.title }}{% endif %}"
47
         value="{% if post %}{{ post.title }}{% endif %}"
48
       />
48
       />
49
     </div>
49
     </div>
50
+    <div class="form__field">
51
+      <label for="slug" class="form__label">Slug</label>
52
+      <input
53
+        class="form__text-field"
54
+        type="text"
55
+        name="slug"
56
+        required
57
+        value="{% if post %}{{ post.slug }}{% endif %}"
58
+      />
59
+    </div>
50
     <div class="form__field">
60
     <div class="form__field">
51
       <label for="body" class="form__label">Body</label>
61
       <label for="body" class="form__label">Body</label>
52
       <div class="editor-helpers">
62
       <div class="editor-helpers">

+ 1
- 1
templates/edit.html View File

2
 {% block content %}
2
 {% block content %}
3
 
3
 
4
   <div class="posts">
4
   <div class="posts">
5
-    {{ components::form(post=post, action="/posts/{{ post.id }}") }}
5
+    {{ components::form(post=post, action="/posts/{{ post.slug }}") }}
6
   </div>
6
   </div>
7
 
7
 
8
 {% endblock %}
8
 {% endblock %}

Loading…
Cancel
Save