Consolidate recovery assistance forms
This commit is contained in:
@@ -1,152 +0,0 @@
|
||||
(function(define) {
|
||||
'use strict';
|
||||
define([
|
||||
'jquery',
|
||||
'underscore',
|
||||
'common/js/spec_helpers/template_helpers',
|
||||
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
|
||||
'js/student_account/models/AccountRecoveryModel',
|
||||
'js/student_account/views/AccountRecoveryView'
|
||||
],
|
||||
function($, _, TemplateHelpers, AjaxHelpers, AccountRecoveryModel, AccountRecoveryView) {
|
||||
describe('edx.student.account.AccountRecoveryView', function() {
|
||||
var model = null,
|
||||
view = null,
|
||||
requests = null,
|
||||
EMAIL = 'xsy@edx.org',
|
||||
FORM_DESCRIPTION = {
|
||||
method: 'post',
|
||||
submit_url: '/account/password',
|
||||
fields: [{
|
||||
name: 'email',
|
||||
label: 'Secondary email',
|
||||
defaultValue: '',
|
||||
type: 'text',
|
||||
required: true,
|
||||
placeholder: 'place@holder.org',
|
||||
instructions: 'Enter your secondary email.',
|
||||
restrictions: {}
|
||||
}]
|
||||
};
|
||||
|
||||
var createAccountRecoveryView = function(that) {
|
||||
// Initialize the account recovery model
|
||||
model = new AccountRecoveryModel({}, {
|
||||
url: FORM_DESCRIPTION.submit_url,
|
||||
method: FORM_DESCRIPTION.method
|
||||
});
|
||||
|
||||
// Initialize the account recovery view
|
||||
view = new AccountRecoveryView({
|
||||
fields: FORM_DESCRIPTION.fields,
|
||||
model: model
|
||||
});
|
||||
|
||||
// Spy on AJAX requests
|
||||
requests = AjaxHelpers.requests(that);
|
||||
};
|
||||
|
||||
var submitEmail = function(validationSuccess) {
|
||||
// Create a fake click event
|
||||
var clickEvent = $.Event('click');
|
||||
|
||||
// Simulate manual entry of an email address
|
||||
$('#password-reset-email').val(EMAIL);
|
||||
|
||||
// If validationSuccess isn't passed, we avoid
|
||||
// spying on `view.validate` twice
|
||||
if (!_.isUndefined(validationSuccess)) {
|
||||
// Force validation to return as expected
|
||||
spyOn(view, 'validate').and.returnValue({
|
||||
isValid: validationSuccess,
|
||||
message: 'Submission was validated.'
|
||||
});
|
||||
}
|
||||
|
||||
// Submit the email address
|
||||
view.submitForm(clickEvent);
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
setFixtures('<div id="password-reset-form" class="form-wrapper hidden"></div>');
|
||||
TemplateHelpers.installTemplate('templates/student_account/account_recovery');
|
||||
TemplateHelpers.installTemplate('templates/student_account/form_field');
|
||||
});
|
||||
|
||||
it('allows the user to request account recovery', function() {
|
||||
var syncSpy, passwordEmailSentSpy;
|
||||
|
||||
createAccountRecoveryView(this);
|
||||
|
||||
// We expect these events to be triggered upon a successful account recovery
|
||||
syncSpy = jasmine.createSpy('syncEvent');
|
||||
passwordEmailSentSpy = jasmine.createSpy('passwordEmailSentEvent');
|
||||
view.listenTo(view.model, 'sync', syncSpy);
|
||||
view.listenTo(view, 'account-recovery-email-sent', passwordEmailSentSpy);
|
||||
|
||||
// Submit the form, with successful validation
|
||||
submitEmail(true);
|
||||
|
||||
// Verify that the client contacts the server with the expected data
|
||||
AjaxHelpers.expectRequest(
|
||||
requests, 'POST',
|
||||
FORM_DESCRIPTION.submit_url,
|
||||
$.param({email: EMAIL})
|
||||
);
|
||||
|
||||
// Respond with status code 200
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
|
||||
// Verify that the events were triggered
|
||||
expect(syncSpy).toHaveBeenCalled();
|
||||
expect(passwordEmailSentSpy).toHaveBeenCalled();
|
||||
|
||||
// Verify that account recovery view has been removed
|
||||
expect($(view.el).html().length).toEqual(0);
|
||||
});
|
||||
|
||||
it('validates the email field', function() {
|
||||
createAccountRecoveryView(this);
|
||||
|
||||
// Submit the form, with successful validation
|
||||
submitEmail(true);
|
||||
|
||||
// Verify that validation of the email field occurred
|
||||
expect(view.validate).toHaveBeenCalledWith($('#password-reset-email')[0]);
|
||||
|
||||
// Verify that no submission errors are visible
|
||||
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
|
||||
});
|
||||
|
||||
it('displays account recovery validation errors', function() {
|
||||
createAccountRecoveryView(this);
|
||||
|
||||
// Submit the form, with failed validation
|
||||
submitEmail(false);
|
||||
|
||||
// Verify that submission errors are visible
|
||||
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
|
||||
});
|
||||
|
||||
it('displays error if the server returns an error while sending account recovery email', function() {
|
||||
createAccountRecoveryView(this);
|
||||
submitEmail(true);
|
||||
|
||||
// Simulate an error from the LMS servers
|
||||
AjaxHelpers.respondWithError(requests);
|
||||
|
||||
// Expect that an error is displayed
|
||||
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(1);
|
||||
|
||||
// If we try again and succeed, the error should go away
|
||||
submitEmail();
|
||||
|
||||
// This time, respond with status code 200
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
|
||||
// Expect that the error is hidden
|
||||
expect(view.$formFeedback.find('.' + view.formErrorsJsHook).length).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -15,13 +15,11 @@
|
||||
'js/student_account/views/RegisterView',
|
||||
'js/student_account/views/InstitutionLoginView',
|
||||
'js/student_account/views/HintedLoginView',
|
||||
'js/student_account/views/AccountRecoveryView',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'js/vendor/history'
|
||||
],
|
||||
function($, utility, _, _s, Backbone, LoginModel, PasswordResetModel, RegisterModel, AccountRecoveryModel,
|
||||
LoginView, PasswordResetView, RegisterView, InstitutionLoginView, HintedLoginView, AccountRecoveryView,
|
||||
HtmlUtils) {
|
||||
LoginView, PasswordResetView, RegisterView, InstitutionLoginView, HintedLoginView, HtmlUtils) {
|
||||
return Backbone.View.extend({
|
||||
tpl: '#access-tpl',
|
||||
events: {
|
||||
@@ -69,7 +67,6 @@
|
||||
login: options.login_form_desc,
|
||||
register: options.registration_form_desc,
|
||||
reset: options.password_reset_form_desc,
|
||||
account_recovery: options.account_recovery_form_desc,
|
||||
institution_login: null,
|
||||
hinted_login: null
|
||||
};
|
||||
@@ -125,9 +122,6 @@
|
||||
if (Backbone.history.getHash() === 'forgot-password-modal') {
|
||||
this.resetPassword();
|
||||
}
|
||||
else if (Backbone.history.getHash() === 'account-recovery-modal') {
|
||||
this.accountRecovery();
|
||||
}
|
||||
this.loadForm(this.activeForm);
|
||||
},
|
||||
|
||||
@@ -163,9 +157,6 @@
|
||||
// Listen for 'password-help' event to toggle sub-views
|
||||
this.listenTo(this.subview.login, 'password-help', this.resetPassword);
|
||||
|
||||
// Listen for 'account-recovery-help' event to toggle sub-views
|
||||
this.listenTo(this.subview.login, 'account-recovery-help', this.accountRecovery);
|
||||
|
||||
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
|
||||
this.listenTo(this.subview.login, 'auth-complete', this.authComplete);
|
||||
},
|
||||
@@ -186,24 +177,6 @@
|
||||
$('.password-reset-form').focus();
|
||||
},
|
||||
|
||||
account_recovery: function(data) {
|
||||
this.accountRecoveryModel.ajaxType = data.method;
|
||||
this.accountRecoveryModel.urlRoot = data.submit_url;
|
||||
|
||||
this.subview.accountRecoveryHelp = new AccountRecoveryView({
|
||||
fields: data.fields,
|
||||
model: this.accountRecoveryModel
|
||||
});
|
||||
|
||||
// Listen for 'account-recovery-email-sent' event to toggle sub-views
|
||||
this.listenTo(
|
||||
this.subview.accountRecoveryHelp, 'account-recovery-email-sent', this.passwordEmailSent
|
||||
);
|
||||
|
||||
// Focus on the form
|
||||
$('.password-reset-form').focus();
|
||||
},
|
||||
|
||||
register: function(data) {
|
||||
var model = new RegisterModel({}, {
|
||||
method: data.method,
|
||||
@@ -260,19 +233,6 @@
|
||||
this.element.scrollTop($('#password-reset-anchor'));
|
||||
},
|
||||
|
||||
accountRecovery: function() {
|
||||
if (this.isAccountRecoveryFeatureEnabled) {
|
||||
window.analytics.track('edx.bi.account_recovery.viewed', {
|
||||
category: 'user-engagement'
|
||||
});
|
||||
|
||||
this.element.hide($(this.el).find('#login-anchor'));
|
||||
this.loadForm('account_recovery');
|
||||
this.element.scrollTop($('#password-reset-anchor'));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
toggleForm: function(e) {
|
||||
var type = $(e.currentTarget).data('type'),
|
||||
$form = $('#' + type + '-form'),
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
(function(define) {
|
||||
'use strict';
|
||||
define([
|
||||
'jquery',
|
||||
'js/student_account/views/FormView'
|
||||
],
|
||||
function($, FormView) {
|
||||
return FormView.extend({
|
||||
el: '#password-reset-form',
|
||||
|
||||
tpl: '#account_recovery-tpl',
|
||||
|
||||
events: {
|
||||
'click .js-reset': 'submitForm'
|
||||
},
|
||||
|
||||
formType: 'password-reset',
|
||||
|
||||
requiredStr: '',
|
||||
optionalStr: '',
|
||||
|
||||
submitButton: '.js-reset',
|
||||
|
||||
preRender: function() {
|
||||
this.element.show($(this.el));
|
||||
this.element.show($(this.el).parent());
|
||||
this.listenTo(this.model, 'sync', this.saveSuccess);
|
||||
},
|
||||
|
||||
saveSuccess: function() {
|
||||
this.trigger('account-recovery-email-sent');
|
||||
|
||||
// Destroy the view (but not el) and unbind events
|
||||
this.$el.empty().off();
|
||||
this.stopListening();
|
||||
}
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -139,12 +139,6 @@
|
||||
this.trigger('password-help');
|
||||
},
|
||||
|
||||
accountRecovery: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.trigger('account-recovery-help');
|
||||
},
|
||||
|
||||
getFormData: function() {
|
||||
var obj = {},
|
||||
$form = this.$form,
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
events: {
|
||||
'click .js-login': 'submitForm',
|
||||
'click .forgot-password': 'forgotPassword',
|
||||
'click .account-recovery': 'accountRecovery',
|
||||
'click .login-provider': 'thirdPartyAuth'
|
||||
},
|
||||
formType: 'login',
|
||||
@@ -137,13 +136,6 @@
|
||||
this.clearPasswordResetSuccess();
|
||||
},
|
||||
|
||||
accountRecovery: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.trigger('account-recovery-help');
|
||||
this.clearPasswordResetSuccess();
|
||||
},
|
||||
|
||||
postFormSubmission: function() {
|
||||
this.clearPasswordResetSuccess();
|
||||
},
|
||||
@@ -152,7 +144,7 @@
|
||||
var email = $('#password-reset-email').val(),
|
||||
successTitle = gettext('Check Your Email'),
|
||||
successMessageHtml = HtmlUtils.interpolateHtml(
|
||||
gettext('{paragraphStart}You entered {boldStart}{email}{boldEnd}. If this email address is associated with your {platform_name} account, we will send a message with password reset instructions to this email address.{paragraphEnd}' + // eslint-disable-line max-len
|
||||
gettext('{paragraphStart}You entered {boldStart}{email}{boldEnd}. If this email address is associated with your {platform_name} account, we will send a message with password recovery instructions to this email address.{paragraphEnd}' + // eslint-disable-line max-len
|
||||
'{paragraphStart}If you do not receive a password reset message, verify that you entered the correct email address, or check your spam folder.{paragraphEnd}' + // eslint-disable-line max-len
|
||||
'{paragraphStart}If you need further assistance, {anchorStart}contact technical support{anchorEnd}.{paragraphEnd}'), { // eslint-disable-line max-len
|
||||
boldStart: HtmlUtils.HTML('<b>'),
|
||||
|
||||
@@ -787,7 +787,6 @@
|
||||
'js/spec/student_account/login_spec.js',
|
||||
'js/spec/student_account/logistration_factory_spec.js',
|
||||
'js/spec/student_account/password_reset_spec.js',
|
||||
'js/spec/student_account/account_recovery_spec.js',
|
||||
'js/spec/student_account/register_spec.js',
|
||||
'js/spec/student_account/shoppingcart_spec.js',
|
||||
'js/spec/verify_student/image_input_spec.js',
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
## mako
|
||||
|
||||
<%page expression_filter="h"/>
|
||||
|
||||
<%!
|
||||
from django.utils.translation import ugettext as _
|
||||
from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
%>
|
||||
|
||||
<%inherit file="../main.html"/>
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
<%block name="title">
|
||||
<title>${_("Create Your {platform_name} Password").format(platform_name=platform_name)}</title>
|
||||
</%block>
|
||||
|
||||
<%block name="head_extra">
|
||||
<link type="text/css" rel="stylesheet" href="${STATIC_URL}paragon/static/paragon.min.css">
|
||||
</%block>
|
||||
|
||||
<%block name="bodyclass">view-passwordreset</%block>
|
||||
|
||||
<%block name="body">
|
||||
<div id="password-reset-confirm-container" class="login-register-content login-register">
|
||||
% if validlink:
|
||||
${static.renderReact(
|
||||
component="PasswordResetConfirmation",
|
||||
id="password-reset-confirm-react",
|
||||
props={
|
||||
'csrfToken': csrf_token,
|
||||
'errorMessage': js_escaped_string(err_msg) if err_msg else '',
|
||||
'primaryActionButtonLabel': 'Create My Password',
|
||||
'formTitle': 'Create Your Password',
|
||||
},
|
||||
)}
|
||||
% else:
|
||||
<div class="status submission-error">
|
||||
<h4 class="message-title">${_("Invalid Password Create Link")}</h4>
|
||||
<ul class="message-copy">
|
||||
${Text(_((
|
||||
"This password create link is invalid. It may have been used already. "
|
||||
"To create your password, go to the {start_link}sign-in{end_link} page and "
|
||||
"select {start_strong}Recovery your account{end_strong}."
|
||||
))).format(
|
||||
start_link=HTML('<a href="/login">'),
|
||||
end_link=HTML('</a>'),
|
||||
start_strong=HTML('<strong>'),
|
||||
end_strong=HTML('</strong>')
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
</%block>
|
||||
@@ -1,13 +0,0 @@
|
||||
<div class="js-form-feedback" aria-live="assertive" tabindex="-1">
|
||||
</div>
|
||||
|
||||
<h2><%- gettext("Account Recovery") %></h2>
|
||||
|
||||
<form id="account-recovery" class="account-recovery-form password-reset-form" tabindex="-1" method="POST">
|
||||
|
||||
<p class="action-label"><%- gettext("Please enter your secondary email address below and we will send you instructions for recovering your account and setting a new password.") %></p>
|
||||
|
||||
<%= HtmlUtils.HTML(fields) %>
|
||||
|
||||
<button type="submit" class="action action-primary action-update js-reset"><%- gettext("Recover my account") %></button>
|
||||
</form>
|
||||
@@ -133,6 +133,6 @@
|
||||
<% } %>
|
||||
|
||||
<% if( form === 'login' && name === 'password' ) { %>
|
||||
<button type="button" class="forgot-password field-link"><%- gettext("Forgot password?") %></button>
|
||||
<button type="button" class="forgot-password field-link"><%- gettext("Need help logging in?") %></button>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</%block>
|
||||
|
||||
<%block name="header_extras">
|
||||
% for template_name in ["account", "access", "form_field", "login", "register", "institution_login", "institution_register", "password_reset", "account_recovery", "hinted_login"]:
|
||||
% for template_name in ["account", "access", "form_field", "login", "register", "institution_login", "institution_register", "password_reset", "hinted_login"]:
|
||||
<script type="text/template" id="${template_name}-tpl">
|
||||
<%static:include path="student_account/${template_name}.underscore" />
|
||||
</script>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
<form id="password-reset" class="password-reset-form" tabindex="-1" method="POST">
|
||||
|
||||
<p class="action-label"><%- gettext("Please enter your email address below and we will send you instructions for setting a new password.") %></p>
|
||||
<p class="action-label"><%- gettext("Please enter your registration or recovery email address below and we will send you an email with instructions.") %></p>
|
||||
|
||||
<%= fields %>
|
||||
<%= HtmlUtils.HTML(fields) %>
|
||||
|
||||
<button type="submit" class="action action-primary action-update js-reset"><%- gettext("Reset my password") %></button>
|
||||
<button type="submit" class="action action-primary action-update js-reset"><%- gettext("Recover my password") %></button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user