use crate::schema::users;
use diesel;
use diesel::pg::PgConnection;
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
#[derive(Serialize, Deserialize, Queryable, AsChangeset)]
#[table_name = "users"]
pub struct User {
pub id: i32,
pub username: String,
pub email: String,
pub password: String,
}
#[derive(Serialize, Deserialize, Insertable)]
#[table_name = "users"]
pub struct InsertableUser {
pub username: String,
pub email: String,
pub password: String,
}
impl User {
pub fn create(user: InsertableUser, connection: &PgConnection) -> QueryResult<User> {
// Generate a salt
let salt = SaltString::generate(&mut OsRng);
// Hash the password to PHC string
let password_hash = Argon2::default()
.hash_password(user.password.as_bytes(), &salt)
.unwrap()
.to_string();
let encrypted_user = InsertableUser {
password: password_hash,
..user
};
// Insert the user into the database
diesel::insert_into(users::table)
.values(encrypted_user)
.execute(connection)?;
// Query the database for the encrypted user
users::table.order(users::id.desc()).first(connection)
}
pub fn get_by_username_and_password(
username: String,
password: String,
connection: &PgConnection,
) -> Option<User> {
// Query the database for the user
let res = users::table
.filter(users::username.eq(username))
.get_result::<User>(connection);
// Check if the user exists
match res {
Ok(user) => {
let parsed_hash = PasswordHash::new(&user.password).unwrap();
// Check if the password is correct
if Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok()
{
Some(user)
} else {
None
}
}
Err(_) => None,
}
}
pub fn get_by_email(email: String, connection: &PgConnection) -> Option<User> {
// Query the database for the user
let res = users::table
.filter(users::email.eq(email))
.get_result::<User>(connection);
// Check if the user exists
match res {
Ok(user) => Some(user),
Err(_) => None,
}
}
pub fn email_is_taken(email: String, connection: &PgConnection) -> bool {
// Query the database for the user
let res = users::table
.filter(users::email.eq(email))
.get_result::<User>(connection);
// Check if the user exists
match res {
Ok(_) => true,
Err(_) => false,
}
}
pub fn username_is_taken(username: String, connection: &PgConnection) -> bool {
// Query the database for the user
let res = users::table
.filter(users::username.eq(username))
.get_result::<User>(connection);
// Check if the user exists
match res {
Ok(_) => true,
Err(_) => false,
}
}
}