From 5bf83f9e0a8c0d0dbcc69fa5a9a19cae51a568c2 Mon Sep 17 00:00:00 2001 From: Umair Khan Date: Fri, 20 Jan 2017 16:27:38 +0500 Subject: [PATCH] change-email: Implement confirmation flow. This adds to Zulip support for a user changing their own email address. It's backed by a huge amount of work by Steve Howell on making email changes actually work from a UI perspective. Fixes #734. --- .../0003_emailchangeconfirmation.py | 24 +++ confirmation/models.py | 24 ++- static/js/settings.js | 32 ++++ .../settings/account-settings.handlebars | 25 ++++ .../confirmation/confirm_email_change.html | 34 +++++ .../emailchangestatus_confirmation_email.html | 42 ++++++ ...ailchangestatus_confirmation_email.subject | 1 + .../emailchangestatus_confirmation_email.txt | 19 +++ .../notify_change_in_email_body.txt | 9 ++ .../notify_change_in_email_subject.txt | 1 + tools/lint-all | 2 + zerver/lib/actions.py | 28 +++- zerver/migrations/0053_emailchangestatus.py | 29 ++++ zerver/models.py | 12 ++ zerver/tests/test_email_change.py | 140 ++++++++++++++++++ zerver/tests/test_templates.py | 4 + zerver/views/user_settings.py | 60 +++++++- zproject/settings.py | 1 + zproject/urls.py | 5 + 19 files changed, 484 insertions(+), 8 deletions(-) create mode 100644 confirmation/migrations/0003_emailchangeconfirmation.py create mode 100644 templates/confirmation/confirm_email_change.html create mode 100644 templates/confirmation/emailchangestatus_confirmation_email.html create mode 100644 templates/confirmation/emailchangestatus_confirmation_email.subject create mode 100644 templates/confirmation/emailchangestatus_confirmation_email.txt create mode 100644 templates/confirmation/notify_change_in_email_body.txt create mode 100644 templates/confirmation/notify_change_in_email_subject.txt create mode 100644 zerver/migrations/0053_emailchangestatus.py create mode 100644 zerver/tests/test_email_change.py diff --git a/confirmation/migrations/0003_emailchangeconfirmation.py b/confirmation/migrations/0003_emailchangeconfirmation.py new file mode 100644 index 0000000000..cd7c126ab9 --- /dev/null +++ b/confirmation/migrations/0003_emailchangeconfirmation.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2017-01-17 09:16 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('confirmation', '0002_realmcreationkey'), + ] + + operations = [ + migrations.CreateModel( + name='EmailChangeConfirmation', + fields=[ + ], + options={ + 'proxy': True, + }, + bases=('confirmation.confirmation',), + ), + ] diff --git a/confirmation/models.py b/confirmation/models.py index 92b5d87f52..312d736d4c 100644 --- a/confirmation/models.py +++ b/confirmation/models.py @@ -19,7 +19,7 @@ from django.utils.timezone import now from confirmation.util import get_status_field from zerver.lib.utils import generate_random_token -from zerver.models import PreregistrationUser +from zerver.models import PreregistrationUser, EmailChangeStatus from typing import Optional, Union, Any, Text B16_RE = re.compile('^[a-f0-9]{40}$') @@ -59,7 +59,7 @@ def generate_realm_creation_url(): class ConfirmationManager(models.Manager): def confirm(self, confirmation_key): - # type: (str) -> Union[bool, PreregistrationUser] + # type: (str) -> Union[bool, PreregistrationUser, EmailChangeStatus] if B16_RE.search(confirmation_key): try: confirmation = self.get(confirmation_key=confirmation_key) @@ -140,6 +140,20 @@ class ConfirmationManager(models.Manager): send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [email_address], html_message=html_content) return self.create(content_object=obj, date_sent=now(), confirmation_key=confirmation_key) +class EmailChangeConfirmationManager(ConfirmationManager): + def get_activation_url(self, key, host=None): + # type: (Text, Optional[str]) -> Text + if host is None: + # This will raise exception if the key doesn't exist. + host = self.get(confirmation_key=key).content_object.realm.host + return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME, + host, + reverse('zerver.views.user_settings.confirm_email_change', + kwargs={'confirmation_key': key})) + + def get_link_validity_in_days(self): + # type: () -> int + return settings.EMAIL_CHANGE_CONFIRMATION_DAYS class Confirmation(models.Model): content_type = models.ForeignKey(ContentType) @@ -158,6 +172,12 @@ class Confirmation(models.Model): # type: () -> Text return _('confirmation email for %s') % (self.content_object,) +class EmailChangeConfirmation(Confirmation): + class Meta(object): + proxy = True + + objects = EmailChangeConfirmationManager() + class RealmCreationKey(models.Model): creation_key = models.CharField(_('activation key'), max_length=40) date_created = models.DateTimeField(_('created'), default=now) diff --git a/static/js/settings.js b/static/js/settings.js index d8ccc2d4f7..f826e23402 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -517,12 +517,44 @@ function _setup_page() { }); }); + $('#change_email_button').on('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + $('#change_email_modal').modal('hide'); + + var data = {}; + data.email = $('.email_change_container').find("input[name='email']").val(); + + channel.patch({ + url: '/json/settings/change', + data: data, + success: function (data) { + if ('account_email' in data) { + settings_change_success(data.account_email); + } else { + settings_change_error(i18n.t("Error changing settings: No new data supplied.")); + } + }, + error: function (xhr) { + settings_change_error("Error changing settings", xhr); + }, + }); + }); + $('#default_language').on('click', function (e) { e.preventDefault(); e.stopPropagation(); $('#default_language_modal').show().attr('aria-hidden', false); }); + $('#change_email').on('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + $('#change_email_modal').modal('show'); + var email = $('#email_value').text(); + $('.email_change_container').find("input[name='email']").val(email); + }); + $("#user_deactivate_account_button").on('click', function (e) { e.preventDefault(); e.stopPropagation(); diff --git a/static/templates/settings/account-settings.handlebars b/static/templates/settings/account-settings.handlebars index c1cbcda069..4fc9df0eb2 100644 --- a/static/templates/settings/account-settings.handlebars +++ b/static/templates/settings/account-settings.handlebars @@ -4,6 +4,31 @@ {{t "Your account" }}
+ +