diff --git a/src/Umbraco.Core/Persistence/Querying/IQuery.cs b/src/Umbraco.Core/Persistence/Querying/IQuery.cs index ae986baddc..cd08274c1b 100644 --- a/src/Umbraco.Core/Persistence/Querying/IQuery.cs +++ b/src/Umbraco.Core/Persistence/Querying/IQuery.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; namespace Umbraco.Core.Persistence.Querying @@ -16,6 +17,11 @@ namespace Umbraco.Core.Persistence.Querying /// This instance so calls to this method are chainable IQuery Where(Expression> predicate); - + /// + /// Adds a set of OR-ed where clauses to the query. + /// + /// + /// This instance so calls to this method are chainable. + IQuery WhereAny(IEnumerable>> predicates); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Querying/Query.cs b/src/Umbraco.Core/Persistence/Querying/Query.cs index 6213ca5ed6..d49296c6d0 100644 --- a/src/Umbraco.Core/Persistence/Querying/Query.cs +++ b/src/Umbraco.Core/Persistence/Querying/Query.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Text; namespace Umbraco.Core.Persistence.Querying { @@ -39,6 +40,50 @@ namespace Umbraco.Core.Persistence.Querying return this; } + /// + /// Adds a set of OR-ed where clauses to the query. + /// + /// + /// This instance so calls to this method are chainable. + public virtual IQuery WhereAny(IEnumerable>> predicates) + { + if (predicates == null) return this; + + StringBuilder sb = null; + List parameters = null; + Sql sql = null; + foreach (var predicate in predicates) + { + // see notes in Where() + var expressionHelper = new ModelToSqlExpressionVisitor(); + var whereExpression = expressionHelper.Visit(predicate); + + if (sb == null) + { + sb = new StringBuilder("("); + parameters = new List(); + sql = new Sql(); + } + else + { + sb.Append(" OR "); + sql.Append(" OR "); + } + + sb.Append(whereExpression); + parameters.AddRange(expressionHelper.GetSqlParameters()); + sql.Append(whereExpression, expressionHelper.GetSqlParameters()); + } + + if (sb == null) return this; + + sb.Append(")"); + //_wheres.Add(Tuple.Create(sb.ToString(), parameters.ToArray())); + _wheres.Add(Tuple.Create("(" + sql.SQL + ")", sql.Arguments)); + + return this; + } + /// /// Returns all translated where clauses and their sql parameters /// diff --git a/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs index 3d291d5e07..be7a31e298 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs @@ -167,7 +167,7 @@ namespace Umbraco.Core.Persistence.Repositories _permissionRepository.AssignPermission(groupId, permission, entityIds); } - #region Overrides of RepositoryBase + #region Overrides of RepositoryBase protected override IUserGroup PerformGet(int id) { diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs index 04d6c276b2..ecf1b5a216 100644 --- a/src/Umbraco.Core/Services/EntityService.cs +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; using Umbraco.Core.Cache; using Umbraco.Core.CodeAnnotations; using Umbraco.Core.Events; @@ -361,6 +364,40 @@ namespace Umbraco.Core.Services return contents; } } + /// + /// Returns a paged collection of descendants. + /// + public IEnumerable GetPagedDescendants(IEnumerable ids, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords, + string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "") + { + var objectTypeId = umbracoObjectType.GetGuid(); + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) + { + var repository = RepositoryFactory.CreateEntityRepository(uow); + + var query = Query.Builder; + var idsA = ids.ToArray(); + if (idsA.All(x => x != Constants.System.Root)) + { + var clauses = new List>>(); + foreach (var id in idsA) + { + var qid = id; + clauses.Add(x => x.Path.SqlContains(string.Format(",{0},", qid), TextColumnType.NVarchar) || x.Path.SqlEndsWith(string.Format(",{0}", qid), TextColumnType.NVarchar)); + } + query.WhereAny(clauses); + } + + IQuery filterQuery = null; + if (filter.IsNullOrWhiteSpace() == false) + { + filterQuery = Query.Builder.Where(x => x.Name.Contains(filter)); + } + + var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery); + return contents; + } + } /// /// Returns a paged collection of descendants from the root diff --git a/src/Umbraco.Core/Services/IEntityService.cs b/src/Umbraco.Core/Services/IEntityService.cs index 82e5227cf2..f6c75c2e98 100644 --- a/src/Umbraco.Core/Services/IEntityService.cs +++ b/src/Umbraco.Core/Services/IEntityService.cs @@ -175,6 +175,12 @@ namespace Umbraco.Core.Services IEnumerable GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = ""); + /// + /// Returns a paged collection of descendants + /// + IEnumerable GetPagedDescendants(IEnumerable ids, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords, + string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = ""); + /// /// Returns a paged collection of descendants from the root /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f9b1c7a752..f25c1c9c79 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -118,6 +118,7 @@ + diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs index 7bf29bb0ab..57d1f80995 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs @@ -64,18 +64,18 @@ namespace Umbraco.Tests.Persistence.Repositories using (var repository = CreateRepository(unitOfWork)) { - var userType1 = MockedUserGroup.CreateUserGroup("1"); - var userType2 = MockedUserGroup.CreateUserGroup("2"); + var userGroup1 = MockedUserGroup.CreateUserGroup("1"); + var userGroup2 = MockedUserGroup.CreateUserGroup("2"); // Act - repository.AddOrUpdate(userType1); + repository.AddOrUpdate(userGroup1); unitOfWork.Commit(); - repository.AddOrUpdate(userType2); + repository.AddOrUpdate(userGroup2); unitOfWork.Commit(); // Assert - Assert.That(userType1.HasIdentity, Is.True); - Assert.That(userType2.HasIdentity, Is.True); + Assert.That(userGroup1.HasIdentity, Is.True); + Assert.That(userGroup2.HasIdentity, Is.True); } } @@ -209,10 +209,10 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); using (var repository = CreateRepository(unitOfWork)) { - var userTypes = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + var userGroups = CreateAndCommitMultipleUserGroups(repository, unitOfWork); // Act - var result = repository.GetAll(userTypes[0].Id, userTypes[1].Id); + var result = repository.GetAll(userGroups[0].Id, userGroups[1].Id); // Assert Assert.That(result, Is.Not.Null); @@ -249,10 +249,10 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); using (var repository = CreateRepository(unitOfWork)) { - var userTypes = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + var userGroups = CreateAndCommitMultipleUserGroups(repository, unitOfWork); // Act - var exists = repository.Exists(userTypes[0].Id); + var exists = repository.Exists(userGroups[0].Id); // Assert Assert.That(exists, Is.True); @@ -267,7 +267,7 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); using (var repository = CreateRepository(unitOfWork)) { - var userTypes = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + var userGroups = CreateAndCommitMultipleUserGroups(repository, unitOfWork); // Act var query = Query.Builder.Where(x => x.Alias == "testUserGroup1" || x.Alias == "testUserGroup2"); diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 88ecb50f2f..334c4f98c2 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -36,7 +36,7 @@ namespace Umbraco.Tests.Persistence.Repositories var tagRepository = new TagRepository(unitOfWork, CacheHelper, Mock.Of(), SqlSyntax); var repository = new MediaRepository(unitOfWork, CacheHelper, Mock.Of(), SqlSyntax, mediaTypeRepository, tagRepository, Mock.Of()); return repository; - } + } private ContentRepository CreateContentRepository(IScopeUnitOfWork unitOfWork, out IContentTypeRepository contentTypeRepository) { @@ -51,7 +51,7 @@ namespace Umbraco.Tests.Persistence.Repositories contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, templateRepository); var repository = new ContentRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, contentTypeRepository, templateRepository, tagRepository, Mock.Of()); return repository; - } + } private UserRepository CreateRepository(IScopeUnitOfWork unitOfWork) { @@ -86,7 +86,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Add_With_Group() { - var group = MockedUserGroup.CreateUserGroup(); + var group = MockedUserGroup.CreateUserGroup(); // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); @@ -95,22 +95,22 @@ namespace Umbraco.Tests.Persistence.Repositories { repository.AddOrUpdate(group); unitOfWork.Commit(); - } + } using (var repository = CreateRepository(unitOfWork)) { IUser user = MockedUser.CreateUser(); - user.AddGroup(group.ToReadOnlyGroup()); + user.AddGroup(group.ToReadOnlyGroup()); // Act repository.AddOrUpdate(user); unitOfWork.Commit(); - user = repository.Get(user.Id); + user = repository.Get(user.Id); // Assert Assert.That(user.HasIdentity, Is.True); - Assert.AreEqual(1, user.Groups.Count()); + Assert.AreEqual(1, user.Groups.Count()); Assert.AreEqual(group.Alias, user.Groups.ElementAt(0).Alias); } } @@ -165,7 +165,7 @@ namespace Umbraco.Tests.Persistence.Repositories var ct = MockedContentTypes.CreateBasicContentType("test"); var content = MockedContent.CreateBasicContent(ct); var mt = MockedContentTypes.CreateSimpleMediaType("testmedia", "TestMedia"); - var media = MockedMedia.CreateSimpleMedia(mt, "asdf", -1); + var media = MockedMedia.CreateSimpleMedia(mt, "asdf", -1); // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); @@ -173,8 +173,8 @@ namespace Umbraco.Tests.Persistence.Repositories IContentTypeRepository contentTypeRepo; IMediaTypeRepository mediaTypeRepo; using (var contentRepository = CreateContentRepository(unitOfWork, out contentTypeRepo)) - using (var mediaRepository = CreateMediaRepository(unitOfWork, out mediaTypeRepo)) - using (contentTypeRepo) + using (var mediaRepository = CreateMediaRepository(unitOfWork, out mediaTypeRepo)) + using (contentTypeRepo) using(mediaTypeRepo) using (var userRepository = CreateRepository(unitOfWork)) using (var userGroupRepository = CreateUserGroupRepository(unitOfWork)) @@ -185,7 +185,7 @@ namespace Umbraco.Tests.Persistence.Repositories contentRepository.AddOrUpdate(content); mediaRepository.AddOrUpdate(media); - unitOfWork.Commit(); + unitOfWork.Commit(); var user = CreateAndCommitUserWithGroup(userRepository, userGroupRepository, unitOfWork); @@ -422,7 +422,7 @@ namespace Umbraco.Tests.Persistence.Repositories var group = MockedUserGroup.CreateUserGroup(); userGroupRepository.AddOrUpdateGroupWithUsers(@group, new[] {user.Id}); - unitOfWork.Commit(); + unitOfWork.Commit(); return user; } diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js index fad2820f56..90d9e58736 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js @@ -59,11 +59,23 @@ "Failed to retrieve user groups"); } + function deleteUserGroups(userGroupIds) { + var query = "userGroupIds=" + userGroupIds.join("&userGroupIds="); + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userGroupsApiBaseUrl", + "PostDeleteUserGroups", + query)), + 'Failed to delete user groups'); + } + var resource = { saveUserGroup: saveUserGroup, getUserGroup: getUserGroup, getUserGroups: getUserGroups, - getUserGroupScaffold: getUserGroupScaffold + getUserGroupScaffold: getUserGroupScaffold, + deleteUserGroups: deleteUserGroups }; return resource; 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/groups/groups.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.controller.js index f10cd8e530..5c30f1354e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function UserGroupsController($scope, $timeout, $location, userGroupsResource) { + function UserGroupsController($scope, $timeout, $location, userGroupsResource, formHelper) { var vm = this; @@ -12,6 +12,7 @@ vm.clickUserGroup = clickUserGroup; vm.clearSelection = clearSelection; vm.selectUserGroup = selectUserGroup; + vm.deleteUserGroups = deleteUserGroups; function onInit() { @@ -57,6 +58,18 @@ } } + function deleteUserGroups() { + if (vm.selection.length > 0) { + userGroupsResource.deleteUserGroups(vm.selection).then(function (data) { + clearSelection(); + onInit(); + formHelper.showNotifications(data); + }, function(error) { + formHelper.showNotifications(error.data); + }); + } + } + function clearSelection() { angular.forEach(vm.userGroups, function (userGroup) { userGroup.selected = false; diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html b/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html index 738fc4f654..38dc7a77f6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html @@ -32,7 +32,7 @@ type="button" label="Delete" icon="icon-trash" - action="vm.deleteUserGroup()" + action="vm.deleteUserGroups()" size="xs"> 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 717c27270c..daddfb57ef 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -1126,6 +1126,17 @@ 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. + 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 8620a5c75f..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,17 +1095,17 @@ 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 Uses CSS syntax ex: h1, .redHeader, .blueTex diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 37d712c362..a2aa8e6b4d 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -19,6 +19,7 @@ using Umbraco.Web.Dynamics; using System.Text.RegularExpressions; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using System.Web.Http.Controllers; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Xml; namespace Umbraco.Web.Editors @@ -541,11 +542,30 @@ namespace Umbraco.Web.Editors var objectType = ConvertToObjectType(type); if (objectType.HasValue) { + IEnumerable entities; long totalRecords; - //if it's from root, don't return recycled - var entities = id == Constants.System.Root - ? Services.EntityService.GetPagedDescendantsFromRoot(objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter, includeTrashed:false) - : Services.EntityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter); + + if (id == Constants.System.Root) + { + int[] aids = null; + switch (type) + { + case UmbracoEntityTypes.Document: + aids = Security.CurrentUser.AllStartContentIds; + break; + case UmbracoEntityTypes.Media: + aids = Security.CurrentUser.AllStartMediaIds; + break; + } + + entities = aids != null && aids.Length > 0 + ? Services.EntityService.GetPagedDescendants(aids, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter) + : Services.EntityService.GetPagedDescendantsFromRoot(objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter, includeTrashed: false); + } + else + { + entities = Services.EntityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter); + } if (totalRecords == 0) { @@ -618,9 +638,17 @@ namespace Umbraco.Web.Editors { if (startNode > 0) { + // descendants + // "__Path: -1*,1234,*" -- the first "*" stands for path-to-1234 sb.Append("__Path: \\-1*\\,"); sb.Append(startNode.ToString(CultureInfo.InvariantCulture)); sb.Append("\\,* "); + + // self + // "__Path: -1*,1234" -- the first "*" stands for path-to-1234 + sb.Append("__Path: \\-1*\\,"); + sb.Append(startNode.ToString(CultureInfo.InvariantCulture)); + sb.Append(" "); } } if (startNodes.Length > 0) @@ -918,6 +946,37 @@ namespace Umbraco.Web.Editors var ids = Services.EntityService.Get(id).Path.Split(',').Select(int.Parse).Distinct().ToArray(); + int[] aids = null; + switch (entityType) + { + case UmbracoEntityTypes.Document: + aids = Security.CurrentUser.AllStartContentIds; + break; + case UmbracoEntityTypes.Media: + aids = Security.CurrentUser.AllStartMediaIds; + break; + } + + if (aids != null && aids.Length > 0) + { + var lids = new List(); + var ok = false; + foreach (var i in ids) + { + if (ok) + { + lids.Add(i); + continue; + } + if (aids.Contains(i)) + { + lids.Add(i); + ok = true; + } + } + ids = lids.ToArray(); + } + return ids.Length == 0 ? Enumerable.Empty() : Services.EntityService.GetAll(objectType.Value, ids) diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index ed4b1c2f63..1603615a58 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -250,6 +250,13 @@ namespace Umbraco.Web.Editors } #region GetChildren + + private int[] _userStartNodes; + protected int[] UserStartNodes + { + get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.AllStartMediaIds); } + } + /// /// Returns the child media objects - using the entity INT id /// @@ -262,6 +269,25 @@ namespace Umbraco.Web.Editors bool orderBySystemField = true, string filter = "") { + //if a request is made for the root node data but the user's start node is not the default, then + // we need to return their start nodes + if (id == Constants.System.Root && UserStartNodes.Length > 0 && UserStartNodes.Contains(Constants.System.Root) == false) + { + if (pageNumber > 0) + return new PagedResult>(0, 0, 0); + var nodes = Services.MediaService.GetByIds(UserStartNodes).ToArray(); + if (nodes.Length == 0) + return new PagedResult>(0, 0, 0); + if (pageSize < nodes.Length) pageSize = nodes.Length; // bah + var pr = new PagedResult>(nodes.Length, pageNumber, pageSize) + { + Items = nodes.Select(Mapper.Map>) + }; + return pr; + } + + // else proceed as usual + long totalChildren; IMedia[] children; if (pageNumber > 0 && pageSize > 0) diff --git a/src/Umbraco.Web/Editors/UserGroupsController.cs b/src/Umbraco.Web/Editors/UserGroupsController.cs index 43e7810227..7c2b589e97 100644 --- a/src/Umbraco.Web/Editors/UserGroupsController.cs +++ b/src/Umbraco.Web/Editors/UserGroupsController.cs @@ -5,7 +5,6 @@ using System.Net; using System.Net.Http; using System.Web.Http; using AutoMapper; -using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; @@ -87,5 +86,21 @@ namespace Umbraco.Web.Editors return display; } + + [HttpPost] + [HttpDelete] + public HttpResponseMessage PostDeleteUserGroups([FromUri] int[] userGroupIds) + { + var userGroups = Services.UserService.GetAllUserGroups(userGroupIds).ToArray(); + foreach (var userGroup in userGroups) + { + Services.UserService.DeleteUserGroup(userGroup); + } + if (userGroups.Length > 1) + return Request.CreateNotificationSuccessResponse( + Services.TextService.Localize("speechBubbles/deleteUserGroupsSuccess", new[] {userGroups.Length.ToString()})); + return Request.CreateNotificationSuccessResponse( + Services.TextService.Localize("speechBubbles/deleteUserGroupSuccess", new[] {userGroups[0].Name})); + } } } \ No newline at end of file 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) diff --git a/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs b/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs index cd19d36f2d..7034101a83 100644 --- a/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs +++ b/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs @@ -46,8 +46,8 @@ namespace Umbraco.Web.Security.Providers { base.Initialize(name, config); - // test for membertype (if not specified, choose the first member type available) - // We'll support both names for legacy reasons: defaultUserTypeAlias & defaultUserGroupAlias + // test for membertype (if not specified, choose the first member type available) + // We'll support both names for legacy reasons: defaultUserTypeAlias & defaultUserGroupAlias if (config["defaultUserTypeAlias"] != null) { diff --git a/src/umbraco.providers/members/UmbracoMembershipProvider.cs b/src/umbraco.providers/members/UmbracoMembershipProvider.cs index 2a563d27ce..648bf5a0d5 100644 --- a/src/umbraco.providers/members/UmbracoMembershipProvider.cs +++ b/src/umbraco.providers/members/UmbracoMembershipProvider.cs @@ -126,7 +126,7 @@ namespace umbraco.providers.members _defaultMemberTypeAlias = config["defaultMemberTypeAlias"]; if (_defaultMemberTypeAlias.IsNullOrWhiteSpace()) { - throw new ProviderException("No default user group alias is specified in the web.config string. Please add a 'defaultUserTypeAlias' to the add element in the provider declaration in web.config"); + throw new ProviderException("No default MemberType alias is specified in the web.config string. Please add a 'defaultMemberTypeAlias' to the add element in the provider declaration in web.config"); } _hasDefaultMember = true; }