diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js index 706142dd18..0acd30afe0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js @@ -55,6 +55,18 @@ 'Failed to enable the users ' + userIds.join(",")); } + function setUserGroupsOnUsers(userGroups, userIds) { + var userGroupAliases = userGroups.map(function(o) { return o.alias; }); + var query = "userGroupAliases=" + userGroupAliases.join("&userGroupAliases=") + "&userIds=" + userIds.join("&userIds="); + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userApiBaseUrl", + "PostSetUserGroupsOnUsers", + query)), + 'Failed to set user groups ' + userGroupAliases.join(",") + ' on the users ' + userIds.join(",")); + } + function getPagedResults(options) { var defaults = { pageSize: 25, @@ -173,6 +185,7 @@ var resource = { disableUsers: disableUsers, enableUsers: enableUsers, + setUserGroupsOnUsers: setUserGroupsOnUsers, getPagedResults: getPagedResults, getUser: getUser, createUser: createUser, 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 acc8c781dd..07539b79d2 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 @@ -22,7 +22,7 @@ vm.enableUser = enableUser; vm.clearAvatar = clearAvatar; vm.save = save; - vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB" + vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB"; vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes); vm.toggleChangePassword = toggleChangePassword; vm.emailIsUsername = true; @@ -56,8 +56,7 @@ vm.loading = false; }); - - }); + }); } function toggleChangePassword() { @@ -91,13 +90,9 @@ //the user has a password if they are not states: Invited, NoCredentials vm.changePasswordModel.config.hasPassword = vm.user.userState !== 3 && vm.user.userState !== 4; - }, function (err) { - vm.page.saveButtonState = "error"; - }); - } function goToPage(ancestor) { @@ -303,7 +298,6 @@ }); } - function makeBreadcrumbs() { vm.breadcrumbs = [ { @@ -322,9 +316,6 @@ } init(); - } - angular.module("umbraco").controller("Umbraco.Editors.Users.UserController", UserEditController); - })(); 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 881c4931ff..abbacf5040 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 @@ -24,6 +24,8 @@ vm.newUser.userGroups = []; vm.usersViewState = 'overview'; + vm.selectedBulkUserGroups = []; + vm.allowDisableUser = true; vm.allowEnableUser = true; vm.allowSetUserGroup = true; @@ -73,6 +75,7 @@ vm.clickUser = clickUser; vm.disableUsers = disableUsers; vm.enableUsers = enableUsers; + vm.openBulkUserGroupPicker = openBulkUserGroupPicker; vm.openUserGroupPicker = openUserGroupPicker; vm.removeSelectedUserGroup = removeSelectedUserGroup; vm.selectAll = selectAll; @@ -216,13 +219,47 @@ } function getUserFromArrayById(userId, users) { - var userFound; - angular.forEach(users, function(user){ - if(userId === user.id) { - userFound = user; + return _.find(users, function(u) { return u.id === userId }); + } + + function openBulkUserGroupPicker(event) { + var firstSelectedUser = getUserFromArrayById(vm.selection[0], vm.users); + + vm.selectedBulkUserGroups = _.clone(firstSelectedUser.userGroups); + + vm.userGroupPicker = { + title: "Select user groups", + view: "usergrouppicker", + selection: vm.selectedBulkUserGroups, + closeButtonLabel: "Cancel", + show: true, + submit: function (model) { + usersResource.setUserGroupsOnUsers(model.selection, vm.selection).then(function (data) { + // sorting to ensure they show up in right order when updating the UI + vm.selectedBulkUserGroups.sort(function (a, b) { + return a.alias > b.alias ? 1 : a.alias < b.alias ? -1 : 0; + }); + // apply changes to UI + _.each(vm.selection, + function(userId) { + var user = getUserFromArrayById(userId, vm.users); + user.userGroups = vm.selectedBulkUserGroups; + }); + vm.selectedBulkUserGroups = []; + vm.userGroupPicker.show = false; + vm.userGroupPicker = null; + formHelper.showNotifications(data); + clearSelection(); + }, function (error) { + formHelper.showNotifications(error.data); + }); + }, + close: function (oldModel) { + vm.selectedBulkUserGroups = []; + vm.userGroupPicker.show = false; + vm.userGroupPicker = null; } - }); - return userFound; + }; } function openUserGroupPicker(event) { @@ -488,6 +525,8 @@ vm.allowEnableUser = true; vm.allowSetUserGroup = true; + var firstSelectedUserGroups; + angular.forEach(users, function (user) { if (!user.selected) { @@ -514,6 +553,19 @@ vm.allowEnableUser = false; } + // store the user group aliases of the first selected user + if (!firstSelectedUserGroups) { + firstSelectedUserGroups = user.userGroups.map(function (ug) { return ug.alias; }); + vm.allowSetUserGroup = true; + } else if (vm.allowSetUserGroup === true) { + // for 2nd+ selected user, compare the user group aliases to determine if we should allow bulk editing. + // we don't allow bulk editing of users not currently having the same assigned user groups, as we can't + // really support that in the user group picker. + var userGroups = user.userGroups.map(function(ug) { return ug.alias; }); + if (_.difference(firstSelectedUserGroups, userGroups).length > 0) { + vm.allowSetUserGroup = false; + } + } }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html index 0293833f76..4490b33e43 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html @@ -47,7 +47,7 @@ @@ -60,32 +60,32 @@
- +
- +
- +
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 53c11eb420..daddfb57ef 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -1128,6 +1128,15 @@ To manage your website, simply open the Umbraco back office and start adding con An error occurred saving the file. Deleted %0% user groups %0% was deleted + Enabled %0% users + An error occurred while enabling the users + Disabled %0% users + An error occurred while disabling the users + %0% is now enabled + An error occurred while enabling the user + %0% is now disabled + An error occurred while disabling the user + User groups have been set Uses CSS syntax ex: h1, .redHeader, .blueTex diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index f4e00c52a9..2ddb6094b4 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -1095,16 +1095,15 @@ To manage your website, simply open the Umbraco back office and start adding con Script view not saved An error occurred saving the file. An error occurred saving the file. - Enabled %0% users An error occurred while enabling the users Disabled %0% users An error occurred while disabling the users - - %0% is now enabled + %0% is now enabled An error occurred while enabling the user %0% is now disabled An error occurred while disabling the user + User groups have been set Deleted %0% user groups %0% was deleted diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 2625568c3e..0039128e86 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -546,6 +546,23 @@ namespace Umbraco.Web.Editors Services.TextService.Localize("speechBubbles/enableUserSuccess", new[] { users[0].Name })); } + public HttpResponseMessage PostSetUserGroupsOnUsers([FromUri]string[] userGroupAliases, [FromUri]int[] userIds) + { + var users = Services.UserService.GetUsersById(userIds).ToArray(); + var userGroups = Services.UserService.GetUserGroupsByAlias(userGroupAliases).Select(x => x.ToReadOnlyGroup()).ToArray(); + foreach (var u in users) + { + u.ClearGroups(); + foreach (var userGroup in userGroups) + { + u.AddGroup(userGroup); + } + } + Services.UserService.Save(users); + return Request.CreateNotificationSuccessResponse( + Services.TextService.Localize("speechBubbles/setUserGroupOnUsersSuccess")); + } + public class PagedUserResult : PagedResult { public PagedUserResult(long totalItems, long pageNumber, long pageSize) : base(totalItems, pageNumber, pageSize)