use std::{any::Any, future::Future};
use topcoat::context::Cx;
use crate::tenancy::{Membership, TenantId};
pub trait PanelUser: Any + Send + Sync {
fn user_id(&self) -> String;
fn display_name(&self) -> &str;
fn subtitle(&self) -> Option<&str> {
None
}
fn email(&self) -> Option<&str> {
None
}
fn can_access_panel(&self, panel: &str) -> bool;
fn tenants(&self) -> &[Membership] {
&[]
}
fn default_tenant(&self) -> Option<TenantId> {
None
}
fn time_zone(&self) -> Option<jiff::tz::TimeZone> {
None
}
fn locale(&self) -> Option<topcoat::l10n::Locale> {
None
}
}
pub trait Authenticator: Send + Sync + 'static {
type User: PanelUser;
fn verify(
&self,
cx: &Cx,
login: &str,
password: &str,
) -> impl Future<Output = topcoat::Result<Option<Self::User>>> + Send;
fn find_by_id(
&self,
cx: &Cx,
id: &str,
) -> impl Future<Output = topcoat::Result<Option<Self::User>>> + Send;
fn confirm_password(
&self,
cx: &Cx,
user: &Self::User,
password: &str,
) -> impl Future<Output = topcoat::Result<bool>> + Send {
async move {
let Some(login) = user.email() else {
return Ok(false);
};
let verified = self.verify(cx, login, password).await?;
Ok(verified.is_some_and(|found| found.user_id() == user.user_id()))
}
}
fn store_locale(
&self,
cx: &Cx,
user: &Self::User,
locale: &topcoat::l10n::Locale,
) -> impl Future<Output = topcoat::Result<()>> + Send {
let _ = (cx, user, locale);
async { Ok(()) }
}
}