From 588a15bdbd2cca462d2215bc5beca9d98f1bc671 Mon Sep 17 00:00:00 2001 From: Amelia Cordwell Date: Thu, 13 Apr 2017 14:23:20 +1200 Subject: [PATCH] Panel and Token Handler for update email Adds a panel in the settings dashboard to allow the user to change their email address, and a token handler for that page. Change-Id: I4991fa599f6cfbf65f143e5b2227867df6fb86c3 --- adjutant_ui/api/adjutant.py | 10 ++++ adjutant_ui/content/email/__init__.py | 0 adjutant_ui/content/email/forms.py | 55 +++++++++++++++++++ adjutant_ui/content/email/panel.py | 22 ++++++++ .../email/templates/email/_change.html | 7 +++ .../content/email/templates/email/change.html | 7 +++ adjutant_ui/content/email/urls.py | 23 ++++++++ adjutant_ui/content/email/views.py | 33 +++++++++++ .../templates/token/_emailtokenconfirm.html | 33 +++++++++++ .../templates/token/emailtokenconfirm.html | 12 ++++ adjutant_ui/content/token/views.py | 15 ++++- .../enabled/_6070_settings_update_email.py | 9 +++ 12 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 adjutant_ui/content/email/__init__.py create mode 100644 adjutant_ui/content/email/forms.py create mode 100644 adjutant_ui/content/email/panel.py create mode 100644 adjutant_ui/content/email/templates/email/_change.html create mode 100644 adjutant_ui/content/email/templates/email/change.html create mode 100644 adjutant_ui/content/email/urls.py create mode 100644 adjutant_ui/content/email/views.py create mode 100644 adjutant_ui/content/token/templates/token/_emailtokenconfirm.html create mode 100644 adjutant_ui/content/token/templates/token/emailtokenconfirm.html create mode 100644 adjutant_ui/enabled/_6070_settings_update_email.py diff --git a/adjutant_ui/api/adjutant.py b/adjutant_ui/api/adjutant.py index 468dbf3..815f3a4 100644 --- a/adjutant_ui/api/adjutant.py +++ b/adjutant_ui/api/adjutant.py @@ -229,6 +229,16 @@ def token_submit(request, token, data): data=json.dumps(data), headers=headers) +def email_update(request, email): + headers = {'Content-Type': 'application/json', + 'X-Auth-Token': request.user.token.id} + data = { + 'new_email': email + } + return post(request, 'openstack/users/email-update', + data=json.dumps(data), headers=headers) + + def forgotpassword_submit(request, data): headers = {"Content-Type": "application/json"} try: diff --git a/adjutant_ui/content/email/__init__.py b/adjutant_ui/content/email/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/adjutant_ui/content/email/forms.py b/adjutant_ui/content/email/forms.py new file mode 100644 index 0000000..0dde204 --- /dev/null +++ b/adjutant_ui/content/email/forms.py @@ -0,0 +1,55 @@ +# Copyright 2013 Centrin Data Systems Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.forms import ValidationError +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms +from horizon import messages + +from adjutant_ui import api + + +class EmailForm(forms.SelfHandlingForm): + new_email = forms.EmailField( + label=_("New email address"), + required=True) + + confirm_email = forms.CharField( + label=_("Confirm email address"), + required=True) + no_autocomplete = True + + def clean(self): + '''Check to make sure email fields match.''' + data = super(forms.Form, self).clean() + if data.get('new_email') != data.get('confirm_email', None): + raise ValidationError(_('Email addresses do not match.')) + return data + + def handle(self, request, data): + try: + response = api.adjutant.email_update(request, data['new_email']) + if response.status_code == 200: + msg = _("Confirmation email sent to %s.") + messages.success(request, msg % data['new_email']) + elif response.status_code == 400: + messages.warning(request, _( + 'Unable to update email. May already be in use.')) + else: + messages.error(request, _('Failed to update email.')) + return True + except Exception as e: + messages.error(request, _('Failed to update email. %s' % str(e))) + return False diff --git a/adjutant_ui/content/email/panel.py b/adjutant_ui/content/email/panel.py new file mode 100644 index 0000000..503feed --- /dev/null +++ b/adjutant_ui/content/email/panel.py @@ -0,0 +1,22 @@ +# Copyright 2013 Centrin Data Systems Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ + +import horizon + + +class EmailPanel(horizon.Panel): + name = _("Update Email Address") + slug = 'email' diff --git a/adjutant_ui/content/email/templates/email/_change.html b/adjutant_ui/content/email/templates/email/_change.html new file mode 100644 index 0000000..d72a412 --- /dev/null +++ b/adjutant_ui/content/email/templates/email/_change.html @@ -0,0 +1,7 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans "A confirmation email will be sent to the new address before your account email address is updated. " %}

+{% endblock %} diff --git a/adjutant_ui/content/email/templates/email/change.html b/adjutant_ui/content/email/templates/email/change.html new file mode 100644 index 0000000..40300eb --- /dev/null +++ b/adjutant_ui/content/email/templates/email/change.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Update Email" %}{% endblock %} + +{% block main %} + {% include "settings/email/_change.html" %} +{% endblock %} diff --git a/adjutant_ui/content/email/urls.py b/adjutant_ui/content/email/urls.py new file mode 100644 index 0000000..b609d2c --- /dev/null +++ b/adjutant_ui/content/email/urls.py @@ -0,0 +1,23 @@ +# Copyright 2013 Centrin Data Systems Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.conf.urls import patterns +from django.conf.urls import url + +from adjutant_ui.content.email import views + + +urlpatterns = patterns( + '', + url(r'^$', views.EmailView.as_view(), name='index')) diff --git a/adjutant_ui/content/email/views.py b/adjutant_ui/content/email/views.py new file mode 100644 index 0000000..570459c --- /dev/null +++ b/adjutant_ui/content/email/views.py @@ -0,0 +1,33 @@ +# Copyright 2013 Centrin Data Systems Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.core.urlresolvers import reverse_lazy +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms + +from adjutant_ui.content.email \ + import forms as pass_forms + + +class EmailView(forms.ModalFormView): + form_class = pass_forms.EmailForm + form_id = "update_email_modal" + modal_header = _("Update Email Address") + modal_id = "update_email_modal" + page_title = _("Update Email Address") + submit_label = _("Update") + submit_url = reverse_lazy("horizon:settings:email:index") + success_url = reverse_lazy("horizon:settings:email:index") + template_name = 'settings/email/change.html' diff --git a/adjutant_ui/content/token/templates/token/_emailtokenconfirm.html b/adjutant_ui/content/token/templates/token/_emailtokenconfirm.html new file mode 100644 index 0000000..0ae83b8 --- /dev/null +++ b/adjutant_ui/content/token/templates/token/_emailtokenconfirm.html @@ -0,0 +1,33 @@ +{% extends 'token/_tokenconfirm_form.html' %} +{% load i18n %} + +{% block pre_login %} +
+
+
+ {{ block.super }} +{% endblock %} + +{% block login_header %} + {% include 'auth/_splash.html' %} + +{% endblock %} + + +{% block post_login %} + {{ block.super }} +
+
+
+{% endblock %} + +{% block login_body %} + Please confirm the change to your email address. +{% endblock %} + +{% block login_footer %} + +
+{% endblock %} diff --git a/adjutant_ui/content/token/templates/token/emailtokenconfirm.html b/adjutant_ui/content/token/templates/token/emailtokenconfirm.html new file mode 100644 index 0000000..7cac38d --- /dev/null +++ b/adjutant_ui/content/token/templates/token/emailtokenconfirm.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% load i18n %} +{% block title %}{% trans "Confirm email update" %}{% endblock %} + +{% block body_id %}splash{% endblock %} + +{% block content %} + {% include 'token/_emailtokenconfirm.html' %} +{% endblock %} + +{% comment %}Explicitly redeclare the piwik block as empty{% endcomment %} +{% block piwik %}{% endblock %} diff --git a/adjutant_ui/content/token/views.py b/adjutant_ui/content/token/views.py index 200f34f..58c7b48 100644 --- a/adjutant_ui/content/token/views.py +++ b/adjutant_ui/content/token/views.py @@ -51,6 +51,10 @@ def submit_token_router(request, *args, **kwargs): if 'password' in json['required_fields']: return SubmitTokenPasswordView.as_view()(request, *args, **kwargs) elif 'confirm' in json['required_fields']: + + if 'UpdateUserEmailAction' in json['actions']: + return UpdateEmailTokenSubmitView.as_view()( + request, *args, **kwargs) return SubmitTokenConfirmView.as_view()(request, *args, **kwargs) return _logout_msg_response(request, _("Unsupported token type.")) @@ -101,6 +105,7 @@ class SubmitTokenPasswordView(forms.ModalFormView): class SubmitTokenConfirmView(forms.ModalFormView): form_class = token_forms.ConfirmForm template_name = 'token/tokenconfirm.html' + success_msg = _("Welcome to the project! Please log in to continue.") def get(self, request, *args, **kwargs): sc = super(SubmitTokenConfirmView, self) @@ -120,10 +125,9 @@ class SubmitTokenConfirmView(forms.ModalFormView): parameters) if token_response.ok: - msg = _("Welcome to the project! Please log in to continue.") - return _logout_msg_response_success(form.request, msg) + return _logout_msg_response_success(form.request, self.success_msg) - msg = (_("Invitation accept form submission failed. " + msg = (_("Token form submission failed. " "Response code %(code)s.") % {'code': token_response.status_code}) return _logout_msg_response(form.request, msg) @@ -136,3 +140,8 @@ class SubmitTokenConfirmView(forms.ModalFormView): except Exception: exceptions.handle(self.request) return context + + +class UpdateEmailTokenSubmitView(SubmitTokenConfirmView): + template_name = 'token/emailtokenconfirm.html' + success_msg = _("Your email has been updated! Please log in to continue.") diff --git a/adjutant_ui/enabled/_6070_settings_update_email.py b/adjutant_ui/enabled/_6070_settings_update_email.py new file mode 100644 index 0000000..6229ba2 --- /dev/null +++ b/adjutant_ui/enabled/_6070_settings_update_email.py @@ -0,0 +1,9 @@ +# The slug of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'email' +# The slug of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'settings' +# The slug of the panel group the PANEL is associated with. +PANEL_GROUP = 'default' + +# Python panel class of the PANEL to be added. +ADD_PANEL = 'adjutant_ui.content.email.panel.EmailPanel'