use chrono::{DateTime, Utc}; use sqlx::PgPool; use super::{Area, Function, Result, Role}; #[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: Function, 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, name: &str, email: &str, role: Role, function: Function, area_id: i32, ) -> Result { sqlx::query!( r#" INSERT INTO user_ (name, email, role, function, areaId) VALUES ($1, $2, $3, $4, $5) RETURNING id; "#, name, email, role as Role, function as Function, area_id ) .fetch_one(pool) .await .and_then(|r| Ok(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 { let b = 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 .and_then(|r| Ok(r.id)); b } 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: Function", areaId, locked, lastLogin, receiveNotifications FROM user_ WHERE id = $1; "#, id, ) .fetch_optional(pool) .await?; let user = record.and_then(|u| Some(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) -> anyhow::Result { 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 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 read_all(pool: &PgPool) -> anyhow::Result> { 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) -> Result> { 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) -> Result> { 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>, password: Option<&str>, salt: Option<&str>, role: Option, function: Option, area_id: Option, receive_notifications: Option, locked: Option, ) -> 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(password) = password { separated.push("password = "); separated.push_bind_unseparated(password); } if let Some(salt) = salt { separated.push("salt = "); separated.push_bind_unseparated(salt); } 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(receive_notifications) = receive_notifications { separated.push("receiveNotifications = "); separated.push_bind_unseparated(receive_notifications); } 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 update_login_timestamp(pool: &PgPool, id: i32) -> anyhow::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(()) } }