brass/db/src/models/user.rs

362 lines
10 KiB
Rust

use chrono::{DateTime, Utc};
use sqlx::PgPool;
use super::{Area, Function, Result, Role, UserChangeset, UserFunction};
#[derive(Clone, Debug)]
pub struct User {
pub id: i32,
pub name: String,
pub email: String,
pub password: Option<String>,
pub salt: Option<String>,
pub role: Role,
pub function: UserFunction,
pub area_id: i32,
pub area: Option<Area>,
pub locked: bool,
pub last_login: Option<DateTime<Utc>>,
pub receive_notifications: bool,
}
impl User {
pub async fn create(pool: &PgPool, changeset: &UserChangeset) -> Result<i32> {
sqlx::query!(
r#"
INSERT INTO user_ (name, email, role, function, areaId)
VALUES ($1, $2, $3, $4, $5)
RETURNING id;
"#,
changeset.name,
changeset.email,
changeset.role as Role,
changeset.functions.as_slice() as &[Function],
changeset.area_id
)
.fetch_one(pool)
.await
.map(|r| r.id)
}
pub async fn create_with_password(
pool: &PgPool,
name: &str,
email: &str,
password: &str,
salt: &str,
role: Role,
function: &[Function],
area_id: i32,
) -> Result<i32> {
sqlx::query!(
r#"
INSERT INTO user_ (name, email, password, salt, role, function, areaId)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id;
"#,
name,
email,
password,
salt,
role as Role,
function as &[Function],
area_id
)
.fetch_one(pool)
.await
.map(|r| r.id)
}
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<User>> {
let record = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: UserFunction",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE id = $1;
"#,
id,
)
.fetch_optional(pool)
.await?;
let user = record.map(|u| User {
id: u.id,
name: u.name,
email: u.email,
password: u.password,
salt: u.salt,
role: u.role,
function: u.function,
area_id: u.areaid,
area: None,
locked: u.locked,
last_login: u.lastlogin,
receive_notifications: u.receivenotifications,
});
Ok(user)
}
pub async fn read_for_login(pool: &PgPool, email: &str) -> Result<User> {
let record = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: UserFunction",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE email = $1 AND locked = FALSE AND password IS NOT NULL AND salt IS NOT NULL;
"#,
email,
)
.fetch_one(pool)
.await?;
let result = User {
id: record.id,
name: record.name,
email: record.email,
password: record.password,
salt: record.salt,
role: record.role,
function: record.function,
area_id: record.areaid,
area: None,
locked: record.locked,
last_login: record.lastlogin,
receive_notifications: record.receivenotifications,
};
Ok(result)
}
pub async fn exists(pool: &PgPool, email: &str) -> Result<Option<i32>> {
let record = sqlx::query!("SELECT id FROM user_ WHERE email = $1;", email)
.fetch_optional(pool)
.await?;
Ok(record.and_then(|r| Some(r.id)))
}
pub async fn read_all(pool: &PgPool) -> Result<Vec<User>> {
let records = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: UserFunction",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
ORDER BY id;
"#,
)
.fetch_all(pool)
.await?;
let result = records
.iter()
.map(|record| User {
id: record.id,
name: record.name.clone(),
email: record.email.clone(),
password: record.password.clone(),
salt: record.salt.clone(),
role: record.role,
function: record.function.clone(),
area_id: record.areaid,
area: None,
locked: record.locked,
last_login: record.lastlogin,
receive_notifications: record.receivenotifications,
})
.collect();
Ok(result)
}
pub async fn read_all_including_area(pool: &PgPool) -> Result<Vec<User>> {
let records = sqlx::query!(
r#"
SELECT
user_.id AS userId,
user_.name,
user_.email,
user_.password,
user_.salt,
user_.role AS "role: Role",
function AS "function: UserFunction",
user_.areaId,
user_.locked,
user_.lastLogin,
user_.receiveNotifications,
area.id,
area.name AS areaName
FROM user_
JOIN area ON user_.areaId = area.id
ORDER BY userId;
"#
)
.fetch_all(pool)
.await?;
let results = records
.iter()
.map(|record| User {
id: record.userid,
name: record.name.clone(),
email: record.email.clone(),
password: record.password.clone(),
salt: record.salt.clone(),
role: record.role,
function: record.function.clone(),
area_id: record.areaid,
area: Some(Area {
id: record.areaid,
name: record.areaname.clone(),
}),
locked: record.locked,
last_login: record.lastlogin,
receive_notifications: record.receivenotifications,
})
.collect();
Ok(results)
}
pub async fn read_all_by_area(pool: &PgPool, area_id: i32) -> Result<Vec<User>> {
let records = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: UserFunction",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE areaId = $1
ORDER BY id;
"#,
area_id
)
.fetch_all(pool)
.await?;
let result = records
.iter()
.map(|record| User {
id: record.id,
name: record.name.clone(),
email: record.email.clone(),
password: record.password.clone(),
salt: record.salt.clone(),
role: record.role,
function: record.function.clone(),
area_id: record.areaid,
area: None,
locked: record.locked,
last_login: record.lastlogin,
receive_notifications: record.receivenotifications,
})
.collect();
Ok(result)
}
pub async fn update(pool: &PgPool, id: i32, changeset: UserChangeset) -> Result<()> {
sqlx::query!(
"UPDATE user_ SET name = $1, email = $2, role = $3, function = $4, areaId = $5 WHERE id = $6;",
changeset.name,
changeset.email,
changeset.role as Role,
changeset.functions.as_slice() as &[Function],
changeset.area_id,
id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn update_password(pool: &PgPool, id: i32, password: &str, salt: &str) -> Result<()> {
sqlx::query!(
"UPDATE user_ SET password = $1, salt = $2 WHERE id = $3;",
password,
salt,
id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn update_locked(pool: &PgPool, id: i32, locked: bool) -> Result<()> {
sqlx::query!("UPDATE user_ SET locked = $1 WHERE id = $2;", locked, id)
.execute(pool)
.await?;
Ok(())
}
pub async fn update_receive_notifications(
pool: &PgPool,
id: i32,
receive_notifications: bool,
) -> Result<()> {
sqlx::query!(
"UPDATE user_ SET receiveNotifications = $1 WHERE id = $2;",
receive_notifications,
id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn update_login_timestamp(pool: &PgPool, id: i32) -> Result<()> {
sqlx::query!("UPDATE user_ SET lastLogin = NOW() WHERE id = $1;", id)
.execute(pool)
.await?;
Ok(())
}
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
sqlx::query!("DELETE FROM user_ WHERE id = $1;", id)
.execute(pool)
.await?;
Ok(())
}
}