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 } - } -}