pub struct Admin { /* private fields */ }Expand description
Builder for the admin. Register models with .model::<M>(), then
hand it to the router via register_admin_routes.
Implementations§
Source§impl Admin
impl Admin
Sourcepub fn new() -> Self
pub fn new() -> Self
Constructs a new Admin with the framework’s core entries
pre-seeded. The only core entry is User; project models are
added on top via Self::model. The outbound mailer
defaults to LogMailer — safe for dev / CI / testing,
not suitable for production (recovery emails are written
to log::info! instead of being sent). Projects opt into a
real mailer via Self::mailer.
Sourcepub fn site_branding(self, branding: SiteBranding) -> Self
pub fn site_branding(self, branding: SiteBranding) -> Self
Replace the entire SiteBranding block. For finer-grained
adjustments, use the per-field builders below
(Admin::app_name, Admin::app_tagline, …).
Sourcepub fn app_name(self, name: impl Into<String>) -> Self
pub fn app_name(self, name: impl Into<String>) -> Self
Set the user-facing product identity. Recommended for every production deployment — the framework name “RustIO” should not appear in operational user surfaces.
Example: Admin::new().app_name("Library Circulation").
Also mirrors the value into the legacy site_title /
site_header fields so older paths that still read them stay
coherent with the new identity.
Sourcepub fn app_tagline(self, tagline: impl Into<String>) -> Self
pub fn app_tagline(self, tagline: impl Into<String>) -> Self
Set an optional secondary line shown under the brand wordmark in emails + auth pages.
Sourcepub fn support_email(self, email: impl Into<String>) -> Self
pub fn support_email(self, email: impl Into<String>) -> Self
Set the support contact surfaced in recovery emails.
Sourcepub fn public_url(self, url: impl Into<String>) -> Self
pub fn public_url(self, url: impl Into<String>) -> Self
Set the canonical public URL — used as a base when composing reset links if request-header derivation is unreliable.
Sourcepub fn show_powered_by(self, show: bool) -> Self
pub fn show_powered_by(self, show: bool) -> Self
Opt in to the small “Powered by RustIO” credit in chrome footer + email footer. Off by default; the framework name stays invisible to end users unless this is enabled.
Sourcepub fn branding(&self) -> &SiteBranding
pub fn branding(&self) -> &SiteBranding
Read-only access to the active branding.
Sourcepub fn accent_color(self, color: impl Into<String>) -> Self
pub fn accent_color(self, color: impl Into<String>) -> Self
Set the admin chrome’s accent colour. Hex form, with or without
the leading # ("#1e6ba8" and "1e6ba8" both work). Replaces
any prior accent override; other AdminTheme fields are
left untouched.
Sourcepub fn theme(self, theme: AdminTheme) -> Self
pub fn theme(self, theme: AdminTheme) -> Self
Replace the entire admin chrome palette patch in one call. See
AdminTheme for the field-by-field contract.
Sourcepub fn accent(&self) -> Option<&str>
pub fn accent(&self) -> Option<&str>
Read-only access to the configured accent colour, if any. None
means “no override — admin.css owns it”.
Sourcepub fn active_theme(&self) -> &AdminTheme
pub fn active_theme(&self) -> &AdminTheme
Read-only access to the active theme override patch.
Sourcepub fn mailer(self, mailer: SharedMailer) -> Self
pub fn mailer(self, mailer: SharedMailer) -> Self
Replace the outbound mailer. Closes the
documented-but-unimplemented gap from 0.4.0 where the doc
comments described this method while the Admin struct had
no mailer field; landed in 0.5.0 alongside the R1 recovery
pipeline that consumes it (DESIGN_RECOVERY.md §10.3).
Typical project wiring:
use std::sync::Arc;
let admin = Admin::new()
.mailer(Arc::new(MyProjectMailer::new(/* SES, Mailgun, … */)));The framework imposes no transport. Anything that implements
the crate::email::Mailer trait (which is Send + Sync
and async-friendly) plugs in here. R1’s recovery flow reads
this via Self::active_mailer and dispatches reset
emails through it.
Sourcepub fn active_mailer(&self) -> &SharedMailer
pub fn active_mailer(&self) -> &SharedMailer
Read-only access to the registered mailer. Returns a borrow
of the Arc so handlers can .clone() it cheaply when they
need to move the handle into an async future. Always returns
a live mailer — Admin::new() seeds LogMailer as the
default, so this never returns None.
Sourcepub fn has_custom_mailer(&self) -> bool
pub fn has_custom_mailer(&self) -> bool
Whether the project explicitly called Self::mailer to
register a mailer. Returns false for Admin::new() (the
framework’s LogMailer default is in place); flips to true
on any subsequent call to mailer(...), regardless of the
concrete type supplied — the framework trusts the operator’s
explicit override.
Read by the R1 strict-mailer boot guard: when
RecoveryPolicy::strict_mailer_required() == true and this
returns false, register_admin_routes panics at startup
rather than registering the recovery routes against a
production-unsafe default mailer.
Sourcepub fn password_policy(self, policy: SharedPasswordPolicy) -> Self
pub fn password_policy(self, policy: SharedPasswordPolicy) -> Self
Replace the active password policy. R1 ships with the
length-only DefaultPasswordPolicy (min_len = 10);
production deployments commonly override to 12+, and
regulated deployments may ship a full custom impl with breach
blocklists or organisational complexity rules
(DESIGN_RECOVERY.md §13).
Typical project wiring:
use std::sync::Arc;
use rustio_admin::auth::DefaultPasswordPolicy;
let admin = Admin::new()
.password_policy(Arc::new(DefaultPasswordPolicy::with_min_len(16)));Sourcepub fn active_password_policy(&self) -> &SharedPasswordPolicy
pub fn active_password_policy(&self) -> &SharedPasswordPolicy
Read-only access to the registered password policy. Returns
a borrow of the Arc so handlers can .clone() it cheaply
when needed. Always returns a live policy — Admin::new()
seeds DefaultPasswordPolicy so this never returns None.
Sourcepub fn recovery_policy(self, policy: SharedRecoveryPolicy) -> Self
pub fn recovery_policy(self, policy: SharedRecoveryPolicy) -> Self
Replace the active recovery policy. R1 ships with
DefaultRecoveryPolicy (TTL 1h, request 5/15min, consume
10/5min, strict-mailer guard off); production deployments
commonly opt into the strict guard via
with_strict_mailer_required(true) after registering a real
mailer (DESIGN_RECOVERY.md §12).
Typical project wiring:
use std::sync::Arc;
use rustio_admin::auth::DefaultRecoveryPolicy;
let admin = Admin::new()
.recovery_policy(Arc::new(
DefaultRecoveryPolicy::new()
.with_strict_mailer_required(true),
));Sourcepub fn active_recovery_policy(&self) -> &SharedRecoveryPolicy
pub fn active_recovery_policy(&self) -> &SharedRecoveryPolicy
Read-only access to the registered recovery policy. Returns
a borrow of the Arc. Always live — Admin::new() seeds
DefaultRecoveryPolicy so this never returns None.
Sourcepub fn require_mfa(self, policy: MfaPolicy) -> Self
pub fn require_mfa(self, policy: MfaPolicy) -> Self
Replace the active MFA enforcement policy. R3 ships with
MfaPolicy::Optional as the default — pre-R3 framework
behaviour, no opt-in required. Production deployments that
want MFA enforcement opt in via this builder.
Forward-only enforcement (D6). Switching to
MfaPolicy::Required does NOT retroactively revoke
existing sessions; the login_guard redirects users
without MFA to /admin/mfa/enroll at the next request.
The pattern mirrors R2’s must_change_password
interstitial (DESIGN_R3_MFA.md §12.3).
Boot guard (D1). When MfaPolicy != Disabled, the
framework refuses to boot if RUSTIO_SECRET_KEY is
unset — the env var is required for AES-256-GCM
encryption of TOTP secrets at rest. The boot check lands
in a later R3 commit; this builder records the policy
without the check.
Typical project wiring:
use rustio_admin::auth::{MfaPolicy, Role};
// Universal:
let admin = Admin::new().require_mfa(MfaPolicy::Required);
// Privileged roles only:
const PRIVILEGED: &[Role] = &[Role::Administrator, Role::Supervisor];
let admin = Admin::new()
.require_mfa(MfaPolicy::RequiredForRoles(PRIVILEGED));Sourcepub fn active_mfa_policy(&self) -> MfaPolicy
pub fn active_mfa_policy(&self) -> MfaPolicy
Read-only access to the active MFA policy. Returns by
value — the policy is Copy. Always live — Admin::new()
seeds MfaPolicy::default (Optional) so this never
returns None.
pub fn model<M>(self) -> Selfwhere
M: ModelAdmin + Model,
pub fn entries(&self) -> &[AdminEntry]
Sourcepub fn user_profile_extension<F, Fut>(self, ext: F) -> Selfwhere
F: Fn(Db, UserProfile) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Vec<UserProfileSection>>> + Send + 'static,
pub fn user_profile_extension<F, Fut>(self, ext: F) -> Selfwhere
F: Fn(Db, UserProfile) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Vec<UserProfileSection>>> + Send + 'static,
Register a project-specific extension that contributes extra
sections to the built-in user profile page. The closure is
invoked on every render of GET /admin/users/:id (Overview tab);
it receives the Db handle and the loaded
crate::auth::UserProfile (no password_hash) and returns a
Vec<UserProfileSection>. Sections render in the order returned,
immediately after the core profile show-grid.
Zero-config baseline: don’t call this method, and the extension
area stays empty. Projects that need richer layout than key-value
rows override the {% block project_user_fields %} template
block in templates/admin/user_view.html instead.
pub fn find(&self, admin_name: &str) -> Option<&AdminEntry>
Sourcepub async fn seed_permissions(&self, db: &Db) -> Result<()>
pub async fn seed_permissions(&self, db: &Db) -> Result<()>
Register the canonical (add/change/delete/view) permissions for
every model. Call during startup after init_tables.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Admin
impl !RefUnwindSafe for Admin
impl Send for Admin
impl Sync for Admin
impl Unpin for Admin
impl UnsafeUnpin for Admin
impl !UnwindSafe for Admin
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more