use rustlavel::prelude::*;
#[derive(Model, Default, Debug, Clone)]
#[model(table = "users")]
pub struct User {
#[model(primary_key, generated)]
pub id: i64,
pub name: String,
pub email: String,
pub password_hash: Option<String>,
pub email_verified_at: Option<String>,
pub locked_until: Option<String>,
pub failed_attempts: i64,
pub last_login_at: Option<String>,
pub last_login_ip: Option<String>,
pub session_epoch: Option<String>,
pub is_active: bool,
pub created_at: Option<String>,
}
impl User {
pub fn by_email(email: &str) -> QueryBuilder {
User::query().filter("email", email.trim().to_lowercase())
}
pub fn can_sign_in(&self, now: &str) -> Result<(), &'static str> {
if !self.is_active {
return Err("inactive");
}
if self.password_hash.is_none() {
return Err("not_activated");
}
if self.locked_until.as_deref().is_some_and(|until| until > now) {
return Err("locked");
}
Ok(())
}
pub fn is_locked(&self, now: &str) -> bool {
self.locked_until.as_deref().is_some_and(|until| until > now)
}
pub fn initials(&self) -> String {
self.name
.split_whitespace()
.filter_map(|word| word.chars().next())
.take(2)
.collect::<String>()
.to_uppercase()
}
pub fn first_name(&self) -> &str {
self.name.split_whitespace().next().unwrap_or(&self.name)
}
pub fn public_json(&self) -> Json {
Json::object([
("id", Json::from(self.id)),
("name", Json::from(self.name.as_str())),
("email", Json::from(self.email.as_str())),
("initials", Json::from(self.initials())),
("activated", Json::from(self.password_hash.is_some())),
("verified", Json::from(self.email_verified_at.is_some())),
("last_login_at", self.last_login_at.clone().map_or(Json::from("Never"), Json::from)),
])
}
}
impl Authenticatable for User {
fn auth_identifier(&self) -> String {
self.id.to_string()
}
}