core: explicitly enable locales (#3889)
* activate locales Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * set locale for email templates Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
8a50279142
commit
30d708dd1f
|
@ -470,7 +470,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
|||
# pylint: disable=invalid-name, unused-argument
|
||||
def recovery_email(self, request: Request, pk: int) -> Response:
|
||||
"""Create a temporary link that a user can use to recover their accounts"""
|
||||
for_user = self.get_object()
|
||||
for_user: User = self.get_object()
|
||||
if for_user.email == "":
|
||||
LOGGER.debug("User doesn't have an email address")
|
||||
return Response(status=404)
|
||||
|
@ -488,8 +488,9 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
|||
email_stage: EmailStage = stages.first()
|
||||
message = TemplateEmailMessage(
|
||||
subject=_(email_stage.subject),
|
||||
template_name=email_stage.template,
|
||||
to=[for_user.email],
|
||||
template_name=email_stage.template,
|
||||
language=for_user.locale(request),
|
||||
template_context={
|
||||
"url": link,
|
||||
"user": for_user,
|
||||
|
|
|
@ -4,6 +4,7 @@ from typing import Callable, Optional
|
|||
from uuid import uuid4
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.translation import activate
|
||||
from sentry_sdk.api import set_tag
|
||||
from structlog.contextvars import STRUCTLOG_KEY_PREFIX
|
||||
|
||||
|
@ -29,6 +30,10 @@ class ImpersonateMiddleware:
|
|||
def __call__(self, request: HttpRequest) -> HttpResponse:
|
||||
# No permission checks are done here, they need to be checked before
|
||||
# SESSION_KEY_IMPERSONATE_USER is set.
|
||||
if request.user.is_authenticated:
|
||||
locale = request.user.locale(request)
|
||||
if locale != "":
|
||||
activate(locale)
|
||||
|
||||
if SESSION_KEY_IMPERSONATE_USER in request.session:
|
||||
request.user = request.session[SESSION_KEY_IMPERSONATE_USER]
|
||||
|
|
|
@ -220,6 +220,17 @@ class User(SerializerModel, GuardianUserMixin, AbstractUser):
|
|||
"""Generate a globally unique UID, based on the user ID and the hashed secret key"""
|
||||
return sha256(f"{self.id}-{settings.SECRET_KEY}".encode("ascii")).hexdigest()
|
||||
|
||||
def locale(self, request: Optional[HttpRequest] = None) -> str:
|
||||
"""Get the locale the user has configured"""
|
||||
try:
|
||||
return self.attributes.get("settings", {}).get("locale", "")
|
||||
# pylint: disable=broad-except
|
||||
except Exception as exc:
|
||||
LOGGER.warning("Failed to get default locale", exc=exc)
|
||||
if request:
|
||||
return request.tenant.locale
|
||||
return ""
|
||||
|
||||
@property
|
||||
def avatar(self) -> str:
|
||||
"""Get avatar, depending on authentik.avatar setting"""
|
||||
|
|
|
@ -445,8 +445,9 @@ class NotificationTransport(SerializerModel):
|
|||
subject += notification.body[:75]
|
||||
mail = TemplateEmailMessage(
|
||||
subject=subject,
|
||||
template_name="email/generic.html",
|
||||
to=[notification.user.email],
|
||||
language=notification.user.locale(),
|
||||
template_name="email/generic.html",
|
||||
template_context={
|
||||
"title": subject,
|
||||
"body": notification.body,
|
||||
|
|
|
@ -28,8 +28,8 @@ class Command(BaseCommand):
|
|||
delete_stage = True
|
||||
message = TemplateEmailMessage(
|
||||
subject="authentik Test-Email",
|
||||
template_name="email/setup.html",
|
||||
to=[options["to"]],
|
||||
template_name="email/setup.html",
|
||||
template_context={},
|
||||
)
|
||||
try:
|
||||
|
|
|
@ -11,6 +11,7 @@ from django.utils.translation import gettext as _
|
|||
from rest_framework.fields import CharField
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||
from authentik.flows.models import FlowToken
|
||||
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
|
||||
|
@ -81,7 +82,7 @@ class EmailStageView(ChallengeStageView):
|
|||
def send_email(self):
|
||||
"""Helper function that sends the actual email. Implies that you've
|
||||
already checked that there is a pending user."""
|
||||
pending_user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||
pending_user: User = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||
email = self.executor.plan.context.get(PLAN_CONTEXT_EMAIL_OVERRIDE, None)
|
||||
if not email:
|
||||
email = pending_user.email
|
||||
|
@ -90,8 +91,9 @@ class EmailStageView(ChallengeStageView):
|
|||
# Send mail to user
|
||||
message = TemplateEmailMessage(
|
||||
subject=_(current_stage.subject),
|
||||
template_name=current_stage.template,
|
||||
to=[email],
|
||||
language=pending_user.locale(self.request),
|
||||
template_name=current_stage.template,
|
||||
template_context={
|
||||
"url": self.get_full_url(**{QS_KEY_TOKEN: token.key}),
|
||||
"user": pending_user,
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
"""email utils"""
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import translation
|
||||
|
||||
|
||||
class TemplateEmailMessage(EmailMultiAlternatives):
|
||||
"""Wrapper around EmailMultiAlternatives with integrated template rendering"""
|
||||
|
||||
def __init__(self, template_name=None, template_context=None, **kwargs):
|
||||
html_content = render_to_string(template_name, template_context)
|
||||
def __init__(self, template_name=None, template_context=None, language="", **kwargs):
|
||||
with translation.override(language):
|
||||
html_content = render_to_string(template_name, template_context)
|
||||
super().__init__(**kwargs)
|
||||
self.content_subtype = "html"
|
||||
self.attach_alternative(html_content, "text/html")
|
||||
|
|
|
@ -3,6 +3,7 @@ from typing import Callable
|
|||
|
||||
from django.http.request import HttpRequest
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import activate
|
||||
from sentry_sdk.api import set_tag
|
||||
|
||||
from authentik.tenants.utils import get_tenant_for_request
|
||||
|
@ -22,4 +23,7 @@ class TenantMiddleware:
|
|||
setattr(request, "tenant", tenant)
|
||||
set_tag("authentik.tenant_uuid", tenant.tenant_uuid.hex)
|
||||
set_tag("authentik.tenant_domain", tenant.domain)
|
||||
locale = tenant.default_locale
|
||||
if locale != "":
|
||||
activate(locale)
|
||||
return self.get_response(request)
|
||||
|
|
Reference in New Issue