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, pub salt: Option, pub role: Role, pub function: UserFunction, pub area_id: i32, pub area: Option, pub locked: bool, pub last_login: Option>, pub receive_notifications: bool, } impl User { pub async fn create(pool: &PgPool, changeset: &UserChangeset) -> Result { 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 { 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> { 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 { 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> { 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> { 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> { 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> { 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(()) } }