362 lines
10 KiB
Rust
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(())
|
|
}
|
|
}
|