use mysql_async::Pool;
use uuid::Uuid;
use mysql_async::Row;
pub async fn get_user_by_id(
pool: &Pool,
user_id: &Uuid,
) -> Result<Option<crate::db::models::User>, mysql_async::Error> {
let mut conn = pool.get_conn().await?;
let query = r#"SELECT id, username, email, password_hash, status, created_at, last_login_at FROM users WHERE id = ?"#;
let row: Option<Row> = mysql_async::prelude::Queryable::exec_first(
&mut conn,
query,
(user_id.to_string(),),
).await?;
let user = row.map(|row| {
let last_login_at_str: Option<String> = row.get("last_login_at");
let last_login_at = last_login_at_str.and_then(|s| chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S").ok());
crate::db::models::User {
id: Uuid::parse_str(row.get::<String, _>("id").unwrap().as_str()).unwrap(),
username: row.get("username").unwrap(),
email: row.get("email").unwrap(),
password_hash: row.get("password_hash").unwrap(),
status: row.get("status").unwrap(),
created_at: chrono::NaiveDateTime::parse_from_str(&row.get::<String, _>("created_at").unwrap(), "%Y-%m-%d %H:%M:%S").unwrap(),
last_login_at,
}
});
Ok(user)
}
pub async fn get_user_by_username(
pool: &Pool,
username: &str,
) -> Result<Option<crate::db::models::User>, mysql_async::Error> {
let mut conn = pool.get_conn().await?;
let query = r#"SELECT id, username, email, password_hash, status, created_at, last_login_at FROM users WHERE username = ?"#;
let row: Option<Row> = mysql_async::prelude::Queryable::exec_first(
&mut conn,
query,
(username,),
).await?;
let user = row.map(|row| {
let last_login_at_str: Option<String> = row.get("last_login_at");
let last_login_at = last_login_at_str.and_then(|s| chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S").ok());
crate::db::models::User {
id: Uuid::parse_str(row.get::<String, _>("id").unwrap().as_str()).unwrap(),
username: row.get("username").unwrap(),
email: row.get("email").unwrap(),
password_hash: row.get("password_hash").unwrap(),
status: row.get("status").unwrap(),
created_at: chrono::NaiveDateTime::parse_from_str(&row.get::<String, _>("created_at").unwrap(), "%Y-%m-%d %H:%M:%S").unwrap(),
last_login_at,
}
});
Ok(user)
}
pub async fn get_all_users(
pool: &Pool,
) -> Result<Vec<crate::db::models::User>, mysql_async::Error> {
let mut conn = pool.get_conn().await?;
let query = r#"SELECT id, username, email, password_hash, status, created_at, last_login_at FROM users"#;
let rows: Vec<Row> = mysql_async::prelude::Queryable::query(&mut conn, query).await?;
let users = rows.into_iter().map(|row| {
let last_login_at_str: Option<String> = row.get("last_login_at");
let last_login_at = last_login_at_str.and_then(|s| chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S").ok());
crate::db::models::User {
id: Uuid::parse_str(row.get::<String, _>("id").unwrap().as_str()).unwrap(),
username: row.get("username").unwrap(),
email: row.get("email").unwrap(),
password_hash: row.get("password_hash").unwrap(),
status: row.get("status").unwrap(),
created_at: chrono::NaiveDateTime::parse_from_str(&row.get::<String, _>("created_at").unwrap(), "%Y-%m-%d %H:%M:%S").unwrap(),
last_login_at,
}
}).collect();
Ok(users)
}
pub async fn create_user(
pool: &Pool,
username: &str,
password_hash: &str,
) -> Result<Uuid, mysql_async::Error> {
let user_id = Uuid::new_v4();
let mut conn = pool.get_conn().await?;
let query = r#"
INSERT INTO users (id, username, password_hash, created_at)
VALUES (?, ?, ?, NOW())
"#;
mysql_async::prelude::Queryable::exec_drop(
&mut conn,
query,
(user_id.to_string(), username, password_hash),
).await?;
Ok(user_id)
}
pub async fn verify_user_security(
pool: &Pool,
user_id: &Uuid,
) -> Result<bool, mysql_async::Error> {
let user = get_user_by_id(pool, user_id).await?;
if let Some(user) = user {
if user.status == "active" {
if user.last_login_at.is_some() {
return Ok(true);
}
}
}
Ok(false)
}
pub async fn verify_user_device_and_role(
pool: &Pool,
user_id: &Uuid,
device_id: &Uuid,
required_role: &str,
) -> Result<bool, mysql_async::Error> {
let user = get_user_by_id(pool, user_id).await?;
if let Some(user) = user {
if user.status == "active" && user.last_login_at.is_some() {
let mut conn = pool.get_conn().await?;
let device_query = r#"SELECT id FROM devices WHERE id = ? AND user_id = ?"#;
let device_row: Option<Row> = mysql_async::prelude::Queryable::exec_first(
&mut conn,
device_query,
(device_id.to_string(), user_id.to_string()),
).await?;
if device_row.is_some() {
let role_query = r#"SELECT role FROM user_roles WHERE user_id = ? AND role = ?"#;
let role_row: Option<Row> = mysql_async::prelude::Queryable::exec_first(
&mut conn,
role_query,
(user_id.to_string(), required_role),
).await?;
if role_row.is_some() {
return Ok(true);
}
}
}
}
Ok(false)
}