emails: Send password reset emails through zerver.lib.send_email.

Previously, the password reset email behaved differently from all the other
email Zulip sends.
This commit is contained in:
Rishi Gupta 2017-06-05 20:53:04 -07:00 committed by Tim Abbott
parent 7aa735294f
commit 769c5ab105
3 changed files with 15 additions and 41 deletions

View File

@ -14,6 +14,7 @@ from jinja2 import Markup as mark_safe
from zerver.lib.actions import do_change_password, is_inactive, user_email_is_unique from zerver.lib.actions import do_change_password, is_inactive, user_email_is_unique
from zerver.lib.name_restrictions import is_reserved_subdomain, is_disposable_domain from zerver.lib.name_restrictions import is_reserved_subdomain, is_disposable_domain
from zerver.lib.request import JsonableError from zerver.lib.request import JsonableError
from zerver.lib.send_email import send_email
from zerver.lib.users import check_full_name from zerver.lib.users import check_full_name
from zerver.lib.utils import get_subdomain, check_subdomain from zerver.lib.utils import get_subdomain, check_subdomain
from zerver.models import Realm, get_user_profile_by_email, UserProfile, \ from zerver.models import Realm, get_user_profile_by_email, UserProfile, \
@ -190,13 +191,16 @@ class ZulipPasswordResetForm(PasswordResetForm):
# type: (str, str, Dict[str, Any], str, str, str) -> None # type: (str, str, Dict[str, Any], str, str, str) -> None
""" """
Currently we don't support accounts in multiple subdomains using Currently we don't support accounts in multiple subdomains using
a single email addresss. We override this function so that we do a single email address. We override this function so that we do
not send a reset link to an email address if the reset attempt is not send a reset link to an email address if the reset attempt is
done on the subdomain which does not match user.realm.subdomain. done on the subdomain which does not match user.realm.subdomain.
Once we start supporting accounts with the same email in Once we start supporting accounts with the same email in
multiple subdomains, we may be able to delete or refactor this multiple subdomains, we may be able to refactor this function.
function.
A second reason we override this function is so that we can send
the mail through the functions in zerver.lib.send_email, to match
how we send all other mail in the codebase.
""" """
user_realm = get_user_profile_by_email(to_email).realm user_realm = get_user_profile_by_email(to_email).realm
attempted_subdomain = get_subdomain(getattr(self, 'request')) attempted_subdomain = get_subdomain(getattr(self, 'request'))
@ -204,14 +208,8 @@ class ZulipPasswordResetForm(PasswordResetForm):
if not check_subdomain(user_realm.subdomain, attempted_subdomain): if not check_subdomain(user_realm.subdomain, attempted_subdomain):
context['attempted_realm'] = get_realm(attempted_subdomain) context['attempted_realm'] = get_realm(attempted_subdomain)
super(ZulipPasswordResetForm, self).send_mail( send_email('zerver/emails/password_reset', to_email, from_email=from_email,
subject_template_name, context=context)
email_template_name,
context,
from_email,
to_email,
html_email_template_name=html_email_template_name
)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
# type: (*Any, **Any) -> None # type: (*Any, **Any) -> None

View File

@ -10,13 +10,13 @@ from django.core.mail import send_mail, BadHeaderError
from zerver.forms import PasswordResetForm from zerver.forms import PasswordResetForm
from zerver.models import UserProfile, get_user_profile_by_email, get_realm from zerver.models import UserProfile, get_user_profile_by_email, get_realm
from django.template import loader from django.template import loader
from django.utils.http import urlsafe_base64_encode from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.contrib.auth.tokens import default_token_generator, PasswordResetTokenGenerator from django.contrib.auth.tokens import default_token_generator, PasswordResetTokenGenerator
from zerver.lib.send_email import send_email
class Command(BaseCommand): class Command(BaseCommand):
help = """Send email to specified email address.""" help = """Send email to specified email address."""
@ -44,9 +44,7 @@ class Command(BaseCommand):
raise RuntimeError("Missing arguments") raise RuntimeError("Missing arguments")
self.send(users) self.send(users)
def send(self, users, def send(self, users, subject_template_name='', email_template_name='',
subject_template_name='zerver/emails/password_reset.subject',
email_template_name='zerver/emails/password_reset.txt',
use_https=True, token_generator=default_token_generator, use_https=True, token_generator=default_token_generator,
from_email=None, html_email_template_name=None): from_email=None, html_email_template_name=None):
# type: (List[UserProfile], str, str, bool, PasswordResetTokenGenerator, Optional[Text], Optional[str]) -> None # type: (List[UserProfile], str, str, bool, PasswordResetTokenGenerator, Optional[Text], Optional[str]) -> None
@ -65,26 +63,4 @@ class Command(BaseCommand):
} }
logging.warning("Sending %s email to %s" % (email_template_name, user_profile.email,)) logging.warning("Sending %s email to %s" % (email_template_name, user_profile.email,))
# Our password reset flow is basically a patch of Django's password send_email('zerver/emails/password_reset', user_profile.email, context=context)
# reset flow, so this is aligned with Django code rather than using
# zerver.lib.send_email.send_email.
self.send_email(subject_template_name, email_template_name,
context, from_email, user_profile.email,
html_email_template_name=html_email_template_name)
def send_email(self, subject_template_name, email_template_name,
context, from_email, to_email, html_email_template_name=None):
# type: (str, str, Dict[str, Any], Text, Text, Optional[str]) -> None
"""
Sends a django.core.mail.send_mail to `to_email`.
"""
subject = loader.render_to_string(subject_template_name, context)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
body = loader.render_to_string(email_template_name, context)
if html_email_template_name is not None:
html_email = loader.render_to_string(html_email_template_name, context)
send_mail(subject, body, from_email, [to_email], html_message=html_email)
else:
send_mail(subject, body, from_email, [to_email])

View File

@ -81,8 +81,8 @@ i18n_urls = [
url(r'^accounts/password/reset/$', password_reset, url(r'^accounts/password/reset/$', password_reset,
{'post_reset_redirect': '/accounts/password/reset/done/', {'post_reset_redirect': '/accounts/password/reset/done/',
'template_name': 'zerver/reset.html', 'template_name': 'zerver/reset.html',
'email_template_name': 'zerver/emails/password_reset.txt', 'email_template_name': '',
'subject_template_name': 'zerver/emails/password_reset.subject', 'subject_template_name': '',
'password_reset_form': zerver.forms.ZulipPasswordResetForm, 'password_reset_form': zerver.forms.ZulipPasswordResetForm,
}, name='django.contrib.auth.views.password_reset'), }, name='django.contrib.auth.views.password_reset'),
url(r'^accounts/password/reset/done/$', password_reset_done, url(r'^accounts/password/reset/done/$', password_reset_done,