Browse Source

Use slugs instead of UUIDs

master
Dylan Baker 1 year 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,7 +1003,6 @@ dependencies = [
1003 1003
  "tera",
1004 1004
  "tide 0.13.0",
1005 1005
  "tide-tera",
1006
- "uuid",
1007 1006
 ]
1008 1007
 
1009 1008
 [[package]]

+ 0
- 1
Cargo.toml View File

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

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

@@ -25,18 +25,18 @@ pub async fn get_all_posts() -> Result<Vec<Post>, Error> {
25 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 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 31
     let contents = read_post_from_disk(&path).await?;
32 32
     let post = Post::from_str(&contents)?;
33 33
 
34 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 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 40
     std::fs::remove_file(path)?;
41 41
     Ok(())
42 42
 }
@@ -56,7 +56,7 @@ async fn read_post_from_disk(path: &PathBuf) -> Result<String, Error> {
56 56
 
57 57
 pub fn write_post_to_disk(post: &Post) -> Result<(), Error> {
58 58
     let mut path: PathBuf = get_posts_directory_path()?;
59
-    let filename = format!("{}.json", post.id);
59
+    let filename = format!("{}.json", post.slug);
60 60
     path = path.join(&filename);
61 61
     let mut file = File::create(&path)?;
62 62
     file.write_all(serde_json::to_string(&post)?.as_bytes())?;

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

@@ -34,11 +34,11 @@ pub async fn build_app() -> Result<tide::Server<State>, tide::Error> {
34 34
     app.at("/posts/new")
35 35
         .with(require_auth)
36 36
         .get(routes::new_post);
37
-    app.at("/posts/:id")
37
+    app.at("/posts/:slug")
38 38
         .get(routes::single_post)
39 39
         .post(routes::update_post)
40 40
         .delete(routes::delete_post);
41
-    app.at("/posts/:id/edit")
41
+    app.at("/posts/:slug/edit")
42 42
         .with(require_auth)
43 43
         .get(routes::edit_post);
44 44
     app.at(&login_path)

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

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

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

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

+ 2
- 2
static/script.js View File

@@ -23,8 +23,8 @@ function createCloseButton() {
23 23
 document.querySelectorAll('[data-delete]').forEach((el) => {
24 24
   el.addEventListener('click', (e) => {
25 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 28
         method: 'DELETE',
29 29
       }).then((r) => {
30 30
         r.json().then((data) => {

+ 2
- 2
static/style.css View File

@@ -122,8 +122,8 @@ a:hover {
122 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 129
 .post__heading {

+ 15
- 5
templates/components.html View File

@@ -1,17 +1,17 @@
1 1
 {% macro post(post, type) %}
2 2
   <div class="post">
3
-    
3
+
4 4
       <div class="post__heading">
5 5
         <div class="post__title">
6 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 8
             {{ post.title }}
9 9
           </a>
10 10
         </div>
11 11
         {% if logged_in %}
12 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 15
           </div>
16 16
         {% endif %}
17 17
       </div>
@@ -29,7 +29,7 @@
29 29
     <input
30 30
       type="hidden"
31 31
       name="id"
32
-      value="{% if post %}{{ post.id }}{% endif %}"
32
+      value="{% if post %}{{ post.slug }}{% endif %}"
33 33
     />
34 34
     <input
35 35
       type="hidden"
@@ -47,6 +47,16 @@
47 47
         value="{% if post %}{{ post.title }}{% endif %}"
48 48
       />
49 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 60
     <div class="form__field">
51 61
       <label for="body" class="form__label">Body</label>
52 62
       <div class="editor-helpers">

+ 1
- 1
templates/edit.html View File

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

Loading…
Cancel
Save