use std::sync::Arc;
use topcoat::{context::Cx, view::BoxView};
use super::AuthConfig;
use crate::{
BoxFuture,
form::{FieldErrors, FormValues},
schema::Schema,
};
pub(crate) struct Realm {
pub(crate) prefix: String,
pub(crate) auth: AuthConfig,
pub(crate) login_hint: Option<crate::Text>,
pub(crate) time_zone: jiff::tz::TimeZone,
pub(crate) catalog: crate::i18n::Catalog,
pub(crate) notifications: bool,
}
impl Realm {
pub(crate) fn gates(&self) -> bool {
!self.auth.is_disabled()
}
}
#[derive(Clone)]
pub(crate) struct CurrentRealm(pub(crate) Arc<Realm>);
pub(crate) trait Host: Send + Sync {
fn realms(&self, cx: &Cx) -> Vec<Arc<Realm>>;
fn declaring(&self, cx: &Cx, path: &str) -> Vec<Arc<Realm>>;
fn enter(&self, cx: &Cx, realm: &Arc<Realm>) -> Option<Cx>;
fn answer(&self, cx: &Cx, error: topcoat::Error) -> topcoat::Error;
fn brand_name(&self, cx: &Cx) -> String;
fn page_brand<'a>(&self, cx: &'a Cx) -> BoxView<'a>;
fn document<'a>(
&self,
cx: &'a Cx,
title: String,
body: BoxView<'a>,
) -> BoxFuture<'a, topcoat::Result<BoxView<'a>>>;
fn settings_page<'a: 'f, 'f>(
&self,
cx: &'a Cx,
page: SettingsPage<'f>,
) -> BoxFuture<'f, topcoat::Result<BoxView<'a>>>;
}
pub(crate) struct SettingsPage<'f> {
pub(crate) title: String,
pub(crate) schema: &'f Schema,
pub(crate) hidden: Option<(&'static str, String)>,
pub(crate) values: &'f FormValues,
pub(crate) errors: &'f FieldErrors,
}
#[derive(Clone, Copy)]
pub(crate) struct AuthHost(pub(crate) &'static dyn Host);
pub(crate) fn host(cx: &Cx) -> Option<&'static dyn Host> {
topcoat::context::try_app_context::<AuthHost>(cx).map(|AuthHost(host)| *host)
}
pub(crate) fn hosted(cx: &Cx) -> topcoat::Result<&'static dyn Host> {
host(cx).ok_or_else(|| {
crate::error::declaration("auth renders only on a router that mounts a panel".to_owned())
})
}
pub(crate) fn current_realm(cx: &Cx) -> Option<&Arc<Realm>> {
topcoat::context::try_request_context::<CurrentRealm>(cx).map(|CurrentRealm(realm)| realm)
}
pub(crate) fn realms(cx: &Cx) -> Vec<Arc<Realm>> {
host(cx).map(|host| host.realms(cx)).unwrap_or_default()
}
pub(crate) fn panel_prefix(cx: &Cx) -> String {
current_realm(cx).map_or_else(
|| crate::naming::path_prefix(topcoat::router::request::uri(cx).path()),
|realm| realm.prefix.clone(),
)
}
#[cfg(test)]
mod tests;