Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f61b7579a2 | |||
| 86a3780c61 | |||
| 552909fde2 | |||
| 7adae4d345 | |||
| d747cf69c3 | |||
| bc5e3b4d66 | |||
| febeb82d10 | |||
| 1c2b2c1409 | |||
| b4eb9f333e | |||
| af00a421cd | |||
| 4dabb606e7 | |||
| d5f66ebe02 | |||
| bd38dde1fc | |||
| cab1536a30 | |||
| 83f75fdaff | |||
| 487792920b | |||
| 6ae06ad2e0 | |||
| 8387c435d4 | |||
| 5807bbccc4 | |||
| 1bfc041bbe | |||
| 7c049b55a8 | |||
| 051b3f2e6a | |||
| 21f947efbd | |||
| 9461e35028 |
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha065
|
||||
alpha066
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha065")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha066")]
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "alpha065"; } }
|
||||
public static string CurrentComment { get { return "alpha066"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -109,6 +109,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media Type object.
|
||||
/// </summary>
|
||||
public static readonly Guid MemberGuid = new Guid(Member);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Group object.
|
||||
/// </summary>
|
||||
|
||||
@@ -66,10 +66,20 @@ namespace Umbraco.Core.Deploy
|
||||
/// <returns>The length of the file, or -1 if the file does not exist.</returns>
|
||||
Task<long> GetFileLengthAsync(StringUdi udi, CancellationToken token);
|
||||
|
||||
// fixme - doc
|
||||
void GetFiles(IEnumerable<StringUdi> udis, IFileStore fileStore);
|
||||
/// <summary>
|
||||
/// Gets files and store them using a file store.
|
||||
/// </summary>
|
||||
/// <param name="udis">The udis of the files to get.</param>
|
||||
/// <param name="fileTypes">A collection of file types which can store the files.</param>
|
||||
void GetFiles(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes);
|
||||
|
||||
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileStore fileStore, CancellationToken token);
|
||||
/// <summary>
|
||||
/// Gets files and store them using a file store.
|
||||
/// </summary>
|
||||
/// <param name="udis">The udis of the files to get.</param>
|
||||
/// <param name="fileTypes">A collection of file types which can store the files.</param>
|
||||
/// <param name="token">A cancellation token.</param>
|
||||
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes, CancellationToken token);
|
||||
|
||||
///// <summary>
|
||||
///// Gets the content of a file as a bytes array.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IFileStore
|
||||
{
|
||||
void SaveStream(StringUdi udi, Stream stream);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -67,22 +68,15 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The for each.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="func">The func.</param>
|
||||
/// <typeparam name="TItem">item type</typeparam>
|
||||
/// <typeparam name="TResult">Result type</typeparam>
|
||||
/// <returns>the Results</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
|
||||
public static TResult[] ForEach<TItem, TResult>(this IEnumerable<TItem> items, Func<TItem, TResult> func)
|
||||
{
|
||||
return items.Select(func).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>The for each.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="action">The action.</param>
|
||||
/// <typeparam name="TItem">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
|
||||
public static IEnumerable<TItem> ForEach<TItem>(this IEnumerable<TItem> items, Action<TItem> action)
|
||||
{
|
||||
if (items != null)
|
||||
@@ -101,6 +95,7 @@ namespace Umbraco.Core
|
||||
/// <param name="f">The select child.</param>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Do not use, use SelectRecursive instead which has far less potential of re-iterating an iterator which may cause significantly more SQL queries")]
|
||||
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Models
|
||||
return descendants;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("The content type must be " + typeof(IContentType) + " or " + typeof(IMediaType));
|
||||
//No other content types have children (i.e. member types)
|
||||
return Enumerable.Empty<IContentTypeBase>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -113,6 +113,11 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolved from EntityService this checks if the entity has the HasChildren flag
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasChildren(this IUmbracoEntity entity)
|
||||
{
|
||||
if (entity.AdditionalData.ContainsKey("HasChildren"))
|
||||
@@ -133,6 +138,11 @@ namespace Umbraco.Core.Models
|
||||
return entity.AdditionalData.GetValueIgnoreCase(key, defaultVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolved from EntityService this checks if the entity has the IsContainer flag
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsContainer(this IUmbracoEntity entity)
|
||||
{
|
||||
if (entity.AdditionalData.ContainsKeyIgnoreCase("IsContainer") == false) return false;
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
entity.ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty;
|
||||
|
||||
var publishedVersion = default(Guid);
|
||||
//some content items don't have a published version
|
||||
//some content items don't have a published/newest version
|
||||
if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null)
|
||||
{
|
||||
Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion);
|
||||
|
||||
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
|
||||
{
|
||||
sqlSelectRemoved = null;
|
||||
@@ -723,10 +723,9 @@ namespace Umbraco.Core.Persistence
|
||||
sqlCount = sql.Substring(0, g.Index) + "COUNT(" + m.Groups[1].ToString().Trim() + ") " + sql.Substring(g.Index + g.Length);
|
||||
else
|
||||
sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
|
||||
|
||||
|
||||
// Look for an "ORDER BY <whatever>" clause
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
|
||||
// Look for an "ORDER BY <whatever>" clause
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
if (!m.Success)
|
||||
{
|
||||
sqlOrderBy = null;
|
||||
@@ -737,8 +736,7 @@ namespace Umbraco.Core.Persistence
|
||||
sqlOrderBy = g.ToString();
|
||||
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -820,7 +818,7 @@ namespace Umbraco.Core.Persistence
|
||||
result.CurrentPage = page;
|
||||
result.ItemsPerPage = itemsPerPage;
|
||||
result.TotalItems = ExecuteScalar<long>(sqlCount, args);
|
||||
result.TotalPages = result.TotalItems / itemsPerPage;
|
||||
result.TotalPages = result.TotalItems / itemsPerPage;
|
||||
if ((result.TotalItems % itemsPerPage) != 0)
|
||||
result.TotalPages++;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -49,6 +50,124 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Query Methods
|
||||
|
||||
public IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null)
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var factory = new UmbracoEntityFactory();
|
||||
|
||||
var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, sql =>
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClaus in filter.GetWhereClauses())
|
||||
{
|
||||
sql.Where(filterClaus.Item1, filterClaus.Item2);
|
||||
}
|
||||
}
|
||||
}, objectTypeId);
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
|
||||
var entitySql = translator.Translate();
|
||||
var pagedSql = entitySql.Append(GetGroupBy(isContent, isMedia, false)).OrderBy("umbracoNode.id");
|
||||
|
||||
IEnumerable<IUmbracoEntity> result;
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
|
||||
|
||||
var ids = pagedResult.Items.Select(x => (int) x.id).InGroupsOf(2000);
|
||||
var entities = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
|
||||
//Now we need to merge in the property data since we need paging and we can't do this the way that the big media query was working before
|
||||
foreach (var idGroup in ids)
|
||||
{
|
||||
var propSql = GetPropertySql(Constants.ObjectTypes.Media)
|
||||
.Where("contentNodeId IN (@ids)", new {ids = idGroup})
|
||||
.OrderBy("contentNodeId");
|
||||
|
||||
//This does NOT fetch all data into memory in a list, this will read
|
||||
// over the records as a data reader, this is much better for performance and memory,
|
||||
// but it means that during the reading of this data set, nothing else can be read
|
||||
// from SQL server otherwise we'll get an exception.
|
||||
var allPropertyData = _work.Database.Query<dynamic>(propSql);
|
||||
|
||||
//keep track of the current property data item being enumerated
|
||||
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
|
||||
var hasCurrent = false; // initially there is no enumerator.Current
|
||||
|
||||
try
|
||||
{
|
||||
//This must be sorted by node id (which is done by SQL) because this is how we are sorting the query to lookup property types above,
|
||||
// which allows us to more efficiently iterate over the large data set of property values.
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
// assemble the dtos for this def
|
||||
// use the available enumerator.Current if any else move to next
|
||||
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.contentNodeId == entity.Id)
|
||||
{
|
||||
hasCurrent = false; // enumerator.Current is not available
|
||||
|
||||
//the property data goes into the additional data
|
||||
entity.AdditionalData[propertyDataSetEnumerator.Current.propertyTypeAlias] = new UmbracoEntity.EntityProperty
|
||||
{
|
||||
PropertyEditorAlias = propertyDataSetEnumerator.Current.propertyEditorAlias,
|
||||
Value = StringExtensions.IsNullOrWhiteSpace(propertyDataSetEnumerator.Current.dataNtext)
|
||||
? propertyDataSetEnumerator.Current.dataNvarchar
|
||||
: StringExtensions.ConvertToJsonIfPossible(propertyDataSetEnumerator.Current.dataNtext)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
hasCurrent = true; // enumerator.Current is available for another def
|
||||
break; // no more propertyDataDto for this def
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
propertyDataSetEnumerator.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
result = entities;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
|
||||
result = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
}
|
||||
|
||||
//The total items from the PetaPoco page query will be wrong due to the Outer join used on parent, depending on the search this will
|
||||
//return duplicate results when the COUNT is used in conjuction with it, so we need to get the total on our own.
|
||||
|
||||
//generate a query that does not contain the LEFT Join for parent, this would cause
|
||||
//the COUNT(*) query to return the wrong
|
||||
var sqlCountClause = GetBaseWhere(
|
||||
(isC, isM, f) => GetBase(isC, isM, f, true), //true == is a count query
|
||||
isContent, isMedia, sql =>
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClaus in filter.GetWhereClauses())
|
||||
{
|
||||
sql.Where(filterClaus.Item1, filterClaus.Item2);
|
||||
}
|
||||
}
|
||||
}, objectTypeId);
|
||||
var translatorCount = new SqlTranslator<IUmbracoEntity>(sqlCountClause, query);
|
||||
var countSql = translatorCount.Translate();
|
||||
|
||||
totalRecords = _work.Database.ExecuteScalar<int>(countSql);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IUmbracoEntity GetByKey(Guid key)
|
||||
{
|
||||
var sql = GetBaseWhere(GetBase, false, false, key);
|
||||
@@ -71,8 +190,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
@@ -115,8 +233,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
@@ -171,8 +288,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
foreach (var entity in entities)
|
||||
@@ -231,8 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
});
|
||||
|
||||
//treat media differently for now
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, mediaSql);
|
||||
return entities;
|
||||
@@ -278,11 +393,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), filter);
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
private Sql GetPropertySql(string nodeObjectType)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = new Sql()
|
||||
var sql = new Sql()
|
||||
.Select("contentNodeId, versionId, dataNvarchar, dataNtext, propertyEditorAlias, alias as propertyTypeAlias")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
@@ -291,7 +404,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.On<PropertyTypeDto, PropertyDataDto>(dto => dto.Id, dto => dto.PropertyTypeId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<PropertyTypeDto, DataTypeDto>(dto => dto.DataTypeId, dto => dto.DataTypeId)
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new {nodeObjectType = Constants.ObjectTypes.Media});
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new { nodeObjectType = nodeObjectType });
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = GetPropertySql(Constants.ObjectTypes.Media);
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
@@ -310,34 +432,52 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderBy("sortOrder, id");
|
||||
|
||||
return wrappedSql;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate",
|
||||
"COUNT(parent.parentID) as children"
|
||||
};
|
||||
return GetBase(isContent, isMedia, customFilter, false);
|
||||
}
|
||||
|
||||
if (isContent || isMedia)
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter, bool isCount)
|
||||
{
|
||||
var columns = new List<object>();
|
||||
if (isCount)
|
||||
{
|
||||
columns.Add("published.versionId as publishedVersion");
|
||||
columns.Add("latest.versionId as newestVersion");
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
columns.Add("COUNT(*)");
|
||||
}
|
||||
else
|
||||
{
|
||||
columns.AddRange(new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate",
|
||||
"COUNT(parent.parentID) as children"
|
||||
});
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
if (isContent)
|
||||
{
|
||||
//only content has this info
|
||||
columns.Add("published.versionId as publishedVersion");
|
||||
columns.Add("document.versionId as newestVersion");
|
||||
}
|
||||
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
}
|
||||
}
|
||||
|
||||
//Creates an SQL query to return a single row for the entity
|
||||
@@ -348,17 +488,24 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
|
||||
.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published")
|
||||
.On("umbracoNode.id = published.nodeId")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest")
|
||||
.On("umbracoNode.id = latest.nodeId");
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id");
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
//only content has this info
|
||||
entitySql
|
||||
.InnerJoin("cmsDocument document").On("document.nodeId = umbracoNode.id")
|
||||
.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1) as published")
|
||||
.On("umbracoNode.id = published.nodeId");
|
||||
}
|
||||
|
||||
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
|
||||
}
|
||||
|
||||
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
if (isCount == false)
|
||||
{
|
||||
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
}
|
||||
|
||||
if (customFilter != null)
|
||||
{
|
||||
@@ -372,22 +519,42 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, filter)
|
||||
.Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = nodeObjectType });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, int id)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id", new { Id = id })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
.Where("umbracoNode.id = @Id", new { Id = id });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
sql.Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
sql.Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -396,6 +563,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new {Id = id, NodeObjectType = nodeObjectType});
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -404,30 +577,39 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new { UniqueID = key, NodeObjectType = nodeObjectType });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetGroupBy(bool isContent, bool isMedia, bool includeSort = true)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate"
|
||||
};
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate"
|
||||
};
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
columns.Add("published.versionId");
|
||||
columns.Add("latest.versionId");
|
||||
if (isContent)
|
||||
{
|
||||
columns.Add("published.versionId");
|
||||
columns.Add("document.versionId");
|
||||
}
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -16,6 +17,21 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query);
|
||||
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged results
|
||||
/// </summary>
|
||||
/// <param name="query">Query to excute</param>
|
||||
/// <param name="objectTypeId"></param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records query would return without paging</param>
|
||||
/// <param name="orderBy">Field to order by</param>
|
||||
/// <param name="orderDirection">Direction to order by</param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns>An Enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the entity exists
|
||||
/// </summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -376,6 +377,115 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of children
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id to return children for</param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId && x.Trashed == false);
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, 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())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
var query = Query<IUmbracoEntity>.Builder;
|
||||
//if the id is System Root, then just get all
|
||||
if (id != Constants.System.Root)
|
||||
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants from the root
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="includeTrashed">true/false to include trashed objects</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
var query = Query<IUmbracoEntity>.Builder;
|
||||
//don't include trashed if specfied
|
||||
if (includeTrashed == false)
|
||||
{
|
||||
query.Where(x => x.Trashed == false);
|
||||
}
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of descendents by the parents Id
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -137,6 +138,51 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
IEnumerable<IUmbracoEntity> GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of children
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id to return children for</param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants from the root
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="includeTrashed">true/false to include trashed objects</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of descendents by the parents Id
|
||||
/// </summary>
|
||||
|
||||
@@ -311,7 +311,8 @@
|
||||
<Compile Include="Deploy\ArtifactSignature.cs" />
|
||||
<Compile Include="Deploy\Difference.cs" />
|
||||
<Compile Include="Deploy\Direction.cs" />
|
||||
<Compile Include="Deploy\IFileStore.cs" />
|
||||
<Compile Include="Deploy\IFileType.cs" />
|
||||
<Compile Include="Deploy\IFileTypeCollection.cs" />
|
||||
<Compile Include="Events\EventDefinitionFilter.cs" />
|
||||
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
|
||||
<Compile Include="Events\ScopeEventDispatcherBase.cs" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -25,8 +26,368 @@ namespace Umbraco.Tests.Services
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Children()
|
||||
{
|
||||
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(6));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(4));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var count = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
count++;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(31));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 1, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(29));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_Including_Recycled()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var toDelete = new List<IContent>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.ContentService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Document, 0, 1000, out total)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var c in toDelete)
|
||||
{
|
||||
Assert.True(entities.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_Without_Recycled()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var toDelete = new List<IContent>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.ContentService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Document, 0, 1000, out total, includeTrashed:false)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var c in toDelete)
|
||||
{
|
||||
Assert.IsFalse(entities.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_With_Search()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, "tttt" + Guid.NewGuid(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, filter: "ssss").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(10));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total, filter: "tttt").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(50));
|
||||
Assert.That(total, Is.EqualTo(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Children()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 0, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(6));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(4));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var count = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
count++;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(31));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 1, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(29));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_Including_Recycled()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var toDelete = new List<IMedia>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.MediaService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Media, 0, 1000, out total)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var media in toDelete)
|
||||
{
|
||||
Assert.IsTrue(entities.Contains(media.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_Without_Recycled()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var toDelete = new List<IMedia>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.MediaService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Media, 0, 1000, out total, includeTrashed:false)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var media in toDelete)
|
||||
{
|
||||
Assert.IsFalse(entities.Contains(media.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_With_Search()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
c1.Name = "ssss" + Guid.NewGuid();
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
c2.Name = "tttt" + Guid.NewGuid();
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, filter: "ssss").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(10));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total, filter: "tttt").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(50));
|
||||
Assert.That(total, Is.EqualTo(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Find_All_Content_By_UmbracoObjectTypes()
|
||||
{
|
||||
|
||||
+11
-14
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MiniListViewDirective(contentResource, memberResource, mediaResource) {
|
||||
function MiniListViewDirective(entityResource) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -52,22 +52,19 @@
|
||||
|
||||
// start loading animation list view
|
||||
miniListView.loading = true;
|
||||
|
||||
// setup the correct resource depending on section
|
||||
var resource = "";
|
||||
|
||||
if (scope.entityType === "Member") {
|
||||
resource = memberResource.getPagedResults;
|
||||
} else if (scope.entityType === "Media") {
|
||||
resource = mediaResource.getChildren;
|
||||
} else {
|
||||
resource = contentResource.getChildren;
|
||||
}
|
||||
|
||||
resource(miniListView.node.id, miniListView.pagination)
|
||||
|
||||
entityResource.getPagedChildren(miniListView.node.id, scope.entityType, miniListView.pagination)
|
||||
.then(function (data) {
|
||||
// update children
|
||||
miniListView.children = data.items;
|
||||
_.each(miniListView.children, function(c) {
|
||||
if (c.metaData) {
|
||||
c.hasChildren = c.metaData.HasChildren;
|
||||
if(scope.entityType === "Document") {
|
||||
c.published = c.metaData.IsPublished;
|
||||
}
|
||||
}
|
||||
});
|
||||
// update pagination
|
||||
miniListView.pagination.totalItems = data.totalItems;
|
||||
miniListView.pagination.totalPages = data.totalPages;
|
||||
|
||||
@@ -477,20 +477,20 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetChildren",
|
||||
[
|
||||
{ id: parentId },
|
||||
{ pageNumber: options.pageNumber },
|
||||
{ pageSize: options.pageSize },
|
||||
{ orderBy: options.orderBy },
|
||||
{ orderDirection: options.orderDirection },
|
||||
{ orderBySystemField: toBool(options.orderBySystemField) },
|
||||
{ filter: options.filter }
|
||||
])),
|
||||
'Failed to retrieve children for content item ' + parentId);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetChildren",
|
||||
{
|
||||
id: parentId,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
orderBySystemField: toBool(options.orderBySystemField),
|
||||
filter: options.filter
|
||||
})),
|
||||
'Failed to retrieve children for content item ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,10 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
|
||||
getSafeAlias: function (value, camelCase) {
|
||||
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -68,6 +72,11 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
getPath: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "-1";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -98,7 +107,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the url.
|
||||
*
|
||||
*/
|
||||
getUrl: function(id, type) {
|
||||
getUrl: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -131,7 +145,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getById: function (id, type) {
|
||||
getById: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -285,18 +304,19 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getAncestors
|
||||
* @name umbraco.resources.entityResource#getChildren
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets children entities for a given item
|
||||
*
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {string} type Object type name
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getChildren: function (id, type) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -305,6 +325,146 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
[{ id: id }, { type: type }])),
|
||||
'Failed to retrieve child data for id ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedChildren
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged children of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedChildren(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 1
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 100
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedChildren: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 1,
|
||||
pageNumber: 100,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedChildren",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedDescendants
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged descendants of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedDescendants(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return descendants of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 1
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 100
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedDescendants: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 1,
|
||||
pageNumber: 100,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedDescendants",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -482,7 +482,49 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"mediaApiBaseUrl",
|
||||
"EmptyRecycleBin")),
|
||||
'Failed to empty the recycle bin');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.mediaResource#search
|
||||
* @methodOf umbraco.resources.mediaResource
|
||||
*
|
||||
* @description
|
||||
* Empties the media recycle bin
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaResource.search("my search", 1, 100, -1)
|
||||
* .then(function(searchResult) {
|
||||
* alert('it's here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} query The search query
|
||||
* @param {int} pageNumber The page number
|
||||
* @param {int} pageSize The number of media items on a page
|
||||
* @param {int} searchFrom Id to search from
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
search: function (query, pageNumber, pageSize, searchFrom) {
|
||||
|
||||
var args = [
|
||||
{ "query": query },
|
||||
{ "pageNumber": pageNumber },
|
||||
{ "pageSize": pageSize },
|
||||
{ "searchFrom": searchFrom }
|
||||
];
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"mediaApiBaseUrl",
|
||||
"Search",
|
||||
args)),
|
||||
'Failed to retrieve media items for search: ' + query);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -288,6 +288,10 @@ input.umb-table__input {
|
||||
color: @black;
|
||||
}
|
||||
|
||||
.umb-table__row-expand--hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.umb-table--condensed {
|
||||
|
||||
.umb-table-cell:first-of-type:not(.not-fixed) {
|
||||
|
||||
+111
-27
@@ -33,6 +33,14 @@ angular.module("umbraco")
|
||||
$scope.acceptedMediatypes = types;
|
||||
});
|
||||
|
||||
$scope.searchOptions = {
|
||||
pageNumber: 1,
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
filter: '',
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
$scope.target = undefined;
|
||||
if (dialogOptions.currentTarget) {
|
||||
@@ -106,35 +114,9 @@ angular.module("umbraco")
|
||||
$scope.path = [];
|
||||
}
|
||||
|
||||
//mediaResource.rootMedia()
|
||||
mediaResource.getChildren(folder.id)
|
||||
.then(function(data) {
|
||||
$scope.searchTerm = "";
|
||||
$scope.images = data.items ? data.items : [];
|
||||
|
||||
// set already selected images to selected
|
||||
for (var folderImageIndex = 0; folderImageIndex < $scope.images.length; folderImageIndex++) {
|
||||
var folderImage = $scope.images[folderImageIndex];
|
||||
var imageIsSelected = false;
|
||||
|
||||
for (var selectedImageIndex = 0;
|
||||
selectedImageIndex < $scope.model.selectedImages.length;
|
||||
selectedImageIndex++) {
|
||||
var selectedImage = $scope.model.selectedImages[selectedImageIndex];
|
||||
|
||||
if (folderImage.key === selectedImage.key) {
|
||||
imageIsSelected = true;
|
||||
}
|
||||
}
|
||||
if (imageIsSelected) {
|
||||
folderImage.selected = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
getChildren(folder.id);
|
||||
$scope.currentFolder = folder;
|
||||
|
||||
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
|
||||
|
||||
};
|
||||
|
||||
$scope.clickHandler = function(image, event, index) {
|
||||
@@ -238,4 +220,106 @@ angular.module("umbraco")
|
||||
$scope.mediaPickerDetailsOverlay = null;
|
||||
};
|
||||
};
|
||||
|
||||
$scope.changeSearch = function() {
|
||||
$scope.loading = true;
|
||||
debounceSearchMedia();
|
||||
};
|
||||
|
||||
$scope.changePagination = function(pageNumber) {
|
||||
$scope.loading = true;
|
||||
$scope.searchOptions.pageNumber = pageNumber;
|
||||
searchMedia();
|
||||
};
|
||||
|
||||
var debounceSearchMedia = _.debounce(function () {
|
||||
$scope.$apply(function () {
|
||||
if ($scope.searchOptions.filter) {
|
||||
searchMedia();
|
||||
} else {
|
||||
// reset pagination
|
||||
$scope.searchOptions = {
|
||||
pageNumber: 1,
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
filter: ''
|
||||
};
|
||||
getChildren($scope.currentFolder.id);
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
function searchMedia() {
|
||||
$scope.loading = true;
|
||||
entityResource.getPagedDescendants($scope.startNodeId, "Media", $scope.searchOptions)
|
||||
.then(function (data) {
|
||||
// update image data to work with image grid
|
||||
angular.forEach(data.items, function(mediaItem){
|
||||
// set thumbnail and src
|
||||
mediaItem.thumbnail = mediaHelper.resolveFileFromEntity(mediaItem, true);
|
||||
mediaItem.image = mediaHelper.resolveFileFromEntity(mediaItem, false);
|
||||
// set properties to match a media object
|
||||
if (mediaItem.metaData &&
|
||||
mediaItem.metaData.umbracoWidth &&
|
||||
mediaItem.metaData.umbracoHeight) {
|
||||
|
||||
mediaItem.properties = [
|
||||
{
|
||||
alias: "umbracoWidth",
|
||||
value: mediaItem.metaData.umbracoWidth.Value
|
||||
},
|
||||
{
|
||||
alias: "umbracoHeight",
|
||||
value: mediaItem.metaData.umbracoHeight.Value
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
// update images
|
||||
$scope.images = data.items ? data.items : [];
|
||||
// update pagination
|
||||
if (data.pageNumber > 0)
|
||||
$scope.searchOptions.pageNumber = data.pageNumber;
|
||||
if (data.pageSize > 0)
|
||||
$scope.searchOptions.pageSize = data.pageSize;
|
||||
$scope.searchOptions.totalItems = data.totalItems;
|
||||
$scope.searchOptions.totalPages = data.totalPages;
|
||||
// set already selected images to selected
|
||||
preSelectImages();
|
||||
$scope.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function getChildren(id) {
|
||||
$scope.loading = true;
|
||||
mediaResource.getChildren(id)
|
||||
.then(function(data) {
|
||||
$scope.searchOptions.filter = "";
|
||||
$scope.images = data.items ? data.items : [];
|
||||
// set already selected images to selected
|
||||
preSelectImages();
|
||||
$scope.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function preSelectImages() {
|
||||
for (var folderImageIndex = 0; folderImageIndex < $scope.images.length; folderImageIndex++) {
|
||||
var folderImage = $scope.images[folderImageIndex];
|
||||
var imageIsSelected = false;
|
||||
|
||||
for (var selectedImageIndex = 0;
|
||||
selectedImageIndex < $scope.model.selectedImages.length;
|
||||
selectedImageIndex++) {
|
||||
var selectedImage = $scope.model.selectedImages[selectedImageIndex];
|
||||
|
||||
if (folderImage.key === selectedImage.key) {
|
||||
imageIsSelected = true;
|
||||
}
|
||||
}
|
||||
if (imageIsSelected) {
|
||||
folderImage.selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,13 +10,18 @@
|
||||
|
||||
<div class="umb-control-group umb-mediapicker-upload">
|
||||
|
||||
<umb-load-indicator
|
||||
ng-if="loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input
|
||||
class="umb-search-field search-query"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query -full-width-input"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
type="text">
|
||||
</div>
|
||||
|
||||
@@ -32,7 +37,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row umb-control-group">
|
||||
<div class="row umb-control-group" ng-if="!searchOptions.filter">
|
||||
<ul class="umb-breadcrumbs">
|
||||
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
|
||||
<a href ng-click="gotoFolder()" prevent-default>Media</a>
|
||||
@@ -63,20 +68,20 @@
|
||||
</div>
|
||||
|
||||
<umb-file-dropzone
|
||||
ng-if="acceptedMediatypes.length > 0"
|
||||
ng-if="acceptedMediatypes.length > 0 && !loading"
|
||||
accepted-mediatypes="acceptedMediatypes"
|
||||
parent-id="{{currentFolder.id}}"
|
||||
files-uploaded="onUploadComplete"
|
||||
files-queued="onFilesQueue"
|
||||
accept="{{acceptedFileTypes}}"
|
||||
max-file-size="{{maxFileSize}}"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0 }}"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0 || searchOptions.filter }}"
|
||||
compact="{{ images.length > 0 }}">
|
||||
</umb-file-dropzone>
|
||||
|
||||
<umb-media-grid
|
||||
ng-if="!loading"
|
||||
items="images"
|
||||
filter-by="searchTerm"
|
||||
on-click="clickHandler"
|
||||
on-click-name="clickItemName"
|
||||
item-max-width="150"
|
||||
@@ -86,6 +91,21 @@
|
||||
only-images={{onlyImages}}>
|
||||
</umb-media-grid>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination
|
||||
ng-if="searchOptions.totalPages > 0 && !loading"
|
||||
page-number="searchOptions.pageNumber"
|
||||
total-pages="searchOptions.totalPages"
|
||||
on-change="changePagination(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="searchOptions.filter && images.length === 0 && !loading"
|
||||
position="center">
|
||||
<localize key="general_searchNoResult"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
</div>
|
||||
|
||||
<umb-overlay
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
$scope.enableSearh = true;
|
||||
|
||||
//if a alternative startnode is used, we need to check if it is a container
|
||||
if (dialogOptions.startNodeId && dialogOptions.startNodeId !== -1) {
|
||||
if (dialogOptions.startNodeId && dialogOptions.startNodeId !== -1 && dialogOptions.startNodeId !== "-1") {
|
||||
entityResource.getById(dialogOptions.startNodeId, $scope.entityType).then(function (node) {
|
||||
if (node.metaData.IsContainer) {
|
||||
openMiniListView(node);
|
||||
|
||||
@@ -62,14 +62,14 @@
|
||||
ng-repeat="child in miniListView.children"
|
||||
ng-click="selectNode(child)"
|
||||
ng-class="{'-selected':child.selected}">
|
||||
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':!child.published && entityType === 'Document'}">
|
||||
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':child.published === false}">
|
||||
<div class="flex items-center">
|
||||
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)"> </ins>
|
||||
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)" ng-class="{'umb-table__row-expand--hidden': child.hasChildren !== true}"> </ins>
|
||||
<i class="umb-table-body__icon umb-table-body__fileicon {{child.icon}}"></i>
|
||||
<i class="umb-table-body__icon umb-table-body__checkicon icon-check"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-cell black" ng-class="{'umb-table-cell--faded':!child.published && entityType === 'Document'}">{{ child.name }}</div>
|
||||
<div class="umb-table-cell black" ng-class="{'umb-table-cell--faded':child.published === false}">{{ child.name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Load indicator when the list doesn't have items -->
|
||||
|
||||
@@ -483,7 +483,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
|
||||
//we need to do a double sync here: first refresh the node where the content was moved,
|
||||
// then refresh the node where the content was moved from
|
||||
navigationService.syncTree({
|
||||
tree: target.nodeType,
|
||||
tree: target.nodeType ? target.nodeType : (target.metaData.treeAlias),
|
||||
path: newPath,
|
||||
forceReload: true,
|
||||
activate: false
|
||||
|
||||
@@ -30,6 +30,7 @@ using Examine.SearchCriteria;
|
||||
using Umbraco.Web.Dynamics;
|
||||
using umbraco;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using System.Web.Http.Controllers;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
@@ -54,6 +55,11 @@ namespace Umbraco.Web.Editors
|
||||
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
|
||||
{
|
||||
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
|
||||
|
||||
//This is a special case, we'll accept a String here so that we can get page members when the special "all-members"
|
||||
//id is passed in eventually we'll probably want to support GUID + Udi too
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetPagedChildren", "id", typeof(int), typeof(string)),
|
||||
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)),
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetByIds", "ids", typeof(int[]), typeof(Guid[]), typeof(Udi[]))));
|
||||
}
|
||||
@@ -216,7 +222,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
public EntityBasic GetByQuery(string query, int nodeContextId, UmbracoEntityTypes type)
|
||||
{
|
||||
//TODO: Rename this!!! It's a bit misleading, it should be GetByXPath
|
||||
//TODO: Rename this!!! It's misleading, it should be GetByXPath
|
||||
|
||||
|
||||
if (type != UmbracoEntityTypes.Document)
|
||||
@@ -382,6 +388,176 @@ namespace Umbraco.Web.Editors
|
||||
return GetResultForChildren(id, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get paged child entities by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="pageNumber"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public PagedResult<EntityBasic> GetPagedChildren(
|
||||
string id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
int intId;
|
||||
|
||||
if (int.TryParse(id, out intId))
|
||||
{
|
||||
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter);
|
||||
}
|
||||
|
||||
Guid guidId;
|
||||
if (Guid.TryParse(id, out guidId))
|
||||
{
|
||||
//Not supported currently
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
Udi udiId;
|
||||
if (Udi.TryParse(id, out udiId))
|
||||
{
|
||||
//Not supported currently
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
//so we don't have an INT, GUID or UDI, it's just a string, so now need to check if it's a special id or a member type
|
||||
if (id == Constants.Conventions.MemberTypes.AllMembersListId)
|
||||
{
|
||||
//the EntityService can search paged members from the root
|
||||
|
||||
intId = -1;
|
||||
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter);
|
||||
}
|
||||
|
||||
//the EntityService cannot search members of a certain type, this is currently not supported and would require
|
||||
//quite a bit of plumbing to do in the Services/Repository, we'll revert to a paged search
|
||||
|
||||
int total;
|
||||
var searchResult = ExamineSearch(filter ?? "", type, pageSize, pageNumber - 1, out total, id);
|
||||
|
||||
return new PagedResult<EntityBasic>(total, pageNumber, pageSize)
|
||||
{
|
||||
Items = searchResult
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get paged child entities by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="pageNumber"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public PagedResult<EntityBasic> GetPagedChildren(
|
||||
int id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
if (pageNumber <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
if (pageSize <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
|
||||
var objectType = ConvertToObjectType(type);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
long totalRecords;
|
||||
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
|
||||
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<EntityBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = entities.Select(Mapper.Map<EntityBasic>)
|
||||
};
|
||||
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
//now we need to convert the unknown ones
|
||||
switch (type)
|
||||
{
|
||||
case UmbracoEntityTypes.PropertyType:
|
||||
case UmbracoEntityTypes.PropertyGroup:
|
||||
case UmbracoEntityTypes.Domain:
|
||||
case UmbracoEntityTypes.Language:
|
||||
case UmbracoEntityTypes.User:
|
||||
case UmbracoEntityTypes.Macro:
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public PagedResult<EntityBasic> GetPagedDescendants(
|
||||
int id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
if (pageNumber <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
if (pageSize <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
|
||||
var objectType = ConvertToObjectType(type);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
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 (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<EntityBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = entities.Select(Mapper.Map<EntityBasic>)
|
||||
};
|
||||
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
//now we need to convert the unknown ones
|
||||
switch (type)
|
||||
{
|
||||
case UmbracoEntityTypes.PropertyType:
|
||||
case UmbracoEntityTypes.PropertyGroup:
|
||||
case UmbracoEntityTypes.Domain:
|
||||
case UmbracoEntityTypes.Language:
|
||||
case UmbracoEntityTypes.User:
|
||||
case UmbracoEntityTypes.Macro:
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityBasic> GetAncestors(int id, UmbracoEntityTypes type)
|
||||
{
|
||||
return GetResultForAncestors(id, type);
|
||||
@@ -397,12 +573,30 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="entityType"></param>
|
||||
/// <param name="searchFrom">
|
||||
/// A starting point for the search, generally a node id, but for members this is a member type alias
|
||||
/// </param>
|
||||
/// <param name="searchFrom"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null)
|
||||
{
|
||||
int total;
|
||||
return ExamineSearch(query, entityType, 200, 0, out total, searchFrom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for results based on the entity type
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="entityType"></param>
|
||||
/// <param name="totalFound"></param>
|
||||
/// <param name="searchFrom">
|
||||
/// A starting point for the search, generally a node id, but for members this is a member type alias
|
||||
/// </param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ExamineSearch(string query, UmbracoEntityTypes entityType, int pageSize, int pageIndex, out int totalFound, string searchFrom = null)
|
||||
{
|
||||
//TODO: We need to update this to support paging
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
string type;
|
||||
@@ -478,91 +672,113 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
if (query.IsNullOrWhiteSpace())
|
||||
//nothing to search
|
||||
if (searchFrom.IsNullOrWhiteSpace() && query.IsNullOrWhiteSpace())
|
||||
{
|
||||
totalFound = 0;
|
||||
return new List<EntityBasic>();
|
||||
}
|
||||
|
||||
//add back the surrounding quotes
|
||||
query = string.Format("{0}{1}{0}", "\"", query);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName: (");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append(")^10.0 ");
|
||||
|
||||
foreach (var f in fields)
|
||||
//update the query with the query term
|
||||
if (query.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(": (");
|
||||
sb.Append(query);
|
||||
//add back the surrounding quotes
|
||||
query = string.Format("{0}{1}{0}", "\"", query);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName: (");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append(")^10.0 ");
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(": (");
|
||||
sb.Append(query);
|
||||
sb.Append(") ");
|
||||
}
|
||||
|
||||
sb.Append(") ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (query.Trim(new[] { '\"', '\'' }).IsNullOrWhiteSpace())
|
||||
var trimmed = query.Trim(new[] {'\"', '\''});
|
||||
|
||||
//nothing to search
|
||||
if (searchFrom.IsNullOrWhiteSpace() && trimmed.IsNullOrWhiteSpace())
|
||||
{
|
||||
totalFound = 0;
|
||||
return new List<EntityBasic>();
|
||||
}
|
||||
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName:");
|
||||
sb.Append("\"");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append("\"");
|
||||
sb.Append("^10.0 ");
|
||||
|
||||
//node name normally with wildcards
|
||||
sb.Append(" __nodeName:");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
//update the query with the query term
|
||||
if (trimmed.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(") ");
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(":");
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName:");
|
||||
sb.Append("\"");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append("\"");
|
||||
sb.Append("^10.0 ");
|
||||
|
||||
//node name normally with wildcards
|
||||
sb.Append(" __nodeName:");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(")");
|
||||
sb.Append(" ");
|
||||
sb.Append(") ");
|
||||
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(":");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(")");
|
||||
sb.Append(" ");
|
||||
}
|
||||
|
||||
sb.Append(") ");
|
||||
}
|
||||
}
|
||||
|
||||
//must match index type
|
||||
sb.Append(") +__IndexType:");
|
||||
sb.Append("+__IndexType:");
|
||||
sb.Append(type);
|
||||
|
||||
|
||||
var raw = internalSearcher.CreateSearchCriteria().RawQuery(sb.ToString());
|
||||
|
||||
//limit results to 200 to avoid huge over processing (CPU)
|
||||
var result = internalSearcher.Search(raw, 200);
|
||||
var result = internalSearcher
|
||||
//only return the number of items specified to read up to the amount of records to fill from 0 -> the number of items on the page requested
|
||||
.Search(raw, pageSize * (pageIndex + 1));
|
||||
|
||||
totalFound = result.TotalItemCount;
|
||||
|
||||
var pagedResult = result.Skip(pageIndex);
|
||||
|
||||
switch (entityType)
|
||||
{
|
||||
case UmbracoEntityTypes.Member:
|
||||
return MemberFromSearchResults(result);
|
||||
return MemberFromSearchResults(pagedResult.ToArray());
|
||||
case UmbracoEntityTypes.Media:
|
||||
return MediaFromSearchResults(result);
|
||||
return MediaFromSearchResults(pagedResult);
|
||||
case UmbracoEntityTypes.Document:
|
||||
return ContentFromSearchResults(result);
|
||||
return ContentFromSearchResults(pagedResult);
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " currently does not support searching against object type " + entityType);
|
||||
}
|
||||
@@ -573,7 +789,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> MemberFromSearchResults(ISearchResults results)
|
||||
private IEnumerable<EntityBasic> MemberFromSearchResults(SearchResult[] results)
|
||||
{
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(results).ToArray();
|
||||
//add additional data
|
||||
@@ -607,7 +823,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> MediaFromSearchResults(ISearchResults results)
|
||||
private IEnumerable<EntityBasic> MediaFromSearchResults(IEnumerable<SearchResult> results)
|
||||
{
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(results).ToArray();
|
||||
//add additional data
|
||||
@@ -627,9 +843,9 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ContentFromSearchResults(ISearchResults results)
|
||||
private IEnumerable<EntityBasic> ContentFromSearchResults(IEnumerable<SearchResult> results)
|
||||
{
|
||||
var mapped = Mapper.Map<ISearchResults, IEnumerable<EntityBasic>>(results).ToArray();
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(results).ToArray();
|
||||
//add additional data
|
||||
foreach (var m in mapped)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@@ -28,7 +29,9 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Http.Controllers;
|
||||
using Examine;
|
||||
using Umbraco.Web.WebApi.Binders;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using umbraco;
|
||||
|
||||
@@ -84,17 +84,21 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The real persisted content object
|
||||
/// The real persisted content object - used during inbound model binding
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is not used for outgoing model information.
|
||||
/// </remarks>
|
||||
[JsonIgnore]
|
||||
internal TPersisted PersistedContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The DTO object used to gather all required content data including data type information etc... for use with validation
|
||||
/// The DTO object used to gather all required content data including data type information etc... for use with validation - used during inbound model binding
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We basically use this object to hydrate all required data from the database into one object so we can validate everything we need
|
||||
/// instead of having to look up all the data individually.
|
||||
/// This is not used for outgoing model information.
|
||||
/// </remarks>
|
||||
[JsonIgnore]
|
||||
internal ContentItemDto<TPersisted> ContentDto { get; set; }
|
||||
|
||||
@@ -21,7 +21,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
|
||||
.ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
|
||||
.ForMember(dto => dto.Trashed, expression => expression.Ignore())
|
||||
.ForMember(x => x.Alias, expression => expression.Ignore());
|
||||
.ForMember(x => x.Alias, expression => expression.Ignore())
|
||||
.AfterMap((entity, basic) =>
|
||||
{
|
||||
if (entity.NodeObjectTypeId == Constants.ObjectTypes.MemberGuid && basic.Icon.IsNullOrWhiteSpace())
|
||||
{
|
||||
basic.Icon = "icon-user";
|
||||
}
|
||||
});
|
||||
|
||||
config.CreateMap<PropertyType, EntityBasic>()
|
||||
.ForMember(x => x.Udi, expression => expression.Ignore())
|
||||
@@ -151,6 +158,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
config.CreateMap<ISearchResults, IEnumerable<EntityBasic>>()
|
||||
.ConvertUsing(results => results.Select(Mapper.Map<EntityBasic>).ToList());
|
||||
|
||||
config.CreateMap<IEnumerable<SearchResult>, IEnumerable<EntityBasic>>()
|
||||
.ConvertUsing(results => results.Select(Mapper.Map<EntityBasic>).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user