nomilo/src/models/users.rs

163 lines
4.1 KiB
Rust
Raw Normal View History

2021-03-26 22:30:38 +00:00
use uuid::Uuid;
use diesel::prelude::*;
2021-03-27 05:45:59 +00:00
use diesel::result::Error as DieselError;
2021-03-26 22:30:38 +00:00
use rocket::request::{FromRequest, Request, Outcome};
use diesel_derive_enum::DbEnum;
2021-03-27 05:45:59 +00:00
use serde::Deserialize;
// TODO: Maybe just use argon2 crate directly
use djangohashers::{make_password_with_algorithm, check_password, HasherError, Algorithm};
2021-03-26 22:30:38 +00:00
use crate::schema::*;
2021-03-27 05:45:59 +00:00
use crate::DbConn;
2021-03-26 22:30:38 +00:00
2021-03-27 05:45:59 +00:00
#[derive(Debug, DbEnum, Deserialize)]
#[serde(rename_all = "snake_case")]
2021-03-26 22:30:38 +00:00
pub enum Role {
Admin,
ZoneAdmin,
}
2021-03-27 05:45:59 +00:00
// TODO: Store Uuid instead of string??
// TODO: Store role as Role and not String.
#[derive(Debug, Queryable, Identifiable, Insertable)]
2021-03-26 22:30:38 +00:00
#[table_name = "user"]
pub struct User {
pub id: String,
pub role: String,
}
2021-03-27 05:45:59 +00:00
#[derive(Debug, Queryable, Identifiable, Insertable)]
2021-03-26 22:30:38 +00:00
#[table_name = "localuser"]
#[primary_key(user_id)]
pub struct LocalUser {
pub user_id: String,
pub username: String,
pub password: String,
}
2021-03-27 05:45:59 +00:00
#[derive(Debug, Deserialize)]
pub struct CreateUserRequest {
pub username: String,
pub password: String,
pub email: String,
pub role: Option<Role>
}
2021-03-26 22:30:38 +00:00
// pub struct LdapUserAssociation {
// user_id: Uuid,
// ldap_id: String
// }
2021-03-27 05:45:59 +00:00
#[derive(Debug)]
2021-03-26 22:30:38 +00:00
pub struct UserInfo {
2021-03-27 05:45:59 +00:00
pub id: String,
pub role: String,
pub username: String,
2021-03-26 22:30:38 +00:00
}
impl<'a, 'r> FromRequest<'a, 'r> for UserInfo {
type Error = ();
fn from_request(request: &'a Request<'r>) -> Outcome<UserInfo, ()> {
2021-03-27 05:45:59 +00:00
// LocalUser::get_user_by_uuid()
2021-03-26 22:30:38 +00:00
Outcome::Forward(())
}
}
2021-03-27 05:45:59 +00:00
#[derive(Debug)]
pub enum UserError {
NotFound,
UserExists,
DbError(DieselError),
PasswordError(HasherError),
}
impl From<DieselError> for UserError {
fn from(e: DieselError) -> Self {
match e {
DieselError::NotFound => UserError::NotFound,
DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserExists,
other => UserError::DbError(other)
}
}
}
impl From<HasherError> for UserError {
fn from(e: HasherError) -> Self {
match e {
other => UserError::PasswordError(other)
}
}
}
impl LocalUser {
pub fn create_user(conn: &DbConn, user_request: CreateUserRequest) -> Result<UserInfo, UserError> {
use crate::schema::localuser::dsl::*;
use crate::schema::user::dsl::*;
let new_user_id = Uuid::new_v4().to_simple().to_string();
let new_user = User {
id: new_user_id.clone(),
// TODO: Use role from request
role: "zoneadmin".into(),
};
let new_localuser = LocalUser {
user_id: new_user_id.clone(),
username: user_request.username.clone(),
password: make_password_with_algorithm(&user_request.password, Algorithm::Argon2),
};
let res = UserInfo {
id: new_user.id.clone(),
role: new_user.role.clone(),
username: new_localuser.username.clone(),
};
conn.immediate_transaction(|| -> diesel::QueryResult<()> {
diesel::insert_into(user)
.values(new_user)
.execute(&**conn)?;
diesel::insert_into(localuser)
.values(new_localuser)
.execute(&**conn)?;
Ok(())
})?;
Ok(res)
}
pub fn get_user_by_creds(
conn: &DbConn,
request_username: &str,
request_password: &str
) -> Result<UserInfo, UserError> {
use crate::schema::localuser::dsl::*;
use crate::schema::user::dsl::*;
let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser)
.filter(username.eq(request_username))
.get_result(&**conn)?;
if !check_password(&request_password, &client_localuser.password)? {
return Err(UserError::NotFound);
}
Ok(UserInfo {
id: client_user.id,
role: client_user.role,
username: client_localuser.username,
})
}
pub fn get_user_by_uuid(user_id: Uuid) -> Result<UserInfo, ()> {
unimplemented!()
}
}