diff --git a/resources/static/dialog/controllers/add_email.js b/resources/static/dialog/controllers/add_email.js index da7755705a1607975ddf09c9ce8bce341e1659b2..f4b1b3c1bf6c2a473995e5724bc6d8c5672d655d 100644 --- a/resources/static/dialog/controllers/add_email.js +++ b/resources/static/dialog/controllers/add_email.js @@ -1,4 +1,4 @@ -/*jshint brgwser:true, jQuery: true, forin: true, laxbreak:true */ +/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ /*global _: true, BrowserID: true, PageController: true */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 diff --git a/resources/static/dialog/controllers/email_chosen.js b/resources/static/dialog/controllers/email_chosen.js index 1042d1eefc0addadabdbe7e40d5479711826650c..0eed93025db81931613d7fded14d54740f171827 100644 --- a/resources/static/dialog/controllers/email_chosen.js +++ b/resources/static/dialog/controllers/email_chosen.js @@ -1,4 +1,4 @@ -/*jshint brgwser:true, jQuery: true, forin: true, laxbreak:true */ +/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ /*global _: true, BrowserID: true, PageController: true */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 diff --git a/resources/static/dialog/controllers/page.js b/resources/static/dialog/controllers/page.js index e0dceb8218bbb4de6f374b70ec8c86f904055a0c..8f29623cdfbb3b22ba7ea26fe16f0956bd3d49a2 100644 --- a/resources/static/dialog/controllers/page.js +++ b/resources/static/dialog/controllers/page.js @@ -129,7 +129,9 @@ BrowserID.Modules.PageModule = (function() { bid.ErrorDisplay.start(); - $("#error").stop().css('opacity', 1).hide().fadeIn(ANIMATION_TIME, oncomplete); + $("#error").stop().css('opacity', 1).hide().fadeIn(ANIMATION_TIME, function() { + if(oncomplete) oncomplete(false); + }); }, validate: function() { diff --git a/resources/static/dialog/controllers/pick_email.js b/resources/static/dialog/controllers/pick_email.js index 55b6789182fe034949249c49df208c3a5ca29cdf..2d88fefeedf4b0adb62018ce7330b7ce434d08ee 100644 --- a/resources/static/dialog/controllers/pick_email.js +++ b/resources/static/dialog/controllers/pick_email.js @@ -1,4 +1,4 @@ -/*jshint brgwser:true, jQuery: true, forin: true, laxbreak:true */ +/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ /*global _: true, BrowserID: true, PageController: true */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 diff --git a/resources/static/dialog/controllers/required_email.js b/resources/static/dialog/controllers/required_email.js index a027061cb9447691587498ca19e34931c0cb94e5..b7754ca1824778f9ac4b3d03df327fc7d07234bb 100644 --- a/resources/static/dialog/controllers/required_email.js +++ b/resources/static/dialog/controllers/required_email.js @@ -1,4 +1,4 @@ -/*jshint brgwser:true, jQuery: true, forin: true, laxbreak:true */ +/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ /*global _: true, BrowserID: true, PageController: true */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 diff --git a/resources/static/dialog/controllers/set_password.js b/resources/static/dialog/controllers/set_password.js new file mode 100644 index 0000000000000000000000000000000000000000..cd84ddd442852c8ee8e7166760cc0129c0310c2f --- /dev/null +++ b/resources/static/dialog/controllers/set_password.js @@ -0,0 +1,95 @@ +/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ +/*global _: true, BrowserID: true, PageController: true */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +BrowserID.Modules.SetPassword = (function() { + "use strict"; + + var bid = BrowserID, + user = bid.User, + errors = bid.Errors, + helpers = bid.Helpers, + dom = bid.DOM, + sc; + + + function setPassword(oncomplete) { + function complete(status) { + if(oncomplete) oncomplete(status); + } + + var self = this, + pass = dom.getInner("#password"), + vpass = dom.getInner("#vpassword"), + valid = bid.Validation.passwordAndValidationPassword(pass, vpass); + + if(valid) { + user.setPassword( + pass, + function(status) { + self.publish("password_set"); + complete(true); + }, + self.getErrorDialog(errors.setPassword, complete) + ); + } + else { + complete(false); + } + } + + var Module = bid.Modules.PageModule.extend({ + start: function(options) { + var self=this; + sc.start.call(self, options); + + self.renderDialog("set_password", options); + }, + + submit: setPassword + + // BEGIN TESTING API + , + + setPassword: setPassword + // END TESTING API + }); + + sc = Module.sc; + + return Module; + +}()); + diff --git a/resources/static/dialog/views/set_password.ejs b/resources/static/dialog/views/set_password.ejs new file mode 100644 index 0000000000000000000000000000000000000000..75572ed6cd4e7018d0f2f3ba44798d7aed14d8bc --- /dev/null +++ b/resources/static/dialog/views/set_password.ejs @@ -0,0 +1,40 @@ + <strong> + Sign in using + </strong> + + <div class="form_section" id="set_password"> + <ul class="inputs"> + <li> + <label for="password" class="serif">Password</label> + <input class="sans" id="password" placeholder="Enter a Password" type="password" autofocus maxlength=80> + + <div class="tooltip" id="password_required" for="password"> + Password is required. + </div> + + <div class="tooltip" id="password_too_short" for="password"> + Password must be at least 8 characters long. + </div> + <li> + + <li> + <label for="vpassword" class="serif">Verify Password</label> + <input class="sans" id="vpassword" placeholder="Repeat Password" type="password" maxlength=80> + + <div class="tooltip" id="vpassword_required" for="vpassword"> + Verification password is required. + </div> + + <div class="tooltip" id="passwords_no_match" for="vpassword"> + Passwords do not match. + </div> + <li> + + + </ul> + + <div class="submit cf"> + <button tabindex="1">Reset Password</button> + <!--button id="cancel_set_password" tabindex="2">Cancel</button--> + </div> + </div> diff --git a/resources/static/shared/error-messages.js b/resources/static/shared/error-messages.js index 894f84ec54ec0c51c47d2c7ce3171c26adbdafbc..9f96220519ce985403b2f6fd745c5684d984f9b5 100644 --- a/resources/static/shared/error-messages.js +++ b/resources/static/shared/error-messages.js @@ -126,6 +126,10 @@ BrowserID.Errors = (function(){ title: "Remove Email Address from Account" }, + setPassword: { + title: "Setting Password" + }, + signIn: { title: "Signin Failed" }, diff --git a/resources/static/shared/network.js b/resources/static/shared/network.js index 847f487a923d39e0b54c225ec752c79384feb836..23b70798690ceb0eef0187ce231f3b9d0a308902 100644 --- a/resources/static/shared/network.js +++ b/resources/static/shared/network.js @@ -387,15 +387,23 @@ BrowserID.Network = (function() { }, /** - * Update the password of the current user. This is for a password reseT - * @method resetPassword + * Set the password of the current user. + * @method setPassword * @param {string} password - new password. * @param {function} [onComplete] - Callback to call when complete. * @param {function} [onFailure] - Called on XHR failure. */ - resetPassword: function(password, onComplete, onFailure) { - // XXX fill this in. - if (onComplete) onComplete(); + setPassword: function(password, onComplete, onFailure) { + post({ + url: "/wsapi/set_password", + data: { + password: password + }, + success: function(status) { + if (onComplete) onComplete(status.success); + }, + error: onFailure + }); }, /** diff --git a/resources/static/test/index.html b/resources/static/test/index.html index d5c1e0a225590a8c0e499018a1f1cae2704b9c50..bc796b39b27c913d26704272c7fc05124e099fda 100644 --- a/resources/static/test/index.html +++ b/resources/static/test/index.html @@ -132,6 +132,7 @@ <script type="text/javascript" src="/dialog/controllers/email_chosen.js"></script> <script type="text/javascript" src="/dialog/controllers/provision_primary_user.js"></script> <script type="text/javascript" src="/dialog/controllers/primary_user_provisioned.js"></script> + <script type="text/javascript" src="/dialog/controllers/set_password.js"></script> <script type="text/javascript" src="/pages/page_helpers.js"></script> <script type="text/javascript" src="/pages/add_email_address.js"></script> @@ -182,6 +183,7 @@ <script type="text/javascript" src="qunit/controllers/email_chosen_unit_test.js"></script> <script type="text/javascript" src="qunit/controllers/provision_primary_user_unit_test.js"></script> <script type="text/javascript" src="qunit/controllers/primary_user_provisioned_unit_test.js"></script> + <script type="text/javascript" src="qunit/controllers/set_password_unit_test.js"></script> <!-- must go last or all other tests will fail. --> <script type="text/javascript" src="qunit/controllers/dialog_unit_test.js"></script> diff --git a/resources/static/test/qunit/controllers/set_password_unit_test.js b/resources/static/test/qunit/controllers/set_password_unit_test.js new file mode 100644 index 0000000000000000000000000000000000000000..e58f84beeacaad5fd5b077a64ce35be87c6a4a00 --- /dev/null +++ b/resources/static/test/qunit/controllers/set_password_unit_test.js @@ -0,0 +1,137 @@ +/*jshint browsers:true, forin: true, laxbreak: true */ +/*global test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID:true */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +(function() { + "use strict"; + + var controller, + bid = BrowserID, + storage = bid.Storage, + testHelpers = bid.TestHelpers, + xhr = bid.Mocks.xhr, + register = bid.TestHelpers.register; + + module("controllers/set_password", { + setup: function() { + testHelpers.setup(); + createController(); + $("#password").val(""); + $("#vpassword").val(""); + }, + + teardown: function() { + if (controller) { + try { + controller.destroy(); + controller = null; + } catch(e) { + // could already be destroyed from the close + } + } + testHelpers.setup(); + } + }); + + + function createController(options) { + controller = bid.Modules.SetPassword.create(); + controller.start(options); + } + + function testInvalidInput() { + controller.setPassword(function(status) { + equal(false, status, "status is false"); + testHelpers.testTooltipVisible(); + start(); + }); + } + + test("create displays the correct template", function() { + equal($("#set_password").length, 1, "the correct template is displayed"); + }); + + asyncTest("setPassword with no password", function() { + $("#password").val(""); + $("#vpassword").val("password"); + testInvalidInput(); + }); + + asyncTest("setPassword with no verification password", function() { + $("#password").val("password"); + $("#vpassword").val(""); + testInvalidInput(); + }); + + asyncTest("setPassword with too short of a password", function() { + $("#password").val("pass"); + $("#vpassword").val("pass"); + testInvalidInput(); + }); + + asyncTest("setPassword with mismatched passwords", function() { + $("#password").val("passwords"); + $("#vpassword").val("password"); + testInvalidInput(); + }); + + asyncTest("setPassword with XHR error", function() { + $("#password").val("password"); + $("#vpassword").val("password"); + xhr.useResult("ajaxError"); + + controller.setPassword(function(status) { + equal(status, false, "correct status"); + testHelpers.testErrorVisible(); + start(); + }); + }); + + asyncTest("setPassword happy case", function() { + $("#password").val("password"); + $("#vpassword").val("password"); + + + register("password_set", function(msg, info) { + ok(true, msg + " message received"); + start(); + }); + + controller.setPassword(function(status) { + equal(status, true, "correct status"); + }); + }); +}()); + diff --git a/resources/static/test/qunit/mocks/xhr.js b/resources/static/test/qunit/mocks/xhr.js index c1f50c5dbbe717b9af189a9757acf72461c32292..b6c2cbde8c5910c1697d0ce76fa339f204e35a1b 100644 --- a/resources/static/test/qunit/mocks/xhr.js +++ b/resources/static/test/qunit/mocks/xhr.js @@ -117,6 +117,9 @@ BrowserID.Mocks.xhr = (function() { "get /wsapi/list_emails ajaxError": undefined, // Used in conjunction with registration to do a complete userflow "get /wsapi/list_emails complete": {"registered@testuser.com":{}}, + "post /wsapi/set_password valid": { success: true }, + "post /wsapi/set_password invalid": { success: false }, + "post /wsapi/set_password ajaxError": undefined, "post /wsapi/update_password valid": { success: true }, "post /wsapi/update_password incorrectPassword": { success: false }, "post /wsapi/update_password invalid": undefined, diff --git a/resources/static/test/qunit/shared/network_unit_test.js b/resources/static/test/qunit/shared/network_unit_test.js index c09235b23545ffd97cfd496f73686fe434624198..ce9edf9b17199add6207fed396ae0ce2a89a58c5 100644 --- a/resources/static/test/qunit/shared/network_unit_test.js +++ b/resources/static/test/qunit/shared/network_unit_test.js @@ -587,32 +587,20 @@ failureCheck(network.requestPasswordReset, "address", "origin"); }); - asyncTest("resetPassword", function() { - network.resetPassword("password", function onSuccess() { - // XXX need a test here; - ok(true); - start(); - }, function onFailure() { - ok(false); + asyncTest("setPassword happy case expects true status", function() { + network.setPassword("password", function onComplete(status) { + equal(status, true, "correct status"); start(); - }); - + }, testHelpers.unexpectedXHRFailure); }); - asyncTest("resetPassword with XHR failure", function() { + asyncTest("setPassword with XHR failure", function() { xhr.useResult("ajaxError"); -/* - the body of this function is not yet written - - network.resetPassword("password", function onSuccess() { - ok(false, "XHR failure should never call success"); - start(); - }, function onFailure() { - ok(true, "XHR failure should always call failure"); - start(); - }); -*/ - start(); + network.setPassword( + "password", + testHelpers.unexpectedSuccess, + testHelpers.expectedXHRFailure + ); }); asyncTest("serverTime", function() { diff --git a/resources/static/test/qunit/testHelpers/helpers.js b/resources/static/test/qunit/testHelpers/helpers.js index 3775abd0ed6b03b8e986f06b5db0e3bde8302ad6..ac78a203cc868faa12e89dd70106288f45e57ef3 100644 --- a/resources/static/test/qunit/testHelpers/helpers.js +++ b/resources/static/test/qunit/testHelpers/helpers.js @@ -102,6 +102,11 @@ unexpectedXHRFailure: function() { ok(false, "unexpected XHR failure"); start(); + }, + + testTooltipVisible: function() { + equal(tooltip.shown, true, "tooltip is visible"); } + }; }()); diff --git a/resources/views/dialog_layout.ejs b/resources/views/dialog_layout.ejs index fbfafcfbde66aad4c81951824eead00d9950613c..212eb3b0e0ecd72c18785d910b8275b6bfd42348 100644 --- a/resources/views/dialog_layout.ejs +++ b/resources/views/dialog_layout.ejs @@ -94,6 +94,7 @@ <script type="text/javascript" src="/dialog/controllers/verify_primary_user.js"></script> <script type="text/javascript" src="/dialog/controllers/provision_primary_user.js"></script> <script type="text/javascript" src="/dialog/controllers/primary_user_provisioned.js"></script> + <script type="text/javascript" src="/dialog/controllers/set_password.js"></script> <script type="text/javascript" src="/dialog/controllers/email_chosen.js"></script> <script type="text/javascript" src="/dialog/start.js"></script> <% } %> diff --git a/resources/views/verifyuser.ejs b/resources/views/verifyuser.ejs index 357644f2d43f64de920aed0ca3f9115e80f1b8e5..7a54af78988fab7a6299b99736c428cddf8cc268 100644 --- a/resources/views/verifyuser.ejs +++ b/resources/views/verifyuser.ejs @@ -37,7 +37,7 @@ </div> <div class="tooltip" id="passwords_no_match" for="vpassword"> - Passwords do not match + Passwords do not match. </div> </li> </ul> diff --git a/scripts/compress.sh b/scripts/compress.sh index d7d5ce845b09dfdb1a70f995728c6af2fcaf8cd7..6c1260f74422590639072f561d67f74285188ebc 100755 --- a/scripts/compress.sh +++ b/scripts/compress.sh @@ -54,7 +54,7 @@ cp templates.js $BUILD_PATH/templates.js cd ../.. # produce the dialog js -cat lib/jquery-1.6.2.min.js lib/winchan.js lib/underscore-min.js lib/vepbundle.js lib/ejs.js shared/browserid.js lib/hub.js lib/dom-jquery.js lib/module.js shared/javascript-extensions.js shared/mediator.js shared/class.js shared/storage.js $BUILD_PATH/templates.js shared/renderer.js shared/error-display.js shared/screens.js shared/tooltip.js shared/validation.js shared/network.js shared/provisioning.js shared/user.js shared/error-messages.js shared/browser-support.js shared/wait-messages.js shared/helpers.js dialog/resources/internal_api.js dialog/resources/helpers.js dialog/resources/state_machine.js dialog/controllers/page.js dialog/controllers/code_check.js dialog/controllers/actions.js dialog/controllers/dialog.js dialog/controllers/authenticate.js dialog/controllers/forgot_password.js dialog/controllers/check_registration.js dialog/controllers/pick_email.js dialog/controllers/add_email.js dialog/controllers/required_email.js dialog/controllers/verify_primary_user.js dialog/controllers/provision_primary_user.js dialog/controllers/primary_user_provisioned.js dialog/controllers/email_chosen.js dialog/start.js > $BUILD_PATH/dialog.uncompressed.js +cat lib/jquery-1.6.2.min.js lib/winchan.js lib/underscore-min.js lib/vepbundle.js lib/ejs.js shared/browserid.js lib/hub.js lib/dom-jquery.js lib/module.js shared/javascript-extensions.js shared/mediator.js shared/class.js shared/storage.js $BUILD_PATH/templates.js shared/renderer.js shared/error-display.js shared/screens.js shared/tooltip.js shared/validation.js shared/network.js shared/provisioning.js shared/user.js shared/error-messages.js shared/browser-support.js shared/wait-messages.js shared/helpers.js dialog/resources/internal_api.js dialog/resources/helpers.js dialog/resources/state_machine.js dialog/controllers/page.js dialog/controllers/code_check.js dialog/controllers/actions.js dialog/controllers/dialog.js dialog/controllers/authenticate.js dialog/controllers/forgot_password.js dialog/controllers/check_registration.js dialog/controllers/pick_email.js dialog/controllers/add_email.js dialog/controllers/required_email.js dialog/controllers/verify_primary_user.js dialog/controllers/provision_primary_user.js dialog/controllers/primary_user_provisioned.js dialog/controllers/set_password.js dialog/controllers/email_chosen.js dialog/start.js > $BUILD_PATH/dialog.uncompressed.js # produce the dialog css cat css/common.css dialog/css/popup.css dialog/css/m.css > $BUILD_PATH/dialog.uncompressed.css