You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-07 17:03:01 +03:00
templates: translate a lot more stuff
This commit is contained in:
@@ -18,7 +18,7 @@ use lettre::{
|
||||
message::{Mailbox, MessageBuilder, MultiPart},
|
||||
AsyncTransport, Message,
|
||||
};
|
||||
use mas_templates::{EmailVerificationContext, Templates};
|
||||
use mas_templates::{EmailVerificationContext, Templates, WithLanguage};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::MailTransport;
|
||||
@@ -66,7 +66,7 @@ impl Mailer {
|
||||
fn prepare_verification_email(
|
||||
&self,
|
||||
to: Mailbox,
|
||||
context: &EmailVerificationContext,
|
||||
context: &WithLanguage<EmailVerificationContext>,
|
||||
) -> Result<Message, Error> {
|
||||
let plain = self.templates.render_email_verification_txt(context)?;
|
||||
|
||||
@@ -95,6 +95,7 @@ impl Mailer {
|
||||
skip_all,
|
||||
fields(
|
||||
email.to = %to,
|
||||
email.language = %context.language(),
|
||||
user.id = %context.user().id,
|
||||
user_email_verification.id = %context.verification().id,
|
||||
user_email_verification.code = context.verification().code,
|
||||
@@ -104,7 +105,7 @@ impl Mailer {
|
||||
pub async fn send_verification_email(
|
||||
&self,
|
||||
to: Mailbox,
|
||||
context: &EmailVerificationContext,
|
||||
context: &WithLanguage<EmailVerificationContext>,
|
||||
) -> Result<(), Error> {
|
||||
let message = self.prepare_verification_email(to, context)?;
|
||||
self.transport.send(message).await?;
|
||||
|
@@ -449,6 +449,7 @@ impl UserEmailMutations {
|
||||
.mark_as_verified(&state.clock(), user_email)
|
||||
.await?;
|
||||
} else {
|
||||
// TODO: figure out the locale
|
||||
repo.job()
|
||||
.schedule_job(VerifyEmailJob::new(&user_email))
|
||||
.await?;
|
||||
@@ -490,6 +491,7 @@ impl UserEmailMutations {
|
||||
// Schedule a job to verify the email address if needed
|
||||
let needs_verification = user_email.confirmed_at.is_none();
|
||||
if needs_verification {
|
||||
// TODO: figure out the locale
|
||||
repo.job()
|
||||
.schedule_job(VerifyEmailJob::new(&user_email))
|
||||
.await?;
|
||||
|
@@ -105,7 +105,8 @@ pub async fn get(
|
||||
if clock.now() > login.created_at + Duration::minutes(30) {
|
||||
let ctx = ErrorContext::new()
|
||||
.with_code("compat_sso_login_expired")
|
||||
.with_description("This login session expired.".to_owned());
|
||||
.with_description("This login session expired.".to_owned())
|
||||
.with_language(&locale);
|
||||
|
||||
let content = templates.render_error(&ctx)?;
|
||||
return Ok((cookie_jar, Html(content)).into_response());
|
||||
@@ -131,6 +132,7 @@ pub async fn post(
|
||||
mut rng: BoxRng,
|
||||
clock: BoxClock,
|
||||
mut repo: BoxRepository,
|
||||
PreferredLanguage(locale): PreferredLanguage,
|
||||
State(templates): State<Templates>,
|
||||
cookie_jar: CookieJar,
|
||||
Path(id): Path<Ulid>,
|
||||
@@ -173,7 +175,8 @@ pub async fn post(
|
||||
if clock.now() > login.created_at + Duration::minutes(30) {
|
||||
let ctx = ErrorContext::new()
|
||||
.with_code("compat_sso_login_expired")
|
||||
.with_description("This login session expired.".to_owned());
|
||||
.with_description("This login session expired.".to_owned())
|
||||
.with_language(&locale);
|
||||
|
||||
let content = templates.render_error(&ctx)?;
|
||||
return Ok((cookie_jar, Html(content)).into_response());
|
||||
|
@@ -77,6 +77,7 @@ pub(crate) async fn post(
|
||||
mut rng: BoxRng,
|
||||
clock: BoxClock,
|
||||
mut repo: BoxRepository,
|
||||
PreferredLanguage(locale): PreferredLanguage,
|
||||
mut policy: Policy,
|
||||
cookie_jar: CookieJar,
|
||||
activity_tracker: BoundActivityTracker,
|
||||
@@ -124,7 +125,7 @@ pub(crate) async fn post(
|
||||
// verify page
|
||||
let next = if user_email.confirmed_at.is_none() {
|
||||
repo.job()
|
||||
.schedule_job(VerifyEmailJob::new(&user_email))
|
||||
.schedule_job(VerifyEmailJob::new(&user_email).with_language(locale.to_string()))
|
||||
.await?;
|
||||
|
||||
let next = mas_router::AccountVerifyEmail::new(user_email.id);
|
||||
|
@@ -34,7 +34,6 @@ pub async fn get(
|
||||
cookie_jar: CookieJar,
|
||||
PreferredLanguage(locale): PreferredLanguage,
|
||||
) -> Result<impl IntoResponse, FancyError> {
|
||||
tracing::info!("{locale}");
|
||||
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng);
|
||||
let (session_info, cookie_jar) = cookie_jar.session_info();
|
||||
let session = session_info.load_session(&mut repo).await?;
|
||||
@@ -52,7 +51,5 @@ pub async fn get(
|
||||
|
||||
let content = templates.render_index(&ctx)?;
|
||||
|
||||
tracing::info!("rendered index page");
|
||||
|
||||
Ok((cookie_jar, Html(content)))
|
||||
}
|
||||
|
@@ -225,7 +225,7 @@ pub(crate) async fn post(
|
||||
.await?;
|
||||
|
||||
repo.job()
|
||||
.schedule_job(VerifyEmailJob::new(&user_email))
|
||||
.schedule_job(VerifyEmailJob::new(&user_email).with_language(locale.to_string()))
|
||||
.await?;
|
||||
|
||||
repo.job()
|
||||
|
@@ -19,6 +19,7 @@ pub mod sprintf;
|
||||
pub mod translations;
|
||||
mod translator;
|
||||
|
||||
pub use icu_locid::locale;
|
||||
pub use icu_provider::DataLocale;
|
||||
|
||||
pub use self::{
|
||||
|
@@ -18,7 +18,7 @@ use ulid::Ulid;
|
||||
pub use crate::traits::*;
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "snake_case", tag = "next")]
|
||||
#[serde(rename_all = "snake_case", tag = "kind")]
|
||||
pub enum PostAuthAction {
|
||||
ContinueAuthorizationGrant {
|
||||
id: Ulid,
|
||||
|
@@ -239,6 +239,7 @@ mod jobs {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct VerifyEmailJob {
|
||||
user_email_id: Ulid,
|
||||
language: Option<String>,
|
||||
}
|
||||
|
||||
impl VerifyEmailJob {
|
||||
@@ -247,9 +248,23 @@ mod jobs {
|
||||
pub fn new(user_email: &UserEmail) -> Self {
|
||||
Self {
|
||||
user_email_id: user_email.id,
|
||||
language: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the language to use for the email.
|
||||
#[must_use]
|
||||
pub fn with_language(mut self, language: String) -> Self {
|
||||
self.language = Some(language);
|
||||
self
|
||||
}
|
||||
|
||||
/// The language to use for the email.
|
||||
#[must_use]
|
||||
pub fn language(&self) -> Option<&str> {
|
||||
self.language.as_deref()
|
||||
}
|
||||
|
||||
/// The ID of the email address to verify.
|
||||
#[must_use]
|
||||
pub fn user_email_id(&self) -> Ulid {
|
||||
|
@@ -32,7 +32,9 @@ serde_json.workspace = true
|
||||
|
||||
mas-data-model = { path = "../data-model" }
|
||||
mas-email = { path = "../email" }
|
||||
mas-i18n = { path = "../i18n" }
|
||||
mas-matrix = { path = "../matrix" }
|
||||
mas-storage = { path = "../storage" }
|
||||
mas-storage-pg = { path = "../storage-pg" }
|
||||
mas-templates = { path = "../templates" }
|
||||
mas-tower = { path = "../tower" }
|
||||
|
@@ -15,8 +15,10 @@
|
||||
use anyhow::Context;
|
||||
use apalis_core::{context::JobContext, executor::TokioExecutor, monitor::Monitor};
|
||||
use chrono::Duration;
|
||||
use mas_email::{Address, EmailVerificationContext, Mailbox};
|
||||
use mas_email::{Address, Mailbox};
|
||||
use mas_i18n::locale;
|
||||
use mas_storage::job::{JobWithSpanContext, VerifyEmailJob};
|
||||
use mas_templates::{EmailVerificationContext, TemplateContext};
|
||||
use rand::{distributions::Uniform, Rng};
|
||||
use tracing::info;
|
||||
|
||||
@@ -38,6 +40,11 @@ async fn verify_email(
|
||||
let mailer = state.mailer();
|
||||
let clock = state.clock();
|
||||
|
||||
let language = job
|
||||
.language()
|
||||
.and_then(|l| l.parse().ok())
|
||||
.unwrap_or(locale!("en").into());
|
||||
|
||||
// Lookup the user email
|
||||
let user_email = repo
|
||||
.user_email()
|
||||
@@ -68,7 +75,8 @@ async fn verify_email(
|
||||
// And send the verification email
|
||||
let mailbox = Mailbox::new(Some(user.username.clone()), address);
|
||||
|
||||
let context = EmailVerificationContext::new(user.clone(), verification.clone());
|
||||
let context =
|
||||
EmailVerificationContext::new(user.clone(), verification.clone()).with_language(language);
|
||||
|
||||
mailer.send_verification_email(mailbox, &context).await?;
|
||||
|
||||
|
@@ -109,6 +109,21 @@ pub struct WithLanguage<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> WithLanguage<T> {
|
||||
/// Get the language of this context
|
||||
pub fn language(&self) -> &str {
|
||||
&self.lang
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for WithLanguage<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TemplateContext> TemplateContext for WithLanguage<T> {
|
||||
fn sample(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self>
|
||||
where
|
||||
@@ -984,6 +999,7 @@ pub struct ErrorContext {
|
||||
code: Option<&'static str>,
|
||||
description: Option<String>,
|
||||
details: Option<String>,
|
||||
lang: Option<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorContext {
|
||||
@@ -1047,6 +1063,13 @@ impl ErrorContext {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add the language to the context
|
||||
#[must_use]
|
||||
pub fn with_language(mut self, lang: &DataLocale) -> Self {
|
||||
self.lang = Some(lang.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the error code, if any
|
||||
#[must_use]
|
||||
pub fn code(&self) -> Option<&'static str> {
|
||||
|
@@ -29,7 +29,7 @@ use std::{collections::HashSet, sync::Arc};
|
||||
use anyhow::Context as _;
|
||||
use arc_swap::ArcSwap;
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use mas_i18n::{Translator};
|
||||
use mas_i18n::Translator;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_spa::ViteManifest;
|
||||
use rand::Rng;
|
||||
@@ -346,13 +346,13 @@ register_templates! {
|
||||
pub fn render_error(ErrorContext) { "pages/error.html" }
|
||||
|
||||
/// Render the email verification email (plain text variant)
|
||||
pub fn render_email_verification_txt(EmailVerificationContext) { "emails/verification.txt" }
|
||||
pub fn render_email_verification_txt(WithLanguage<EmailVerificationContext>) { "emails/verification.txt" }
|
||||
|
||||
/// Render the email verification email (HTML text variant)
|
||||
pub fn render_email_verification_html(EmailVerificationContext) { "emails/verification.html" }
|
||||
pub fn render_email_verification_html(WithLanguage<EmailVerificationContext>) { "emails/verification.html" }
|
||||
|
||||
/// Render the email verification subject
|
||||
pub fn render_email_verification_subject(EmailVerificationContext) { "emails/verification.subject" }
|
||||
pub fn render_email_verification_subject(WithLanguage<EmailVerificationContext>) { "emails/verification.subject" }
|
||||
|
||||
/// Render the upstream link mismatch message
|
||||
pub fn render_upstream_oauth2_link_mismatch(WithLanguage<WithCsrf<WithSession<UpstreamExistingLinkContext>>>) { "pages/upstream_oauth2/link_mismatch.html" }
|
||||
|
Reference in New Issue
Block a user