From 29aaa2602258557fa8a38f116194245df6d0309e Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 14 Jul 2017 20:13:57 +0200 Subject: [PATCH] U4-10023 - fix media picker for multiple start nodes --- .../Persistence/Querying/IQuery.cs | 8 ++- .../Persistence/Querying/Query.cs | 45 +++++++++++++ src/Umbraco.Core/Services/EntityService.cs | 37 ++++++++++ src/Umbraco.Core/Services/IEntityService.cs | 6 ++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Web/Editors/EntityController.cs | 67 +++++++++++++++++-- src/Umbraco.Web/Editors/MediaController.cs | 26 +++++++ 7 files changed, 185 insertions(+), 5 deletions(-) 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/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 8a635b966c..109b11f156 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -118,6 +118,7 @@ + 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)