use std::marker::PhantomData;
use sea_orm::DatabaseConnection;
use crate::forms::fields::text::TextField;
use crate::middleware::auth::RuniqueUser;
use crate::middleware::auth::{AdminAuth, AdminLoginResult};
#[async_trait::async_trait]
pub trait UserEntity: Send + Sync + 'static {
type Model: RuniqueUser;
async fn find_by_username(db: &DatabaseConnection, username: &str) -> Option<Self::Model>;
async fn find_by_email(db: &DatabaseConnection, email: &str) -> Option<Self::Model>;
}
pub struct DefaultAdminAuth<E: UserEntity>(PhantomData<E>);
impl<E: UserEntity> DefaultAdminAuth<E> {
pub fn new() -> Self {
Self(PhantomData)
}
}
impl<E: UserEntity> Default for DefaultAdminAuth<E> {
fn default() -> Self {
Self::new()
}
}
#[async_trait::async_trait]
impl<E: UserEntity> AdminAuth for DefaultAdminAuth<E> {
async fn authenticate(
&self,
username: &str,
password: &str,
db: &DatabaseConnection,
) -> Option<AdminLoginResult> {
let user = E::find_by_username(db, username).await?;
if !user.can_access_admin() {
return None;
}
if !TextField::verify_password(password, user.password_hash()) {
return None;
}
Some(AdminLoginResult {
user_id: user.user_id(),
username: user.username().to_string(),
is_staff: user.is_staff(),
is_superuser: user.is_superuser(),
roles: user.roles(),
})
}
}