Send password-reset emails

Python · Django · beginner · modification

Support has been resetting passwords by hand; this sends the reset email ourselves. The view looks the address up within the current workspace and always shows the same "check your inbox" page, so the form does not reveal which emails have accounts. The link is built from `default_token_generator` and the existing `password_reset_confirm` route, so the existing confirm view validates it. Tested with the locmem email backend: the email renders with the link, and its token passes `default_token_generator.check_token`.

Multi-tenant HR app on Django 5.1. Each workspace (`Tenant`) has exactly one `domain`: either `<slug>.acmepeople.app` or a custom domain such as `people.northwind.com`, and both are served by this app over HTTPS. `TenantMiddleware` (existing) sets `request.tenant` from the request's host and answers 404 for any host that is not a workspace domain. `accounts.User` has a `tenant` foreign key, and `(tenant, email)` is unique, case-insensitively. Sign-in and the reset confirm view look users up within `request.tenant`. Every account has a usable password (there is no SSO). `PASSWORD_RESET_TIMEOUT` is left at Django's default (3 days), and rate limiting of the form is handled at the proxy. `settings.APP_URL` is `https://app.acmepeople.com`, the "find your workspace" page of the marketing site, which is a separate site not served by this app and has no `/reset/` route. The email backend hands messages to a queue and does not fail at request time.

Requirements

Files touched

--- accounts/views.py
 from django.views.generic import FormView
 
+from .emails import send_password_reset
 from .forms import PasswordResetRequestForm
+from .models import User
 
 
 
     def form_valid(self, form):
-        # Support resets passwords by hand until reset emails ship.
+        user = User.objects.filter(
+            tenant=self.request.tenant,
+            email__iexact=form.cleaned_data["email"],
+            is_active=True,
+        ).first()
+        if user is not None:
+            send_password_reset(user)
+        # Same response whether or not the address has an account.
         return super().form_valid(form)
 
--- accounts/emails.py
+from django.conf import settings
+from django.contrib.auth.tokens import default_token_generator
+from django.core.mail import send_mail
+from django.template.loader import render_to_string
+from django.urls import reverse
+from django.utils.encoding import force_bytes
+from django.utils.http import urlsafe_base64_encode
+

Review this PR

Python practice