brass/src/models/user.rs

332 lines
9.4 KiB
Rust

use chrono::{DateTime, Utc};
use sqlx::{Execute, PgPool};
use super::{Area, Function, Role};
#[derive(Clone)]
pub struct User {
pub id: i32,
pub name: String,
pub email: String,
pub password: String,
pub salt: String,
pub role: Role,
pub function: Function,
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,
name: &str,
email: &str,
password: &str,
salt: &str,
role: Role,
function: Function,
area_id: i32,
) -> anyhow::Result<i32> {
let created = 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;
match created {
Ok(result) => Ok(result.id),
Err(err) => Err(err.into()),
}
}
pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result<User> {
let record = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: Function",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE id = $1;
"#,
id,
)
.fetch_one(pool)
.await?;
let user = 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(user)
}
pub async fn read_for_login(pool: &PgPool, email: &str) -> anyhow::Result<Option<User>> {
let record = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: Function",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE email = $1;
"#,
email,
)
.fetch_optional(pool)
.await?;
let result = match record {
Some(record) => Some(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,
}),
None => None,
};
Ok(result)
}
pub async fn read_all(pool: &PgPool) -> anyhow::Result<Vec<User>> {
let records = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: Function",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_;
"#,
)
.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.clone(),
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) -> anyhow::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",
user_.function AS "function: Function",
user_.areaId,
user_.locked,
user_.lastLogin,
user_.receiveNotifications,
area.id,
area.name AS areaName
FROM user_
JOIN area ON user_.areaId = area.id
"#
)
.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.clone(),
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) -> anyhow::Result<Vec<User>> {
let records = sqlx::query!(
r#"
SELECT id,
name,
email,
password,
salt,
role AS "role: Role",
function AS "function: Function",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE areaId = $1;
"#,
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.clone(),
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,
email: Option<&str>,
name: Option<&str>,
role: Option<Role>,
function: Option<Function>,
area_id: Option<i32>,
locked: Option<bool>
) -> anyhow::Result<()> {
let mut query_builder = sqlx::QueryBuilder::new("UPDATE user_ SET ");
let mut separated = query_builder.separated(", ");
if let Some(email) = email {
separated.push("email = ");
separated.push_bind_unseparated(email);
}
if let Some(name) = name {
separated.push("name = ");
separated.push_bind_unseparated(name);
}
if let Some(role) = role {
separated.push("role = ");
separated.push_bind_unseparated(role as Role);
}
if let Some(function) = function {
separated.push("function = ");
separated.push_bind_unseparated(function as Function);
}
if let Some(area_id) = area_id {
separated.push("areaId = ");
separated.push_bind_unseparated(area_id);
}
if let Some(locked) = locked {
separated.push("locked = ");
separated.push_bind_unseparated(locked);
}
query_builder.push(" WHERE id = ");
query_builder.push_bind(id);
query_builder.push(";");
query_builder.build()
.execute(pool)
.await?;
Ok(())
}
pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<()> {
sqlx::query!("DELETE FROM user_ WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
}