Commit a4342070 by AlasdairSwan

ECOM-783 updated logistration in light of redesign

parent 8d577563
...@@ -12,7 +12,7 @@ describe('edx.utils.validate', function () { ...@@ -12,7 +12,7 @@ describe('edx.utils.validate', function () {
EMAIL_ERROR_FRAGMENT = 'formatted', EMAIL_ERROR_FRAGMENT = 'formatted',
MIN_ERROR_FRAGMENT = 'least', MIN_ERROR_FRAGMENT = 'least',
MAX_ERROR_FRAGMENT = 'up to', MAX_ERROR_FRAGMENT = 'up to',
REQUIRED_ERROR_FRAGMENT = 'empty', REQUIRED_ERROR_FRAGMENT = 'Please enter your',
CUSTOM_MESSAGE = 'custom message'; CUSTOM_MESSAGE = 'custom message';
var createFixture = function( type, name, required, minlength, maxlength, value ) { var createFixture = function( type, name, required, minlength, maxlength, value ) {
......
...@@ -19,9 +19,9 @@ var edx = edx || {}; ...@@ -19,9 +19,9 @@ var edx = edx || {};
msg: { msg: {
email: '<li><%- gettext("The email address you\'ve provided isn\'t formatted correctly.") %></li>', email: '<li><%- gettext("The email address you\'ve provided isn\'t formatted correctly.") %></li>',
min: '<li><%- _.sprintf(gettext("%(field)s must have at least %(count)d characters."), context) %></li>', min: '<li><%- _.sprintf( gettext("%(field)s must have at least %(count)d characters."), context ) %></li>',
max: '<li><%- _.sprintf(gettext("%(field)s can only contain up to %(count)d characters."), context) %></li>', max: '<li><%- _.sprintf( gettext("%(field)s can only contain up to %(count)d characters."), context ) %></li>',
required: '<li><%- _.sprintf(gettext("The %(field)s field cannot be empty."), context) %></li>', required: '<li><%- _.sprintf( gettext("Please enter your %(field)s."), context ) %></li>',
custom: '<li><%= content %></li>' custom: '<li><%= content %></li>'
}, },
......
...@@ -120,8 +120,8 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -120,8 +120,8 @@ class CombinedLoginAndRegisterPage(PageObject):
def is_browser_on_page(self): def is_browser_on_page(self):
"""Check whether the combined login/registration page has loaded. """ """Check whether the combined login/registration page has loaded. """
return ( return (
self.q(css="#register-option").is_present() and self.q(css="#login-anchor").is_present() and
self.q(css="#login-option").is_present() and self.q(css="#register-anchor").is_present() and
self.current_form is not None self.current_form is not None
) )
...@@ -130,7 +130,10 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -130,7 +130,10 @@ class CombinedLoginAndRegisterPage(PageObject):
old_form = self.current_form old_form = self.current_form
# Toggle the form # Toggle the form
self.q(css=".form-toggle:not(:checked)").click() if old_form == "login":
self.q(css=".form-toggle[data-type='register']").click()
else:
self.q(css=".form-toggle[data-type='login']").click()
# Wait for the form to change before returning # Wait for the form to change before returning
EmptyPromise( EmptyPromise(
...@@ -157,9 +160,9 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -157,9 +160,9 @@ class CombinedLoginAndRegisterPage(PageObject):
""" """
# Fill in the form # Fill in the form
self.q(css="#register-email").fill(email) self.q(css="#register-email").fill(email)
self.q(css="#register-password").fill(password)
self.q(css="#register-username").fill(username)
self.q(css="#register-name").fill(full_name) self.q(css="#register-name").fill(full_name)
self.q(css="#register-username").fill(username)
self.q(css="#register-password").fill(password)
if country: if country:
self.q(css="#register-country option[value='{country}']".format(country=country)).click() self.q(css="#register-country option[value='{country}']".format(country=country)).click()
if (terms_of_service): if (terms_of_service):
...@@ -168,7 +171,7 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -168,7 +171,7 @@ class CombinedLoginAndRegisterPage(PageObject):
# Submit it # Submit it
self.q(css=".register-button").click() self.q(css=".register-button").click()
def login(self, email="", password="", remember_me=True): def login(self, email="", password=""):
"""Fills in and submits the login form. """Fills in and submits the login form.
Requires that the "login" form is visible. Requires that the "login" form is visible.
...@@ -179,14 +182,11 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -179,14 +182,11 @@ class CombinedLoginAndRegisterPage(PageObject):
Keyword Arguments: Keyword Arguments:
email (unicode): The user's email address. email (unicode): The user's email address.
password (unicode): The user's password. password (unicode): The user's password.
remember_me (boolean): If True, check the "remember me" box.
""" """
# Fill in the form # Fill in the form
self.q(css="#login-email").fill(email) self.q(css="#login-email").fill(email)
self.q(css="#login-password").fill(password) self.q(css="#login-password").fill(password)
if remember_me:
self.q(css="#login-remember").click()
# Submit it # Submit it
self.q(css=".login-button").click() self.q(css=".login-button").click()
...@@ -217,6 +217,8 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -217,6 +217,8 @@ class CombinedLoginAndRegisterPage(PageObject):
# Submit it # Submit it
self.q(css="button.js-reset").click() self.q(css="button.js-reset").click()
return CombinedLoginAndRegisterPage(self.browser).wait_for_page()
@property @property
@unguarded @unguarded
def current_form(self): def current_form(self):
...@@ -233,7 +235,7 @@ class CombinedLoginAndRegisterPage(PageObject): ...@@ -233,7 +235,7 @@ class CombinedLoginAndRegisterPage(PageObject):
return "register" return "register"
elif self.q(css=".login-button").visible: elif self.q(css=".login-button").visible:
return "login" return "login"
elif self.q(css=".js-reset").visible or self.q(css=".js-reset-success").visible: elif self.q(css=".js-reset").visible:
return "password-reset" return "password-reset"
@property @property
......
...@@ -218,9 +218,9 @@ class RegisterFromCombinedPageTest(UniqueCourseTest): ...@@ -218,9 +218,9 @@ class RegisterFromCombinedPageTest(UniqueCourseTest):
# Verify that the expected errors are displayed. # Verify that the expected errors are displayed.
errors = self.register_page.wait_for_errors() errors = self.register_page.wait_for_errors()
self.assertIn(u'The Username field cannot be empty.', errors) self.assertIn(u'Please enter your Public username.', errors)
self.assertIn(u'You must agree to the edX Terms of Service and Honor Code.', errors) self.assertIn(u'You must agree to the edX Terms of Service and Honor Code.', errors)
self.assertIn(u'The Country field cannot be empty.', errors) self.assertIn(u'Please select your Country.', errors)
def test_toggle_to_login_form(self): def test_toggle_to_login_form(self):
self.register_page.visit().toggle_form() self.register_page.visit().toggle_form()
......
@shard_1 @shard_1
Feature: LMS.Homepage for web users Feature: LMS.Homepage for web users
In order to get an idea what edX is about In order to get an idea what edX is about
As a an anonymous web user As an anonymous web user
I want to check the information on the home page I want to check the information on the home page
Scenario: User can see the "Login" button Scenario: User can see the "Sign in" button
Given I visit the homepage Given I visit the homepage
Then I should see a link called "Log in" Then I should see a link called "Sign in"
Scenario: User can see the "Register Now" button Scenario: User can see the "Register Now" button
Given I visit the homepage Given I visit the homepage
......
...@@ -8,7 +8,7 @@ Feature: LMS.Login in as a registered user ...@@ -8,7 +8,7 @@ Feature: LMS.Login in as a registered user
Given I am an edX user Given I am an edX user
And I am an unactivated user And I am an unactivated user
And I visit the homepage And I visit the homepage
When I click the link with the text "Log in" When I click the link with the text "Sign in"
And I submit my credentials on the login form And I submit my credentials on the login form
Then I should see the login error message "This account has not been activated" Then I should see the login error message "This account has not been activated"
...@@ -18,15 +18,15 @@ Feature: LMS.Login in as a registered user ...@@ -18,15 +18,15 @@ Feature: LMS.Login in as a registered user
Given I am an edX user Given I am an edX user
And I am an activated user And I am an activated user
And I visit the homepage And I visit the homepage
When I click the link with the text "Log in" When I click the link with the text "Sign in"
And I submit my credentials on the login form And I submit my credentials on the login form
Then I should be on the dashboard page Then I should be on the dashboard page
Scenario: Logout of a signed in account Scenario: Logout of a signed in account
Given I am logged in Given I am logged in
When I click the dropdown arrow When I click the dropdown arrow
And I click the link with the text "Log Out" And I click the link with the text "Sign out"
Then I should see a link with the text "Log in" Then I should see a link with the text "Sign in"
And I should see that the path is "/" And I should see that the path is "/"
Scenario: Login with valid redirect Scenario: Login with valid redirect
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
'string_utils': 'xmodule_js/common_static/js/src/string_utils', 'string_utils': 'xmodule_js/common_static/js/src/string_utils',
// Manually specify LMS files that are not converted to RequireJS // Manually specify LMS files that are not converted to RequireJS
'history': 'js/vendor/history',
'js/verify_student/photocapture': 'js/verify_student/photocapture', 'js/verify_student/photocapture': 'js/verify_student/photocapture',
'js/staff_debug_actions': 'js/staff_debug_actions', 'js/staff_debug_actions': 'js/staff_debug_actions',
...@@ -372,6 +373,7 @@ ...@@ -372,6 +373,7 @@
'underscore', 'underscore',
'backbone', 'backbone',
'gettext', 'gettext',
'history',
'utility', 'utility',
'js/student_account/views/LoginView', 'js/student_account/views/LoginView',
'js/student_account/views/PasswordResetView', 'js/student_account/views/PasswordResetView',
......
...@@ -96,13 +96,13 @@ define([ ...@@ -96,13 +96,13 @@ define([
var assertForms = function(visibleType, hiddenType) { var assertForms = function(visibleType, hiddenType) {
expect($(visibleType)).not.toHaveClass('hidden'); expect($(visibleType)).not.toHaveClass('hidden');
expect($(hiddenType)).toHaveClass('hidden'); expect($(hiddenType)).toHaveClass('hidden');
expect($('#password-reset-wrapper')).toBeEmpty(); expect($('#password-reset-form')).toHaveClass('hidden');
}; };
var selectForm = function(type) { var selectForm = function(type) {
// Create a fake change event to control form toggling // Create a fake change event to control form toggling
var changeEvent = $.Event('change'); var changeEvent = $.Event('change');
changeEvent.currentTarget = $('#' + type + '-option'); changeEvent.currentTarget = $('.form-toggle[data-type="' + type + '"]');
// Load form corresponding to the change event // Load form corresponding to the change event
view.toggleForm(changeEvent); view.toggleForm(changeEvent);
...@@ -133,9 +133,7 @@ define([ ...@@ -133,9 +133,7 @@ define([
TemplateHelpers.installTemplate('templates/student_account/form_field'); TemplateHelpers.installTemplate('templates/student_account/form_field');
// Stub analytics tracking // Stub analytics tracking
// TODO: use RequireJS to ensure that this is loaded correctly window.analytics = jasmine.createSpyObj('analytics', ['track', 'page', 'pageview', 'trackLink']);
window.analytics = window.analytics || {};
window.analytics.track = window.analytics.track || function() {};
}); });
it('can initially display the login form', function() { it('can initially display the login form', function() {
......
...@@ -4,12 +4,14 @@ define([ ...@@ -4,12 +4,14 @@ define([
'js/common_helpers/template_helpers', 'js/common_helpers/template_helpers',
'js/common_helpers/ajax_helpers', 'js/common_helpers/ajax_helpers',
'js/student_account/models/LoginModel', 'js/student_account/models/LoginModel',
'js/student_account/views/LoginView' 'js/student_account/views/LoginView',
], function($, _, TemplateHelpers, AjaxHelpers, LoginModel, LoginView) { 'js/student_account/models/PasswordResetModel'
], function($, _, TemplateHelpers, AjaxHelpers, LoginModel, LoginView, PasswordResetModel) {
'use strict'; 'use strict';
describe('edx.student.account.LoginView', function() { describe('edx.student.account.LoginView', function() {
var model = null, var model = null,
resetModel = null,
view = null, view = null,
requests = null, requests = null,
authComplete = false, authComplete = false,
...@@ -79,10 +81,17 @@ define([ ...@@ -79,10 +81,17 @@ define([
method: FORM_DESCRIPTION.method method: FORM_DESCRIPTION.method
}); });
// Initialize the passwordReset model
resetModel = new PasswordResetModel({}, {
method: 'GET',
url: '#'
});
// Initialize the login view // Initialize the login view
view = new LoginView({ view = new LoginView({
fields: FORM_DESCRIPTION.fields, fields: FORM_DESCRIPTION.fields,
model: model, model: model,
resetModel: resetModel,
thirdPartyAuth: THIRD_PARTY_AUTH, thirdPartyAuth: THIRD_PARTY_AUTH,
platformName: PLATFORM_NAME platformName: PLATFORM_NAME
}); });
......
...@@ -67,7 +67,7 @@ define([ ...@@ -67,7 +67,7 @@ define([
}; };
beforeEach(function() { beforeEach(function() {
setFixtures('<div id="password-reset-wrapper"></div>'); setFixtures('<div id="password-reset-form" class="form-wrapper hidden"></div>');
TemplateHelpers.installTemplate('templates/student_account/password_reset'); TemplateHelpers.installTemplate('templates/student_account/password_reset');
TemplateHelpers.installTemplate('templates/student_account/form_field'); TemplateHelpers.installTemplate('templates/student_account/form_field');
}); });
...@@ -90,6 +90,12 @@ define([ ...@@ -90,6 +90,12 @@ define([
// Verify that the success message is visible // Verify that the success message is visible
expect($('.js-reset-success')).not.toHaveClass('hidden'); expect($('.js-reset-success')).not.toHaveClass('hidden');
// Verify that login form has loaded
expect($('#login-form')).not.toHaveClass('hidden');
// Verify that password reset view has been removed
expect($( view.el ).html().length).toEqual(0);
}); });
it('validates the email field', function() { it('validates the email field', function() {
......
...@@ -21,7 +21,7 @@ var edx = edx || {}; ...@@ -21,7 +21,7 @@ var edx = edx || {};
this.urlRoot = options.url; this.urlRoot = options.url;
}, },
sync: function(method, model) { sync: function( method, model ) {
var headers = { var headers = {
'X-CSRFToken': $.cookie('csrftoken') 'X-CSRFToken': $.cookie('csrftoken')
}; };
......
...@@ -6,13 +6,21 @@ var edx = edx || {}; ...@@ -6,13 +6,21 @@ var edx = edx || {};
edx.student = edx.student || {}; edx.student = edx.student || {};
edx.student.account = edx.student.account || {}; edx.student.account = edx.student.account || {};
// Bind to StateChange Event
History.Adapter.bind( window, 'statechange', function() {
/* Note: We are using History.getState() for legacy browser (IE) support
* using History.js plugin instead of the native event.state
*/
var State = History.getState();
});
edx.student.account.AccessView = Backbone.View.extend({ edx.student.account.AccessView = Backbone.View.extend({
el: '#login-and-registration-container', el: '#login-and-registration-container',
tpl: '#access-tpl', tpl: '#access-tpl',
events: { events: {
'change .form-toggle': 'toggleForm' 'click .form-toggle': 'toggleForm'
}, },
subview: { subview: {
...@@ -37,8 +45,15 @@ var edx = edx || {}; ...@@ -37,8 +45,15 @@ var edx = edx || {};
currentProvider: null, currentProvider: null,
providers: [] providers: []
}; };
this.platformName = obj.platformName; this.platformName = obj.platformName;
// The login view listens for 'sync' events from the reset model
this.resetModel = new edx.student.account.PasswordResetModel({}, {
method: 'GET',
url: '#'
});
this.render(); this.render();
}, },
...@@ -55,7 +70,6 @@ var edx = edx || {}; ...@@ -55,7 +70,6 @@ var edx = edx || {};
postRender: function() { postRender: function() {
// Load the default form // Load the default form
this.loadForm( this.activeForm ); this.loadForm( this.activeForm );
this.$header = $(this.el).find('.js-login-register-header');
}, },
loadForm: function( type ) { loadForm: function( type ) {
...@@ -72,6 +86,7 @@ var edx = edx || {}; ...@@ -72,6 +86,7 @@ var edx = edx || {};
context.subview.login = new edx.student.account.LoginView({ context.subview.login = new edx.student.account.LoginView({
fields: data.fields, fields: data.fields,
model: model, model: model,
resetModel: context.resetModel,
thirdPartyAuth: context.thirdPartyAuth, thirdPartyAuth: context.thirdPartyAuth,
platformName: context.platformName platformName: context.platformName
}); });
...@@ -85,15 +100,16 @@ var edx = edx || {}; ...@@ -85,15 +100,16 @@ var edx = edx || {};
}, },
reset: function( data, context ) { reset: function( data, context ) {
var model = new edx.student.account.PasswordResetModel({}, { context.resetModel.ajaxType = data.method;
method: data.method, context.resetModel.urlRoot = data.submit_url;
url: data.submit_url
});
context.subview.passwordHelp = new edx.student.account.PasswordResetView({ context.subview.passwordHelp = new edx.student.account.PasswordResetView({
fields: data.fields, fields: data.fields,
model: model model: context.resetModel
}); });
// Listen for 'password-email-sent' event to toggle sub-views
context.listenTo( context.subview.passwordHelp, 'password-email-sent', context.passwordEmailSent );
}, },
register: function( data, context ) { register: function( data, context ) {
...@@ -133,15 +149,20 @@ var edx = edx || {}; ...@@ -133,15 +149,20 @@ var edx = edx || {};
}); });
}, },
passwordEmailSent: function() {
this.element.hide( $(this.el).find('#password-reset-anchor') );
this.element.show( $('#login-anchor') );
this.element.scrollTop( $('#login-anchor') );
},
resetPassword: function() { resetPassword: function() {
window.analytics.track('edx.bi.password_reset_form.viewed', { window.analytics.track('edx.bi.password_reset_form.viewed', {
category: 'user-engagement' category: 'user-engagement'
}); });
this.element.hide( this.$header ); this.element.hide( $(this.el).find('#login-anchor') );
this.element.hide( $(this.el).find('.form-type') );
this.loadForm('reset'); this.loadForm('reset');
this.element.scrollTop( $('#password-reset-wrapper') ); this.element.scrollTop( $('#password-reset-anchor') );
}, },
showFormError: function() { showFormError: function() {
...@@ -149,10 +170,12 @@ var edx = edx || {}; ...@@ -149,10 +170,12 @@ var edx = edx || {};
}, },
toggleForm: function( e ) { toggleForm: function( e ) {
var type = $(e.currentTarget).val(), var type = $(e.currentTarget).data('type'),
$form = $('#' + type + '-form'), $form = $('#' + type + '-form'),
$anchor = $('#' + type + '-anchor'); $anchor = $('#' + type + '-anchor');
e.preventDefault();
window.analytics.track('edx.bi.' + type + '_form.toggled', { window.analytics.track('edx.bi.' + type + '_form.toggled', {
category: 'user-engagement' category: 'user-engagement'
}); });
...@@ -161,9 +184,14 @@ var edx = edx || {}; ...@@ -161,9 +184,14 @@ var edx = edx || {};
this.loadForm( type ); this.loadForm( type );
} }
this.element.hide( $(this.el).find('.submission-success') );
this.element.hide( $(this.el).find('.form-wrapper') ); this.element.hide( $(this.el).find('.form-wrapper') );
this.element.show( $form ); this.element.show( $form );
this.element.scrollTop( $anchor ); this.element.scrollTop( $anchor );
// Update url without reloading page
History.pushState( null, document.title, '/account/' + type + '/' );
analytics.page( 'login_and_registration', type );
}, },
/** /**
...@@ -291,8 +319,7 @@ var edx = edx || {}; ...@@ -291,8 +319,7 @@ var edx = edx || {};
*/ */
element: { element: {
hide: function( $el ) { hide: function( $el ) {
$el.addClass('hidden') $el.addClass('hidden');
.attr('aria-hidden', true);
}, },
scrollTop: function( $el ) { scrollTop: function( $el ) {
...@@ -303,8 +330,7 @@ var edx = edx || {}; ...@@ -303,8 +330,7 @@ var edx = edx || {};
}, },
show: function( $el ) { show: function( $el ) {
$el.removeClass('hidden') $el.removeClass('hidden');
.attr('aria-hidden', false);
} }
} }
}); });
......
...@@ -98,8 +98,7 @@ var edx = edx || {}; ...@@ -98,8 +98,7 @@ var edx = edx || {};
element: { element: {
hide: function( $el ) { hide: function( $el ) {
if ( $el ) { if ( $el ) {
$el.addClass('hidden') $el.addClass('hidden');
.attr('aria-hidden', true);
} }
}, },
...@@ -112,8 +111,7 @@ var edx = edx || {}; ...@@ -112,8 +111,7 @@ var edx = edx || {};
show: function( $el ) { show: function( $el ) {
if ( $el ) { if ( $el ) {
$el.removeClass('hidden') $el.removeClass('hidden');
.attr('aria-hidden', false);
} }
} }
}, },
...@@ -148,7 +146,6 @@ var edx = edx || {}; ...@@ -148,7 +146,6 @@ var edx = edx || {};
}, },
getFormData: function() { getFormData: function() {
var obj = {}, var obj = {},
$form = this.$form, $form = this.$form,
elements = $form[0].elements, elements = $form[0].elements,
...@@ -229,6 +226,15 @@ var edx = edx || {}; ...@@ -229,6 +226,15 @@ var edx = edx || {};
} else { } else {
this.toggleErrorMsg( true ); this.toggleErrorMsg( true );
} }
this.postFormSubmission();
},
/* Allows extended views to add custom
* code after form submission
*/
postFormSubmission: function() {
return true;
}, },
toggleErrorMsg: function( show ) { toggleErrorMsg: function( show ) {
......
...@@ -27,8 +27,10 @@ var edx = edx || {}; ...@@ -27,8 +27,10 @@ var edx = edx || {};
this.providers = data.thirdPartyAuth.providers || []; this.providers = data.thirdPartyAuth.providers || [];
this.currentProvider = data.thirdPartyAuth.currentProvider || ''; this.currentProvider = data.thirdPartyAuth.currentProvider || '';
this.platformName = data.platformName; this.platformName = data.platformName;
this.resetModel = data.resetModel;
this.listenTo( this.model, 'sync', this.saveSuccess ); this.listenTo( this.model, 'sync', this.saveSuccess );
this.listenTo( this.resetModel, 'sync', this.resetEmail );
}, },
render: function( html ) { render: function( html ) {
...@@ -55,6 +57,7 @@ var edx = edx || {}; ...@@ -55,6 +57,7 @@ var edx = edx || {};
this.$form = this.$container.find('form'); this.$form = this.$container.find('form');
this.$errors = this.$container.find('.submission-error'); this.$errors = this.$container.find('.submission-error');
this.$resetSuccess = this.$container.find('.js-reset-success');
this.$authError = this.$container.find('.already-authenticated-msg'); this.$authError = this.$container.find('.already-authenticated-msg');
this.$submitButton = this.$container.find(this.submitButton); this.$submitButton = this.$container.find(this.submitButton);
...@@ -71,6 +74,16 @@ var edx = edx || {}; ...@@ -71,6 +74,16 @@ var edx = edx || {};
event.preventDefault(); event.preventDefault();
this.trigger('password-help'); this.trigger('password-help');
this.element.hide( this.$resetSuccess );
},
postFormSubmission: function() {
this.element.hide( this.$resetSuccess );
},
resetEmail: function() {
this.element.hide( this.$errors );
this.element.show( this.$resetSuccess );
}, },
thirdPartyAuth: function( event ) { thirdPartyAuth: function( event ) {
...@@ -81,13 +94,15 @@ var edx = edx || {}; ...@@ -81,13 +94,15 @@ var edx = edx || {};
} }
}, },
saveSuccess: function () { saveSuccess: function() {
this.trigger('auth-complete'); this.trigger('auth-complete');
this.element.hide( this.$resetSuccess );
}, },
saveError: function( error ) { saveError: function( error ) {
this.errors = ['<li>' + error.responseText + '</li>']; this.errors = ['<li>' + error.responseText + '</li>'];
this.setErrors(); this.setErrors();
this.element.hide( this.$resetSuccess );
/* If we've gotten a 403 error, it means that we've successfully /* If we've gotten a 403 error, it means that we've successfully
* authenticated with a third-party provider, but we haven't * authenticated with a third-party provider, but we haven't
......
...@@ -7,7 +7,7 @@ var edx = edx || {}; ...@@ -7,7 +7,7 @@ var edx = edx || {};
edx.student.account = edx.student.account || {}; edx.student.account = edx.student.account || {};
edx.student.account.PasswordResetView = edx.student.account.FormView.extend({ edx.student.account.PasswordResetView = edx.student.account.FormView.extend({
el: '#password-reset-wrapper', el: '#password-reset-form',
tpl: '#password_reset-tpl', tpl: '#password_reset-tpl',
...@@ -22,6 +22,8 @@ var edx = edx || {}; ...@@ -22,6 +22,8 @@ var edx = edx || {};
submitButton: '.js-reset', submitButton: '.js-reset',
preRender: function() { preRender: function() {
this.element.show( $( this.el ) );
this.element.show( $( this.el ).parent() );
this.listenTo( this.model, 'sync', this.saveSuccess ); this.listenTo( this.model, 'sync', this.saveSuccess );
}, },
...@@ -35,12 +37,11 @@ var edx = edx || {}; ...@@ -35,12 +37,11 @@ var edx = edx || {};
}, },
saveSuccess: function() { saveSuccess: function() {
var $el = $(this.el), this.trigger('password-email-sent');
$msg = $el.find('.js-reset-success');
this.element.hide( $el.find('#password-reset-form') ); // Destroy the view (but not el) and unbind events
this.element.show( $msg ); this.$el.empty().off();
this.element.scrollTop( $msg ); this.stopListening();
} }
}); });
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// } // }
html, body { html, body {
background: $body-bg;
font-family: $sans-serif; font-family: $sans-serif;
font-size: 1em; font-size: 1em;
font-style: normal; font-style: normal;
...@@ -11,6 +10,14 @@ html, body { ...@@ -11,6 +10,14 @@ html, body {
//-webkit-font-smoothing: antialiased; //-webkit-font-smoothing: antialiased;
} }
html{
background: white;
}
body {
background: $body-bg;
}
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
color: $base-font-color; color: $base-font-color;
font: normal 1.2em/1.2em $serif; font: normal 1.2em/1.2em $serif;
......
...@@ -68,18 +68,18 @@ $white-t1: rgba($white, 0.25); ...@@ -68,18 +68,18 @@ $white-t1: rgba($white, 0.25);
$white-t2: rgba($white, 0.5); $white-t2: rgba($white, 0.5);
$white-t3: rgba($white, 0.75); $white-t3: rgba($white, 0.75);
$gray: rgb(127,127,127); $gray: rgb(127,127,127); // #7f7f7f
$gray-l1: tint($gray,20%); $gray-l1: tint($gray,20%); // #989898
$gray-l2: tint($gray,40%); $gray-l2: tint($gray,40%); // #b2b2b2
$gray-l3: tint($gray,60%); // #cbcbcb; $gray-l3: tint($gray,60%); // #cbcbcb
$gray-l4: tint($gray,80%); // #e5e5e5; $gray-l4: tint($gray,80%); // #e5e5e5
$gray-l5: tint($gray,90%); // #f2f2f2; $gray-l5: tint($gray,90%); // #f2f2f2
$gray-l6: tint($gray,95%); // #f8f8f8; $gray-l6: tint($gray,95%); // #f8f8f8
$gray-l7: tint($gray,99%); $gray-l7: tint($gray,99%); // #fdfdfd
$gray-d1: shade($gray,20%); $gray-d1: shade($gray,20%); // #656565
$gray-d2: shade($gray,40%); $gray-d2: shade($gray,40%); // #4c4c4c
$gray-d3: shade($gray,60%); $gray-d3: shade($gray,60%); // #323232
$gray-d4: shade($gray,80%); $gray-d4: shade($gray,80%); // #191919
$pink: rgb(182,37,103); $pink: rgb(182,37,103);
$pink-l1: tint($pink,20%); $pink-l1: tint($pink,20%);
...@@ -175,11 +175,13 @@ $m-blue-l2: #42B5E9; ...@@ -175,11 +175,13 @@ $m-blue-l2: #42B5E9;
$m-blue-l3: #59BEEC; $m-blue-l3: #59BEEC;
$m-blue-l4: tint($m-blue,90%); $m-blue-l4: tint($m-blue,90%);
$m-blue-l5: tint($m-blue,95%); $m-blue-l5: tint($m-blue,95%);
$m-blue-l6: #4bb4fb;
$m-blue-d1: #1790C7; $m-blue-d1: #1790C7;
$m-blue-d2: #1580B0; $m-blue-d2: #1580B0;
$m-blue-d3: #126F9A; $m-blue-d3: #126F9A;
$m-blue-d4: #0A4A67; $m-blue-d4: #0A4A67;
$m-blue-d5: #009EE7; $m-blue-d5: #009EE7;
$m-blue-d6: #256A97;
$m-blue-t0: rgba($m-blue,0.125); $m-blue-t0: rgba($m-blue,0.125);
$m-blue-t1: rgba($m-blue,0.25); $m-blue-t1: rgba($m-blue,0.25);
$m-blue-t2: rgba($m-blue,0.50); $m-blue-t2: rgba($m-blue,0.50);
......
...@@ -97,7 +97,6 @@ ...@@ -97,7 +97,6 @@
header_extra_file = 'theme-head-extra.html' header_extra_file = 'theme-head-extra.html'
header_file = 'theme-header.html' header_file = 'theme-header.html'
google_analytics_file = 'theme-google-analytics.html' google_analytics_file = 'theme-google-analytics.html'
footer_file = 'theme-footer.html'
style_overrides_file = None style_overrides_file = None
...@@ -111,12 +110,6 @@ ...@@ -111,12 +110,6 @@
google_analytics_file = microsite.get_template_path('google_analytics.html') google_analytics_file = microsite.get_template_path('google_analytics.html')
if settings.FEATURES['IS_EDX_DOMAIN'] and not is_microsite():
footer_file = microsite.get_template_path('footer-edx-new.html')
else:
footer_file = microsite.get_template_path('footer.html')
style_overrides_file = microsite.get_value('css_overrides_file') style_overrides_file = microsite.get_value('css_overrides_file')
%> %>
...@@ -136,7 +129,6 @@ ...@@ -136,7 +129,6 @@
<%include file="${google_analytics_file}" /> <%include file="${google_analytics_file}" />
% if style_overrides_file: % if style_overrides_file:
<link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" /> <link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" />
% endif % endif
...@@ -149,18 +141,25 @@ ...@@ -149,18 +141,25 @@
<%include file="mathjax_accessible.html" /> <%include file="mathjax_accessible.html" />
% if not suppress_toplevel_navigation:
<%include file="${header_file}" /> <%include file="${header_file}" />
%endif
<div class="content-wrapper" id="content"> <div class="content-wrapper" id="content">
${self.body()} ${self.body()}
<%block name="bodyextra"/> <%block name="bodyextra"/>
</div> </div>
% if not suppress_toplevel_navigation: <%block name="footer">
<%include file="${footer_file}" /> ## Can be overridden by child templates wanting to hide the footer.
% endif <%
if theme_enabled() and not is_microsite():
footer_file = 'theme-footer.html'
elif settings.FEATURES['IS_EDX_DOMAIN'] and not is_microsite():
footer_file = microsite.get_template_path('footer-edx-new.html')
else:
footer_file = microsite.get_template_path('footer.html')
%>
<%include file="${footer_file}" />
</%block>
</div> </div>
......
...@@ -80,7 +80,7 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -80,7 +80,7 @@ site_status_msg = get_site_status_msg(course_id)
<li><a href="${marketing_link('FAQ')}">${_("Help")}</a></li> <li><a href="${marketing_link('FAQ')}">${_("Help")}</a></li>
% endif % endif
</%block> </%block>
<li><a href="${reverse('logout')}" role="menuitem">${_("Log Out")}</a></li> <li><a href="${reverse('logout')}" role="menuitem">${_("Sign out")}</a></li>
</ul> </ul>
</li> </li>
</ol> </ol>
...@@ -126,9 +126,9 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -126,9 +126,9 @@ site_status_msg = get_site_status_msg(course_id)
<div class="nav-courseware-02"> <div class="nav-courseware-02">
% if not settings.FEATURES['DISABLE_LOGIN_BUTTON']: % if not settings.FEATURES['DISABLE_LOGIN_BUTTON']:
% if course and settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD') and course.enrollment_domain: % if course and settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD') and course.enrollment_domain:
<a class="cta cta-login nav-courseware-button" href="${reverse('course-specific-login', args=[course.id.to_deprecated_string()])}${login_query()}">${_("Log in")}</a> <a class="cta cta-login nav-courseware-button" href="${reverse('course-specific-login', args=[course.id.to_deprecated_string()])}${login_query()}">${_("Sign in")}</a>
% else: % else:
<a class="cta cta-login nav-courseware-button" href="/login${login_query()}">${_("Log in")}</a> <a class="cta cta-login nav-courseware-button" href="/login${login_query()}">${_("Sign in")}</a>
% endif % endif
% endif % endif
</div> </div>
......
...@@ -75,7 +75,7 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -75,7 +75,7 @@ site_status_msg = get_site_status_msg(course_id)
<li><a href="${marketing_link('FAQ')}">${_("Help")}</a></li> <li><a href="${marketing_link('FAQ')}">${_("Help")}</a></li>
% endif % endif
</%block> </%block>
<li><a href="${reverse('logout')}" role="menuitem">${_("Log Out")}</a></li> <li><a href="${reverse('logout')}" role="menuitem">${_("Sign out")}</a></li>
</ul> </ul>
</li> </li>
</ol> </ol>
...@@ -120,9 +120,9 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -120,9 +120,9 @@ site_status_msg = get_site_status_msg(course_id)
<li class="nav-courseware-01"> <li class="nav-courseware-01">
% if not settings.FEATURES['DISABLE_LOGIN_BUTTON']: % if not settings.FEATURES['DISABLE_LOGIN_BUTTON']:
% if course and settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD') and course.enrollment_domain: % if course and settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD') and course.enrollment_domain:
<a class="cta cta-login" href="${reverse('course-specific-login', args=[course.id.to_deprecated_string()])}${login_query()}">${_("Log in")}</a> <a class="cta cta-login" href="${reverse('course-specific-login', args=[course.id.to_deprecated_string()])}${login_query()}">${_("Sign in")}</a>
% else: % else:
<a class="cta cta-login" href="/login${login_query()}">${_("Log in")}</a> <a class="cta cta-login" href="/login${login_query()}">${_("Sign in")}</a>
% endif % endif
% endif % endif
</li> </li>
......
<header class="js-login-register-header header"> <section id="form-load-fail" class="form-type hidden">
<h1 class="headline"><%- gettext("Welcome!") %></h1>
<p class="tagline"><%- gettext("Log in or register to take courses from the world's best universities.") %></p>
</header>
<section id="form-load-fail" class="form-type hidden" aria-hidden="true">
<div class="status submission-error"> <div class="status submission-error">
<p class="message-copy"><%- gettext("Sorry, we're having some technical problems. Wait a few minutes and try again.") %></p> <p class="message-copy"><%- gettext("Sorry, we're having some technical problems. Wait a few minutes and try again.") %></p>
</div> </div>
</section> </section>
<% if ( mode === 'login' ) { %>
<section id="register-anchor" class="form-type">
<span>
<input type="radio" name="form" id="register-option" value="register" class="form-toggle" <% if ( mode === 'register' ) { %>checked<% } %> >
<label for="register-option" class="form-label"><%- gettext("I am a new user") %></label>
</span>
<div id="register-form" class="form-wrapper <% if ( mode !== 'register' ) { %>hidden" aria-hidden="true<% } %>"></div>
</section>
<% } %>
<section id="login-anchor" class="form-type"> <section id="login-anchor" class="form-type">
<span> <div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden<% } %>"></div>
<input type="radio" name="form" id="login-option" value="login" class="form-toggle" <% if ( mode === 'login' ) { %>checked<% } %>>
<label for="login-option" class="form-label"><%- gettext("I am a returning user") %></label>
</span>
<div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden" aria-hidden="true<% } %>"></div>
</section> </section>
<% if ( mode === 'register' ) { %> <section id="register-anchor" class="form-type">
<section id="register-anchor" class="form-type"> <div id="register-form" class="form-wrapper <% if ( mode !== 'register' ) { %>hidden<% } %>"></div>
<span> </section>
<input type="radio" name="form" id="register-option" value="register" class="form-toggle" <% if ( mode === 'register' ) { %>checked<% } %> >
<label for="register-option" class="form-label"><%- gettext("I am a new user") %></label>
</span>
<div id="register-form" class="form-wrapper <% if ( mode !== 'register' ) { %>hidden" aria-hidden="true<% } %>"></div>
</section>
<% } %>
<div id="password-reset-wrapper"></div> <section id="password-reset-anchor" class="form-type">
\ No newline at end of file <div id="password-reset-form" class="form-wrapper hidden" aria-hidden="true"></div>
</section>
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
name="<%= name %>" name="<%= name %>"
class="input-inline" class="input-inline"
aria-describedby="<%= form %>-<%= name %>-desc" aria-describedby="<%= form %>-<%= name %>-desc"
<% if ( typeof errorMessages !== 'undefined' ) {
_.each(errorMessages, function( msg, type ) {%>
data-errormsg-<%= type %>="<%= msg %>"
<% });
} %>
<% if ( required ) { %> aria-required="true" required<% } %>> <% if ( required ) { %> aria-required="true" required<% } %>>
<% _.each(options, function(el) { %> <% _.each(options, function(el) { %>
<option value="<%= el.value%>"<% if ( el.default ) { %> data-isdefault="true"<% } %>><%= el.name %></option> <option value="<%= el.value%>"<% if ( el.default ) { %> data-isdefault="true"<% } %>><%= el.name %></option>
...@@ -49,7 +54,7 @@ ...@@ -49,7 +54,7 @@
<% } %> <% } %>
<% if ( type === 'checkbox' ) { %> <% if ( type === 'checkbox' ) { %>
<label for="<%= form %>-<%= name %>" class="inline"> <label for="<%= form %>-<%= name %>">
<%= label %> <%= label %>
<% if ( required && requiredStr ) { %> <%= requiredStr %><% } %> <% if ( required && requiredStr ) { %> <%= requiredStr %><% } %>
</label> </label>
...@@ -58,6 +63,4 @@ ...@@ -58,6 +63,4 @@
<% if( form === 'login' && name === 'password' ) { %> <% if( form === 'login' && name === 'password' ) { %>
<a href="#" class="forgot-password field-link"><%- gettext("Forgot password?") %></a> <a href="#" class="forgot-password field-link"><%- gettext("Forgot password?") %></a>
<% } %> <% } %>
<span id="<%= form %>-<%= name %>-desc" class="desc"><%= instructions %></span>
</p> </p>
<form id="login" class="login-form"> <div class="status already-authenticated-msg hidden">
<div class="status already-authenticated-msg hidden" aria-hidden="true"> <% if (context.currentProvider) { %>
<% if (context.currentProvider) { %> <p class="message-copy">
<p class="message-copy"> <%- _.sprintf( gettext("You've successfully signed into %(currentProvider)s, but your %(currentProvider)s account isn't linked with an %(platformName)s account. To link your accounts, go to your %(platformName)s dashboard."), context ) %>
<%- _.sprintf(gettext("You've successfully logged into %(currentProvider)s, but your %(currentProvider)s account isn't linked with an %(platformName)s account. To link your accounts, go to your %(platformName)s dashboard."), context) %> </p>
</p> <% } %>
<% } %> </div>
<div class="js-reset-success status submission-success hidden">
<h4 class="message-title"><%- gettext("Password Reset Email Sent") %></h4>
<div class="message-copy">
<p>
<%- gettext("We've sent instructions for resetting your password to the email address you provided.") %>
</p>
</div> </div>
</div>
<div class="status submission-error hidden" aria-live="polite">
<h4 class="message-title"><%- gettext("We couldn't sign you in.") %></h4>
<ul class="message-copy"></ul>
</div>
<form id="login" class="login-form">
<div class="status submission-error hidden" aria-hidden="true" aria-live="polite"> <div class="section-title lines">
<h4 class="message-title"><%- gettext("We couldn't log you in.") %></h4> <h2>
<ul class="message-copy"></ul> <span class="text"><%- gettext("Sign in") %></span>
</h2>
</div> </div>
<%= context.fields %> <%= context.fields %>
<button class="action action-primary action-update js-login login-button"><%- gettext("Log in") %></button> <button class="action action-primary action-update js-login login-button"><%- gettext("Sign in") %></button>
<div class="login-providers">
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("or sign in with") %></span>
</h2>
</div>
<% _.each( context.providers, function( provider ) {
if ( provider.loginUrl ) { %>
<button type="submit" class="button button-primary button-<%- provider.name %> login-provider login-<%- provider.name %>" data-provider-url="<%- provider.loginUrl %>">
<div class="icon <%- provider.iconClass %>" aria-hidden="true"></div>
<%- provider.name %>
</button>
<% }
}); %>
</div>
</form> </form>
<% _.each( context.providers, function( provider ) { <div class="toggle-form">
if ( provider.loginUrl ) { %> <div class="section-title">
<button type="submit" class="button button-primary button-<%- provider.name %> login-provider login-<%- provider.name %>" data-provider-url="<%- provider.loginUrl %>"> <h2>
<span class="icon <%- provider.iconClass %>" aria-hidden="true"></span> <span class="text"><%- _.sprintf( gettext("New to %(platformName)s?"), context ) %></span>
<%- _.sprintf(gettext("Log in using %(name)s"), provider) %> </h2>
</button> </div>
<% } <button class="nav-btn form-toggle" data-type="register"><%- gettext("Create an account") %></button>
}); %> </div>
...@@ -3,13 +3,14 @@ ...@@ -3,13 +3,14 @@
<%inherit file="../main.html" /> <%inherit file="../main.html" />
<%block name="pagetitle">${_("Log in or Register")}</%block> <%block name="pagetitle">${_("Sign in or Register")}</%block>
<%block name="js_extra"> <%block name="js_extra">
<script src="${static.url('js/vendor/underscore-min.js')}"></script> <script src="${static.url('js/vendor/underscore-min.js')}"></script>
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script> <script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<script src="${static.url('js/vendor/backbone-min.js')}"></script> <script src="${static.url('js/vendor/backbone-min.js')}"></script>
<script src="${static.url('js/vendor/url.min.js')}"></script> <script src="${static.url('js/vendor/url.min.js')}"></script>
<script src="${static.url('js/vendor/history.js')}"></script>
<%static:js group='student_account'/> <%static:js group='student_account'/>
</%block> </%block>
...@@ -29,3 +30,10 @@ ...@@ -29,3 +30,10 @@
data-platform-name='${platform_name}' data-platform-name='${platform_name}'
/> />
</div> </div>
% if settings.FEATURES.get('ENABLE_COMBINED_LOGIN_REGISTRATION'):
## This overwrites the "footer" block declared in main.html
## with an empty block, effectively hiding the footer
## from logistration pages.
<%block name="footer"/>
% endif
<header class="header"> <div class="status submission-error hidden" aria-live="polite">
<h1 class="headline"><%- gettext("Reset Password") %></h1> <h4 class="message-title"><%- gettext("An error occurred.") %></h4>
</header> <ul class="message-copy"></ul>
</div>
<section class="form-type"> <form id="password-reset" class="password-reset-form">
<div id="password-reset-form" class="form-wrapper">
<p class="action-label"><%- gettext("Enter the email address you used to create your account. We'll send you a link you can use to reset your password.") %></p>
<form id="password-reset-form">
<div class="status submission-error hidden" aria-hidden="true" aria-live="polite">
<h4 class="message-title"><%- gettext("An error occurred.") %></h4>
<ul class="message-copy"></ul>
</div>
<%= fields %> <div class="section-title lines">
<h2>
<button class="action action-primary action-update js-reset"><%- gettext("Reset password") %></button> <span class="text"><%- gettext("Password assistance") %></span>
</form> </h2>
</div> </div>
<div class="js-reset-success status submission-success hidden" aria-hidden="true"> <p class="action-label"><%- gettext("Please enter your email address below and we will send you instructions for setting a new password.") %></p>
<h4 class="message-title"><%- gettext("Password Reset Email Sent") %></h4>
<div class="message-copy"> <%= fields %>
<p>
<%- gettext("We've sent instructions for resetting your password to the email address you provided.") %> <button class="action action-primary action-update js-reset"><%- gettext("Reset my password") %></button>
</p> </form>
</div>
</div>
</section>
<% if (context.currentProvider) { %> <div class="status submission-error hidden" aria-live="polite">
<div class="status" aria-hidden="false"> <h4 class="message-title"><%- gettext("We couldn't create your account.") %></h4>
<p class="message-copy"> <ul class="message-copy"></ul>
<%- _.sprintf(gettext("You've successfully logged into %(currentProvider)s."), context) %> </div>
<%- _.sprintf(gettext("We just need a little more information before you start learning with %(platformName)s."), context) %>
</p>
</div>
<% } else {
_.each( context.providers, function( provider) {
if ( provider.registerUrl ) { %>
<button type="submit" class="button button-primary button-<%- provider.name %> login-provider register-<%- provider.name %>" data-provider-url="<%- provider.registerUrl %>">
<span class="icon <%- provider.iconClass %>" aria-hidden="true"></span>
<%- _.sprintf(gettext("Register using %(name)s"), provider) %>
</button>
<% }
});
} %>
<form id="register" autocomplete="off"> <form id="register" autocomplete="off">
<div class="status submission-error hidden" aria-hidden="true" aria-live="polite"> <% if (context.currentProvider) { %>
<h4 class="message-title"><%- gettext("We couldn't complete your registration.") %></h4> <div class="status" aria-hidden="false">
<ul class="message-copy"></ul> <p class="message-copy">
<%- _.sprintf( gettext("You've successfully signed into %(currentProvider)s."), context ) %>
<%- _.sprintf( gettext("We just need a little more information before you start learning with %(platformName)s."), context ) %>
</p>
</div>
<% } else { %>
<div class="login-providers">
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("Create an account using") %></span>
</h2>
</div>
<%
_.each( context.providers, function( provider) {
if ( provider.registerUrl ) { %>
<button type="submit" class="button button-primary button-<%- provider.name %> login-provider register-<%- provider.name %>" data-provider-url="<%- provider.registerUrl %>">
<span class="icon <%- provider.iconClass %>" aria-hidden="true"></span>
<%- provider.name %>
</button>
<% }
}); %>
</div>
<% } %>
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("or create a new one here") %></span>
</h2>
</div> </div>
<%= context.fields %> <%= context.fields %>
<button class="action action-primary action-update js-register register-button"><%- gettext("Register") %></button> <button class="action action-primary action-update js-register register-button"><%- gettext("Create your account") %></button>
<p class="note">* <%- gettext("Required field") %></p> <p class="note">* <%- gettext("Required field") %></p>
</form> </form>
<div class="toggle-form">
<div class="section-title">
<h2>
<span class="text"><%- gettext("Already have an account?") %></span>
</h2>
</div>
<button class="nav-btn form-toggle" data-type="login"><%- gettext("Sign in") %></button>
</div>
...@@ -633,17 +633,6 @@ class LoginSessionViewTest(ApiTestCase): ...@@ -633,17 +633,6 @@ class LoginSessionViewTest(ApiTestCase):
"max_length": account_api.PASSWORD_MAX_LENGTH "max_length": account_api.PASSWORD_MAX_LENGTH
}, },
"errorMessages": {}, "errorMessages": {},
},
{
"name": "remember",
"defaultValue": False,
"type": "checkbox",
"required": False,
"label": "Remember me",
"placeholder": "",
"instructions": "",
"restrictions": {},
"errorMessages": {},
} }
]) ])
...@@ -847,7 +836,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -847,7 +836,7 @@ class RegistrationViewTest(ApiTestCase):
u"name": u"name", u"name": u"name",
u"type": u"text", u"type": u"text",
u"required": True, u"required": True,
u"label": u"Full Name", u"label": u"Full name",
u"instructions": u"The name that will appear on your certificates", u"instructions": u"The name that will appear on your certificates",
u"restrictions": { u"restrictions": {
"max_length": profile_api.FULL_NAME_MAX_LENGTH, "max_length": profile_api.FULL_NAME_MAX_LENGTH,
...@@ -861,7 +850,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -861,7 +850,7 @@ class RegistrationViewTest(ApiTestCase):
u"name": u"username", u"name": u"username",
u"type": u"text", u"type": u"text",
u"required": True, u"required": True,
u"label": u"Username", u"label": u"Public username",
u"instructions": u"The name that will identify you in your courses", u"instructions": u"The name that will identify you in your courses",
u"restrictions": { u"restrictions": {
"min_length": account_api.USERNAME_MIN_LENGTH, "min_length": account_api.USERNAME_MIN_LENGTH,
...@@ -927,7 +916,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -927,7 +916,7 @@ class RegistrationViewTest(ApiTestCase):
u"defaultValue": u"Bob", u"defaultValue": u"Bob",
u"type": u"text", u"type": u"text",
u"required": True, u"required": True,
u"label": u"Full Name", u"label": u"Full name",
u"instructions": u"The name that will appear on your certificates", u"instructions": u"The name that will appear on your certificates",
u"restrictions": { u"restrictions": {
"max_length": profile_api.FULL_NAME_MAX_LENGTH "max_length": profile_api.FULL_NAME_MAX_LENGTH
...@@ -943,7 +932,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -943,7 +932,7 @@ class RegistrationViewTest(ApiTestCase):
u"defaultValue": u"Bob123", u"defaultValue": u"Bob123",
u"type": u"text", u"type": u"text",
u"required": True, u"required": True,
u"label": u"Username", u"label": u"Public username",
u"placeholder": u"", u"placeholder": u"",
u"instructions": u"The name that will identify you in your courses", u"instructions": u"The name that will identify you in your courses",
u"restrictions": { u"restrictions": {
...@@ -960,7 +949,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -960,7 +949,7 @@ class RegistrationViewTest(ApiTestCase):
"name": "level_of_education", "name": "level_of_education",
"type": "select", "type": "select",
"required": False, "required": False,
"label": "Highest Level of Education Completed", "label": "Highest level of education completed",
"options": [ "options": [
{"value": "", "name": "--", "default": True}, {"value": "", "name": "--", "default": True},
{"value": "p", "name": "Doctorate"}, {"value": "p", "name": "Doctorate"},
...@@ -1007,7 +996,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1007,7 +996,7 @@ class RegistrationViewTest(ApiTestCase):
"name": "year_of_birth", "name": "year_of_birth",
"type": "select", "type": "select",
"required": False, "required": False,
"label": "Year of Birth", "label": "Year of birth",
"options": year_options, "options": year_options,
} }
) )
...@@ -1019,7 +1008,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1019,7 +1008,7 @@ class RegistrationViewTest(ApiTestCase):
"name": "mailing_address", "name": "mailing_address",
"type": "textarea", "type": "textarea",
"required": False, "required": False,
"label": "Mailing Address", "label": "Mailing address",
} }
) )
...@@ -1030,7 +1019,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1030,7 +1019,7 @@ class RegistrationViewTest(ApiTestCase):
"name": "goals", "name": "goals",
"type": "textarea", "type": "textarea",
"required": False, "required": False,
"label": "If you'd like, tell us why you're interested in {platform_name}".format( "label": "Tell us why you're interested in {platform_name}".format(
platform_name=settings.PLATFORM_NAME platform_name=settings.PLATFORM_NAME
) )
} }
...@@ -1063,6 +1052,9 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1063,6 +1052,9 @@ class RegistrationViewTest(ApiTestCase):
"type": "select", "type": "select",
"required": True, "required": True,
"options": country_options, "options": country_options,
"errorMessages": {
"required": "Please select your Country."
},
} }
) )
...@@ -1222,9 +1214,9 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1222,9 +1214,9 @@ class RegistrationViewTest(ApiTestCase):
"password", "password",
"city", "city",
"country", "country",
"level_of_education",
"gender", "gender",
"year_of_birth", "year_of_birth",
"level_of_education",
"mailing_address", "mailing_address",
"goals", "goals",
"honor_code", "honor_code",
......
...@@ -112,19 +112,6 @@ class LoginSessionView(APIView): ...@@ -112,19 +112,6 @@ class LoginSessionView(APIView):
} }
) )
# Translators: This phrase appears next to a checkbox on the login form
# which the user can check in order to remain logged in after their
# session ends.
remember_label = _(u"Remember me")
form_desc.add_field(
"remember",
field_type="checkbox",
label=remember_label,
default=False,
required=False,
)
return HttpResponse(form_desc.to_json(), content_type="application/json") return HttpResponse(form_desc.to_json(), content_type="application/json")
@method_decorator(require_post_params(["email", "password"])) @method_decorator(require_post_params(["email", "password"]))
...@@ -171,9 +158,15 @@ class RegistrationView(APIView): ...@@ -171,9 +158,15 @@ class RegistrationView(APIView):
DEFAULT_FIELDS = ["email", "name", "username", "password"] DEFAULT_FIELDS = ["email", "name", "username", "password"]
EXTRA_FIELDS = [ EXTRA_FIELDS = [
"city", "country", "level_of_education", "gender", "city",
"year_of_birth", "mailing_address", "goals", "country",
"honor_code", "terms_of_service", "gender",
"year_of_birth",
"level_of_education",
"mailing_address",
"goals",
"honor_code",
"terms_of_service",
] ]
# This end-point is available to anonymous users, # This end-point is available to anonymous users,
...@@ -348,7 +341,7 @@ class RegistrationView(APIView): ...@@ -348,7 +341,7 @@ class RegistrationView(APIView):
""" """
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's full name. # meant to hold the user's full name.
name_label = _(u"Full Name") name_label = _(u"Full name")
# Translators: These instructions appear on the registration form, immediately # Translators: These instructions appear on the registration form, immediately
# below a field meant to hold the user's full name. # below a field meant to hold the user's full name.
...@@ -376,7 +369,7 @@ class RegistrationView(APIView): ...@@ -376,7 +369,7 @@ class RegistrationView(APIView):
""" """
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's public username. # meant to hold the user's public username.
username_label = _(u"Username") username_label = _(u"Public username")
# Translators: These instructions appear on the registration form, immediately # Translators: These instructions appear on the registration form, immediately
# below a field meant to hold the user's public username. # below a field meant to hold the user's public username.
...@@ -432,7 +425,7 @@ class RegistrationView(APIView): ...@@ -432,7 +425,7 @@ class RegistrationView(APIView):
""" """
# Translators: This label appears above a dropdown menu on the registration # Translators: This label appears above a dropdown menu on the registration
# form used to select the user's highest completed level of education. # form used to select the user's highest completed level of education.
education_level_label = _(u"Highest Level of Education Completed") education_level_label = _(u"Highest level of education completed")
form_desc.add_field( form_desc.add_field(
"level_of_education", "level_of_education",
...@@ -478,7 +471,7 @@ class RegistrationView(APIView): ...@@ -478,7 +471,7 @@ class RegistrationView(APIView):
""" """
# Translators: This label appears above a dropdown menu on the registration # Translators: This label appears above a dropdown menu on the registration
# form used to select the user's year of birth. # form used to select the user's year of birth.
yob_label = _(u"Year of Birth") yob_label = _(u"Year of birth")
options = [(unicode(year), unicode(year)) for year in UserProfile.VALID_YEARS] options = [(unicode(year), unicode(year)) for year in UserProfile.VALID_YEARS]
form_desc.add_field( form_desc.add_field(
...@@ -502,7 +495,7 @@ class RegistrationView(APIView): ...@@ -502,7 +495,7 @@ class RegistrationView(APIView):
""" """
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's mailing address. # meant to hold the user's mailing address.
mailing_address_label = _(u"Mailing Address") mailing_address_label = _(u"Mailing address")
form_desc.add_field( form_desc.add_field(
"mailing_address", "mailing_address",
...@@ -524,7 +517,7 @@ class RegistrationView(APIView): ...@@ -524,7 +517,7 @@ class RegistrationView(APIView):
# Translators: This phrase appears above a field on the registration form # Translators: This phrase appears above a field on the registration form
# meant to hold the user's reasons for registering with edX. # meant to hold the user's reasons for registering with edX.
goals_label = _( goals_label = _(
u"If you'd like, tell us why you're interested in {platform_name}" u"Tell us why you're interested in {platform_name}"
).format(platform_name=settings.PLATFORM_NAME) ).format(platform_name=settings.PLATFORM_NAME)
form_desc.add_field( form_desc.add_field(
...@@ -575,13 +568,19 @@ class RegistrationView(APIView): ...@@ -575,13 +568,19 @@ class RegistrationView(APIView):
(country_code, unicode(country_name)) (country_code, unicode(country_name))
for country_code, country_name in sorted_countries for country_code, country_name in sorted_countries
] ]
error_msg = _(u"Please select your Country.")
form_desc.add_field( form_desc.add_field(
"country", "country",
label=country_label, label=country_label,
field_type="select", field_type="select",
options=options, options=options,
include_default_option=True, include_default_option=True,
required=required required=required,
error_messages={
"required": error_msg
}
) )
def _add_honor_code_field(self, form_desc, required=True): def _add_honor_code_field(self, form_desc, required=True):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment