Database integration WIP
This commit is contained in:
parent
f3e5cd62b1
commit
2bcda34f6a
13 changed files with 225 additions and 37 deletions
|
@ -1,21 +1,31 @@
|
|||
use actix_web::web::Data;
|
||||
#![allow(dead_code, unused_imports)]
|
||||
use actix_web::web::{Data, Query};
|
||||
use actix_web::{web::scope, App, HttpServer};
|
||||
use log::info;
|
||||
// use uuid::Uuid;
|
||||
|
||||
mod routes;
|
||||
mod state;
|
||||
mod types;
|
||||
|
||||
use log::info;
|
||||
use routes::{get_posts, new_post, test};
|
||||
use types::AppState;
|
||||
use routes::{get_posts, new_post, register, test};
|
||||
use sqlx::ConnectOptions;
|
||||
use state::AppState;
|
||||
|
||||
use sqlx::{migrate::MigrateDatabase, query, sqlite};
|
||||
|
||||
struct User {
|
||||
name: String,
|
||||
pass: String,
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
|
||||
info!("Starting server...");
|
||||
|
||||
let data = AppState::new();
|
||||
let data = AppState::new().await;
|
||||
|
||||
info!("Spinning up server on http://localhost:8080");
|
||||
HttpServer::new(move || {
|
||||
App::new().service(
|
||||
scope("api")
|
||||
|
@ -23,6 +33,7 @@ async fn main() -> std::io::Result<()> {
|
|||
.service(new_post)
|
||||
.service(routes::vote)
|
||||
.service(test)
|
||||
.service(register)
|
||||
.app_data(Data::new(data.clone())),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::types::{AppState, NewPost, Post};
|
||||
use crate::types::{NewPost, Post};
|
||||
use crate::AppState;
|
||||
|
||||
use actix_web::web::{Data, Path};
|
||||
use actix_web::{get, post, web::Json, HttpResponse, Responder};
|
||||
use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
|
||||
use argon2::password_hash::SaltString;
|
||||
use log::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
@ -24,6 +27,13 @@ pub async fn new_post(new_post: Json<NewPost>, data: Data<AppState>) -> impl Res
|
|||
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);
|
||||
|
@ -86,3 +96,44 @@ pub async fn vote(params: Path<(Uuid, VoteDirection)>, data: Data<AppState>) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RegisterData {
|
||||
username: String,
|
||||
password: String,
|
||||
captcha: String,
|
||||
}
|
||||
|
||||
use argon2::password_hash::rand_core::OsRng;
|
||||
use argon2::password_hash::*;
|
||||
use argon2::Algorithm;
|
||||
use argon2::Argon2;
|
||||
use argon2::PasswordHasher;
|
||||
use argon2::PasswordVerifier;
|
||||
use argon2::Version;
|
||||
|
||||
#[post("/register")]
|
||||
pub async fn register(data: Json<RegisterData>, state: Data<AppState>) -> Result<impl Responder> {
|
||||
let q = "SELECT password FROM users WHERE username = ?";
|
||||
let query = sqlx::query(q).bind(&data.username);
|
||||
let result = query.fetch_one(&state.pool).await.ok();
|
||||
if result.is_some() {
|
||||
info!("User \"{}\" already exists", data.username);
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
|
||||
let password = data.password.clone();
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let phc_hash = Argon2::default().hash_password(password.as_bytes(), &salt);
|
||||
if let Ok(phc_hash) = phc_hash {
|
||||
info!("User: {} registered", data.username);
|
||||
let phc_hash = phc_hash.to_string();
|
||||
let q = "INSERT INTO users (username, password) VALUES (?, ?)";
|
||||
let query = sqlx::query(q).bind(&data.username).bind(&phc_hash);
|
||||
query.execute(&state.pool).await.unwrap();
|
||||
} else {
|
||||
return Ok(HttpResponse::BadRequest().json("Error"));
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json("User registered"))
|
||||
}
|
||||
|
|
31
server/src/state.rs
Normal file
31
server/src/state.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use crate::types::Post;
|
||||
use sqlx::Sqlite;
|
||||
use sqlx::{self, sqlite};
|
||||
use sqlx::{AnyPool, Pool};
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub posts: Arc<Mutex<BTreeMap<Uuid, Post>>>,
|
||||
pub pool: Pool<Sqlite>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub async fn new() -> Self {
|
||||
let pool = sqlite::SqlitePoolOptions::new()
|
||||
.max_connections(5)
|
||||
.connect(":memory:")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
sqlx::migrate!("./migrations").run(&pool).await.unwrap();
|
||||
|
||||
Self {
|
||||
posts: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
pool: pool,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,16 +4,17 @@ use std::sync::Arc;
|
|||
use std::sync::Mutex;
|
||||
use uuid::Uuid;
|
||||
|
||||
// The post as it is received from the client
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NewPost {
|
||||
title: String,
|
||||
content: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
// The post as it is stored in the database
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Post {
|
||||
pub uuid: Uuid,
|
||||
pub title: String,
|
||||
pub content: String,
|
||||
pub votes: VoteCount,
|
||||
}
|
||||
|
@ -22,26 +23,12 @@ impl From<NewPost> for Post {
|
|||
fn from(post: NewPost) -> Self {
|
||||
Self {
|
||||
uuid: Uuid::new_v4(),
|
||||
title: post.title,
|
||||
content: post.content,
|
||||
votes: VoteCount::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub posts: Arc<Mutex<BTreeMap<Uuid, Post>>>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
posts: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Part of the post struct
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct VoteCount {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue