use mysql_async::Pool;
use mysql_async::Row;
use uuid::Uuid;
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)
}