✨ (auth): Añade idioma y tema preferidos al usuario
- CurrentUser pasa de enum a struct con `id` opcional (anónimo = None) y preferencias de idioma, zona horaria y tema validadas en `with_*()`. - `RequestLocale` tiene en cuenta el idioma preferido del usuario, y Context usa su tema si lo tiene (`default_theme()` en otro caso). - Nuevos componentes `form::SelectLanguage`, `form::SelectTheme` y `form::SelectTimezone`, con `Timezone::supported_by_region()` para listar y validar las zonas IANA ofrecidas.
This commit is contained in:
parent
35f2b66161
commit
70744a51a5
25 changed files with 1162 additions and 190 deletions
107
tests/auth.rs
107
tests/auth.rs
|
|
@ -4,7 +4,7 @@ use pagetop::prelude::*;
|
|||
|
||||
#[pagetop::test]
|
||||
async fn anonymous_reports_itself_correctly() {
|
||||
let user = CurrentUser::Anonymous;
|
||||
let user = CurrentUser::anonymous();
|
||||
assert!(user.is_anonymous());
|
||||
assert!(!user.is_authenticated());
|
||||
assert_eq!(user.id(), None);
|
||||
|
|
@ -14,11 +14,7 @@ async fn anonymous_reports_itself_correctly() {
|
|||
#[pagetop::test]
|
||||
async fn authenticated_reports_itself_correctly() {
|
||||
let madrid: Tz = "Europe/Madrid".parse().unwrap();
|
||||
let user = CurrentUser::Authenticated {
|
||||
id: 42,
|
||||
display_name: "Alice".to_owned(),
|
||||
timezone: Some(madrid),
|
||||
};
|
||||
let user = CurrentUser::authenticated(42, "Alice").with_timezone("Europe/Madrid");
|
||||
assert!(!user.is_anonymous());
|
||||
assert!(user.is_authenticated());
|
||||
assert_eq!(user.id(), Some(42));
|
||||
|
|
@ -28,14 +24,39 @@ async fn authenticated_reports_itself_correctly() {
|
|||
|
||||
#[pagetop::test]
|
||||
async fn authenticated_falls_back_to_default_timezone_when_none() {
|
||||
let user = CurrentUser::Authenticated {
|
||||
id: 42,
|
||||
display_name: "Alice".to_owned(),
|
||||
timezone: None,
|
||||
};
|
||||
let user = CurrentUser::authenticated(42, "Alice");
|
||||
assert_eq!(user.timezone(), Timezone::default_tz());
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn authenticated_discards_invalid_preferences() {
|
||||
let user = CurrentUser::authenticated(42, "Alice")
|
||||
.with_language("xx-XX")
|
||||
.with_timezone("Mars/Olympus")
|
||||
.with_theme("NotRegistered");
|
||||
assert_eq!(user.language(), None);
|
||||
assert_eq!(user.timezone(), Timezone::default_tz());
|
||||
assert!(user.theme().is_none());
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn anonymous_can_have_preferences() {
|
||||
let madrid: Tz = "Europe/Madrid".parse().unwrap();
|
||||
let user = CurrentUser::anonymous()
|
||||
.with_language("es-ES")
|
||||
.with_timezone("Europe/Madrid");
|
||||
assert!(user.is_anonymous());
|
||||
assert_eq!(user.language(), Locale::resolve("es-ES").as_option());
|
||||
assert_eq!(user.timezone(), madrid);
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn authenticated_resolves_language_to_a_supported_one() {
|
||||
let user = CurrentUser::authenticated(42, "Alice").with_language("es");
|
||||
assert_eq!(user.language(), Locale::resolve("es").as_option());
|
||||
assert!(user.language().is_some());
|
||||
}
|
||||
|
||||
// **< Context::current_user() >********************************************************************
|
||||
|
||||
#[pagetop::test]
|
||||
|
|
@ -47,11 +68,7 @@ async fn current_user_defaults_to_anonymous() {
|
|||
#[pagetop::test]
|
||||
async fn current_user_propagates_from_request_extensions() {
|
||||
let req = web::test::TestRequest::get()
|
||||
.with_extension(CurrentUser::Authenticated {
|
||||
id: 7,
|
||||
display_name: "Bob".to_owned(),
|
||||
timezone: None,
|
||||
})
|
||||
.with_extension(CurrentUser::authenticated(7, "Bob"))
|
||||
.to_http_request();
|
||||
let cx = Context::new(req);
|
||||
let user = cx.current_user();
|
||||
|
|
@ -60,6 +77,52 @@ async fn current_user_propagates_from_request_extensions() {
|
|||
assert_eq!(user.display_name(), Some("Bob"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn user_language_sets_the_request_language() {
|
||||
let req = web::test::TestRequest::get()
|
||||
.header("Accept-Language", "en-US")
|
||||
.with_extension(CurrentUser::authenticated(7, "Bob").with_language("es-ES"))
|
||||
.to_http_request();
|
||||
let cx = Context::new(req);
|
||||
assert_eq!(cx.langid().to_string(), "es-ES");
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn lang_query_overrides_user_language() {
|
||||
let req = web::test::TestRequest::get()
|
||||
.uri("/?lang=en-US")
|
||||
.with_extension(CurrentUser::authenticated(7, "Bob").with_language("es-ES"))
|
||||
.to_http_request();
|
||||
let cx = Context::new(req);
|
||||
assert_eq!(cx.langid().to_string(), "en-US");
|
||||
}
|
||||
|
||||
struct UserTheme;
|
||||
|
||||
impl Extension for UserTheme {
|
||||
fn theme(&self) -> Option<ThemeRef> {
|
||||
Some(&UserTheme)
|
||||
}
|
||||
}
|
||||
|
||||
impl Theme for UserTheme {}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn user_theme_sets_the_context_theme() {
|
||||
let _ = Application::prepare(&UserTheme).await;
|
||||
let req = web::test::TestRequest::get()
|
||||
.with_extension(CurrentUser::authenticated(7, "Bob").with_theme("UserTheme"))
|
||||
.to_http_request();
|
||||
let cx = Context::new(req);
|
||||
assert_eq!(cx.theme().short_name(), "UserTheme");
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn context_uses_the_default_theme_without_user_theme() {
|
||||
let cx = Context::default();
|
||||
assert_eq!(cx.theme().short_name(), "Basic");
|
||||
}
|
||||
|
||||
// **< HttpRequest::extension() >*******************************************************************
|
||||
|
||||
#[pagetop::test]
|
||||
|
|
@ -71,11 +134,7 @@ async fn request_extension_returns_none_for_unknown_type() {
|
|||
#[pagetop::test]
|
||||
async fn request_extension_returns_injected_value() {
|
||||
let req = web::test::TestRequest::get()
|
||||
.with_extension(CurrentUser::Authenticated {
|
||||
id: 1,
|
||||
display_name: "Carol".to_owned(),
|
||||
timezone: None,
|
||||
})
|
||||
.with_extension(CurrentUser::authenticated(1, "Carol"))
|
||||
.to_http_request();
|
||||
|
||||
let user = req
|
||||
|
|
@ -91,11 +150,7 @@ async fn request_extension_returns_injected_value() {
|
|||
#[pagetop::test]
|
||||
async fn page_new_propagates_current_user_from_request_extensions() {
|
||||
let req = web::test::TestRequest::get()
|
||||
.with_extension(CurrentUser::Authenticated {
|
||||
id: 5,
|
||||
display_name: "Dave".to_owned(),
|
||||
timezone: None,
|
||||
})
|
||||
.with_extension(CurrentUser::authenticated(5, "Dave"))
|
||||
.to_http_request();
|
||||
let page = Page::new(req);
|
||||
let user = page.current_user();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue