From 27386d5d18ef6ac921a9ffcca63f1950ea00dc94 Mon Sep 17 00:00:00 2001
From: Imbus <imbus64@protonmail.com>
Date: Fri, 20 Oct 2023 06:06:55 +0200
Subject: [PATCH] Major restructure

---
 server/migrations/0002_posts_table.sql    |  2 +
 server/src/db.rs                          | 25 +++++++
 server/src/main.rs                        |  4 +-
 server/src/routes/mod.rs                  |  7 ++
 server/src/routes/post.rs                 | 27 +++++++
 server/src/{routes.rs => routes/users.rs} | 89 -----------------------
 server/src/routes/vote.rs                 | 16 ++++
 server/src/state.rs                       |  4 +-
 server/src/types.rs                       | 23 ++----
 9 files changed, 87 insertions(+), 110 deletions(-)
 create mode 100644 server/src/db.rs
 create mode 100644 server/src/routes/mod.rs
 create mode 100755 server/src/routes/post.rs
 rename server/src/{routes.rs => routes/users.rs} (54%)
 create mode 100644 server/src/routes/vote.rs

diff --git a/server/migrations/0002_posts_table.sql b/server/migrations/0002_posts_table.sql
index 35c0660..97d6a83 100644
--- a/server/migrations/0002_posts_table.sql
+++ b/server/migrations/0002_posts_table.sql
@@ -2,6 +2,8 @@ CREATE TABLE IF NOT EXISTS posts (
     id SERIAL PRIMARY KEY,
     user_id SERIAL NOT NULL,
     content TEXT NOT NULL,
+    upvotes INT NOT NULL DEFAULT 0,
+    downvotes INT NOT NULL DEFAULT 0,
     created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
     updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
     FOREIGN KEY (user_id) REFERENCES users (id)
diff --git a/server/src/db.rs b/server/src/db.rs
new file mode 100644
index 0000000..2afb3a4
--- /dev/null
+++ b/server/src/db.rs
@@ -0,0 +1,25 @@
+use crate::types::{NewPost, Post};
+use sqlx::{Any, AnyPool, Row};
+
+fn db_get_user() -> String {
+    unimplemented!();
+}
+
+fn db_get_posts() -> Vec<Post> {
+    unimplemented!();
+}
+
+async fn db_new_post(post: NewPost, pool: &AnyPool) -> i32 {
+    let q = "INSERT INTO posts (content) VALUES (?)";
+    let query = sqlx::query(q).bind(post.content);
+    let result = query.fetch_one(pool).await.ok();
+    if let Some(row) = result {
+        row.get::<i32, _>("id")
+    } else {
+        panic!("Failed to insert post into database");
+    }
+}
+
+fn db_vote(post_id: i32, user_id: i32, upvote: bool) {
+    unimplemented!();
+}
diff --git a/server/src/main.rs b/server/src/main.rs
index ab9f334..d1a377d 100755
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -4,12 +4,13 @@ use actix_web::web::Data;
 use actix_web::{web::scope, App, HttpServer};
 use log::info;
 
+mod db;
 mod jwt;
 mod routes;
 mod state;
 mod types;
 
-use routes::{get_posts, login, new_post, register, test};
+use routes::{get_posts, login, new_post, register};
 use state::ServerState;
 
 #[actix_web::main]
@@ -28,7 +29,6 @@ async fn main() -> std::io::Result<()> {
                     .service(get_posts)
                     .service(new_post)
                     .service(routes::vote)
-                    .service(test)
                     .service(login)
                     .service(register)
                     .app_data(Data::new(data.clone())),
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs
new file mode 100644
index 0000000..8413972
--- /dev/null
+++ b/server/src/routes/mod.rs
@@ -0,0 +1,7 @@
+mod post;
+mod users;
+mod vote;
+
+pub use post::*;
+pub use users::*;
+pub use vote::*;
diff --git a/server/src/routes/post.rs b/server/src/routes/post.rs
new file mode 100755
index 0000000..e2c465b
--- /dev/null
+++ b/server/src/routes/post.rs
@@ -0,0 +1,27 @@
+use crate::jwt::token_factory;
+use crate::types::{NewPost, Post};
+use crate::ServerState;
+
+use actix_web::web::{Data, Path};
+use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
+use argon2::password_hash::rand_core::OsRng;
+use argon2::password_hash::SaltString;
+use argon2::password_hash::*;
+use argon2::Argon2;
+use argon2::PasswordHasher;
+use argon2::PasswordVerifier;
+use log::*;
+use serde::{Deserialize, Serialize};
+use uuid::Uuid;
+
+#[get("/posts")]
+pub async fn get_posts(data: Data<ServerState>) -> impl Responder {
+    HttpResponse::InternalServerError().body("Unimplemented")
+}
+
+#[post("/posts")]
+pub async fn new_post(new_post: Json<NewPost>, data: Data<ServerState>) -> impl Responder {
+    let post = Post::from(new_post.into_inner());
+    info!("Created post {:?}", post.uuid);
+    HttpResponse::Ok().json("Post added!")
+}
diff --git a/server/src/routes.rs b/server/src/routes/users.rs
similarity index 54%
rename from server/src/routes.rs
rename to server/src/routes/users.rs
index ef19c75..e5b568b 100755
--- a/server/src/routes.rs
+++ b/server/src/routes/users.rs
@@ -14,95 +14,6 @@ use log::*;
 use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 
-#[get("/")]
-pub async fn get_posts(data: Data<ServerState>) -> impl Responder {
-    match data.posts.lock() {
-        Ok(posts) => {
-            let posts: Vec<Post> = posts.values().cloned().collect();
-            HttpResponse::Ok().json(posts)
-        }
-        Err(e) => {
-            warn!("Error: {:?}", e);
-            HttpResponse::InternalServerError().body("Error")
-        }
-    }
-}
-
-#[post("/")]
-pub async fn new_post(new_post: Json<NewPost>, data: Data<ServerState>) -> impl Responder {
-    let post = Post::from(new_post.into_inner());
-    info!("Created post {:?}", post.uuid);
-
-    // let q = "INSERT INTO posts (uuid, content, upvotes, downvotes) VALUES (?, ?, ?, ?)";
-    // let query = sqlx::query(q)
-    //     .bind(post.uuid)
-    //     .bind(post.content)
-    //     .bind(post.votes.up)
-    //     .bind(post.votes.down);
-
-    match data.posts.lock() {
-        Ok(mut posts) => {
-            posts.insert(post.uuid, post);
-        }
-        Err(e) => {
-            warn!("Error: {:?}", e);
-        }
-    };
-
-    HttpResponse::Ok().json("Post added!")
-}
-
-// This is a test route, returns "Hello, world!"
-#[get("/test")]
-pub async fn test(data: Data<ServerState>) -> impl Responder {
-    match data.posts.lock() {
-        Ok(posts) => {
-            let posts: Vec<Post> = posts.values().cloned().collect();
-            HttpResponse::Ok().body(format!("Hello, world! {:?}", posts))
-        }
-        Err(e) => {
-            warn!("Error: {:?}", e);
-            HttpResponse::InternalServerError().body("Error")
-        }
-    }
-}
-
-#[derive(Debug, Deserialize, Serialize)]
-#[serde(rename_all = "snake_case")]
-pub enum VoteDirection {
-    Up,
-    Down,
-    Unupvote,
-    Undownvote,
-}
-
-#[post("vote/{uuid}/{direction}")]
-pub async fn vote(params: Path<(Uuid, VoteDirection)>, data: Data<ServerState>) -> impl Responder {
-    let (uuid, direction) = params.into_inner();
-    println!("Voting {:?} on post {:?}", direction, uuid);
-
-    match data.posts.lock() {
-        Ok(mut posts) => {
-            let uuid = uuid;
-            if let Some(post) = posts.get_mut(&uuid) {
-                match direction {
-                    VoteDirection::Up => post.votes.up += 1,
-                    VoteDirection::Unupvote => post.votes.up -= 1,
-                    VoteDirection::Down => post.votes.down += 1,
-                    VoteDirection::Undownvote => post.votes.down -= 1,
-                }
-                HttpResponse::Ok().body("Downvoted!")
-            } else {
-                HttpResponse::NotFound().body("Post not found!")
-            }
-        }
-        Err(e) => {
-            warn!("Error: {:?}", e);
-            HttpResponse::InternalServerError().body("Error")
-        }
-    }
-}
-
 #[derive(Debug, Serialize, Deserialize)]
 pub struct RegisterData {
     username: String,
diff --git a/server/src/routes/vote.rs b/server/src/routes/vote.rs
new file mode 100644
index 0000000..a2dc987
--- /dev/null
+++ b/server/src/routes/vote.rs
@@ -0,0 +1,16 @@
+use crate::state::ServerState;
+use actix_web::web::{Data, Path};
+use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
+use serde::{Deserialize, Serialize};
+use uuid::Uuid;
+
+#[derive(Debug, Serialize, Deserialize)]
+enum VoteDirection {
+    Up,
+    Down,
+}
+
+#[post("vote/{uuid}")]
+pub async fn vote(params: Path<(Uuid, VoteDirection)>, data: Data<ServerState>) -> impl Responder {
+    HttpResponse::InternalServerError().body("Unimplemented")
+}
diff --git a/server/src/state.rs b/server/src/state.rs
index 8699d93..39c66a0 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -9,7 +9,7 @@ use uuid::Uuid;
 
 #[derive(Clone)]
 pub struct ServerState {
-    pub posts: Arc<Mutex<BTreeMap<Uuid, Post>>>,
+    // pub posts: Arc<Mutex<BTreeMap<Uuid, Post>>>,
     pub pool: Pool<Sqlite>,
 }
 
@@ -24,7 +24,7 @@ impl ServerState {
         sqlx::migrate!("./migrations").run(&pool).await.unwrap();
 
         Self {
-            posts: Arc::new(Mutex::new(BTreeMap::new())),
+            // posts: Arc::new(Mutex::new(BTreeMap::new())),
             pool: pool,
         }
     }
diff --git a/server/src/types.rs b/server/src/types.rs
index 267be22..e59b086 100755
--- a/server/src/types.rs
+++ b/server/src/types.rs
@@ -4,8 +4,8 @@ use uuid::Uuid;
 // The post as it is received from the client
 #[derive(Debug, Serialize, Deserialize)]
 pub struct NewPost {
-    content: String,
-    token: String,
+    pub content: String,
+    pub token: String,
 }
 
 // The post as it is stored in the database
@@ -13,7 +13,8 @@ pub struct NewPost {
 pub struct Post {
     pub uuid: Uuid,
     pub content: String,
-    pub votes: VoteCount,
+    pub upvotes: i32,
+    pub downvotes: i32,
 }
 
 impl From<NewPost> for Post {
@@ -21,20 +22,8 @@ impl From<NewPost> for Post {
         Self {
             uuid: Uuid::new_v4(),
             content: post.content,
-            votes: VoteCount::new(),
+            upvotes: 0,
+            downvotes: 0,
         }
     }
 }
-
-// Part of the post struct
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct VoteCount {
-    pub up: u32,
-    pub down: u32,
-}
-
-impl VoteCount {
-    fn new() -> Self {
-        Self { up: 0, down: 0 }
-    }
-}