From 7df7b9c9092409cfc08236eaafc14871f3b59b00 Mon Sep 17 00:00:00 2001 From: Shane Tomlinson <stomlinson@mozilla.com> Date: Wed, 2 May 2012 16:40:19 +0100 Subject: [PATCH] Putting the set password back into add_email_address and verify_email_address * user.js: Update verifyEmail and verifyUser to take a password. * network.js: Update completeEmailRegistration and completeUserRegistration to take a password. * Replace verify_email_address.js and add_email_address.js with a single verify_secondary_address.js to reduce duplication. * Update the templates. * Bring back verify_email_address and add_email_address templates, but remove the verify password field. * To dom-jquery, add show, hide functions. --- lib/static_resources.js | 3 +- resources/static/css/style.css | 5 +- resources/static/lib/dom-jquery.js | 18 ++++ resources/static/pages/add_email_address.js | 98 ------------------- resources/static/pages/start.js | 11 ++- .../static/pages/verify_email_address.js | 56 ----------- .../static/pages/verify_secondary_address.js | 94 ++++++++++++++++++ resources/static/shared/network.js | 12 ++- resources/static/shared/user.js | 34 ++++--- .../cases/pages/verify_email_address_test.js | 73 -------------- ...ss_test.js => verify_secondary_address.js} | 53 ++++++++-- resources/static/test/cases/shared/network.js | 45 ++++++--- resources/static/test/cases/shared/user.js | 10 +- resources/static/test/mocks/xhr.js | 4 +- resources/static/test/testHelpers/helpers.js | 11 +++ resources/views/add_email_address.ejs | 21 +++- resources/views/test.ejs | 6 +- resources/views/verify_email_address.ejs | 17 +++- 18 files changed, 285 insertions(+), 286 deletions(-) delete mode 100644 resources/static/pages/add_email_address.js delete mode 100644 resources/static/pages/verify_email_address.js create mode 100644 resources/static/pages/verify_secondary_address.js delete mode 100644 resources/static/test/cases/pages/verify_email_address_test.js rename resources/static/test/cases/pages/{add_email_address_test.js => verify_secondary_address.js} (63%) diff --git a/lib/static_resources.js b/lib/static_resources.js index e387b3748..1bd4a35f5 100644 --- a/lib/static_resources.js +++ b/lib/static_resources.js @@ -62,8 +62,7 @@ var browserid_js = und.flatten([ '/pages/page_helpers.js', '/pages/index.js', '/pages/start.js', - '/pages/add_email_address.js', - '/pages/verify_email_address.js', + '/pages/verify_secondary_address.js', '/pages/forgot.js', '/pages/manage_account.js', '/pages/signin.js', diff --git a/resources/static/css/style.css b/resources/static/css/style.css index c4cbd340c..b41a98431 100644 --- a/resources/static/css/style.css +++ b/resources/static/css/style.css @@ -667,7 +667,7 @@ h1 { margin-bottom: 10px; } -.siteinfo, #congrats, #signUpForm .password_entry, .enter_password .hint, #unknown_secondary, #primary_verify, .verify_primary .submit { +.siteinfo, #congrats, .password_entry, .enter_password .hint, #unknown_secondary, #primary_verify, .verify_primary .submit { display: none; } @@ -675,7 +675,7 @@ h1 { float: left; } -.enter_password #signUpForm .password_entry, .known_secondary #signUpForm .password_entry, +.enter_password .password_entry, .known_secondary .password_entry, .unknown_secondary #unknown_secondary, .verify_primary #verify_primary { display: block; } @@ -820,3 +820,4 @@ footer a:hover { .newsbanner a:hover { color: #000; } + diff --git a/resources/static/lib/dom-jquery.js b/resources/static/lib/dom-jquery.js index 860c03327..6438fec06 100644 --- a/resources/static/lib/dom-jquery.js +++ b/resources/static/lib/dom-jquery.js @@ -310,6 +310,24 @@ BrowserID.DOM = ( function() { */ is: function( elementToCheck, type ) { return jQuery( elementToCheck ).is( type ); + }, + + /** + * Show an element/elements + * @method show + * @param {selector || element} elementToShow + */ + show: function( elementToShow ) { + return jQuery( elementToShow ).show(); + }, + + /** + * Hide an element/elements + * @method hide + * @param {selector || element} elementToHide + */ + hide: function( elementToHide ) { + return jQuery( elementToHide ).hide(); } diff --git a/resources/static/pages/add_email_address.js b/resources/static/pages/add_email_address.js deleted file mode 100644 index dccdd3240..000000000 --- a/resources/static/pages/add_email_address.js +++ /dev/null @@ -1,98 +0,0 @@ -/*globals BrowserID: true, $:true */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -BrowserID.addEmailAddress = (function() { - "use strict"; - - var ANIMATION_TIME=250, - bid = BrowserID, - user = bid.User, - storage = bid.Storage, - errors = bid.Errors, - pageHelpers = bid.PageHelpers, - dom = bid.DOM, - token, - sc; - - function showError(el, oncomplete) { - $(".hint,#signUpForm").hide(); - $(el).fadeIn(ANIMATION_TIME, oncomplete); - } - - function emailRegistrationComplete(oncomplete, info) { - function complete(status) { - oncomplete && oncomplete(status); - } - - var valid = info.valid; - if (valid) { - emailRegistrationSuccess(info, complete.curry(true)); - } - else { - showError("#cannotconfirm", complete.curry(false)); - } - } - - function showRegistrationInfo(info) { - dom.setInner(".email", info.email); - - if (info.origin) { - dom.setInner(".website", info.origin); - $(".siteinfo").show(); - } - } - - function emailRegistrationSuccess(info, oncomplete) { - dom.addClass("body", "complete"); - - showRegistrationInfo(info); - - setTimeout(function() { - pageHelpers.replaceFormWithNotice("#congrats", oncomplete); - }, 2000); - } - - function verifyEmail(oncomplete) { - user.verifyEmail(token, - emailRegistrationComplete.curry(oncomplete), - pageHelpers.getFailure(errors.verifyEmail, oncomplete) - ); - } - - function startVerification(oncomplete) { - user.tokenInfo(token, function(info) { - if(info) { - showRegistrationInfo(info); - verifyEmail(oncomplete); - } - else { - showError("#cannotconfirm"); - oncomplete(false); - } - }, pageHelpers.getFailure(errors.getTokenInfo, oncomplete)); - } - - var Module = bid.Modules.PageModule.extend({ - start: function(options) { - function oncomplete(status) { - options.ready && options.ready(status); - } - - this.checkRequired(options, "token"); - - token = options.token; - - startVerification(oncomplete); - - sc.start.call(this, options); - }, - - submit: verifyEmail - }); - - sc = Module.sc; - - return Module; -}()); diff --git a/resources/static/pages/start.js b/resources/static/pages/start.js index cd57372ba..530e09f8d 100644 --- a/resources/static/pages/start.js +++ b/resources/static/pages/start.js @@ -73,13 +73,18 @@ $(function() { bid.forgot(); } else if (path === "/add_email_address") { - var module = bid.addEmailAddress.create(); + var module = bid.verifySecondaryAddress.create(); module.start({ - token: token + token: token, + verifyFunction: "verifyEmail" }); } else if(token && path === "/verify_email_address") { - bid.verifyEmailAddress(token); + var module = bid.verifySecondaryAddress.create(); + module.start({ + token: token, + verifyFunction: "verifyUser" + }); } else { // Instead of throwing a hard error here, adding a message to the console diff --git a/resources/static/pages/verify_email_address.js b/resources/static/pages/verify_email_address.js deleted file mode 100644 index aa7b7cdd7..000000000 --- a/resources/static/pages/verify_email_address.js +++ /dev/null @@ -1,56 +0,0 @@ -/*globals BrowserID: true, $:true */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -(function() { - "use strict"; - - var bid = BrowserID, - network = bid.Network, - storage = bid.Storage, - errors = bid.Errors, - pageHelpers = bid.PageHelpers, - token; - - function submit(oncomplete) { - network.completeUserRegistration(token, function onSuccess(registered) { - var selector = registered ? "#congrats" : "#cannotcomplete"; - pageHelpers.replaceFormWithNotice(selector, oncomplete); - }, pageHelpers.getFailure(errors.completeUserRegistration, oncomplete)); - } - - function init(tok, oncomplete) { - $(".siteinfo").hide(); - $("#congrats").hide(); - token = tok; - - var staged = storage.getStagedOnBehalfOf(); - if (staged) { - $('.website').html(staged); - $('.siteinfo').show(); - } - - // go get the email address - network.emailForVerificationToken(token, function(info) { - if (info) { - $('#email').val(info.email); - submit(oncomplete); - } - else { - pageHelpers.replaceFormWithNotice("#cannotconfirm", oncomplete); - } - }, pageHelpers.getFailure(errors.completeUserRegistration, oncomplete)); - } - - // BEGIN TESTING API - function reset() { - } - - init.submit = submit; - init.reset = reset; - // END TESTING API; - - bid.verifyEmailAddress = init; - -}()); diff --git a/resources/static/pages/verify_secondary_address.js b/resources/static/pages/verify_secondary_address.js new file mode 100644 index 000000000..2ccfb0c80 --- /dev/null +++ b/resources/static/pages/verify_secondary_address.js @@ -0,0 +1,94 @@ +/*globals BrowserID: true, $:true */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +BrowserID.verifySecondaryAddress = (function() { + "use strict"; + + var ANIMATION_TIME=250, + bid = BrowserID, + user = bid.User, + errors = bid.Errors, + pageHelpers = bid.PageHelpers, + dom = bid.DOM, + helpers = bid.Helpers, + complete = helpers.complete, + validation = bid.Validation, + token, + sc, + mustAuth, + verifyFunction; + + function showError(el, oncomplete) { + dom.hide(".hint,#signUpForm"); + $(el).fadeIn(ANIMATION_TIME, oncomplete); + } + + function showRegistrationInfo(info) { + dom.setInner("#email", info.email); + + if (info.origin) { + dom.setInner(".website", info.origin); + dom.show(".siteinfo"); + } + } + + function submit(oncomplete) { + var pass = dom.getInner("#password") || undefined, + valid = !mustAuth || validation.password(pass); + + if (valid) { + user[verifyFunction](token, pass, function(info) { + dom.addClass("body", "complete"); + + var selector = info.valid ? "#congrats" : "#cannotcomplete"; + pageHelpers.replaceFormWithNotice(selector, complete.curry(oncomplete, info.valid)); + }, pageHelpers.getFailure(errors.verifyEmail, oncomplete)); + } + else { + complete(oncomplete, false); + } + } + + function startVerification(oncomplete) { + user.tokenInfo(token, function(info) { + if(info) { + showRegistrationInfo(info); + + mustAuth = info.must_auth; + + if (mustAuth) { + dom.addClass("body", "enter_password"); + complete(oncomplete, true); + } + else { + submit(oncomplete); + } + } + else { + showError("#cannotconfirm"); + complete(oncomplete, false); + } + }, pageHelpers.getFailure(errors.getTokenInfo, oncomplete)); + } + + var Module = bid.Modules.PageModule.extend({ + start: function(options) { + this.checkRequired(options, "token", "verifyFunction"); + + token = options.token; + verifyFunction = options.verifyFunction; + + startVerification(options.ready); + + sc.start.call(this, options); + }, + + submit: submit + }); + + sc = Module.sc; + + return Module; +}()); diff --git a/resources/static/shared/network.js b/resources/static/shared/network.js index f5c1eb7f4..45f422fbe 100644 --- a/resources/static/shared/network.js +++ b/resources/static/shared/network.js @@ -277,14 +277,16 @@ BrowserID.Network = (function() { * Complete user registration, give user a password * @method completeUserRegistration * @param {string} token - token to register for. + * @param {string} password * @param {function} [onComplete] - Called when complete. * @param {function} [onFailure] - Called on XHR failure. */ - completeUserRegistration: function(token, onComplete, onFailure) { + completeUserRegistration: function(token, password, onComplete, onFailure) { post({ url: "/wsapi/complete_user_creation", data: { - token: token + token: token, + pass: password }, success: function(status, textStatus, jqXHR) { complete(onComplete, status.success); @@ -297,15 +299,17 @@ BrowserID.Network = (function() { * Call with a token to prove an email address ownership. * @method completeEmailRegistration * @param {string} token - token proving email ownership. + * @param {string} password * @param {function} [onComplete] - Callback to call when complete. Called * with one boolean parameter that specifies the validity of the token. * @param {function} [onFailure] - Called on XHR failure. */ - completeEmailRegistration: function(token, onComplete, onFailure) { + completeEmailRegistration: function(token, password, onComplete, onFailure) { post({ url: "/wsapi/complete_email_addition", data: { - token: token + token: token, + pass: password }, success: function(status, textStatus, jqXHR) { complete(onComplete, status.success); diff --git a/resources/static/shared/user.js b/resources/static/shared/user.js index cb9e52e84..fb95b2556 100644 --- a/resources/static/shared/user.js +++ b/resources/static/shared/user.js @@ -497,17 +497,25 @@ BrowserID.User = (function() { * Verify a user * @method verifyUser * @param {string} token - token to verify. - * @param {function} [onComplete] - Called to give status updates. + * @param {string} password + * @param {function} [onComplete] - Called on completion. + * Called with an object with valid, email, and origin if valid, called + * with valid=false otw. * @param {function} [onFailure] - Called on error. */ - verifyUser: function(token, onComplete, onFailure) { + verifyUser: function(token, password, onComplete, onFailure) { User.tokenInfo(token, function(info) { var invalidInfo = { valid: false }; if (info) { - network.completeUserRegistration(token, function (valid) { - info.valid = valid; - storage.setStagedOnBehalfOf(""); - if (onComplete) onComplete(info); + network.completeUserRegistration(token, password, function (valid) { + var result = invalidInfo; + + if(valid) { + result = _.extend({ valid: valid, origin: storage.getStagedOnBehalfOf() }, info); + storage.setStagedOnBehalfOf(""); + } + + complete(onComplete, result); }, onFailure); } else if (onComplete) { onComplete(invalidInfo); @@ -851,19 +859,17 @@ BrowserID.User = (function() { * Verify a users email address given by the token * @method verifyEmail * @param {string} token + * @param {string} password * @param {function} [onComplete] - Called on completion. * Called with an object with valid, email, and origin if valid, called - * with only valid otw. + * with valid=false otw. * @param {function} [onFailure] - Called on error. */ - verifyEmail: function(token, onComplete, onFailure) { - function complete(status) { - onComplete && onComplete(status); - } + verifyEmail: function(token, password, onComplete, onFailure) { network.emailForVerificationToken(token, function (info) { var invalidInfo = { valid: false }; if (info) { - network.completeEmailRegistration(token, function (valid) { + network.completeEmailRegistration(token, password, function (valid) { var result = invalidInfo; if(valid) { @@ -871,10 +877,10 @@ BrowserID.User = (function() { storage.setStagedOnBehalfOf(""); } - complete(result); + complete(onComplete, result); }, onFailure); } else { - complete(invalidInfo); + complete(onComplete, invalidInfo); } }, onFailure); }, diff --git a/resources/static/test/cases/pages/verify_email_address_test.js b/resources/static/test/cases/pages/verify_email_address_test.js deleted file mode 100644 index d797739b6..000000000 --- a/resources/static/test/cases/pages/verify_email_address_test.js +++ /dev/null @@ -1,73 +0,0 @@ -/*jshint browsers:true, forin: true, laxbreak: true */ -/*global test: true, start: true, module: true, ok: true, equal: true, BrowserID:true */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -(function() { - "use strict"; - - var bid = BrowserID, - network = bid.Network, - storage = bid.Storage, - xhr = bid.Mocks.xhr, - testHelpers = bid.TestHelpers, - testTooltipVisible = testHelpers.testTooltipVisible, - validToken = true; - - module("pages/verify_email_address", { - setup: function() { - testHelpers.setup(); - bid.Renderer.render("#page_head", "site/verify_email_address", {}); - }, - teardown: function() { - testHelpers.teardown(); - } - }); - - asyncTest("verifyEmailAddress with good token and site", function() { - storage.setStagedOnBehalfOf("browserid.org"); - - bid.verifyEmailAddress("token", function() { - equal($("#email").val(), "testuser@testuser.com", "email set"); - ok($(".siteinfo").is(":visible"), "siteinfo is visible when we say what it is"); - equal($(".website:nth(0)").text(), "browserid.org", "origin is updated"); - start(); - }); - }); - - asyncTest("verifyEmailAddress with good token and nosite", function() { - $(".siteinfo").hide(); - storage.setStagedOnBehalfOf(""); - - bid.verifyEmailAddress("token", function() { - equal($("#email").val(), "testuser@testuser.com", "email set"); - equal($(".siteinfo").is(":visible"), false, "siteinfo is not visible without having it"); - equal($(".siteinfo .website").text(), "", "origin is not updated"); - start(); - }); - }); - - asyncTest("verifyEmailAddress with bad token", function() { - xhr.useResult("invalid"); - - bid.verifyEmailAddress("token", function() { - ok($("#cannotconfirm").is(":visible"), "cannot confirm box is visible"); - start(); - }); - }); - - asyncTest("verifyEmailAddress with emailForVerficationToken XHR failure", function() { - xhr.useResult("ajaxError"); - bid.verifyEmailAddress("token", function() { - testHelpers.testErrorVisible(); - start(); - }); - }); - - asyncTest("submit with good token", function() { - bid.verifyEmailAddress("token", function() { - equal($("#congrats").is(":visible"), true, "congrats is visible, we are complete"); - start(); - }); - }); -}()); diff --git a/resources/static/test/cases/pages/add_email_address_test.js b/resources/static/test/cases/pages/verify_secondary_address.js similarity index 63% rename from resources/static/test/cases/pages/add_email_address_test.js rename to resources/static/test/cases/pages/verify_secondary_address.js index 14c49d383..a770237db 100644 --- a/resources/static/test/cases/pages/add_email_address_test.js +++ b/resources/static/test/cases/pages/verify_secondary_address.js @@ -11,13 +11,15 @@ xhr = bid.Mocks.xhr, dom = bid.DOM, testHelpers = bid.TestHelpers, + testHasClass = testHelpers.testHasClass, validToken = true, controller, config = { - token: "token" + token: "token", + verifyFunction: "verifyEmail" }; - module("pages/add_email_address", { + module("pages/verify_secondary_address", { setup: function() { testHelpers.setup(); bid.Renderer.render("#page_head", "site/add_email_address", {}); @@ -29,14 +31,14 @@ }); function createController(options, callback) { - controller = BrowserID.addEmailAddress.create(); + controller = BrowserID.verifySecondaryAddress.create(); options = options || {}; options.ready = callback; controller.start(options); } function expectTooltipVisible() { - xhr.useResult("needsPassword"); + xhr.useResult("mustAuth"); createController(config, function() { controller.submit(function() { testHelpers.testTooltipVisible(); @@ -46,7 +48,7 @@ } function testEmail() { - equal(dom.getInner(".email"), "testuser@testuser.com", "correct email shown"); + equal(dom.getInner("#email"), "testuser@testuser.com", "correct email shown"); } function testCannotConfirm() { @@ -64,19 +66,19 @@ equal(error, "missing config option: token", "correct error thrown"); }); - asyncTest("no start with good token and site", function() { + asyncTest("no password: start with good token and site", function() { storage.setStagedOnBehalfOf("browserid.org"); createController(config, function() { testEmail(); ok($(".siteinfo").is(":visible"), "siteinfo is visible when we say what it is"); equal($(".website:nth(0)").text(), "browserid.org", "origin is updated"); - equal($("body").hasClass("complete"), true, "body has complete class"); + testHasClass("body", "complete"); start(); }); }); - asyncTest("no start with good token and nosite", function() { + asyncTest("no password: start with good token and nosite", function() { createController(config, function() { testEmail(); equal($(".siteinfo").is(":visible"), false, "siteinfo is not visible without having it"); @@ -85,7 +87,7 @@ }); }); - asyncTest("no start with bad token", function() { + asyncTest("no password: start with bad token", function() { xhr.useResult("invalid"); createController(config, function() { @@ -94,11 +96,42 @@ }); }); - asyncTest("no start with emailForVerficationToken XHR failure", function() { + asyncTest("no password: start with emailForVerficationToken XHR failure", function() { xhr.useResult("ajaxError"); createController(config, function() { testHelpers.testErrorVisible(); start(); }); }); + + asyncTest("password: missing password", function() { + $("#password").val(); + + expectTooltipVisible(); + }); + + asyncTest("password: good password", function() { + $("#password").val("password"); + + xhr.useResult("mustAuth"); + createController(config, function() { + xhr.useResult("valid"); + controller.submit(function(status) { + equal(status, true, "correct status"); + testHasClass("body", "complete"); + start(); + }); + }); + }); + + asyncTest("password: good password bad token", function() { + $("#password").val("password"); + + xhr.useResult("invalid"); + createController(config, function() { + testCannotConfirm(); + start(); + }); + }); + }()); diff --git a/resources/static/test/cases/shared/network.js b/resources/static/test/cases/shared/network.js index fdf07b9e0..a4accfb68 100644 --- a/resources/static/test/cases/shared/network.js +++ b/resources/static/test/cases/shared/network.js @@ -12,7 +12,8 @@ testHelpers = bid.TestHelpers, TEST_EMAIL = "testuser@testuser.com", TEST_PASSWORD = "password", - failureCheck = testHelpers.failureCheck; + failureCheck = testHelpers.failureCheck, + testObjectValuesEqual = testHelpers.testObjectValuesEqual; var network = BrowserID.Network; @@ -167,22 +168,29 @@ asyncTest("completeEmailRegistration valid", function() { - network.completeEmailRegistration("goodtoken", function onSuccess(proven) { + network.completeEmailRegistration("goodtoken", "password", function onSuccess(proven) { equal(proven, true, "good token proved"); start(); }, testHelpers.unexpectedXHRFailure); }); + asyncTest("completeEmailRegistration with valid token, missing password", function() { + transport.useResult("missing_password"); + network.completeEmailRegistration("token", undefined, + testHelpers.unexpectedSuccess, + testHelpers.expectedXHRFailure); + }); + asyncTest("completeEmailRegistration with invalid token", function() { transport.useResult("invalid"); - network.completeEmailRegistration("badtoken", function onSuccess(proven) { + network.completeEmailRegistration("badtoken", "password", function onSuccess(proven) { equal(proven, false, "bad token could not be proved"); start(); }, testHelpers.unexpectedXHRFailure); }); asyncTest("completeEmailRegistration with XHR failure", function() { - failureCheck(network.completeEmailRegistration, "goodtoken"); + failureCheck(network.completeEmailRegistration, "goodtoken", "password"); }); asyncTest("createUser with valid user", function() { @@ -265,8 +273,22 @@ failureCheck(network.checkUserRegistration, "registered@testuser.com"); }); - asyncTest("completeUserRegistration with valid token", function() { - network.completeUserRegistration("token", function(registered) { + asyncTest("completeUserRegistration with valid token, no password required", function() { + network.completeUserRegistration("token", undefined, function(registered) { + ok(registered); + start(); + }, testHelpers.unexpectedFailure); + }); + + asyncTest("completeUserRegistration with valid token, missing password", function() { + transport.useResult("missing_password"); + network.completeUserRegistration("token", undefined, + testHelpers.unexpectedSuccess, + testHelpers.expectedXHRFailure); + }); + + asyncTest("completeUserRegistration with valid token, password required", function() { + network.completeUserRegistration("token", "password", function(registered) { ok(registered); start(); }, testHelpers.unexpectedFailure); @@ -275,14 +297,14 @@ asyncTest("completeUserRegistration with invalid token", function() { transport.useResult("invalid"); - network.completeUserRegistration("token", function(registered) { + network.completeUserRegistration("token", "password", function(registered) { equal(registered, false); start(); }, testHelpers.unexpectedFailure); }); asyncTest("completeUserRegistration with XHR failure", function() { - failureCheck(network.completeUserRegistration, "token"); + failureCheck(network.completeUserRegistration, "token", "password"); }); asyncTest("cancelUser valid", function() { @@ -416,12 +438,11 @@ }, testHelpers.unexpectedXHRFailure); }); - asyncTest("emailForVerificationToken that needs password - returns needs_password and email address", function() { - transport.useResult("needsPassword"); + asyncTest("emailForVerificationToken that must authenticate - returns must_auth and email address", function() { + transport.useResult("mustAuth"); network.emailForVerificationToken("token", function(result) { - equal(result.needs_password, true, "needs_password correctly set to true"); - equal(result.email, TEST_EMAIL, "email address correctly added"); + testObjectValuesEqual(result, { must_auth: true, email: TEST_EMAIL }); start(); }, testHelpers.unexpectedXHRFailure); }); diff --git a/resources/static/test/cases/shared/user.js b/resources/static/test/cases/shared/user.js index 6a27aa825..455736004 100644 --- a/resources/static/test/cases/shared/user.js +++ b/resources/static/test/cases/shared/user.js @@ -393,7 +393,7 @@ var vep = require("./vep"); asyncTest("verifyUser with a good token", function() { storage.setStagedOnBehalfOf(testOrigin); - lib.verifyUser("token", function onSuccess(info) { + lib.verifyUser("token", "password", function onSuccess(info) { ok(info.valid, "token was valid"); equal(info.email, TEST_EMAIL, "email part of info"); @@ -407,7 +407,7 @@ var vep = require("./vep"); asyncTest("verifyUser with a bad token", function() { xhr.useResult("invalid"); - lib.verifyUser("token", function onSuccess(info) { + lib.verifyUser("token", "password", function onSuccess(info) { equal(info.valid, false, "bad token calls onSuccess with a false validity"); start(); }, testHelpers.unexpectedXHRFailure); @@ -418,6 +418,7 @@ var vep = require("./vep"); lib.verifyUser( "token", + "password", testHelpers.unexpectedSuccess, testHelpers.expectedXHRFailure ); @@ -716,7 +717,7 @@ var vep = require("./vep"); asyncTest("verifyEmail with a good token - callback with email, origin, valid", function() { storage.setStagedOnBehalfOf(testOrigin); - lib.verifyEmail("token", function onSuccess(info) { + lib.verifyEmail("token", "password", function onSuccess(info) { ok(info.valid, "token was valid"); equal(info.email, TEST_EMAIL, "email part of info"); @@ -730,7 +731,7 @@ var vep = require("./vep"); asyncTest("verifyEmail with a bad token - callback with valid: false", function() { xhr.useResult("invalid"); - lib.verifyEmail("token", function onSuccess(info) { + lib.verifyEmail("token", "password", function onSuccess(info) { equal(info.valid, false, "bad token calls onSuccess with a false validity"); start(); @@ -742,6 +743,7 @@ var vep = require("./vep"); lib.verifyEmail( "token", + "password", testHelpers.unexpectedSuccess, testHelpers.expectedXHRFailure ); diff --git a/resources/static/test/mocks/xhr.js b/resources/static/test/mocks/xhr.js index d78791805..f7ede54d1 100644 --- a/resources/static/test/mocks/xhr.js +++ b/resources/static/test/mocks/xhr.js @@ -32,7 +32,7 @@ BrowserID.Mocks.xhr = (function() { // the flag contextAjaxError. "get /wsapi/session_context contextAjaxError": undefined, "get /wsapi/email_for_token?token=token valid": { email: "testuser@testuser.com" }, - "get /wsapi/email_for_token?token=token needsPassword": { email: "testuser@testuser.com", needs_password: true }, + "get /wsapi/email_for_token?token=token mustAuth": { email: "testuser@testuser.com", must_auth: true }, "get /wsapi/email_for_token?token=token invalid": { success: false }, "post /wsapi/authenticate_user valid": { success: true, userid: 1 }, "post /wsapi/authenticate_user invalid": { success: false }, @@ -46,6 +46,7 @@ BrowserID.Mocks.xhr = (function() { "post /wsapi/cert_key invalid": undefined, "post /wsapi/cert_key ajaxError": undefined, "post /wsapi/complete_email_addition valid": { success: true }, + "post /wsapi/complete_email_addition missing_password": 401, "post /wsapi/complete_email_addition invalid": { success: false }, "post /wsapi/complete_email_addition ajaxError": undefined, "post /wsapi/stage_user unknown_secondary": { success: true }, @@ -59,6 +60,7 @@ BrowserID.Mocks.xhr = (function() { "get /wsapi/user_creation_status?email=registered%40testuser.com noRegistration": { status: "noRegistration" }, "get /wsapi/user_creation_status?email=registered%40testuser.com ajaxError": undefined, "post /wsapi/complete_user_creation valid": { success: true }, + "post /wsapi/complete_user_creation missing_password": 401, "post /wsapi/complete_user_creation invalid": { success: false }, "post /wsapi/complete_user_creation ajaxError": undefined, "post /wsapi/logout valid": { success: true }, diff --git a/resources/static/test/testHelpers/helpers.js b/resources/static/test/testHelpers/helpers.js index 9c85bf656..3b4ba0d30 100644 --- a/resources/static/test/testHelpers/helpers.js +++ b/resources/static/test/testHelpers/helpers.js @@ -197,6 +197,17 @@ BrowserID.TestHelpers = (function() { str += (i % 10); } return str; + }, + + testObjectValuesEqual: function(objToTest, expected, msg) { + for(var key in expected) { + equal(objToTest[key], expected[key], key + " set to: " + expected[key] + (msg ? " - " + msg : "")); + } + }, + + testHasClass: function(selector, className, msg) { + ok($(selector).hasClass(className), + selector + " has className " + className + " - " + msg); } }; diff --git a/resources/views/add_email_address.ejs b/resources/views/add_email_address.ejs index 553e9c69a..fa6fbd891 100644 --- a/resources/views/add_email_address.ejs +++ b/resources/views/add_email_address.ejs @@ -14,13 +14,30 @@ <h1 class="serif"><%= gettext('Email Verification') %></h1> - <ul class="inputs password_entry"> + <ul class="inputs"> <li> <label class="serif" for="email"><%= gettext('Email Address') %></label> - <input class="youraddress sans email" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" /> + <input class="youraddress sans" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" /> + </li> + <li class="password_entry"> + <label class="serif" for="password"><%= gettext('Password') %></label> + <input class="sans" id="password" placeholder="<%= gettext('Your Password') %>" type="password" autofocus maxlength=80 /> + + <div class="tooltip" id="password_required" for="password"> + <%= gettext('Password is required.') %> + </div> + + <div class="tooltip" id="password_length" for="password"> + <%= gettext('Password must be between 8 and 80 characters long.') %> + </div> </li> </ul> + <div class="submit cf password_entry"> + <button><%= gettext('finish') %></button> + </div> + + </form> <div id="congrats"> diff --git a/resources/views/test.ejs b/resources/views/test.ejs index b7fcf298b..cde560335 100644 --- a/resources/views/test.ejs +++ b/resources/views/test.ejs @@ -128,12 +128,11 @@ <script src="/dialog/controllers/set_password.js"></script> <script src="/pages/page_helpers.js"></script> - <script src="/pages/add_email_address.js"></script> + <script src="/pages/verify_secondary_address.js"></script> <script src="/pages/forgot.js"></script> <script src="/pages/manage_account.js"></script> <script src="/pages/signin.js"></script> <script src="/pages/signup.js"></script> - <script src="/pages/verify_email_address.js"></script> <script src="testHelpers/helpers.js"></script> @@ -162,8 +161,7 @@ <script src="cases/pages/browserid.js"></script> <script src="cases/pages/page_helpers.js"></script> - <script src="cases/pages/add_email_address_test.js"></script> - <script src="cases/pages/verify_email_address_test.js"></script> + <script src="cases/pages/verify_secondary_address.js"></script> <script src="cases/pages/forgot.js"></script> <script src="cases/pages/signin.js"></script> <script src="cases/pages/signup.js"></script> diff --git a/resources/views/verify_email_address.ejs b/resources/views/verify_email_address.ejs index 058c44572..a73c80ead 100644 --- a/resources/views/verify_email_address.ejs +++ b/resources/views/verify_email_address.ejs @@ -6,7 +6,6 @@ <div id="signUpFormWrap"> <ul class="notifications"> <li class="notification error" id="cannotconfirm"><%= gettext('There was a problem with your signup link. Has this address already been registered?') %></li> - <li class="notification error" id="cannotcommunicate"><%= gettext('Error communicating with server.') %></li> <li class="notification error" id="cannotcomplete"><%= gettext('Error encountered trying to complete registration.') %></li> </ul> @@ -19,8 +18,24 @@ <label class="serif" for="email"><%= gettext('Email Address') %></label> <input class="youraddress sans" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" /> </li> + <li class="password_entry"> + <label class="serif" for="password"><%= gettext('Password') %></label> + <input class="sans" id="password" placeholder="<%= gettext('Your Password') %>" type="password" autofocus maxlength=80 /> + + <div class="tooltip" id="password_required" for="password"> + <%= gettext('Password is required.') %> + </div> + + <div class="tooltip" id="password_length" for="password"> + <%= gettext('Password must be between 8 and 80 characters long.') %> + </div> + </li> </ul> + <div class="submit cf password_entry"> + <button><%= gettext('finish') %></button> + </div> + </form> <div id="congrats"> -- GitLab