Source code for ferrosoft.apps.ferrobase.session.password_reset
"""Password reset email dispatch using templated messages."""
from django.core import mail
from django.http import HttpRequest
from django.template import Engine, Context
from django.urls import reverse
from django.utils.translation import gettext as _
from ferrosoft.apps.date_time import now_utc
from ferrosoft.apps.ferrobase.models import PasswordResetRequest
[docs]
class UserMissingEmail(Exception):
"""Raised when a password reset is attempted for a user without an email address."""
[docs]
def send_password_reset_email(
reset_req: PasswordResetRequest,
http_req: HttpRequest,
sender_address: str = None,
):
"""Render and send the password reset email for a pending reset request.
The mail body is rendered from the ``ferrobase/session/reset-password-mail.html``
template and contains a tokenised link back to the ``set_new_password`` view.
Args:
reset_req: The persisted reset-request record carrying the user and
access key.
http_req: The current HTTP request, used solely to build an absolute
URI for the reset link.
sender_address: Optional sender address. Falls back to the Django
``DEFAULT_FROM_EMAIL`` setting when omitted.
Raises:
UserMissingEmail: If the target user has no email address recorded.
Exception: Any underlying mail-backend error is propagated; the call
uses ``fail_silently=False``.
"""
from django.conf import settings
with mail.get_connection() as conn:
if not reset_req.user.email:
raise UserMissingEmail(
"user is missing email: ID " + str(reset_req.user.pk)
)
body_template = Engine.get_default().get_template(
"ferrobase/session/reset-password-mail.html"
)
reset_url = reverse("ferrobase:set_new_password", args=[reset_req.access_key])
body = body_template.render(
Context(
{
"name": reset_req.user.get_short_name(),
"request_time": now_utc().isoformat(),
"reset_url": http_req.build_absolute_uri(reset_url),
}
)
)
msg = mail.EmailMessage(
_("Reset password for Ferrosoft Platform"),
body,
sender_address or getattr(settings, "DEFAULT_FROM_EMAIL"),
[reset_req.user.email],
connection=conn,
)
msg.send(fail_silently=False)