From 6d22f7f86faf682ee2f1ca8228148f8e78d28126 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 15 Jun 2017 00:05:12 +0200 Subject: [PATCH] Getting the invite password setting done with validation, almost there --- .../src/common/resources/auth.resource.js | 17 +++- .../common/resources/currentuser.resource.js | 82 +++++++++---------- .../services/contenteditinghelper.service.js | 3 +- .../views/common/dialogs/login.controller.js | 35 ++++++-- .../src/views/common/dialogs/login.html | 15 ++-- .../users/views/users/users.controller.js | 4 +- .../Editors/AuthenticationController.cs | 28 +++++++ .../EnableOverrideAuthorizationAttribute.cs | 2 +- 8 files changed, 130 insertions(+), 56 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js index e4f3190355..5de92527d3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js @@ -86,7 +86,7 @@ function authResource($q, $http, umbRequestHelper, angularHelper) { }), 'Login failed for user ' + username); }, - + /** * There are not parameters for this since when the user has clicked on their invite email they will be partially * logged in (but they will not be approved) so we need to use this method to verify the non approved logged in user's details. @@ -196,6 +196,21 @@ function authResource($q, $http, umbRequestHelper, angularHelper) { 'Password reset code validation failed for userId ' + userId + ', code' + resetCode); }, + performSetInvitedUserPassword: function (newPassword) { + + if (!newPassword) { + return angularHelper.rejectedPromise({ errorMsg: 'newPassword cannot be empty' }); + } + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "authenticationApiBaseUrl", + "PostSetInvitedUserPassword"), + angular.toJson(newPassword)), + 'Failed to change password'); + }, + /** * @ngdoc method * @name umbraco.resources.authResource#performSetPassword diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js index 5375c9507b..21f55dd6a1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/currentuser.resource.js @@ -7,47 +7,47 @@ **/ function currentUserResource($q, $http, umbRequestHelper) { - //the factory object returned - return { - - /** - * @ngdoc method - * @name umbraco.resources.currentUserResource#changePassword - * @methodOf umbraco.resources.currentUserResource - * - * @description - * Changes the current users password - * - * @returns {Promise} resourcePromise object containing the user array. - * - */ - changePassword: function (changePasswordArgs) { - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "currentUserApiBaseUrl", - "PostChangePassword"), - changePasswordArgs), - 'Failed to change password'); - }, - - /** - * @ngdoc method - * @name umbraco.resources.currentUserResource#getMembershipProviderConfig - * @methodOf umbraco.resources.currentUserResource - * - * @description - * Gets the configuration of the user membership provider which is used to configure the change password form - */ - getMembershipProviderConfig: function () { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "currentUserApiBaseUrl", - "GetMembershipProviderConfig")), - 'Failed to retrieve membership provider config'); - }, - }; + //the factory object returned + return { + + /** + * @ngdoc method + * @name umbraco.resources.currentUserResource#changePassword + * @methodOf umbraco.resources.currentUserResource + * + * @description + * Changes the current users password + * + * @returns {Promise} resourcePromise object containing the user array. + * + */ + changePassword: function (changePasswordArgs) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "currentUserApiBaseUrl", + "PostChangePassword"), + changePasswordArgs), + 'Failed to change password'); + }, + + /** + * @ngdoc method + * @name umbraco.resources.currentUserResource#getMembershipProviderConfig + * @methodOf umbraco.resources.currentUserResource + * + * @description + * Gets the configuration of the user membership provider which is used to configure the change password form + */ + getMembershipProviderConfig: function () { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "currentUserApiBaseUrl", + "GetMembershipProviderConfig")), + 'Failed to retrieve membership provider config'); + }, + }; } angular.module('umbraco.resources').factory('currentUserResource', currentUserResource); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 020ac9c710..d1014adc69 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -28,7 +28,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica return { - /** Used by the content editor and mini content editor to perform saving operations */ + /** Used by the content editor and mini content editor to perform saving operations */ + //TODO: Make this a more helpful/reusable method for other form operations! we can simplify this form most forms contentEditorPerformSave: function (args) { if (!angular.isObject(args)) { throw "args must be an object"; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js index e241ec7753..229bc1047a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js @@ -1,7 +1,11 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LoginController", - function ($scope, $cookies, $location, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, dialogService) { + function ($scope, $cookies, $location, currentUserResource, formHelper, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, dialogService) { $scope.invitedUser = null; + $scope.invitedUserPasswordModel = { + password: "", + confirmPassword: "" + } function init() { // Check if it is a new user @@ -17,11 +21,31 @@ } } - $scope.inviteSavePassword = function () { + $scope.inviteSavePassword = function () { + if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) { + + $scope.inviteChangePasswordButtonState = "busy"; - $scope.inviteSetPassword = false; - $scope.inviteSetAvatar = true; + authResource.performSetInvitedUserPassword($scope.invitedUserPasswordModel.password) + .then(function (data) { + + //success + formHelper.resetForm({ scope: $scope, notifications: data.notifications }); + $scope.inviteChangePasswordButtonState = "success"; + + $scope.inviteSetPassword = false; + $scope.inviteSetAvatar = true; + + }, function(err) { + + //error + formHelper.handleError(err); + + $scope.inviteChangePasswordButtonState = "error"; + + }); + } }; var setFieldFocus = function (form, field) { @@ -212,7 +236,8 @@ if ($scope.setPasswordForm.$invalid) { return; } - + + //TODO: All of this logic can/should be shared! We should do validation the nice way instead of all of this manual stuff, see: inviteSavePassword authResource.performSetPassword($scope.resetPasswordCodeInfo.resetCodeModel.userId, password, confirmPassword, $scope.resetPasswordCodeInfo.resetCodeModel.resetCode) .then(function () { $scope.showSetPasswordConfirmation = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html index 42d977070d..059366659b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html @@ -10,7 +10,7 @@
-
+

Hi, {{invitedUser.name}}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non libero vel turpis ultrices pharetra.

@@ -18,20 +18,23 @@
- + + Required +
- + + Required
-
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js index 2eb0b0a406..4717d2b3c9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js @@ -280,7 +280,9 @@ contentEditingHelper.contentEditorPerformSave({ statusMessage: localizeSaving, - saveMethod: usersResource.inviteUser, + saveMethod: function(obj, isCreate, files) { + usersResource.inviteUser(a, b, c); + }, scope: $scope, content: vm.newUser, // We do not redirect on failure for users - this is because it is not possible to actually save a user diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 1fcb4e6ea8..eaa26625cf 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -357,6 +357,34 @@ namespace Umbraco.Web.Editors } } + /// + /// When a user is invited and they click on the invitation link, they will be partially logged in + /// where they can set their username/password + /// + /// + /// + /// + /// This only works when the user is logged in (partially) + /// + [WebApi.UmbracoAuthorize(requireApproval: false)] + public async Task PostSetInvitedUserPassword([FromBody]string newPassword) + { + var result = await UserManager.AddPasswordAsync(Security.GetUserId(), newPassword); + + if (result.Succeeded == false) + { + //it wasn't successful, so add the change error to the model state, we've name the property alias _umb_password on the form + // so that is why it is being used here. + ModelState.AddModelError( + "value", + string.Join(", ", result.Errors)); + + throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); + } + + return Request.CreateResponse(HttpStatusCode.OK); + } + /// /// Processes a set password request. Validates the request and sets a new password. /// diff --git a/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs index a8c26fc167..b2fdcb3c56 100644 --- a/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs @@ -11,6 +11,6 @@ namespace Umbraco.Web.WebApi.Filters [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] public sealed class EnableOverrideAuthorizationAttribute : Attribute { - + //TODO: Can we remove this and use the System.Web.Http.OverrideAuthorizationAttribute which uses IOverrideFilter instead? } } \ No newline at end of file