Major restructure
This commit is contained in:
parent
5b8d1cbdb1
commit
27386d5d18
9 changed files with 87 additions and 110 deletions
|
@ -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)
|
||||
|
|
25
server/src/db.rs
Normal file
25
server/src/db.rs
Normal file
|
@ -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!();
|
||||
}
|
|
@ -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())),
|
||||
|
|
7
server/src/routes/mod.rs
Normal file
7
server/src/routes/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
mod post;
|
||||
mod users;
|
||||
mod vote;
|
||||
|
||||
pub use post::*;
|
||||
pub use users::*;
|
||||
pub use vote::*;
|
27
server/src/routes/post.rs
Executable file
27
server/src/routes/post.rs
Executable file
|
@ -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!")
|
||||
}
|
|
@ -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,
|
16
server/src/routes/vote.rs
Normal file
16
server/src/routes/vote.rs
Normal file
|
@ -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")
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue