From f127a29d62c095599731c54e4292c8d401459c34 Mon Sep 17 00:00:00 2001 From: Sven Marnach <sven@marnach.net> Date: Wed, 5 Apr 2017 21:25:04 +0200 Subject: [PATCH] Add feature flag to disable email address changes. --- .../templates/static_content.html | 4 ++ lms/envs/common.py | 3 ++ .../account_settings_factory_spec.js | 5 +- lms/static/js/spec/student_account/helpers.js | 2 + .../views/account_settings_factory.js | 47 +++++++++++++------ lms/static/sass/views/_account-settings.scss | 4 +- .../student_account/account_settings.html | 12 +++-- .../core/djangoapps/user_api/accounts/api.py | 2 + .../user_api/accounts/tests/test_api.py | 10 ++++ 9 files changed, 69 insertions(+), 20 deletions(-) diff --git a/common/djangoapps/pipeline_mako/templates/static_content.html b/common/djangoapps/pipeline_mako/templates/static_content.html index 1af6ee8a140..39318c8ebbc 100644 --- a/common/djangoapps/pipeline_mako/templates/static_content.html +++ b/common/djangoapps/pipeline_mako/templates/static_content.html @@ -193,3 +193,7 @@ else: <%def name="get_tech_support_email_address()"><% return get_value('email_from_address', settings.TECH_SUPPORT_EMAIL) %></%def> + +<%def name="get_contact_email_address()"><% + return get_value('email_from_address', settings.CONTACT_EMAIL) +%></%def> diff --git a/lms/envs/common.py b/lms/envs/common.py index bec8589139a..97aaec66cf5 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -387,6 +387,9 @@ FEATURES = { # Whether to display account activation notification on dashboard. 'DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR': False, + + # Allow users to change their email address. + 'ALLOW_EMAIL_ADDRESS_CHANGE': True, } # Ignore static asset files on import which match this pattern diff --git a/lms/static/js/spec/student_account/account_settings_factory_spec.js b/lms/static/js/spec/student_account/account_settings_factory_spec.js index 95fd417b37f..4b098bf8db6 100644 --- a/lms/static/js/spec/student_account/account_settings_factory_spec.js +++ b/lms/static/js/spec/student_account/account_settings_factory_spec.js @@ -22,7 +22,10 @@ define(['backbone', Helpers.PASSWORD_RESET_SUPPORT_LINK, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL, - Helpers.PLATFORM_NAME + 1, + Helpers.PLATFORM_NAME, + Helpers.CONTACT_EMAIL, + true ); return context.accountSettingsView; }; diff --git a/lms/static/js/spec/student_account/helpers.js b/lms/static/js/spec/student_account/helpers.js index 7978f01a2da..6660e07b80c 100644 --- a/lms/static/js/spec/student_account/helpers.js +++ b/lms/static/js/spec/student_account/helpers.js @@ -9,6 +9,7 @@ define(['underscore'], function(_) { var FIND_COURSES_URL = '/courses'; var PASSWORD_RESET_SUPPORT_LINK = 'https://support.edx.org/hc/en-us/articles/206212088-What-if-I-did-not-receive-a-password-reset-message-'; // eslint-disable-line max-len var PLATFORM_NAME = 'edX'; + var CONTACT_EMAIL = 'info@example.com'; var PROFILE_IMAGE = { image_url_large: '/media/profile-images/image.jpg', has_image: true @@ -160,6 +161,7 @@ define(['underscore'], function(_) { IMAGE_REMOVE_API_URL: IMAGE_REMOVE_API_URL, PASSWORD_RESET_SUPPORT_LINK: PASSWORD_RESET_SUPPORT_LINK, PLATFORM_NAME: PLATFORM_NAME, + CONTACT_EMAIL: CONTACT_EMAIL, PROFILE_IMAGE: PROFILE_IMAGE, FIELD_OPTIONS: FIELD_OPTIONS, TIME_ZONE_RESPONSE: TIME_ZONE_RESPONSE, diff --git a/lms/static/js/student_account/views/account_settings_factory.js b/lms/static/js/student_account/views/account_settings_factory.js index 1fa127e78be..4e5abcb9703 100644 --- a/lms/static/js/student_account/views/account_settings_factory.js +++ b/lms/static/js/student_account/views/account_settings_factory.js @@ -17,11 +17,14 @@ userAccountsApiUrl, userPreferencesApiUrl, accountUserId, - platformName + platformName, + contactEmail, + allowEmailChange ) { var accountSettingsElement, userAccountModel, userPreferencesModel, aboutSectionsData, accountsSectionData, ordersSectionData, accountSettingsView, showAccountSettingsPage, - showLoadingError, orderNumber, getUserField, userFields, timeZoneDropdownField, countryDropdownField; + showLoadingError, orderNumber, getUserField, userFields, timeZoneDropdownField, countryDropdownField, + emailFieldView; accountSettingsElement = $('.wrapper-account-settings'); @@ -31,6 +34,33 @@ userPreferencesModel = new UserPreferencesModel(); userPreferencesModel.url = userPreferencesApiUrl; + if (allowEmailChange) { + emailFieldView = { + view: new AccountSettingsFieldViews.EmailFieldView({ + model: userAccountModel, + title: gettext('Email Address'), + valueAttribute: 'email', + helpMessage: StringUtils.interpolate( + gettext('The email address you use to sign in. Communications from {platform_name} and your courses are sent to this address.'), // eslint-disable-line max-len + {platform_name: platformName} + ), + persistChanges: true + }) + }; + } else { + emailFieldView = { + view: new AccountSettingsFieldViews.ReadonlyFieldView({ + model: userAccountModel, + title: gettext('Email Address'), + valueAttribute: 'email', + helpMessage: StringUtils.interpolate( + gettext('The email address you use to sign in. Communications from {platform_name} and your courses are sent to this address. To change the email address, please contact {contact_email}.'), // eslint-disable-line max-len + {platform_name: platformName, contact_email: contactEmail} + ) + }) + }; + } + aboutSectionsData = [ { title: gettext('Basic Account Information'), @@ -58,18 +88,7 @@ persistChanges: true }) }, - { - view: new AccountSettingsFieldViews.EmailFieldView({ - model: userAccountModel, - title: gettext('Email Address'), - valueAttribute: 'email', - helpMessage: StringUtils.interpolate( - gettext('The email address you use to sign in. Communications from {platform_name} and your courses are sent to this address.'), // eslint-disable-line max-len - {platform_name: platformName} - ), - persistChanges: true - }) - }, + emailFieldView, { view: new AccountSettingsFieldViews.PasswordFieldView({ model: userAccountModel, diff --git a/lms/static/sass/views/_account-settings.scss b/lms/static/sass/views/_account-settings.scss index 03b7e7922d5..4bb819ccc56 100644 --- a/lms/static/sass/views/_account-settings.scss +++ b/lms/static/sass/views/_account-settings.scss @@ -184,7 +184,9 @@ line-height: normal; } - #u-field-value-username { + // This should only apply for the email field if email address + // changes are disabled, so we explicitly specify "span". + #u-field-value-username, span#u-field-value-email { padding-top: ($baseline/2); } } diff --git a/lms/templates/student_account/account_settings.html b/lms/templates/student_account/account_settings.html index fdfd520aaaf..5c92f0577cd 100644 --- a/lms/templates/student_account/account_settings.html +++ b/lms/templates/student_account/account_settings.html @@ -33,9 +33,11 @@ from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_str <%block name="js_extra"> <%static:require_module module_name="js/student_account/views/account_settings_factory" class_name="AccountSettingsFactory"> var fieldsData = ${ fields | n, dump_js_escaped_json }, - ordersHistoryData = ${ order_history | n, dump_js_escaped_json }, - authData = ${ auth | n, dump_js_escaped_json }, - platformName = '${ static.get_platform_name() | n, js_escaped_string }'; + ordersHistoryData = ${ order_history | n, dump_js_escaped_json }, + authData = ${ auth | n, dump_js_escaped_json }, + platformName = '${ static.get_platform_name() | n, js_escaped_string }', + contactEmail = '${ static.get_contact_email_address() | n, js_escaped_string }', + allowEmailChange = ${ bool(settings.FEATURES['ALLOW_EMAIL_ADDRESS_CHANGE']) | n, dump_js_escaped_json }; AccountSettingsFactory( fieldsData, @@ -45,7 +47,9 @@ from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_str '${ user_accounts_api_url | n, js_escaped_string }', '${ user_preferences_api_url | n, js_escaped_string }', ${ user.id | n, dump_js_escaped_json }, - platformName + platformName, + contactEmail, + allowEmailChange ); </%static:require_module> </%block> diff --git a/openedx/core/djangoapps/user_api/accounts/api.py b/openedx/core/djangoapps/user_api/accounts/api.py index fe9754f88f7..543a319a7d3 100644 --- a/openedx/core/djangoapps/user_api/accounts/api.py +++ b/openedx/core/djangoapps/user_api/accounts/api.py @@ -231,6 +231,8 @@ def update_account_settings(requesting_user, update, username=None): # And try to send the email change request if necessary. if changing_email: + if not settings.FEATURES['ALLOW_EMAIL_ADDRESS_CHANGE']: + raise AccountUpdateError(u"Email address changes have been disabled by the site operators.") try: student_views.do_email_change_request(existing_user, new_email) except ValueError as err: diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_api.py b/openedx/core/djangoapps/user_api/accounts/tests/test_api.py index 21dc1dc92b6..6b646be6e26 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_api.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_api.py @@ -193,6 +193,16 @@ class TestAccountApi(UserSettingsEventTestMixin, TestCase): account_settings = get_account_settings(self.default_request)[0] self.assertEqual("Mickey Mouse", account_settings["name"]) + @patch.dict(settings.FEATURES, dict(ALLOW_EMAIL_ADDRESS_CHANGE=False)) + def test_email_changes_disabled(self): + """ + Test that email address changes are rejected when ALLOW_EMAIL_ADDRESS_CHANGE is not set. + """ + disabled_update = {"email": "valid@example.com"} + with self.assertRaises(AccountUpdateError) as context_manager: + update_account_settings(self.user, disabled_update) + self.assertIn("Email address changes have been disabled", context_manager.exception.developer_message) + @patch('openedx.core.djangoapps.user_api.accounts.serializers.AccountUserSerializer.save') def test_serializer_save_fails(self, serializer_save): """ -- GitLab