feat: Add display name to user profiles

Introduce `display_name` field to `User` struct for human-readable names
in the UI.
This falls back to the user's `slug` if not provided.

Update `AuthenticatedWebUser` and `MyCasesTemplate` to use this new
field for rendering.
Add tests for parsing `display_name` and ensure fallback logic works
correctly.
Update `users.toml.example` to document the new field.
This commit is contained in:
2026-05-04 11:46:19 +02:00
parent 03129ad592
commit 2fc7f8ddd2
6 changed files with 97 additions and 24 deletions
+11 -6
View File
@@ -78,6 +78,11 @@ pub struct AuthenticatedWebUser {
/// Mirrors [`AuthenticatedUser::window_hours`] so the same policy
/// is available to web handlers without a second config lookup.
pub window_hours: u32,
/// Human-readable label rendered in the page header (browser title
/// stays neutral). Resolved from the user's `display_name` field
/// in users.toml, falling back to `slug` if absent. Pre-resolved
/// here so handlers and templates don't repeat the fallback logic.
pub display_name: String,
/// Session's CSRF token. Rendered into every state-changing form
/// as a hidden field so the `CsrfForm` extractor can validate it
/// on the matching POST. Cloned out of the session record here so
@@ -140,17 +145,17 @@ where
// does not carry. A missing record can only happen if users.toml
// was edited while a session was still live; fall back to the
// serde default so the request stays functional.
let window_hours = config
.users
.iter()
.find(|u| u.slug == session.slug)
.map(|u| u.window_hours)
.unwrap_or(72);
let user_record = config.users.iter().find(|u| u.slug == session.slug);
let window_hours = user_record.map(|u| u.window_hours).unwrap_or(72);
let display_name = user_record
.map(|u| u.display_name().to_owned())
.unwrap_or_else(|| session.slug.clone());
Ok(Self {
slug: session.slug.clone(),
role: session.role.clone(),
data_dir,
window_hours,
display_name,
csrf_token: session.csrf_token.clone(),
})
}