parent
f611c5378d
commit
2893bbd595
25
src/main.rs
25
src/main.rs
|
@ -14,7 +14,6 @@ extern crate serde;
|
|||
extern crate crypto;
|
||||
extern crate scrypt;
|
||||
#[macro_use]
|
||||
#[cfg(test)]
|
||||
extern crate lazy_static;
|
||||
|
||||
mod schema;
|
||||
|
@ -31,9 +30,33 @@ use rocket::Rocket;
|
|||
use rocket::config::{Config, Environment, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::sync::RwLock;
|
||||
|
||||
embed_migrations!();
|
||||
|
||||
// We need a global RwLock for SQLite
|
||||
// This is unfortunate when we still use SQLite
|
||||
// but should be mostly fine for our purpose
|
||||
lazy_static! {
|
||||
pub static ref DB_LOCK: RwLock<()> = RwLock::new(());
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! lock_db_write {
|
||||
() => {
|
||||
crate::DB_LOCK.write()
|
||||
.map_err(|_| "Cannot lock database for writing".into())
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! lock_db_read {
|
||||
() => {
|
||||
crate::DB_LOCK.read()
|
||||
.map_err(|_| "Cannot lock database for reading".into())
|
||||
};
|
||||
}
|
||||
|
||||
#[database("db")]
|
||||
pub struct DbConn(SqliteConnection);
|
||||
|
||||
|
|
38
src/user.rs
38
src/user.rs
|
@ -1,5 +1,6 @@
|
|||
use crate::schema::users;
|
||||
use crate::schema::users::dsl::*;
|
||||
use crate::{lock_db_write, lock_db_read};
|
||||
use diesel::prelude::*;
|
||||
use diesel::sqlite::SqliteConnection;
|
||||
use serde::Deserialize;
|
||||
|
@ -15,6 +16,12 @@ impl UserOpError {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<UserOpError> for &str {
|
||||
fn into(self) -> UserOpError {
|
||||
UserOpError::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Password should ALWAYS be hashed
|
||||
#[derive(Debug)]
|
||||
pub struct Password(String);
|
||||
|
@ -104,19 +111,21 @@ impl User {
|
|||
|
||||
match Self::find_user_by_email(db, &new_user.email) {
|
||||
Ok(_) => Err(UserOpError::new("User already registered")),
|
||||
Err(_) => diesel::insert_into(users::table)
|
||||
.values(user_hashed)
|
||||
.execute(db)
|
||||
.map(|_| ())
|
||||
.map_err(|_| UserOpError::new("Database error"))
|
||||
Err(_) => lock_db_write!()
|
||||
.and_then(|_| diesel::insert_into(users::table)
|
||||
.values(user_hashed)
|
||||
.execute(db)
|
||||
.map(|_| ())
|
||||
.map_err(|_| UserOpError::new("Database error")))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_user_by_email(db: &SqliteConnection, user_email: &str) -> Result<User, UserOpError> {
|
||||
let mut results = users.filter(email.eq(user_email))
|
||||
.limit(1)
|
||||
.load::<UserQuery>(db)
|
||||
.map_err(|_| UserOpError::new("Database error"))?;
|
||||
let mut results = lock_db_read!()
|
||||
.and_then(|_| users.filter(email.eq(user_email))
|
||||
.limit(1)
|
||||
.load::<UserQuery>(db)
|
||||
.map_err(|_| UserOpError::new("Database error")))?;
|
||||
if results.is_empty() {
|
||||
Result::Err(UserOpError::new("No matching user found"))
|
||||
} else {
|
||||
|
@ -157,11 +166,12 @@ impl User {
|
|||
// Update database
|
||||
// TODO: Maybe we should revoke all JWTs somehow?
|
||||
// maybe we can record when the user last changed?
|
||||
diesel::update(users.find(self.id))
|
||||
.set(password.eq::<String>(Password::new(new_passwd).into()))
|
||||
.execute(db)
|
||||
.map(|_| ())
|
||||
.map_err(|_| UserOpError::new("Database error"))
|
||||
lock_db_write!()
|
||||
.and_then(|_| diesel::update(users.find(self.id))
|
||||
.set(password.eq::<String>(Password::new(new_passwd).into()))
|
||||
.execute(db)
|
||||
.map(|_| ())
|
||||
.map_err(|_| UserOpError::new("Database error")))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue