diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js new file mode 100644 index 0000000000..d1626e21a3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js @@ -0,0 +1,170 @@ +(function () { + 'use strict'; + + function ChangePasswordController($scope) { + + function resetModel(isNew) { + //the model config will contain an object, if it does not we'll create defaults + //NOTE: We will not support doing the password regex on the client side because the regex on the server side + //based on the membership provider cannot always be ported to js from .net directly. + /* + { + hasPassword: true/false, + requiresQuestionAnswer: true/false, + enableReset: true/false, + enablePasswordRetrieval: true/false, + minPasswordLength: 10 + } + */ + + //set defaults if they are not available + if ($scope.config.disableToggle === undefined) { + $scope.config.disableToggle = false; + } + if ($scope.config.hasPassword === undefined) { + $scope.config.hasPassword = false; + } + if ($scope.config.enablePasswordRetrieval === undefined) { + $scope.config.enablePasswordRetrieval = true; + } + if ($scope.config.requiresQuestionAnswer === undefined) { + $scope.config.requiresQuestionAnswer = false; + } + if ($scope.config.enableReset === undefined) { + $scope.config.enableReset = true; + } + if ($scope.config.minPasswordLength === undefined) { + $scope.config.minPasswordLength = 0; + } + + //set the model defaults + if (!angular.isObject($scope.passwordValues)) { + //if it's not an object then just create a new one + $scope.passwordValues = { + newPassword: null, + oldPassword: null, + reset: null, + answer: null + }; + } + else { + //just reset the values + + if (!isNew) { + //if it is new, then leave the generated pass displayed + $scope.passwordValues.newPassword = null; + $scope.passwordValues.oldPassword = null; + } + $scope.passwordValues.reset = null; + $scope.passwordValues.answer = null; + } + + //the value to compare to match passwords + if (!isNew) { + $scope.confirm = ""; + } + else if ($scope.passwordValues.newPassword && $scope.passwordValues.newPassword.length > 0) { + //if it is new and a new password has been set, then set the confirm password too + $scope.confirm = $scope.passwordValues.newPassword; + } + + } + + resetModel($scope.isNew); + + //if there is no password saved for this entity , it must be new so we do not allow toggling of the change password, it is always there + //with validators turned on. + $scope.changing = $scope.config.disableToggle === true || !$scope.config.hasPassword; + + //we're not currently changing so set the model to null + if (!$scope.changing) { + $scope.passwordValues = null; + } + + $scope.doChange = function () { + resetModel(); + $scope.changing = true; + //if there was a previously generated password displaying, clear it + $scope.passwordValues.generatedPassword = null; + }; + + $scope.cancelChange = function () { + $scope.changing = false; + //set model to null + $scope.passwordValues = null; + }; + + var unsubscribe = []; + + //listen for the saved event, when that occurs we'll + //change to changing = false; + unsubscribe.push($scope.$on("formSubmitted", function () { + if ($scope.config.disableToggle === false) { + $scope.changing = false; + } + })); + unsubscribe.push($scope.$on("formSubmitting", function () { + //if there was a previously generated password displaying, clear it + if ($scope.changing && $scope.passwordValues) { + $scope.passwordValues.generatedPassword = null; + } + else if (!$scope.changing) { + //we are not changing, so the model needs to be null + $scope.passwordValues = null; + } + })); + + //when the scope is destroyed we need to unsubscribe + $scope.$on('$destroy', function () { + for (var u in unsubscribe) { + unsubscribe[u](); + } + }); + + $scope.showReset = function () { + return $scope.config.hasPassword && $scope.config.enableReset; + }; + + $scope.showOldPass = function () { + return $scope.config.hasPassword && + !$scope.config.allowManuallyChangingPassword && + !$scope.config.enablePasswordRetrieval && !$scope.passwordValues.reset; + }; + + $scope.showNewPass = function () { + return !$scope.passwordValues.reset; + }; + + $scope.showConfirmPass = function () { + return !$scope.passwordValues.reset; + }; + + $scope.showCancelBtn = function () { + return $scope.config.disableToggle !== true && $scope.config.hasPassword; + }; + + } + + function ChangePasswordDirective() { + + var directive = { + restrict: 'E', + replace: true, + templateUrl: 'views/components/users/change-password.html', + controller: 'Umbraco.Editors.Users.ChangePasswordDirectiveController', + scope: { + isNew: "=?", + passwordValues: "=", + config: "=" + } + }; + + return directive; + + } + + angular.module('umbraco.directives').controller('Umbraco.Editors.Users.ChangePasswordDirectiveController', ChangePasswordController); + angular.module('umbraco.directives').directive('changePassword', ChangePasswordDirective); + + +})(); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index 3b55753ee5..a935acb66e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -81,7 +81,7 @@ formatUserPostData: function (displayModel) { //create the save model from the display model - var saveModel = _.pick(displayModel, 'id', 'parentId', 'name', 'username', 'culture', 'email', 'startContentIds', 'startMediaIds', 'userGroups', 'message'); + var saveModel = _.pick(displayModel, 'id', 'parentId', 'name', 'username', 'culture', 'email', 'startContentIds', 'startMediaIds', 'userGroups', 'message', 'changePassword'); //make sure the userGroups are just a string array var currGroups = saveModel.userGroups; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js index f59292dcc8..5082543b9d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js @@ -112,10 +112,8 @@ angular.module("umbraco") /* ---------- UPDATE PASSWORD ---------- */ - //create the initial model for change password property editor + //create the initial model for change password $scope.changePasswordModel = { - alias: "_umb_password", - view: "changepassword", config: {}, value: {} }; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.html index 31ff07aeb9..fad32bf9dd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.html @@ -97,8 +97,10 @@ ng-submit="changePassword()" novalidate val-form-manager> - - + + + +
+ Password has been reset to: +
+ {{passwordValues.generatedPassword}} +
+
+
+ + Change password + +
+
+ + + + + + + + + + Required + + + + + + Required + Minimum {{$parent.config.minPasswordLength}} characters + + + + + + + + The confirmed password doesn't match the new password! + + + + + Cancel + +
+
+ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js index 71d84a8412..239be5eebc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.controller.js @@ -1,144 +1,65 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordController", - function ($scope, $routeParams) { - - function resetModel(isNew) { - //the model config will contain an object, if it does not we'll create defaults - //NOTE: We will not support doing the password regex on the client side because the regex on the server side - //based on the membership provider cannot always be ported to js from .net directly. - /* - { - hasPassword: true/false, - requiresQuestionAnswer: true/false, - enableReset: true/false, - enablePasswordRetrieval: true/false, - minPasswordLength: 10 - } - */ + function ($scope, $routeParams) { - //set defaults if they are not available - if (!$scope.model.config || $scope.model.config.disableToggle === undefined) { - $scope.model.config.disableToggle = false; - } - if (!$scope.model.config || $scope.model.config.hasPassword === undefined) { - $scope.model.config.hasPassword = false; - } - if (!$scope.model.config || $scope.model.config.enablePasswordRetrieval === undefined) { - $scope.model.config.enablePasswordRetrieval = true; - } - if (!$scope.model.config || $scope.model.config.requiresQuestionAnswer === undefined) { - $scope.model.config.requiresQuestionAnswer = false; - } - if (!$scope.model.config || $scope.model.config.enableReset === undefined) { - $scope.model.config.enableReset = true; - } - if (!$scope.model.config || $scope.model.config.minPasswordLength === undefined) { - $scope.model.config.minPasswordLength = 0; - } - - //set the model defaults - if (!angular.isObject($scope.model.value)) { - //if it's not an object then just create a new one - $scope.model.value = { - newPassword: null, - oldPassword: null, - reset: null, - answer: null - }; - } - else { - //just reset the values + $scope.isNew = $routeParams.create; - if (!isNew) { - //if it is new, then leave the generated pass displayed - $scope.model.value.newPassword = null; - $scope.model.value.oldPassword = null; - } - $scope.model.value.reset = null; - $scope.model.value.answer = null; - } + function resetModel() { + //the model config will contain an object, if it does not we'll create defaults + //NOTE: We will not support doing the password regex on the client side because the regex on the server side + //based on the membership provider cannot always be ported to js from .net directly. + /* + { + hasPassword: true/false, + requiresQuestionAnswer: true/false, + enableReset: true/false, + enablePasswordRetrieval: true/false, + minPasswordLength: 10 + } + */ - //the value to compare to match passwords - if (!isNew) { - $scope.model.confirm = ""; - } - else if ($scope.model.value.newPassword && $scope.model.value.newPassword.length > 0) { - //if it is new and a new password has been set, then set the confirm password too - $scope.model.confirm = $scope.model.value.newPassword; - } - + //set defaults if they are not available + if (!$scope.model.config || $scope.model.config.disableToggle === undefined) { + $scope.model.config.disableToggle = false; + } + if (!$scope.model.config || $scope.model.config.hasPassword === undefined) { + $scope.model.config.hasPassword = false; + } + if (!$scope.model.config || $scope.model.config.enablePasswordRetrieval === undefined) { + $scope.model.config.enablePasswordRetrieval = true; + } + if (!$scope.model.config || $scope.model.config.requiresQuestionAnswer === undefined) { + $scope.model.config.requiresQuestionAnswer = false; + } + if (!$scope.model.config || $scope.model.config.enableReset === undefined) { + $scope.model.config.enableReset = true; + } + if (!$scope.model.config || $scope.model.config.minPasswordLength === undefined) { + $scope.model.config.minPasswordLength = 0; + } + + //set the model defaults + if (!angular.isObject($scope.model.value)) { + //if it's not an object then just create a new one + $scope.model.value = { + newPassword: null, + oldPassword: null, + reset: null, + answer: null + }; + } + else { + //just reset the values + + if (!$scope.isNew) { + //if it is new, then leave the generated pass displayed + $scope.model.value.newPassword = null; + $scope.model.value.oldPassword = null; } + $scope.model.value.reset = null; + $scope.model.value.answer = null; + } + } - resetModel($routeParams.create); + resetModel(); - //if there is no password saved for this entity , it must be new so we do not allow toggling of the change password, it is always there - //with validators turned on. - $scope.changing = $scope.model.config.disableToggle === true || !$scope.model.config.hasPassword; - - //we're not currently changing so set the model to null - if (!$scope.changing) { - $scope.model.value = null; - } - - $scope.doChange = function() { - resetModel(); - $scope.changing = true; - //if there was a previously generated password displaying, clear it - $scope.model.value.generatedPassword = null; - }; - - $scope.cancelChange = function() { - $scope.changing = false; - //set model to null - $scope.model.value = null; - }; - - var unsubscribe = []; - - //listen for the saved event, when that occurs we'll - //change to changing = false; - unsubscribe.push($scope.$on("formSubmitted", function() { - if ($scope.model.config.disableToggle === false) { - $scope.changing = false; - } - })); - unsubscribe.push($scope.$on("formSubmitting", function() { - //if there was a previously generated password displaying, clear it - if ($scope.changing && $scope.model.value) { - $scope.model.value.generatedPassword = null; - } - else if (!$scope.changing) { - //we are not changing, so the model needs to be null - $scope.model.value = null; - } - })); - - //when the scope is destroyed we need to unsubscribe - $scope.$on('$destroy', function () { - for (var u in unsubscribe) { - unsubscribe[u](); - } - }); - - $scope.showReset = function() { - return $scope.model.config.hasPassword && $scope.model.config.enableReset; - }; - - $scope.showOldPass = function() { - return $scope.model.config.hasPassword && - !$scope.model.config.allowManuallyChangingPassword && - !$scope.model.config.enablePasswordRetrieval && !$scope.model.value.reset; - }; - - $scope.showNewPass = function () { - return !$scope.model.value.reset; - }; - - $scope.showConfirmPass = function() { - return !$scope.model.value.reset; - }; - - $scope.showCancelBtn = function() { - return $scope.model.config.disableToggle !== true && $scope.model.config.hasPassword; - }; - - }); + }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.html index 78ae6afa6b..2a08fa29bc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/changepassword/changepassword.html @@ -1,62 +1,6 @@ -
-
- Password has been reset to: -
- {{model.value.generatedPassword}} -
-
-
- - Change password - -
-
- - - - - - - - - - Required - - - - - - Required - Minimum {{$parent.model.config.minPasswordLength}} characters - - - - - - - - The confirmed password doesn't match the new password! - - - - - Cancel - -
-
+
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js index 2d28ee8cd8..f241ae9244 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js @@ -1,13 +1,15 @@ (function () { "use strict"; - function UserEditController($scope, $timeout, $location, $routeParams, usersResource, contentEditingHelper, localizationService, notificationsService, mediaHelper, Upload, umbRequestHelper, usersHelper) { + function UserEditController($scope, $timeout, $location, $routeParams, usersResource, contentEditingHelper, localizationService, notificationsService, mediaHelper, Upload, umbRequestHelper, usersHelper, authResource) { var vm = this; var localizeSaving = localizationService.localize("general_saving"); vm.page = {}; - vm.user = {}; + vm.user = { + changePassword: null + }; vm.breadcrumbs = []; vm.avatarFile = {}; @@ -23,6 +25,13 @@ vm.save = save; vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB" vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes); + vm.toggleChangePassword = toggleChangePassword; + + //create the initial model for change password + vm.changePasswordModel = { + config: {}, + isChanging: false + }; function init() { @@ -36,6 +45,22 @@ vm.loading = false; }); + //go get the config for the membership provider and add it to the model + authResource.getMembershipProviderConfig().then(function (data) { + vm.changePasswordModel.config = data; + //ensure the hasPassword config option is set to true (the user of course has a password already assigned) + //this will ensure the oldPassword is shown so they can change it + // disable reset password functionality beacuse it does not make sense inside the backoffice + vm.changePasswordModel.config.hasPassword = true; + vm.changePasswordModel.config.disableToggle = true; + vm.changePasswordModel.config.enableReset = false; + }); + } + + function toggleChangePassword() { + vm.changePasswordModel.isChanging = !vm.changePasswordModel.isChanging; + //reset it + vm.user.changePassword = null; } function save() { @@ -56,6 +81,7 @@ vm.user = saved; setUserDisplayState(); + vm.changePasswordModel.isChanging = false; vm.page.saveButtonState = "success"; }, function (err) { diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.html b/src/Umbraco.Web.UI.Client/src/views/users/user.html index 517dde209d..4c9c377737 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.html @@ -24,7 +24,8 @@
Meta
- + + + + + +