Merge branch 'temp8' into temp8-migrations

This commit is contained in:
Stephan
2018-12-21 10:46:37 +01:00
80 changed files with 760 additions and 587 deletions
+2 -1
View File
@@ -33,4 +33,5 @@ dotnet_naming_style.prefix_underscore.required_prefix = _
[*.cs]
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_prefer_braces = false : none
-1
View File
@@ -82,7 +82,6 @@ You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
- We're also [active in the Gitter chatroom](https://gitter.im/umbraco/Umbraco-CMS)
## Code of Conduct
+1
View File
@@ -107,6 +107,7 @@ src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
src/Umbraco.Web.UI.Client/vwd.webinfo
src/Umbraco.Web.UI/App_Plugins/*
src/*.psess
+2 -3
View File
@@ -14,7 +14,7 @@
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
@@ -25,8 +25,7 @@
<dependency id="ClientDependency" version="[1.9.7,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.0-beta046,1.999999)" />
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
<dependency id="Examine" version="[1.0.0-beta067,1.999999)" />
<dependency id="HtmlAgilityPack" version="[1.8.9,1.999999)" />
<dependency id="ImageProcessor" version="[2.6.2.25,2.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
+2
View File
@@ -618,6 +618,8 @@ namespace Umbraco.Core.Composing
// doesn't actualy load in all assemblies, only the types that have been referenced so far.
// However, in a web context, the BuildManager will have executed which will force all assemblies
// to be loaded so it's fine for now.
// It could be fairly easy to parse the typeName to get the assembly name and then do Assembly.Load and
// find the type from there.
//now try fall back procedures.
type = Type.GetType(typeName);
@@ -4,6 +4,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -30,6 +31,6 @@ namespace Umbraco.Core.Persistence.Repositories
bool Exists(Guid key);
IEnumerable<IEntitySlim> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null);
IQuery<IUmbracoEntity> filter, Ordering ordering);
}
}
@@ -10,6 +10,7 @@ using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
@@ -25,12 +26,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
internal class EntityRepository : IEntityRepository
{
private readonly IScopeAccessor _scopeAccessor;
private readonly ILanguageRepository _langRepository;
public EntityRepository(IScopeAccessor scopeAccessor, ILanguageRepository langRepository)
public EntityRepository(IScopeAccessor scopeAccessor)
{
_scopeAccessor = scopeAccessor;
_langRepository = langRepository;
}
protected IUmbracoDatabase Database => _scopeAccessor.AmbientScope.Database;
@@ -41,7 +40,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// get a page of entities
public IEnumerable<IEntitySlim> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null)
IQuery<IUmbracoEntity> filter, Ordering ordering)
{
var isContent = objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint;
var isMedia = objectType == Constants.ObjectTypes.Media;
@@ -53,11 +52,21 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
x.Where(filterClause.Item1, filterClause.Item2);
}, objectType);
ordering = ordering ?? Ordering.ByDefault();
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
sql = translator.Translate();
sql = AddGroupBy(isContent, isMedia, sql);
sql = AddGroupBy(isContent, isMedia, sql, ordering.IsEmpty);
if (!ordering.IsEmpty)
{
// apply ordering
ApplyOrdering(ref sql, ordering);
}
//fixme - we should be able to do sql = sql.OrderBy(x => Alias(x.NodeId, "NodeId")); but we can't because the OrderBy extension don't support Alias currently
sql = sql.OrderBy("NodeId");
//no matter what we always must have node id ordered at the end
sql = ordering.Direction == Direction.Ascending ? sql.OrderBy("NodeId") : sql.OrderByDescending("NodeId");
var page = Database.Page<BaseDto>(pageIndex + 1, pageSize, sql);
var dtos = page.Items;
@@ -81,6 +90,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return dto == null ? null : BuildEntity(false, false, dto);
}
private IEntitySlim GetEntity(Sql<ISqlContext> sql, bool isContent, bool isMedia)
{
//isContent is going to return a 1:M result now with the variants so we need to do different things
@@ -200,7 +210,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var sqlClause = GetBase(false, false, null);
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
var sql = translator.Translate();
sql = AddGroupBy(false, false, sql);
sql = AddGroupBy(false, false, sql, true);
var dtos = Database.Fetch<BaseDto>(sql);
return dtos.Select(x => BuildEntity(false, false, x)).ToList();
}
@@ -214,7 +224,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
sql = translator.Translate();
sql = AddGroupBy(isContent, isMedia, sql);
sql = AddGroupBy(isContent, isMedia, sql, true);
return GetEntities(sql, isContent, isMedia, true);
}
@@ -229,7 +239,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
sql = translator.Translate();
sql = AddGroupBy(isContent, isMedia, sql);
sql = AddGroupBy(isContent, isMedia, sql, true);
return GetEntities(sql, isContent, isMedia, false);
}
@@ -361,21 +371,21 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectType, Guid uniqueId)
{
var sql = GetBaseWhere(isContent, isMedia, false, objectType, uniqueId);
return AddGroupBy(isContent, isMedia, sql);
return AddGroupBy(isContent, isMedia, sql, true);
}
// gets the full sql for a given object type and a given node id
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectType, int nodeId)
{
var sql = GetBaseWhere(isContent, isMedia, false, objectType, nodeId);
return AddGroupBy(isContent, isMedia, sql);
return AddGroupBy(isContent, isMedia, sql, true);
}
// gets the full sql for a given object type, with a given filter
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectType, Action<Sql<ISqlContext>> filter)
{
var sql = GetBaseWhere(isContent, isMedia, false, filter, objectType);
return AddGroupBy(isContent, isMedia, sql);
return AddGroupBy(isContent, isMedia, sql, true);
}
private Sql<ISqlContext> GetPropertyData(int versionId)
@@ -401,7 +411,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the base SELECT + FROM [+ filter] sql
// always from the 'current' content version
protected virtual Sql<ISqlContext> GetBase(bool isContent, bool isMedia, Action<Sql<ISqlContext>> filter, bool isCount = false)
protected Sql<ISqlContext> GetBase(bool isContent, bool isMedia, Action<Sql<ISqlContext>> filter, bool isCount = false)
{
var sql = Sql();
@@ -460,7 +470,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the base SELECT + FROM [+ filter] + WHERE sql
// for a given object type, with a given filter
protected virtual Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Action<Sql<ISqlContext>> filter, Guid objectType)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Action<Sql<ISqlContext>> filter, Guid objectType)
{
return GetBase(isContent, isMedia, filter, isCount)
.Where<NodeDto>(x => x.NodeObjectType == objectType);
@@ -468,25 +478,25 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the base SELECT + FROM + WHERE sql
// for a given node id
protected virtual Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, int id)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, int id)
{
var sql = GetBase(isContent, isMedia, null, isCount)
.Where<NodeDto>(x => x.NodeId == id);
return AddGroupBy(isContent, isMedia, sql);
return AddGroupBy(isContent, isMedia, sql, true);
}
// gets the base SELECT + FROM + WHERE sql
// for a given unique id
protected virtual Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid uniqueId)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid uniqueId)
{
var sql = GetBase(isContent, isMedia, null, isCount)
.Where<NodeDto>(x => x.UniqueId == uniqueId);
return AddGroupBy(isContent, isMedia, sql);
return AddGroupBy(isContent, isMedia, sql, true);
}
// gets the base SELECT + FROM + WHERE sql
// for a given object type and node id
protected virtual Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid objectType, int nodeId)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid objectType, int nodeId)
{
return GetBase(isContent, isMedia, null, isCount)
.Where<NodeDto>(x => x.NodeId == nodeId && x.NodeObjectType == objectType);
@@ -494,7 +504,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the base SELECT + FROM + WHERE sql
// for a given object type and unique id
protected virtual Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid objectType, Guid uniqueId)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid objectType, Guid uniqueId)
{
return GetBase(isContent, isMedia, null, isCount)
.Where<NodeDto>(x => x.UniqueId == uniqueId && x.NodeObjectType == objectType);
@@ -502,7 +512,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the GROUP BY / ORDER BY sql
// required in order to count children
protected virtual Sql<ISqlContext> AddGroupBy(bool isContent, bool isMedia, Sql<ISqlContext> sql, bool sort = true)
protected Sql<ISqlContext> AddGroupBy(bool isContent, bool isMedia, Sql<ISqlContext> sql, bool defaultSort)
{
sql
.GroupBy<NodeDto>(x => x.NodeId, x => x.Trashed, x => x.ParentId, x => x.UserId, x => x.Level, x => x.Path)
@@ -520,12 +530,26 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
.AndBy<ContentVersionDto>(x => x.Id)
.AndBy<ContentTypeDto>(x => x.Alias, x => x.Icon, x => x.Thumbnail, x => x.IsContainer, x => x.Variations);
if (sort)
if (defaultSort)
sql.OrderBy<NodeDto>(x => x.SortOrder);
return sql;
}
private void ApplyOrdering(ref Sql<ISqlContext> sql, Ordering ordering)
{
if (sql == null) throw new ArgumentNullException(nameof(sql));
if (ordering == null) throw new ArgumentNullException(nameof(ordering));
//fixme - although this works for name, it probably doesn't work for others without an alias of some sort
var orderBy = ordering.OrderBy;
if (ordering.Direction == Direction.Ascending)
sql.OrderBy(orderBy);
else
sql.OrderByDescending(orderBy);
}
#endregion
#region Classes
@@ -423,6 +423,7 @@ ORDER BY colName";
{
"DELETE FROM umbracoUser2UserGroup WHERE userId = @id",
"DELETE FROM umbracoUser2NodeNotify WHERE userId = @id",
"DELETE FROM umbracoUserStartNode WHERE userId = @id",
"DELETE FROM umbracoUser WHERE id = @id",
"DELETE FROM umbracoExternalLogin WHERE id = @id"
};
+6 -5
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Services
{
@@ -227,25 +228,25 @@ namespace Umbraco.Core.Services
/// Gets children of an entity.
/// </summary>
IEnumerable<IEntitySlim> GetPagedChildren(int id, UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null);
/// <summary>
/// Gets descendants of an entity.
/// </summary>
IEnumerable<IEntitySlim> GetPagedDescendants(int id, UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null);
/// <summary>
/// Gets descendants of entities.
/// </summary>
IEnumerable<IEntitySlim> GetPagedDescendants(IEnumerable<int> ids, UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null);
/// <summary>
/// Gets descendants of root.
/// Gets descendants of root. fixme: Do we really need this? why not just pass in -1
/// </summary>
IEnumerable<IEntitySlim> GetPagedDescendants(UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true);
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null, bool includeTrashed = true);
/// <summary>
/// Gets the object type of an entity.
@@ -415,20 +415,19 @@ namespace Umbraco.Core.Services.Implement
/// <inheritdoc />
public IEnumerable<IEntitySlim> GetPagedChildren(int id, UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "")
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null)
{
using (ScopeProvider.CreateScope(autoComplete: true))
{
var query = Query<IUmbracoEntity>().Where(x => x.ParentId == id && x.Trashed == false);
var filterQuery = string.IsNullOrWhiteSpace(filter) ? null : Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter));
return _entityRepository.GetPagedResultsByQuery(query, objectType.GetGuid(), pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
return _entityRepository.GetPagedResultsByQuery(query, objectType.GetGuid(), pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
/// <inheritdoc />
public IEnumerable<IEntitySlim> GetPagedDescendants(int id, UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null)
{
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -448,14 +447,13 @@ namespace Umbraco.Core.Services.Implement
query.Where(x => x.Path.SqlStartsWith(path + ",", TextColumnType.NVarchar));
}
var filterQuery = string.IsNullOrWhiteSpace(filter) ? null : Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter));
return _entityRepository.GetPagedResultsByQuery(query, objectTypeGuid, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
return _entityRepository.GetPagedResultsByQuery(query, objectTypeGuid, pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
/// <inheritdoc />
public IEnumerable<IEntitySlim> GetPagedDescendants(IEnumerable<int> ids, UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null)
{
totalRecords = 0;
@@ -492,14 +490,13 @@ namespace Umbraco.Core.Services.Implement
query.WhereAny(clauses);
}
var filterQuery = string.IsNullOrWhiteSpace(filter) ? null : Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter));
return _entityRepository.GetPagedResultsByQuery(query, objectTypeGuid, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
return _entityRepository.GetPagedResultsByQuery(query, objectTypeGuid, pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
/// <inheritdoc />
public IEnumerable<IEntitySlim> GetPagedDescendants(UmbracoObjectTypes objectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true)
IQuery<IUmbracoEntity> filter = null, Ordering ordering = null, bool includeTrashed = true)
{
using (ScopeProvider.CreateScope(autoComplete: true))
{
@@ -507,8 +504,7 @@ namespace Umbraco.Core.Services.Implement
if (includeTrashed == false)
query.Where(x => x.Trashed == false);
var filterQuery = string.IsNullOrWhiteSpace(filter) ? null : Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter));
return _entityRepository.GetPagedResultsByQuery(query, objectType.GetGuid(), pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
return _entityRepository.GetPagedResultsByQuery(query, objectType.GetGuid(), pageIndex, pageSize, out totalRecords, filter, ordering);
}
}
+1 -4
View File
@@ -15,7 +15,7 @@ namespace Umbraco.Examine
/// <summary>
/// Performs the data lookups required to rebuild a content index
/// </summary>
public class ContentIndexPopulator : IndexPopulator
public class ContentIndexPopulator : IndexPopulator<UmbracoContentIndex>
{
private readonly IContentService _contentService;
private readonly IValueSetBuilder<IContent> _contentValueSetBuilder;
@@ -56,9 +56,6 @@ namespace Umbraco.Examine
_publishedQuery = sqlContext.Query<IContent>().Where(x => x.Published);
_publishedValuesOnly = publishedValuesOnly;
_parentId = parentId;
RegisterIndex(Constants.UmbracoIndexes.InternalIndexName);
RegisterIndex(Constants.UmbracoIndexes.ExternalIndexName);
}
protected override void PopulateIndexes(IEnumerable<IIndex> indexes)
+6 -4
View File
@@ -3,12 +3,14 @@ using Examine;
namespace Umbraco.Examine
{
public interface IIndexPopulator
{
bool IsRegistered(string indexName);
void RegisterIndex(string indexName);
/// <summary>
/// If this index is registered with this populatr
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
bool IsRegistered(IIndex index);
/// <summary>
/// Populate indexers
@@ -1,11 +1,12 @@
using Examine;
using System.Collections.Generic;
using Examine;
namespace Umbraco.Examine
{
/// <summary>
/// A Marker interface for defining an Umbraco indexer
/// </summary>
public interface IUmbracoIndexer : IIndex
public interface IUmbracoIndex : IIndex
{
/// <summary>
/// When set to true Umbraco will keep the index in sync with Umbraco data automatically
@@ -21,5 +22,11 @@ namespace Umbraco.Examine
/// * non-published Variants
/// </remarks>
bool PublishedValuesOnly { get; }
/// <summary>
/// Returns a list of all indexed fields
/// </summary>
/// <returns></returns>
IEnumerable<string> GetFields();
}
}
+16 -3
View File
@@ -5,13 +5,26 @@ using Umbraco.Core.Collections;
namespace Umbraco.Examine
{
/// <summary>
/// An <see cref="IIndexPopulator"/> that is automatically associated to any index of type <see cref="TIndex"/>
/// </summary>
/// <typeparam name="TIndex"></typeparam>
public abstract class IndexPopulator<TIndex> : IndexPopulator where TIndex : IIndex
{
public override bool IsRegistered(IIndex index)
{
if (base.IsRegistered(index)) return true;
return index is TIndex;
}
}
public abstract class IndexPopulator : IIndexPopulator
{
private readonly ConcurrentHashSet<string> _registeredIndexes = new ConcurrentHashSet<string>();
public bool IsRegistered(string indexName)
public virtual bool IsRegistered(IIndex index)
{
return _registeredIndexes.Contains(indexName);
return _registeredIndexes.Contains(index.Name);
}
/// <summary>
@@ -25,7 +38,7 @@ namespace Umbraco.Examine
public void Populate(params IIndex[] indexes)
{
PopulateIndexes(indexes.Where(x => IsRegistered(x.Name)));
PopulateIndexes(indexes.Where(IsRegistered));
}
protected abstract void PopulateIndexes(IEnumerable<IIndex> indexes);
+2 -2
View File
@@ -20,9 +20,9 @@ namespace Umbraco.Examine
ExamineManager = examineManager;
}
public bool CanRebuild(string indexName)
public bool CanRebuild(IIndex index)
{
return _populators.Any(x => x.IsRegistered(indexName));
return _populators.Any(x => x.IsRegistered(index));
}
public void RebuildIndex(string indexName)
+26 -7
View File
@@ -1,8 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using Examine;
using Examine.LuceneEngine.Directories;
using Lucene.Net.Store;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
namespace Umbraco.Examine
@@ -18,17 +22,30 @@ namespace Umbraco.Examine
/// <summary>
/// Creates a file system based Lucene <see cref="Lucene.Net.Store.Directory"/> with the correct locking guidelines for Umbraco
/// </summary>
/// <param name="name"></param>
/// <param name="folderName">
/// The folder name to store the index (single word, not a fully qualified folder) (i.e. Internal)
/// </param>
/// <returns></returns>
public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string name)
public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string folderName)
{
//TODO: We should have a single AppSetting to be able to specify a default DirectoryFactory so we can have a single
//setting to configure all indexes that use this to easily swap the directory to Sync/%temp%/blog, etc...
var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Data), "TEMP", "ExamineIndexes", name));
var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Data), "TEMP", "ExamineIndexes", folderName));
if (!dirInfo.Exists)
System.IO.Directory.CreateDirectory(dirInfo.FullName);
//check if there's a configured directory factory, if so create it and use that to create the lucene dir
var configuredDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"];
if (!configuredDirectoryFactory.IsNullOrWhiteSpace())
{
//this should be a fully qualified type
var factoryType = TypeFinder.GetTypeByName(configuredDirectoryFactory);
if (factoryType == null) throw new NullReferenceException("No directory type found for value: " + configuredDirectoryFactory);
var directoryFactory = (IDirectoryFactory)Activator.CreateInstance(factoryType);
return directoryFactory.CreateDirectory(dirInfo);
}
//no dir factory, just create a normal fs directory
var luceneDir = new SimpleFSDirectory(dirInfo);
//we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain
@@ -38,6 +55,8 @@ namespace Umbraco.Examine
// however, we are setting the DefaultLockFactory in startup so we'll use that instead since it can be managed globally.
luceneDir.SetLockFactory(DirectoryFactory.DefaultLockFactory(dirInfo));
return luceneDir;
}
}
}
+1 -4
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Examine
/// <summary>
/// Performs the data lookups required to rebuild a media index
/// </summary>
public class MediaIndexPopulator : IndexPopulator
public class MediaIndexPopulator : IndexPopulator<UmbracoContentIndex>
{
private readonly int? _parentId;
private readonly IMediaService _mediaService;
@@ -37,9 +37,6 @@ namespace Umbraco.Examine
_parentId = parentId;
_mediaService = mediaService;
_mediaValueSetBuilder = mediaValueSetBuilder;
RegisterIndex(Constants.UmbracoIndexes.InternalIndexName);
RegisterIndex(Constants.UmbracoIndexes.ExternalIndexName);
}
protected override void PopulateIndexes(IEnumerable<IIndex> indexes)
+1 -3
View File
@@ -7,7 +7,7 @@ using Umbraco.Core.Services;
namespace Umbraco.Examine
{
public class MemberIndexPopulator : IndexPopulator
public class MemberIndexPopulator : IndexPopulator<UmbracoMemberIndex>
{
private readonly IMemberService _memberService;
private readonly IValueSetBuilder<IMember> _valueSetBuilder;
@@ -16,8 +16,6 @@ namespace Umbraco.Examine
{
_memberService = memberService;
_valueSetBuilder = valueSetBuilder;
RegisterIndex(Core.Constants.UmbracoIndexes.MembersIndexName);
}
protected override void PopulateIndexes(IEnumerable<IIndex> indexes)
{
+3 -3
View File
@@ -48,7 +48,7 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Examine" Version="1.0.0-beta046" />
<PackageReference Include="Examine" Version="1.0.0-beta067" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NPoco" Version="3.9.4" />
</ItemGroup>
@@ -72,7 +72,7 @@
<Compile Include="IndexPopulator.cs" />
<Compile Include="IndexRebuilder.cs" />
<Compile Include="IPublishedContentValueSetBuilder.cs" />
<Compile Include="IUmbracoIndexer.cs" />
<Compile Include="IUmbracoIndex.cs" />
<Compile Include="IValueSetBuilder.cs" />
<Compile Include="MediaIndexPopulator.cs" />
<Compile Include="MediaValueSetBuilder.cs" />
@@ -88,8 +88,8 @@
<Compile Include="ContentValueSetValidator.cs" />
<Compile Include="UmbracoExamineIndexDiagnostics.cs" />
<Compile Include="UmbracoExamineIndex.cs" />
<Compile Include="UmbracoExamineSearcher.cs" />
<Compile Include="LuceneIndexCreator.cs" />
<Compile Include="UmbracoFieldDefinitionCollection.cs" />
<Compile Include="UmbracoMemberIndex.cs" />
<Compile Include="..\SolutionInfo.cs">
<Link>Properties\SolutionInfo.cs</Link>
+7 -31
View File
@@ -52,13 +52,13 @@ namespace Umbraco.Examine
/// <param name="indexValueTypes"></param>
public UmbracoContentIndex(
string name,
IEnumerable<FieldDefinition> fieldDefinitions,
FieldDefinitionCollection fieldDefinitions,
Directory luceneDirectory,
Analyzer defaultAnalyzer,
ProfilingLogger profilingLogger,
ILocalizationService languageService,
IContentValueSetValidator validator,
IReadOnlyDictionary<string, Func<string, IIndexValueType>> indexValueTypes = null)
IReadOnlyDictionary<string, IFieldValueTypeFactory> indexValueTypes = null)
: base(name, fieldDefinitions, luceneDirectory, defaultAnalyzer, profilingLogger, validator, indexValueTypes)
{
if (validator == null) throw new ArgumentNullException(nameof(validator));
@@ -122,7 +122,7 @@ namespace Umbraco.Examine
//anywhere else in this class
Current.Services.PublicAccessService,
parentId,
ConfigIndexCriteria.IncludeItemTypes, ConfigIndexCriteria.ExcludeItemTypes);
ConfigIndexCriteria?.IncludeItemTypes, ConfigIndexCriteria?.ExcludeItemTypes);
PublishedValuesOnly = supportUnpublished;
}
@@ -200,41 +200,17 @@ namespace Umbraco.Examine
var descendantPath = $@"\-1\,*{nodeId}\,*";
var rawQuery = $"{IndexPathFieldName}:{descendantPath}";
var searcher = GetSearcher();
var c = searcher.CreateCriteria();
var filtered = c.RawQuery(rawQuery);
var results = searcher.Search(filtered);
var c = searcher.CreateQuery();
var filtered = c.NativeQuery(rawQuery);
var results = filtered.Execute();
ProfilingLogger.Logger.Debug(GetType(), "DeleteFromIndex with query: {Query} (found {TotalItems} results)", rawQuery, results.TotalItemCount);
//need to queue a delete item for each one found
foreach (var r in results)
{
QueueIndexOperation(new IndexOperation(new ValueSet(r.Id), IndexOperationType.Delete));
}
QueueIndexOperation(results.Select(r => new IndexOperation(new ValueSet(r.Id), IndexOperationType.Delete)));
base.PerformDeleteFromIndex(nodeId, onComplete);
}
/// <summary>
/// Overridden to ensure that the variant system fields have the right value types
/// </summary>
/// <param name="x"></param>
/// <param name="indexValueTypesFactory"></param>
/// <returns></returns>
protected override FieldValueTypeCollection CreateFieldValueTypes(IReadOnlyDictionary<string, Func<string, IIndexValueType>> indexValueTypesFactory = null)
{
//fixme: languages are dynamic so although this will work on startup it wont work when languages are edited
foreach(var lang in LanguageService.GetAllLanguages())
{
foreach (var field in UmbracoIndexFieldDefinitions)
{
var def = new FieldDefinition($"{field.Name}_{lang.IsoCode.ToLowerInvariant()}", field.Type);
FieldDefinitionCollection.TryAdd(def.Name, def);
}
}
return base.CreateFieldValueTypes(indexValueTypesFactory);
}
}
}
@@ -1,10 +1,6 @@
using System;
using System.ComponentModel;
using System.Web;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Examine.LuceneEngine.Search;
using Examine.Search;
using Umbraco.Core;
using Umbraco.Examine.Config;
namespace Umbraco.Examine
{
+34 -80
View File
@@ -20,10 +20,9 @@ namespace Umbraco.Examine
{
/// <summary>
/// An abstract provider containing the basic functionality to be able to query against
/// Umbraco data.
/// An abstract provider containing the basic functionality to be able to query against Umbraco data.
/// </summary>
public abstract class UmbracoExamineIndex : LuceneIndex, IUmbracoIndexer, IIndexDiagnostics
public abstract class UmbracoExamineIndex : LuceneIndex, IUmbracoIndex, IIndexDiagnostics
{
// note
// wrapping all operations that end up calling base.SafelyProcessQueueItems in a safe call
@@ -53,6 +52,7 @@ namespace Umbraco.Examine
{
ProfilingLogger = Current.ProfilingLogger;
_configBased = true;
_diagnostics = new UmbracoExamineIndexDiagnostics(this, ProfilingLogger.Logger);
}
/// <summary>
@@ -67,12 +67,12 @@ namespace Umbraco.Examine
/// <param name="indexValueTypes"></param>
protected UmbracoExamineIndex(
string name,
IEnumerable<FieldDefinition> fieldDefinitions,
FieldDefinitionCollection fieldDefinitions,
Directory luceneDirectory,
Analyzer defaultAnalyzer,
ProfilingLogger profilingLogger,
IValueSetValidator validator = null,
IReadOnlyDictionary<string, Func<string, IIndexValueType>> indexValueTypes = null)
IReadOnlyDictionary<string, IFieldValueTypeFactory> indexValueTypes = null)
: base(name, fieldDefinitions, luceneDirectory, defaultAnalyzer, validator, indexValueTypes)
{
ProfilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger));
@@ -86,60 +86,10 @@ namespace Umbraco.Examine
private readonly bool _configBased = false;
/// <summary>
/// A type that defines the type of index for each Umbraco field (non user defined fields)
/// Alot of standard umbraco fields shouldn't be tokenized or even indexed, just stored into lucene
/// for retreival after searching.
/// </summary>
public static readonly FieldDefinition[] UmbracoIndexFieldDefinitions =
{
new FieldDefinition("parentID", FieldDefinitionTypes.Integer),
new FieldDefinition("level", FieldDefinitionTypes.Integer),
new FieldDefinition("writerID", FieldDefinitionTypes.Integer),
new FieldDefinition("creatorID", FieldDefinitionTypes.Integer),
new FieldDefinition("sortOrder", FieldDefinitionTypes.Integer),
new FieldDefinition("template", FieldDefinitionTypes.Integer),
new FieldDefinition("createDate", FieldDefinitionTypes.DateTime),
new FieldDefinition("updateDate", FieldDefinitionTypes.DateTime),
new FieldDefinition("key", FieldDefinitionTypes.InvariantCultureIgnoreCase),
new FieldDefinition("version", FieldDefinitionTypes.Raw),
new FieldDefinition("nodeType", FieldDefinitionTypes.InvariantCultureIgnoreCase),
new FieldDefinition("template", FieldDefinitionTypes.Raw),
new FieldDefinition("urlName", FieldDefinitionTypes.InvariantCultureIgnoreCase),
new FieldDefinition("path", FieldDefinitionTypes.Raw),
new FieldDefinition("email", FieldDefinitionTypes.EmailAddress),
new FieldDefinition(PublishedFieldName, FieldDefinitionTypes.Raw),
new FieldDefinition(NodeKeyFieldName, FieldDefinitionTypes.Raw),
new FieldDefinition(IndexPathFieldName, FieldDefinitionTypes.Raw),
new FieldDefinition(IconFieldName, FieldDefinitionTypes.Raw)
};
protected ProfilingLogger ProfilingLogger { get; }
/// <summary>
/// Overridden to ensure that the umbraco system field definitions are in place
/// </summary>
/// <param name="indexValueTypesFactory"></param>
/// <returns></returns>
protected override FieldValueTypeCollection CreateFieldValueTypes(IReadOnlyDictionary<string, Func<string, IIndexValueType>> indexValueTypesFactory = null)
{
//if config based then ensure the value types else it's assumed these were passed in via ctor
if (_configBased)
{
foreach (var field in UmbracoIndexFieldDefinitions)
{
FieldDefinitionCollection.TryAdd(field.Name, field);
}
}
return base.CreateFieldValueTypes(indexValueTypesFactory);
}
/// <summary>
/// When set to true Umbraco will keep the index in sync with Umbraco data automatically
/// </summary>
@@ -147,6 +97,14 @@ namespace Umbraco.Examine
public bool PublishedValuesOnly { get; protected set; } = false;
/// <inheritdoc />
public IEnumerable<string> GetFields()
{
//we know this is a LuceneSearcher
var searcher = (LuceneSearcher) GetSearcher();
return searcher.GetAllIndexedFields();
}
protected ConfigIndexCriteria ConfigIndexCriteria { get; private set; }
/// <summary>
@@ -174,12 +132,15 @@ namespace Umbraco.Examine
EnableDefaultEventHandler = enabled;
}
//Need to check if the index set or IndexerData is specified...
if (config["indexSet"] == null && FieldDefinitionCollection.Count == 0)
//this is config based, so add the default definitions
foreach (var field in UmbracoFieldDefinitionCollection.UmbracoIndexFieldDefinitions)
{
//if we don't have either, then we'll try to set the index set by naming conventions
var found = false;
FieldDefinitionCollection.TryAdd(field);
}
//Need to check if the index set is specified...
if (config["indexSet"] == null)
{
var possibleSuffixes = new[] {"Index", "Indexer"};
foreach (var suffix in possibleSuffixes)
{
@@ -200,36 +161,29 @@ namespace Umbraco.Examine
ConfigIndexCriteria = CreateFieldDefinitionsFromConfig(indexSet);
foreach (var fieldDefinition in ConfigIndexCriteria.StandardFields.Union(ConfigIndexCriteria.UserFields))
{
FieldDefinitionCollection.TryAdd(fieldDefinition.Name, fieldDefinition);
//replace any existing or add
FieldDefinitionCollection.AddOrUpdate(fieldDefinition);
}
found = true;
break;
}
if (!found)
throw new ArgumentNullException("indexSet on LuceneExamineIndexer provider has not been set in configuration and/or the IndexerData property has not been explicitly set");
}
else if (config["indexSet"] != null)
else
{
//if an index set is specified, ensure it exists and initialize the indexer based on the set
if (IndexSets.Instance.Sets[config["indexSet"]] == null)
{
throw new ArgumentException("The indexSet specified for the LuceneExamineIndexer provider does not exist");
}
else
IndexSetName = config["indexSet"];
var indexSet = IndexSets.Instance.Sets[IndexSetName];
//get the index criteria and ensure folder
ConfigIndexCriteria = CreateFieldDefinitionsFromConfig(indexSet);
foreach (var fieldDefinition in ConfigIndexCriteria.StandardFields.Union(ConfigIndexCriteria.UserFields))
{
IndexSetName = config["indexSet"];
var indexSet = IndexSets.Instance.Sets[IndexSetName];
//get the index criteria and ensure folder
ConfigIndexCriteria = CreateFieldDefinitionsFromConfig(indexSet);
foreach (var fieldDefinition in ConfigIndexCriteria.StandardFields.Union(ConfigIndexCriteria.UserFields))
{
FieldDefinitionCollection.TryAdd(fieldDefinition.Name, fieldDefinition);
}
//replace any existing or add
FieldDefinitionCollection.AddOrUpdate(fieldDefinition);
}
}
@@ -1,52 +0,0 @@
//using System;
//using System.ComponentModel;
//using System.IO;
//using System.Linq;
//using Umbraco.Core;
//using Examine.LuceneEngine.Providers;
//using Lucene.Net.Analysis;
//using Lucene.Net.Index;
//using Umbraco.Core.Composing;
//using Umbraco.Examine.Config;
//using Directory = Lucene.Net.Store.Directory;
//using Examine.LuceneEngine;
//namespace Umbraco.Examine
//{
// /// <summary>
// /// An Examine searcher which uses Lucene.Net as the
// /// </summary>
// public class UmbracoExamineSearcher : LuceneSearcher
// {
// /// <summary>
// /// Constructor to allow for creating an indexer at runtime
// /// </summary>
// /// <param name="name"></param>
// /// <param name="luceneDirectory"></param>
// /// <param name="analyzer"></param>
// public UmbracoExamineSearcher(string name, Directory luceneDirectory, Analyzer analyzer, FieldValueTypeCollection fieldValueTypeCollection)
// : base(name, luceneDirectory, analyzer, fieldValueTypeCollection)
// {
// }
// /// <inheritdoc />
// public UmbracoExamineSearcher(string name, IndexWriter writer, Analyzer analyzer, FieldValueTypeCollection fieldValueTypeCollection)
// : base(name, writer, analyzer, fieldValueTypeCollection)
// {
// }
// /// <summary>
// /// Returns a list of fields to search on, this will also exclude the IndexPathFieldName and node type alias
// /// </summary>
// /// <returns></returns>
// public override string[] GetAllIndexedFields()
// {
// var fields = base.GetAllIndexedFields();
// return fields
// .Where(x => x != UmbracoExamineIndexer.IndexPathFieldName)
// .Where(x => x != LuceneIndex.ItemTypeFieldName)
// .ToArray();
// }
// }
//}
@@ -0,0 +1,75 @@
using Examine;
namespace Umbraco.Examine
{
/// <summary>
/// Custom <see cref="FieldDefinitionCollection"/> allowing dynamic creation of <see cref="FieldDefinition"/>
/// </summary>
public class UmbracoFieldDefinitionCollection : FieldDefinitionCollection
{
public UmbracoFieldDefinitionCollection()
: base(UmbracoIndexFieldDefinitions)
{
}
/// <summary>
/// A type that defines the type of index for each Umbraco field (non user defined fields)
/// Alot of standard umbraco fields shouldn't be tokenized or even indexed, just stored into lucene
/// for retreival after searching.
/// </summary>
public static readonly FieldDefinition[] UmbracoIndexFieldDefinitions =
{
new FieldDefinition("parentID", FieldDefinitionTypes.Integer),
new FieldDefinition("level", FieldDefinitionTypes.Integer),
new FieldDefinition("writerID", FieldDefinitionTypes.Integer),
new FieldDefinition("creatorID", FieldDefinitionTypes.Integer),
new FieldDefinition("sortOrder", FieldDefinitionTypes.Integer),
new FieldDefinition("template", FieldDefinitionTypes.Integer),
new FieldDefinition("createDate", FieldDefinitionTypes.DateTime),
new FieldDefinition("updateDate", FieldDefinitionTypes.DateTime),
new FieldDefinition("key", FieldDefinitionTypes.InvariantCultureIgnoreCase),
new FieldDefinition("version", FieldDefinitionTypes.Raw),
new FieldDefinition("nodeType", FieldDefinitionTypes.InvariantCultureIgnoreCase),
new FieldDefinition("template", FieldDefinitionTypes.Raw),
new FieldDefinition("urlName", FieldDefinitionTypes.InvariantCultureIgnoreCase),
new FieldDefinition("path", FieldDefinitionTypes.Raw),
new FieldDefinition("email", FieldDefinitionTypes.EmailAddress),
new FieldDefinition(UmbracoExamineIndex.PublishedFieldName, FieldDefinitionTypes.Raw),
new FieldDefinition(UmbracoExamineIndex.NodeKeyFieldName, FieldDefinitionTypes.Raw),
new FieldDefinition(UmbracoExamineIndex.IndexPathFieldName, FieldDefinitionTypes.Raw),
new FieldDefinition(UmbracoExamineIndex.IconFieldName, FieldDefinitionTypes.Raw)
};
///// <summary>
///// Overridden to dynamically add field definitions for culture variations
///// </summary>
///// <param name="fieldName"></param>
///// <param name="fieldDefinition"></param>
///// <returns></returns>
//public override bool TryGetValue(string fieldName, out FieldDefinition fieldDefinition)
//{
// var result = base.TryGetValue(fieldName, out fieldDefinition);
// if (result) return true;
// //if the fieldName is not suffixed with _iso-Code
// var underscoreIndex = fieldName.LastIndexOf('_');
// if (underscoreIndex == -1) return false;
// var isoCode = fieldName.Substring(underscoreIndex);
// if (isoCode.Length < 6) return false; //invalid isoCode
// var hyphenIndex = isoCode.IndexOf('-');
// if (hyphenIndex != 3) return false; //invalid isoCode
// //we'll assume this is a valid isoCode
//}
}
}
+4 -4
View File
@@ -42,8 +42,8 @@ namespace Umbraco.Examine
/// <param name="validator"></param>
/// <param name="analyzer"></param>
public UmbracoMemberIndex(
string name,
IEnumerable<FieldDefinition> fieldDefinitions,
string name,
FieldDefinitionCollection fieldDefinitions,
Directory luceneDirectory,
Analyzer analyzer,
ProfilingLogger profilingLogger,
@@ -64,10 +64,10 @@ namespace Umbraco.Examine
/// </summary>
/// <param name="indexValueTypesFactory"></param>
/// <returns></returns>
protected override FieldValueTypeCollection CreateFieldValueTypes(IReadOnlyDictionary<string, Func<string, IIndexValueType>> indexValueTypesFactory = null)
protected override FieldValueTypeCollection CreateFieldValueTypes(IReadOnlyDictionary<string, IFieldValueTypeFactory> indexValueTypesFactory = null)
{
var keyDef = new FieldDefinition("__key", FieldDefinitionTypes.Raw);
FieldDefinitionCollection.TryAdd(keyDef.Name, keyDef);
FieldDefinitionCollection.TryAdd(keyDef);
return base.CreateFieldValueTypes(indexValueTypesFactory);
}
@@ -173,9 +173,9 @@ namespace Umbraco.Tests.PublishedContent
//ensure it still exists in the index (raw examine search)
var criteria = searcher.CreateCriteria();
var criteria = searcher.CreateQuery();
var filter = criteria.Id(3113);
var found = searcher.Search(filter.Compile());
var found = filter.Execute();
Assert.IsNotNull(found);
Assert.AreEqual(1, found.TotalItemCount);
@@ -6,6 +6,7 @@ using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -37,6 +38,53 @@ namespace Umbraco.Tests.Services
}
}
[Test]
public void EntityService_Can_Get_Paged_Descendants_Ordering_Path()
{
var contentType = ServiceContext.ContentTypeService.Get("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
var rootId = root.Id;
var ids = new List<int>();
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
ServiceContext.ContentService.Save(c1);
ids.Add(c1.Id);
root = c1; // make a hierarchy
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(6));
Assert.That(total, Is.EqualTo(10));
Assert.AreEqual(ids[0], entities[0].Id);
entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 1, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(4));
Assert.That(total, Is.EqualTo(10));
Assert.AreEqual(ids[6], entities[0].Id);
//Test ordering direction
entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 0, 6, out total,
ordering: Ordering.By("Path", Direction.Descending)).ToArray();
Assert.That(entities.Length, Is.EqualTo(6));
Assert.That(total, Is.EqualTo(10));
Assert.AreEqual(ids[ids.Count - 1], entities[0].Id);
entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 1, 6, out total,
ordering: Ordering.By("Path", Direction.Descending)).ToArray();
Assert.That(entities.Length, Is.EqualTo(4));
Assert.That(total, Is.EqualTo(10));
Assert.AreEqual(ids[ids.Count - 1 - 6], entities[0].Id);
}
[Test]
public void EntityService_Can_Get_Paged_Content_Children()
{
@@ -45,21 +93,41 @@ namespace Umbraco.Tests.Services
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
var ids = new List<int>();
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
ServiceContext.ContentService.Save(c1);
ids.Add(c1.Id);
}
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));
Assert.AreEqual(ids[0], entities[0].Id);
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));
Assert.AreEqual(ids[6], entities[0].Id);
//Test ordering direction
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total,
ordering: Ordering.By("SortOrder", Direction.Descending)).ToArray();
Assert.That(entities.Length, Is.EqualTo(6));
Assert.That(total, Is.EqualTo(10));
Assert.AreEqual(ids[ids.Count - 1], entities[0].Id);
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total,
ordering: Ordering.By("SortOrder", Direction.Descending)).ToArray();
Assert.That(entities.Length, Is.EqualTo(4));
Assert.That(total, Is.EqualTo(10));
Assert.AreEqual(ids[ids.Count - 1 - 6], entities[0].Id);
}
[Test]
@@ -206,10 +274,12 @@ namespace Umbraco.Tests.Services
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, filter: "ssss").ToArray();
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains("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();
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains("tttt"))).ToArray();
Assert.That(entities.Length, Is.EqualTo(50));
Assert.That(total, Is.EqualTo(50));
}
@@ -389,10 +459,12 @@ namespace Umbraco.Tests.Services
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, filter: "ssss").ToArray();
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains("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();
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains("tttt"))).ToArray();
Assert.That(entities.Length, Is.EqualTo(50));
Assert.That(total, Is.EqualTo(50));
}
+1 -1
View File
@@ -77,7 +77,7 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="7.0.1" />
<PackageReference Include="Castle.Core" Version="4.2.1" />
<PackageReference Include="Examine" Version="1.0.0-beta046" />
<PackageReference Include="Examine" Version="1.0.0-beta067" />
<PackageReference Include="HtmlAgilityPack">
<Version>1.8.9</Version>
</PackageReference>
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.UmbracoExamine
var valueSet = node.ConvertToValueSet(IndexTypes.Content);
indexer.IndexItems(new[] { valueSet });
var found = searcher.Search(searcher.CreateCriteria().Id((string)node.Attribute("id")).Compile());
var found = searcher.CreateQuery().Id((string)node.Attribute("id")).Execute();
Assert.AreEqual(0, found.TotalItemCount);
}
@@ -164,7 +164,7 @@ namespace Umbraco.Tests.UmbracoExamine
var i = new UmbracoContentIndex(
"testIndexer",
UmbracoExamineIndex.UmbracoIndexFieldDefinitions,
new UmbracoFieldDefinitionCollection(),
luceneDir,
analyzer,
profilingLogger,
+11 -14
View File
@@ -105,7 +105,7 @@ namespace Umbraco.Tests.UmbracoExamine
var searcher = indexer.GetSearcher();
var results = searcher.Search(searcher.CreateCriteria().Id(555).Compile());
var results = searcher.CreateQuery().Id(555).Execute();
Assert.AreEqual(1, results.TotalItemCount);
var result = results.First();
@@ -130,8 +130,6 @@ namespace Umbraco.Tests.UmbracoExamine
validator: new ContentValueSetValidator(false)))
using (indexer.ProcessNonAsync())
{
contentRebuilder.RegisterIndex(indexer.Name);
mediaRebuilder.RegisterIndex(indexer.Name);
var searcher = indexer.GetSearcher();
@@ -139,7 +137,7 @@ namespace Umbraco.Tests.UmbracoExamine
contentRebuilder.Populate(indexer);
mediaRebuilder.Populate(indexer);
var result = searcher.Search(searcher.CreateCriteria().All().Compile());
var result = searcher.CreateQuery().All().Execute();
Assert.AreEqual(29, result.TotalItemCount);
}
@@ -210,7 +208,7 @@ namespace Umbraco.Tests.UmbracoExamine
indexer.IndexItem(node.ConvertToValueSet(IndexTypes.Media));
//it will not exist because it exists under 2222
var results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile());
var results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(0, results.Count());
//now mimic moving 2112 to 1116
@@ -222,7 +220,7 @@ namespace Umbraco.Tests.UmbracoExamine
indexer.IndexItems(new[] { node.ConvertToValueSet(IndexTypes.Media) });
//now ensure it exists
results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile());
results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(1, results.Count());
}
}
@@ -253,7 +251,7 @@ namespace Umbraco.Tests.UmbracoExamine
indexer1.IndexItem(node.ConvertToValueSet(IndexTypes.Media));
//it will exist because it exists under 2222
var results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile());
var results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(1, results.Count());
//now mimic moving the node underneath 1116 instead of 2222
@@ -264,7 +262,7 @@ namespace Umbraco.Tests.UmbracoExamine
indexer1.IndexItems(new[] { node.ConvertToValueSet(IndexTypes.Media) });
//now ensure it's deleted
results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile());
results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(0, results.Count());
}
}
@@ -283,14 +281,13 @@ namespace Umbraco.Tests.UmbracoExamine
validator: new ContentValueSetValidator(false)))
using (indexer.ProcessNonAsync())
{
rebuilder.RegisterIndex(indexer.Name);
var searcher = indexer.GetSearcher();
//create the whole thing
rebuilder.Populate(indexer);
var result = searcher.Search(searcher.CreateCriteria().Field(LuceneIndex.CategoryFieldName, IndexTypes.Content).Compile());
var result = searcher.CreateQuery().Field(LuceneIndex.CategoryFieldName, IndexTypes.Content).Execute();
Assert.AreEqual(21, result.TotalItemCount);
//delete all content
@@ -301,13 +298,13 @@ namespace Umbraco.Tests.UmbracoExamine
//ensure it's all gone
result = searcher.Search(searcher.CreateCriteria().Field(LuceneIndex.CategoryFieldName, IndexTypes.Content).Compile());
result = searcher.CreateQuery().Field(LuceneIndex.CategoryFieldName, IndexTypes.Content).Execute();
Assert.AreEqual(0, result.TotalItemCount);
//call our indexing methods
rebuilder.Populate(indexer);
result = searcher.Search(searcher.CreateCriteria().Field(LuceneIndex.CategoryFieldName, IndexTypes.Content).Compile());
result = searcher.CreateQuery().Field(LuceneIndex.CategoryFieldName, IndexTypes.Content).Execute();
Assert.AreEqual(21, result.TotalItemCount);
}
}
@@ -335,10 +332,10 @@ namespace Umbraco.Tests.UmbracoExamine
indexer.DeleteFromIndex(1140.ToString());
//this node had children: 1141 & 1142, let's ensure they are also removed
var results = searcher.Search(searcher.CreateCriteria().Id(1141).Compile());
var results = searcher.CreateQuery().Id(1141).Execute();
Assert.AreEqual(0, results.Count());
results = searcher.Search(searcher.CreateCriteria().Id(1142).Compile());
results = searcher.CreateQuery().Id(1142).Execute();
Assert.AreEqual(0, results.Count());
}
@@ -3,17 +3,15 @@ using System.Collections.Generic;
using System.Linq;
using LightInject;
using Examine;
using Examine.Search;
using NUnit.Framework;
using Examine.LuceneEngine.SearchCriteria;
using Moq;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Tests.Testing;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
using Umbraco.Examine;
namespace Umbraco.Tests.UmbracoExamine
{
@@ -62,21 +60,20 @@ namespace Umbraco.Tests.UmbracoExamine
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir))
using (indexer.ProcessNonAsync())
{
rebuilder.RegisterIndex(indexer.Name);
indexer.CreateIndex();
rebuilder.Populate(indexer);
var searcher = indexer.GetSearcher();
var numberSortedCriteria = searcher.CreateCriteria()
.ParentId(1148).And()
var numberSortedCriteria = searcher.CreateQuery()
.ParentId(1148)
.OrderBy(new SortableField("sortOrder", SortType.Int));
var numberSortedResult = searcher.Search(numberSortedCriteria.Compile());
var numberSortedResult = numberSortedCriteria.Execute();
var stringSortedCriteria = searcher.CreateCriteria()
.ParentId(1148).And()
.OrderBy("sortOrder"); //will default to string
var stringSortedResult = searcher.Search(stringSortedCriteria.Compile());
var stringSortedCriteria = searcher.CreateQuery()
.ParentId(1148)
.OrderBy(new SortableField("sortOrder"));//will default to string
var stringSortedResult = stringSortedCriteria.Execute();
Assert.AreEqual(12, numberSortedResult.TotalItemCount);
Assert.AreEqual(12, stringSortedResult.TotalItemCount);
@@ -262,7 +262,7 @@ Use this directive to construct a header inside the main editor window.
icon: "=",
hideIcon: "@",
alias: "=",
hideAlias: "@",
hideAlias: "=",
description: "=",
hideDescription: "@",
descriptionLocked: "@",
@@ -30,12 +30,6 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
var nonRoutingQueryStrings = ["mculture", "cculture"];
var retainedQueryStrings = ['mculture'];
//used to track the current dialog object
var currentDialog = null;
//tracks the user profile dialog
var userDialog = null;
function setMode(mode) {
switch (mode) {
case 'tree':
@@ -287,7 +281,7 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
appState.setGlobalState("showTray", false);
},
/**
/**
* @ngdoc method
* @name umbraco.services.navigationService#syncTree
* @methodOf umbraco.services.navigationService
@@ -242,4 +242,5 @@
.umb-healthcheck-group__details-status-action-description {
margin-top: 5px;
font-size: 12px;
padding-left: 165px;
}
@@ -1,7 +1,7 @@
(function() {
"use strict";
(function () {
"use strict";
function CompositionsController($scope,$location) {
function CompositionsController($scope, $location, $filter) {
var vm = this;
var oldModel = null;
@@ -19,18 +19,34 @@
back the changes on cancel */
oldModel = angular.copy($scope.model);
if(!$scope.model.title) {
if (!$scope.model.title) {
$scope.model.title = "Compositions";
}
// group the content types by their container paths
vm.availableGroups = $filter("orderBy")(
_.map(
_.groupBy($scope.model.availableCompositeContentTypes, function (compositeContentType) {
return compositeContentType.contentType.metaData.containerPath;
}), function (group) {
return {
containerPath: group[0].contentType.metaData.containerPath,
compositeContentTypes: group
};
}
), function (group) {
return group.containerPath.replace(/\//g, " ");
});
}
function isSelected(alias) {
if($scope.model.contentType.compositeContentTypes.indexOf(alias) !== -1) {
if ($scope.model.contentType.compositeContentTypes.indexOf(alias) !== -1) {
return true;
}
}
function openContentType(contentType, section) {
var url = (section === "documentType" ? "/settings/documenttypes/edit/" : "/settings/mediaTypes/edit/") + contentType.id;
$location.path(url);
@@ -38,19 +54,19 @@
function submit() {
if ($scope.model && $scope.model.submit) {
// check if any compositions has been removed
vm.compositionRemoved = false;
for(var i = 0; oldModel.compositeContentTypes.length > i; i++) {
for (var i = 0; oldModel.compositeContentTypes.length > i; i++) {
var oldComposition = oldModel.compositeContentTypes[i];
if(_.contains($scope.model.compositeContentTypes, oldComposition) === false) {
if (_.contains($scope.model.compositeContentTypes, oldComposition) === false) {
vm.compositionRemoved = true;
}
}
/* submit the form if there havne't been removed any composition
or the confirm checkbox has been checked */
if(!vm.compositionRemoved || vm.allowSubmit) {
if (!vm.compositionRemoved || vm.allowSubmit) {
$scope.model.submit($scope.model);
}
}
@@ -63,8 +79,8 @@
}
onInit();
}
}
angular.module("umbraco").controller("Umbraco.Editors.CompositionsController", CompositionsController);
angular.module("umbraco").controller("Umbraco.Editors.CompositionsController", CompositionsController);
})();
@@ -60,29 +60,35 @@
</ul>
</div>
<ul class="umb-checkbox-list">
<li class="umb-checkbox-list__item"
ng-repeat="compositeContentType in model.availableCompositeContentTypes | filter:searchTerm"
ng-class="{'-disabled': compositeContentType.allowed===false || compositeContentType.inherited, '-selected': vm.isSelected(compositeContentType.contentType.alias)}">
<div class="umb-checkbox-list__item-checkbox"
ng-class="{ '-selected': model.compositeContentTypes.indexOf(compositeContentType.contentType.alias)+1 }">
<input type="checkbox"
id="umb-overlay-comp-{{compositeContentType.contentType.key}}"
checklist-model="model.compositeContentTypes"
checklist-value="compositeContentType.contentType.alias"
ng-change="model.selectCompositeContentType(compositeContentType.contentType)"
ng-disabled="compositeContentType.allowed===false || compositeContentType.inherited" />
</div>
<label for="umb-overlay-comp-{{compositeContentType.contentType.key}}" class="umb-checkbox-list__item-text" ng-class="{'-faded': compositeContentType.allowed===false}">
<i class="{{ compositeContentType.contentType.icon }} umb-checkbox-list__item-icon"></i>
{{ compositeContentType.contentType.name }}
<span class="umb-checkbox-list__item-caption" ng-if="compositeContentType.inherited">(inherited)</span>
</label>
</li>
</ul>
<div ng-if="vm.availableGroups.length > 0">
<ul class="umb-checkbox-list" ng-repeat="group in vm.availableGroups | filter:searchTerm">
<li style="font-weight: bold" ng-show="vm.availableGroups.length > 1">
<i class="icon-folder umb-checkbox-list__item-icon"></i>
{{group.containerPath}}
</li>
<li class="umb-checkbox-list__item"
ng-repeat="compositeContentType in group.compositeContentTypes | orderBy:'contentType.name' | filter:searchTerm"
ng-class="{'-disabled': compositeContentType.allowed===false || compositeContentType.inherited, '-selected': vm.isSelected(compositeContentType.contentType.alias)}">
<div class="umb-checkbox-list__item-checkbox"
ng-class="{ '-selected': model.compositeContentTypes.indexOf(compositeContentType.contentType.alias)+1 }">
<input type="checkbox"
id="umb-overlay-comp-{{compositeContentType.contentType.key}}"
checklist-model="model.compositeContentTypes"
checklist-value="compositeContentType.contentType.alias"
ng-change="model.selectCompositeContentType(compositeContentType.contentType)"
ng-disabled="compositeContentType.allowed===false || compositeContentType.inherited" />
</div>
<label for="umb-overlay-comp-{{compositeContentType.contentType.key}}" class="umb-checkbox-list__item-text" ng-class="{'-faded': compositeContentType.allowed===false}">
<i class="{{ compositeContentType.contentType.icon }} umb-checkbox-list__item-icon"></i>
{{ compositeContentType.contentType.name }}
<span class="umb-checkbox-list__item-caption" ng-if="compositeContentType.inherited">(inherited)</span>
</label>
</li>
</ul>
</div>
</umb-box-content>
</umb-box>
@@ -97,14 +97,7 @@
<umb-button
type="button"
button-style="success"
label="Get started"
action="vm.getStarted()">
</umb-button>
<umb-button
ng-if="!vm.avatarFile.uploaded"
type="button"
button-style="link"
label="Skip"
label="Done"
action="vm.getStarted()">
</umb-button>
</div>
@@ -268,4 +261,4 @@
</div>
</div>
</div>
</div>
</div>
@@ -34,22 +34,25 @@ function ContentDeleteController($scope, $timeout, contentResource, treeService,
toggleDeleting(false);
if (rootNode) {
$timeout(function () {
//ensure the recycle bin has child nodes now
var recycleBin = treeService.getDescendantNode(rootNode, -20);
if (recycleBin) {
//TODO: This seems to return a rejection and we end up with "Possibly unhanded rejection"
treeService.syncTree({ node: recycleBin, path: treeService.getPath(recycleBin), forceReload: true });
//ensure the recycle bin has child nodes now
var recycleBin = treeService.getDescendantNode(rootNode, -20);
if (recycleBin) {
recycleBin.hasChildren = true;
//reload the recycle bin if it's already expanded so the deleted item is shown
if (recycleBin.expanded) {
treeService.loadNodeChildren({ node: recycleBin, section: "content" });
}
}, 500);
}
}
//if the current edited item is the same one as we're deleting, we need to navigate elsewhere
if (editorState.current && editorState.current.id == $scope.currentNode.id) {
//If the deleted item lived at the root then just redirect back to the root, otherwise redirect to the item's parent
var location = "/content";
if ($scope.currentNode.parentId.toString() !== "-1")
if ($scope.currentNode.parentId.toString() === "-20")
location = "/content/content/recyclebin";
else if ($scope.currentNode.parentId.toString() !== "-1")
location = "/content/content/edit/" + $scope.currentNode.parentId;
$location.path(location);
@@ -15,10 +15,11 @@
<div class="alert alert-success">
<localize key="notify_notificationsSavedFor"></localize><strong> {{currentNode.name}}</strong>
</div>
<button class="btn btn-primary" ng-click="vm.cancel()"><localize key="general_ok">Ok</localize></button>
</div>
<div ng-cloak>
<div ng-hide="vm.saveSuccces || vm.saveError" ng-cloak>
<div class="block-form" ng-show="!vm.loading">
<h5><localize key="notify_notifySet">Set your notification for</localize> {{ currentNode.name }}</h5>
<localize key="notify_notifySet">Set your notification for</localize> <strong>{{ currentNode.name }}</strong>
<umb-control-group>
<umb-permission ng-repeat="option in vm.notifyOptions"
name="option.name"
@@ -31,7 +32,7 @@
</form>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="vm.saveSuccces || vm.saveError">
<umb-button label-key="general_cancel"
action="vm.cancel()"
type="button"
@@ -40,6 +41,7 @@
<umb-button label-key="buttons_save"
type="button"
action="vm.save(vm.notifyOptions)"
state="vm.saveState"
button-style="success">
</umb-button>
</div>
@@ -30,6 +30,10 @@ function MediaDeleteController($scope, mediaResource, treeService, navigationSer
var recycleBin = treeService.getDescendantNode(rootNode, -21);
if (recycleBin) {
recycleBin.hasChildren = true;
//reload the recycle bin if it's already expanded so the deleted item is shown
if (recycleBin.expanded) {
treeService.loadNodeChildren({ node: recycleBin, section: "media" });
}
}
}
@@ -37,8 +41,10 @@ function MediaDeleteController($scope, mediaResource, treeService, navigationSer
if (editorState.current && editorState.current.id == $scope.currentNode.id) {
//If the deleted item lived at the root then just redirect back to the root, otherwise redirect to the item's parent
var location = "/media";
if ($scope.currentNode.parentId.toString() !== "-1")
var location = "/media";
if ($scope.currentNode.parentId.toString() === "-21")
location = "/media/media/recyclebin";
else if ($scope.currentNode.parentId.toString() !== "-1")
location = "/media/media/edit/" + $scope.currentNode.parentId;
$location.path(location);
@@ -5,6 +5,14 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.dialogTreeApi = {};
$scope.source = _.clone($scope.currentNode);
$scope.busy = false;
$scope.searchInfo = {
searchFromId: null,
searchFromName: null,
showSearch: false,
results: [],
selectedSearchResults: []
}
$scope.treeModel = {
hideHeader: false
}
@@ -52,6 +60,24 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.close = function() {
navigationService.hideDialog();
};
$scope.hideSearch = function () {
$scope.searchInfo.showSearch = false;
$scope.searchInfo.searchFromId = null;
$scope.searchInfo.searchFromName = null;
$scope.searchInfo.results = [];
}
// method to select a search result
$scope.selectResult = function (evt, result) {
result.selected = result.selected === true ? false : true;
nodeSelectHandler({ event: evt, node: result });
};
//callback when there are search results
$scope.onSearchResults = function (results) {
$scope.searchInfo.results = results;
$scope.searchInfo.showSearch = true;
};
$scope.move = function () {
$scope.busy = true;
@@ -83,11 +109,11 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.error = err;
});
};
// Mini list view
$scope.selectListViewNode = function (node) {
node.selected = node.selected === true ? false : true;
nodeSelectHandler({}, { node: node });
nodeSelectHandler({ node: node });
};
$scope.closeMiniListView = function () {
@@ -25,16 +25,35 @@
<div ng-hide="success">
<div ng-hide="miniListView">
<umb-tree
section="media"
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
<umb-tree-search-box
hide-search-callback="hideSearch"
search-callback="onSearchResults"
search-from-id="{{searchInfo.searchFromId}}"
search-from-name="{{searchInfo.searchFromName}}"
show-search="{{searchInfo.showSearch}}"
section="media">
</umb-tree-search-box>
<br />
<umb-tree-search-results
ng-if="searchInfo.showSearch"
results="searchInfo.results"
select-result-callback="selectResult">
</umb-tree-search-results>
<div ng-hide="searchInfo.showSearch">
<umb-tree
section="media"
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
</div>
</div>
<umb-mini-list-view
@@ -24,16 +24,6 @@ angular.module("umbraco")
return ((spans / $scope.columns) * 100).toFixed(8);
};
$scope.toggleCollection = function(collection, toggle){
if(toggle){
collection = [];
}else{
collection = null;
}
};
/****************
Section
*****************/
@@ -47,8 +37,18 @@ angular.module("umbraco")
}
$scope.currentSection = section;
$scope.currentSection.allowAll = section.allowAll || !section.allowed || !section.allowed.length;
};
$scope.toggleAllowed = function (section) {
if (section.allowed) {
delete section.allowed;
}
else {
section.allowed = [];
}
}
$scope.deleteSection = function(section, template) {
if ($scope.currentSection === section) {
$scope.currentSection = undefined;
@@ -61,8 +61,7 @@
<input type="checkbox"
ng-model="currentSection.allowAll"
style="float: left; margin-right: 10px;"
ng-checked="currentSection.allowed === undefined"
ng-change="toggleCollection(currentSection.allowed, currentSection.allowAll)" />
ng-change="toggleAllowed(currentSection)" />
<localize key="grid_allowAllRowConfigurations"/>
</label>
</li>
@@ -22,16 +22,6 @@ function RowConfigController($scope) {
return ((spans / $scope.columns) * 100).toFixed(8);
};
$scope.toggleCollection = function(collection, toggle) {
if (toggle) {
collection = [];
}
else {
collection = null;
}
};
/****************
area
*****************/
@@ -55,9 +45,19 @@ function RowConfigController($scope) {
row.areas.push(cell);
}
$scope.currentCell = cell;
$scope.currentCell.allowAll = cell.allowAll || !cell.allowed || !cell.allowed.length;
}
};
$scope.toggleAllowed = function (cell) {
if (cell.allowed) {
delete cell.allowed;
}
else {
cell.allowed = [];
}
}
$scope.deleteArea = function (cell, row) {
if ($scope.currentCell === cell) {
$scope.currentCell = undefined;
@@ -72,8 +72,7 @@
<label>
<input type="checkbox"
ng-model="currentCell.allowAll"
ng-checked="currentCell.allowed === undefined"
ng-change="toggleCollection(currentCell.allowed, currentCell.allowAll)" />
ng-change="toggleAllowed(currentCell)" />
<localize key="grid_allowAllEditors"/>
</label>
</li>
@@ -701,13 +701,17 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
}
getContentTypesCallback(id).then(function (listViewAllowedTypes) {
var blueprints = false;
$scope.listViewAllowedTypes = listViewAllowedTypes;
angular.forEach(listViewAllowedTypes, function (allowedType) {
angular.forEach(allowedType.blueprints, function (value, key) {
var blueprints = false;
_.each(listViewAllowedTypes, function (allowedType) {
if (_.isEmpty(allowedType.blueprints)) {
// this helps the view understand that there are no blueprints available
allowedType.blueprints = null;
}
else {
blueprints = true;
});
}
});
if (listViewAllowedTypes.length === 1 && blueprints === false) {
@@ -46,7 +46,7 @@
<umb-dropdown-item ng-repeat="contentType in listViewAllowedTypes track by contentType.key | orderBy:'name':false">
<a ng-click="createBlank(entityType,contentType.alias)" prevent-default ng-href="">
<i class="{{::contentType.icon}}"></i>
{{::contentType.name}} <span ng-show="contentType.blueprints && contentType.blueprints.length != 0" style="text-transform: lowercase;">(<localize key="blueprints_blankBlueprint">blank</localize>)</span>
{{::contentType.name}} <span ng-show="contentType.blueprints" style="text-transform: lowercase;">(<localize key="blueprints_blankBlueprint">blank</localize>)</span>
</a>
<a href="" ng-repeat="(key, value) in contentType.blueprints track by key" ng-click="createFromBlueprint(entityType,contentType.alias , key)" prevent-default>
&nbsp;&nbsp;<i class="{{::contentType.icon}}"></i>
+1 -1
View File
@@ -88,7 +88,7 @@
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
<PackageReference Include="ClientDependency" Version="1.9.7" />
<PackageReference Include="ClientDependency-Mvc5" Version="1.8.0.0" />
<PackageReference Include="Examine" Version="1.0.0-beta046" />
<PackageReference Include="Examine" Version="1.0.0-beta067" />
<PackageReference Include="ImageProcessor.Web" Version="4.9.3.25" />
<PackageReference Include="ImageProcessor.Web.Config" Version="2.4.1.19" />
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.2" />
@@ -1379,7 +1379,7 @@ Mange hilsner fra Umbraco robotten
<key alias="userInvited">er blevet inviteret</key>
<key alias="userInvitedSuccessHelp">En invitation er blevet sendt til den nye bruger med oplysninger om, hvordan man logger ind i Umbraco.</key>
<key alias="userinviteWelcomeMessage">Hej og velkommen til Umbraco! På bare 1 minut vil du være klar til at komme i gang, vi skal bare have dig til at oprette en adgangskode og tilføje et billede til din avatar.</key>
<key alias="userinviteAvatarMessage">Upload et billede for at gøre det nemt for andre brugere at genkende dig.</key>
<key alias="userinviteAvatarMessage">Hvis du uploader et billede af dig selv, gør du det nemt for andre brugere at genkende dig. Klik på cirklen ovenfor for at uploade et billede.</key>
<key alias="writer">Forfatter</key>
<key alias="change">Skift</key>
<key alias="yourProfile">Din profil</key>
@@ -1434,8 +1434,8 @@ Mange hilsner fra Umbraco robotten
<area alias="recycleBin">
<key alias="contentTrashed">Slettet indhold med Id: {0} Relateret til original "parent" med id: {1}</key>
<key alias="mediaTrashed">Slettet medie med Id: {0} relateret til original "parent" / mappe med id: {1}</key>
<key alias="itemCannotBeRestored">Kan ikke automatisk genoprette dette dokument/medie</key>
<key alias="noRestoreRelation">Der findes ikke nogen "Genopret" relation for dette dokument/medie. Brug "Flyt" muligheden fra menuen for at flytte det manuelt.</key>
<key alias="restoreUnderRecycled">Det dokument/medie du ønsker at genoprette under ('%0%') er i skraldespanden. Brug "Flyt" muligheden fra menuen for at flytte det manuelt.</key>
<key alias="itemCannotBeRestored">Kan ikke automatisk genoprette dette element</key>
<key alias="itemCannotBeRestoredHelpText">Der er ikke nogen placering hvor dette element automatisk kan genoprettes. Du kan flytte elementet manuelt i træet nedenfor.</key>
<key alias="wasRestored">blev genoprettet under</key>
</area>
</language>
@@ -1706,7 +1706,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="userInvitedSuccessHelp">An invitation has been sent to the new user with details about how to log in to Umbraco.</key>
<key alias="userinviteWelcomeMessage">Hello there and welcome to Umbraco! In just 1 minute youll be good to go, we just need you to setup a password and add a picture for your avatar.</key>
<key alias="userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it.</key>
<key alias="userinviteAvatarMessage">Upload a picture to make it easy for other users to recognize you.</key>
<key alias="userinviteAvatarMessage">Uploading a photo of yourself will make it easy for other users to recognize you. Click the circle above to upload your photo.</key>
<key alias="writer">Writer</key>
<key alias="change">Change</key>
<key alias="yourProfile" version="7.0">Your profile</key>
@@ -292,7 +292,7 @@
<area alias="media">
<key alias="clickToUpload">Click to upload</key>
<key alias="orClickHereToUpload">or click here to choose files</key>
<key alias="dragFilesHereToUpload">You can drag files here to upload</key>
<key alias="dragFilesHereToUpload">You can drag files here to upload.</key>
<key alias="disallowedFileType">Cannot upload this file, it does not have an approved file type</key>
<key alias="maxFileSize">Max file size is</key>
<key alias="mediaRoot">Media root</key>
@@ -1757,7 +1757,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="userInvitedSuccessHelp">An invitation has been sent to the new user with details about how to log in to Umbraco.</key>
<key alias="userinviteWelcomeMessage">Hello there and welcome to Umbraco! In just 1 minute youll be good to go, we just need you to setup a password and add a picture for your avatar.</key>
<key alias="userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it.</key>
<key alias="userinviteAvatarMessage">Upload a picture to make it easy for other users to recognize you.</key>
<key alias="userinviteAvatarMessage">Uploading a photo of yourself will make it easy for other users to recognize you. Click the circle above to upload your photo.</key>
<key alias="writer">Writer</key>
<key alias="change">Change</key>
<key alias="yourProfile" version="7.0">Your profile</key>
@@ -32,6 +32,7 @@
<notifications>
<!-- the email that should be used as from mail when umbraco sends a notification -->
<!-- you can add a display name to the email like thist: <email>Your display name here &lt;your@email.here&gt;</email> -->
<email>your@email.here</email>
</notifications>
@@ -48,6 +48,7 @@
</errors>
<notifications>
<!-- the email that should be used as from mail when umbraco sends a notification -->
<!-- you can add a display name to the email like this: <email>Your display name here &lt;your@email.here&gt;</email> -->
<email>your@email.here</email>
</notifications>
@@ -8,6 +8,7 @@ namespace Umbraco.Web.Controllers
public class UmbLoginController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleLogin([Bind(Prefix = "loginModel")]LoginModel model)
{
if (ModelState.IsValid == false)
@@ -10,6 +10,7 @@ namespace Umbraco.Web.Controllers
public class UmbLoginStatusController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model)
{
if (ModelState.IsValid == false)
@@ -11,6 +11,7 @@ namespace Umbraco.Web.Controllers
public class UmbProfileController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model)
{
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
@@ -10,6 +10,7 @@ namespace Umbraco.Web.Controllers
public class UmbRegisterController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model)
{
if (ModelState.IsValid == false)
+4 -1
View File
@@ -354,6 +354,9 @@ namespace Umbraco.Web.Editors
var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0));
var mapped = MapToDisplay(emptyContent);
// translate the content type name if applicable
mapped.ContentTypeName = Services.TextService.UmbracoDictionaryTranslate(mapped.ContentTypeName);
mapped.DocumentType.Name = Services.TextService.UmbracoDictionaryTranslate(mapped.DocumentType.Name);
//remove the listview app if it exists
mapped.ContentApps = mapped.ContentApps.Where(x => x.Alias != "umbListView").ToList();
@@ -1062,7 +1065,7 @@ namespace Umbraco.Web.Editors
var descendants = Services.EntityService.GetPagedDescendants(contentItem.Id, UmbracoObjectTypes.Document, page++, pageSize, out total,
//order by shallowest to deepest, this allows us to check permissions from top to bottom so we can exit
//early if a permission higher up fails
"path", Direction.Ascending);
ordering: Ordering.By("path", Direction.Ascending));
foreach (var c in descendants)
{
@@ -89,6 +89,8 @@ namespace Umbraco.Web.Editors
var availableCompositions = Services.ContentTypeService.GetAvailableCompositeContentTypes(source, allContentTypes, filterContentTypes, filterPropertyTypes);
var currCompositions = source == null ? new IContentTypeComposition[] { } : source.ContentTypeComposition.ToArray();
var compAliases = currCompositions.Select(x => x.Alias).ToArray();
var ancestors = availableCompositions.Ancestors.Select(x => x.Alias);
@@ -97,9 +99,6 @@ namespace Umbraco.Web.Editors
.Select(x => new Tuple<EntityBasic, bool>(Mapper.Map<IContentTypeComposition, EntityBasic>(x.Composition), x.Allowed))
.Select(x =>
{
//translate the name
x.Item1.Name = TranslateItem(x.Item1.Name);
//we need to ensure that the item is enabled if it is already selected
// but do not allow it if it is any of the ancestors
if (compAliases.Contains(x.Item1.Alias) && ancestors.Contains(x.Item1.Alias) == false)
@@ -108,11 +107,39 @@ namespace Umbraco.Web.Editors
x = new Tuple<EntityBasic, bool>(x.Item1, true);
}
//translate the name
x.Item1.Name = TranslateItem(x.Item1.Name);
var contentType = allContentTypes.FirstOrDefault(c => c.Key == x.Item1.Key);
var containers = GetEntityContainers(contentType, type)?.ToArray();
var containerPath = $"/{(containers != null && containers.Any() ? $"{string.Join("/", containers.Select(c => c.Name))}/" : null)}";
x.Item1.AdditionalData["containerPath"] = containerPath;
return x;
})
.ToList();
}
private IEnumerable<EntityContainer> GetEntityContainers(IContentTypeComposition contentType, UmbracoObjectTypes type)
{
if (contentType == null)
{
return null;
}
switch (type)
{
case UmbracoObjectTypes.DocumentType:
return Services.ContentTypeService.GetContainers(contentType as IContentType);
case UmbracoObjectTypes.MediaType:
return Services.MediaTypeService.GetContainers(contentType as IMediaType);
case UmbracoObjectTypes.MemberType:
return new EntityContainer[0];
default:
throw new ArgumentOutOfRangeException("The entity type was not a content type");
}
}
/// <summary>
/// Returns a list of content types where a particular composition content type is used
/// </summary>
+13 -4
View File
@@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using System.Web.Http.Controllers;
using Examine;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Core.Xml;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.Search;
@@ -477,7 +478,9 @@ namespace Umbraco.Web.Editors
var objectType = ConvertToObjectType(type);
if (objectType.HasValue)
{
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out var totalRecords, orderBy, orderDirection, filter);
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out var totalRecords,
SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection));
if (totalRecords == 0)
{
@@ -545,12 +548,18 @@ namespace Umbraco.Web.Editors
}
entities = aids == null || aids.Contains(Constants.System.Root)
? Services.EntityService.GetPagedDescendants(objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter, includeTrashed: false)
: Services.EntityService.GetPagedDescendants(aids, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
? Services.EntityService.GetPagedDescendants(objectType.Value, pageNumber - 1, pageSize, out totalRecords,
SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection), includeTrashed: false)
: Services.EntityService.GetPagedDescendants(aids, objectType.Value, pageNumber - 1, pageSize, out totalRecords,
SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection));
}
else
{
entities = Services.EntityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
entities = Services.EntityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords,
SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection));
}
if (totalRecords == 0)
@@ -74,8 +74,8 @@ namespace Umbraco.Web.Editors
throw new HttpResponseException(msg);
var results = Examine.ExamineExtensions.TryParseLuceneQuery(query)
? searcher.Search(searcher.CreateCriteria().RawQuery(query), maxResults: pageSize * (pageIndex + 1))
: searcher.Search(query, true, maxResults: pageSize * (pageIndex + 1));
? searcher.CreateQuery().NativeQuery(query).Execute(maxResults: pageSize * (pageIndex + 1))
: searcher.Search(query, maxResults: pageSize * (pageIndex + 1));
var pagedResults = results.Skip(pageIndex * pageSize);
@@ -109,7 +109,7 @@ namespace Umbraco.Web.Editors
if (!validate.IsSuccessStatusCode)
throw new HttpResponseException(validate);
validate = ValidatePopulator(indexName);
validate = ValidatePopulator(index);
if (!validate.IsSuccessStatusCode)
throw new HttpResponseException(validate);
@@ -134,7 +134,7 @@ namespace Umbraco.Web.Editors
if (!validate.IsSuccessStatusCode)
return validate;
validate = ValidatePopulator(indexName);
validate = ValidatePopulator(index);
if (!validate.IsSuccessStatusCode)
return validate;
@@ -201,7 +201,7 @@ namespace Umbraco.Web.Editors
Name = indexName,
HealthStatus = isHealth.Success ? (isHealth.Result ?? "Healthy") : (isHealth.Result ?? "Unhealthy"),
ProviderProperties = properties,
CanRebuild = _indexRebuilder.CanRebuild(indexName)
CanRebuild = _indexRebuilder.CanRebuild(index)
};
@@ -228,13 +228,13 @@ namespace Umbraco.Web.Editors
return response1;
}
private HttpResponseMessage ValidatePopulator(string indexName)
private HttpResponseMessage ValidatePopulator(IIndex index)
{
if (_indexRebuilder.CanRebuild(indexName))
if (_indexRebuilder.CanRebuild(index))
return Request.CreateResponse(HttpStatusCode.OK);
var response = Request.CreateResponse(HttpStatusCode.BadRequest);
response.Content = new StringContent($"The index {indexName} cannot be rebuilt because it does not have an associated {typeof(IIndexPopulator)}");
response.Content = new StringContent($"The index {index.Name} cannot be rebuilt because it does not have an associated {typeof(IIndexPopulator)}");
response.ReasonPhrase = "Index cannot be rebuilt";
return response;
}
@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
@@ -222,6 +223,7 @@ namespace Umbraco.Web
{
_viewContext = viewContext;
_method = method;
_controllerName = controllerName;
_encryptedString = UmbracoHelper.CreateEncryptedRouteString(controllerName, controllerAction, area, additionalRouteVals);
}
@@ -229,6 +231,7 @@ namespace Umbraco.Web
private readonly FormMethod _method;
private bool _disposed;
private readonly string _encryptedString;
private readonly string _controllerName;
protected override void Dispose(bool disposing)
{
@@ -236,6 +239,16 @@ namespace Umbraco.Web
return;
this._disposed = true;
//Detect if the call is targeting UmbRegisterController/UmbProfileController/UmbLoginStatusController/UmbLoginController and if it is we automatically output a AntiForgeryToken()
// We have a controllerName and area so we can match
if (_controllerName == "UmbRegister"
|| _controllerName == "UmbProfile"
|| _controllerName == "UmbLoginStatus"
|| _controllerName == "UmbLogin")
{
_viewContext.Writer.Write(AntiForgery.GetHtml().ToString());
}
//write out the hidden surface form routes
_viewContext.Writer.Write("<input name='ufprt' type='hidden' value='" + _encryptedString + "' />");
+22 -6
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Xml.XPath;
using Examine.Search;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;
@@ -34,21 +35,36 @@ namespace Umbraco.Web
/// <summary>
/// Searches content.
/// </summary>
IEnumerable<PublishedSearchResult> Search(string term, bool useWildCards = true, string indexName = null);
/// <param name="term">Term to search.</param>
/// <param name="culture">Optional culture.</param>
/// <param name="indexName">Optional index name.</param>
/// <remarks>
/// <para>When the <paramref name="culture"/> is not specified, all cultures are searched.</para>
/// </remarks>
IEnumerable<PublishedSearchResult> Search(string term, string culture = null, string indexName = null);
/// <summary>
/// Searches content.
/// </summary>
IEnumerable<PublishedSearchResult> Search(int skip, int take, out long totalRecords, string term, bool useWildCards = true, string indexName = null);
/// <param name="term">Term to search.</param>
/// <param name="skip">Numbers of items to skip.</param>
/// <param name="take">Numbers of items to return.</param>
/// <param name="totalRecords">Total number of matching items.</param>
/// <param name="culture">Optional culture.</param>
/// <param name="indexName">Optional index name.</param>
/// <remarks>
/// <para>When the <paramref name="culture"/> is not specified, all cultures are searched.</para>
/// </remarks>
IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords, string culture = null, string indexName = null);
/// <summary>
/// Searches content.
/// Executes the query and converts the results to PublishedSearchResult.
/// </summary>
IEnumerable<PublishedSearchResult> Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.ISearcher searchProvider = null);
IEnumerable<PublishedSearchResult> Search(IQueryExecutor query);
/// <summary>
/// Searches content.
/// Executes the query and converts the results to PublishedSearchResult.
/// </summary>
IEnumerable<PublishedSearchResult> Search(int skip, int take, out long totalRecords, Examine.SearchCriteria.ISearchCriteria criteria, Examine.ISearcher searcher = null);
IEnumerable<PublishedSearchResult> Search(IQueryExecutor query, int skip, int take, out long totalRecords);
}
}
@@ -6,8 +6,8 @@ using System.Linq;
using System.Threading;
using System.Xml.XPath;
using Examine;
using Examine.LuceneEngine.SearchCriteria;
using Examine.Providers;
using Examine.Search;
using Lucene.Net.Store;
using Umbraco.Core;
using Umbraco.Core.Logging;
@@ -15,7 +15,6 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;
using Umbraco.Examine;
using umbraco;
using Umbraco.Core.Cache;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
@@ -107,10 +106,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
// first check in Examine for the cache values
// +(+parentID:-1) +__IndexType:media
var criteria = searchProvider.CreateCriteria("media");
var criteria = searchProvider.CreateQuery("media");
var filter = criteria.ParentId(-1).Not().Field(UmbracoExamineIndex.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
var result = searchProvider.Search(filter.Compile());
var result = filter.Execute();
if (result != null)
return result.Select(x => CreateFromCacheValues(ConvertFromSearchResult(x)));
}
@@ -293,10 +292,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
//
// note that since the use of the wildcard, it automatically escapes it in Lucene.
var criteria = searchProvider.CreateCriteria("media");
var criteria = searchProvider.CreateQuery("media");
var filter = criteria.Id(id.ToInvariantString()).Not().Field(UmbracoExamineIndex.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
var result = searchProvider.Search(filter.Compile()).FirstOrDefault();
var result = filter.Execute().FirstOrDefault();
if (result != null) return ConvertFromSearchResult(result);
}
catch (Exception ex)
@@ -507,15 +506,15 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
try
{
//first check in Examine as this is WAY faster
var criteria = searchProvider.CreateCriteria("media");
var criteria = searchProvider.CreateQuery("media");
var filter = criteria.ParentId(parentId).Not().Field(UmbracoExamineIndex.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
var filter = criteria.ParentId(parentId).Not().Field(UmbracoExamineIndex.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard())
.OrderBy(new SortableField("sortOrder", SortType.Int));
//the above filter will create a query like this, NOTE: That since the use of the wildcard, it automatically escapes it in Lucene.
//+(+parentId:3113 -__Path:-1,-21,*) +__IndexType:media
// sort with the Sort field (updated for 8.0)
var results = searchProvider.Search(
filter.And().OrderBy(new SortableField("sortOrder", SortType.Int)).Compile());
var results = filter.Execute();
if (results.Any())
{
+18 -29
View File
@@ -4,12 +4,13 @@ using System.Data;
using System.Linq;
using System.Web;
using Examine;
using Examine.LuceneEngine.SearchCriteria;
using Examine.Search;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Composing;
namespace Umbraco.Web
@@ -266,7 +267,7 @@ namespace Umbraco.Web
#region Search
public static IEnumerable<PublishedSearchResult> SearchDescendants(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
public static IEnumerable<PublishedSearchResult> SearchDescendants(this IPublishedContent content, string term, string indexName = null)
{
//fixme: pass in the IExamineManager
@@ -276,17 +277,18 @@ namespace Umbraco.Web
var searcher = index.GetSearcher();
var t = term.Escape().Value;
if (useWildCards)
t = term.MultipleCharacterWildcard().Value;
//var t = term.Escape().Value;
//var luceneQuery = "+__Path:(" + content.Path.Replace("-", "\\-") + "*) +" + t;
var luceneQuery = "+__Path:(" + content.Path.Replace("-", "\\-") + "*) +" + t;
var crit = searcher.CreateCriteria().RawQuery(luceneQuery);
var query = searcher.CreateQuery()
.Field(UmbracoExamineIndex.IndexPathFieldName, (content.Path + ",").MultipleCharacterWildcard())
.And()
.ManagedQuery(term);
return content.Search(crit, searcher);
return query.Execute().ToPublishedSearchResults(UmbracoContext.Current.ContentCache);
}
public static IEnumerable<PublishedSearchResult> SearchChildren(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
public static IEnumerable<PublishedSearchResult> SearchChildren(this IPublishedContent content, string term, string indexName = null)
{
//fixme: pass in the IExamineManager
@@ -296,28 +298,15 @@ namespace Umbraco.Web
var searcher = index.GetSearcher();
var t = term.Escape().Value;
if (useWildCards)
t = term.MultipleCharacterWildcard().Value;
//var t = term.Escape().Value;
//var luceneQuery = "+parentID:" + content.Id + " +" + t;
var luceneQuery = "+parentID:" + content.Id + " +" + t;
var crit = searcher.CreateCriteria().RawQuery(luceneQuery);
var query = searcher.CreateQuery()
.Field("parentID", content.Id)
.And()
.ManagedQuery(term);
return content.Search(crit, searcher);
}
public static IEnumerable<PublishedSearchResult> Search(this IPublishedContent content, Examine.SearchCriteria.ISearchCriteria criteria, ISearcher searchProvider = null)
{
//fixme: pass in the IExamineManager
if (searchProvider == null)
{
if (!ExamineManager.Instance.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out var index))
throw new InvalidOperationException("No index found with name " + Constants.UmbracoIndexes.ExternalIndexName);
searchProvider = index.GetSearcher();
}
var results = searchProvider.Search(criteria);
return results.ToPublishedSearchResults(UmbracoContext.Current.ContentCache);
return query.Execute().ToPublishedSearchResults(UmbracoContext.Current.ContentCache);
}
#endregion
+54 -34
View File
@@ -2,15 +2,15 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.XPath;
using Examine;
using Examine.LuceneEngine.Providers;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Examine.Search;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Core.Xml;
using Umbraco.Examine;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web
@@ -181,58 +181,78 @@ namespace Umbraco.Web
#region Search
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(string term, bool useWildCards = true, string indexName = null)
public IEnumerable<PublishedSearchResult> Search(string term, string culture = null, string indexName = null)
{
return Search(0, 0, out _, term, useWildCards, indexName);
return Search(term, 0, 0, out _, culture, indexName);
}
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(int skip, int take, out long totalRecords, string term, bool useWildCards = true, string indexName = null)
public IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords, string culture = null, string indexName = null)
{
//fixme: inject IExamineManager
indexName = string.IsNullOrEmpty(indexName)
? Constants.UmbracoIndexes.ExternalIndexName
: indexName;
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index))
throw new InvalidOperationException($"No index found by name {indexName}");
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index) || !(index is IUmbracoIndex umbIndex))
throw new InvalidOperationException($"No index found by name {indexName} or is not of type {typeof(IUmbracoIndex)}");
var searcher = index.GetSearcher();
var searcher = umbIndex.GetSearcher();
var results = skip == 0 && take == 0
? searcher.Search(term, true)
: searcher.Search(term, true, maxResults: skip + take);
// default to max 500 results
var count = skip == 0 && take == 0 ? 500 : skip + take;
totalRecords = results.TotalItemCount;
return results.ToPublishedSearchResults(_contentCache);
}
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(ISearchCriteria criteria, ISearcher searchProvider = null)
{
return Search(0, 0, out _, criteria, searchProvider);
}
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(int skip, int take, out long totalRecords, ISearchCriteria criteria, ISearcher searcher = null)
{
//fixme: inject IExamineManager
if (searcher == null)
ISearchResults results;
if (culture.IsNullOrWhiteSpace())
{
if (!ExamineManager.Instance.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out var index))
throw new InvalidOperationException($"No index found by name {Constants.UmbracoIndexes.ExternalIndexName}");
searcher = index.GetSearcher();
results = searcher.Search(term, count);
}
else
{
//get all index fields suffixed with the culture name supplied
var cultureFields = new List<string>();
var fields = umbIndex.GetFields();
var qry = searcher.CreateQuery().Field(UmbracoContentIndex.VariesByCultureFieldName, 1); //must vary by culture
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var field in fields)
{
var match = CultureIsoCodeFieldName.Match(field);
if (match.Success && match.Groups.Count == 2 && culture.InvariantEquals(match.Groups[1].Value))
cultureFields.Add(field);
}
qry = qry.And().ManagedQuery(term, cultureFields.ToArray());
results = qry.Execute(count);
}
totalRecords = results.TotalItemCount;
return results.ToPublishedSearchResults(_contentCache);
}
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(IQueryExecutor query)
{
return Search(query, 0, 0, out _);
}
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(IQueryExecutor query, int skip, int take, out long totalRecords)
{
var results = skip == 0 && take == 0
? searcher.Search(criteria)
: searcher.Search(criteria, maxResults: skip + take);
? query.Execute()
: query.Execute(maxResults: skip + take);
totalRecords = results.TotalItemCount;
return results.ToPublishedSearchResults(_contentCache);
}
/// <summary>
/// Matches a culture iso name suffix
/// </summary>
/// <remarks>
/// myFieldName_en-us will match the "en-us"
/// </remarks>
private static readonly Regex CultureIsoCodeFieldName = new Regex("^[_\\w]+_([a-z]{2}-[a-z0-9]{2,4})$", RegexOptions.Compiled);
#endregion
}
+9 -10
View File
@@ -23,6 +23,7 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Web.Scheduling;
using System.Threading.Tasks;
using Examine.LuceneEngine.Directories;
using Examine.LuceneEngine.Indexing;
using LightInject;
using Umbraco.Core.Composing;
using Umbraco.Core.Strings;
@@ -149,7 +150,7 @@ namespace Umbraco.Web.Search
profilingLogger.Logger.Debug<ExamineComponent>("Examine shutdown registered with MainDom");
var registeredIndexers = examineManager.Indexes.OfType<IUmbracoIndexer>().Count(x => x.EnableDefaultEventHandler);
var registeredIndexers = examineManager.Indexes.OfType<IUmbracoIndex>().Count(x => x.EnableDefaultEventHandler);
profilingLogger.Logger.Info<ExamineComponent>("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers);
@@ -166,10 +167,10 @@ namespace Umbraco.Web.Search
EnsureUnlocked(profilingLogger.Logger, examineManager);
//TODO: Instead of waiting 5000 ms, we could add an event handler on to fulfilling the first request, then start?
RebuildIndexes(indexRebuilder, profilingLogger.Logger, true, 5000);
}
/// <summary>
/// Called to rebuild empty indexes on startup
/// </summary>
@@ -480,7 +481,7 @@ namespace Umbraco.Web.Search
//Delete all content of this content/media/member type that is in any content indexer by looking up matched examine docs
foreach (var id in ci.Value.removedIds)
{
foreach (var index in _examineManager.Indexes.OfType<IUmbracoIndexer>())
foreach (var index in _examineManager.Indexes.OfType<IUmbracoIndex>())
{
var searcher = index.GetSearcher();
@@ -489,9 +490,7 @@ namespace Umbraco.Web.Search
while (page * pageSize < total)
{
//paging with examine, see https://shazwazza.com/post/paging-with-examine/
var results = searcher.Search(
searcher.CreateCriteria().Field("nodeType", id).Compile(),
maxResults: pageSize * (page + 1));
var results = searcher.CreateQuery().Field("nodeType", id).Execute(maxResults: pageSize * (page + 1));
total = results.TotalItemCount;
var paged = results.Skip(page * pageSize);
@@ -686,7 +685,7 @@ namespace Umbraco.Web.Search
public static void Execute(ExamineComponent examineComponent, IContent content, bool isPublished)
{
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
//filter the indexers
.Where(x => isPublished || !x.PublishedValuesOnly)
.Where(x => x.EnableDefaultEventHandler))
@@ -723,7 +722,7 @@ namespace Umbraco.Web.Search
{
var valueSet = examineComponent._mediaValueSetBuilder.GetValueSets(media).ToList();
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
//filter the indexers
.Where(x => isPublished || !x.PublishedValuesOnly)
.Where(x => x.EnableDefaultEventHandler))
@@ -752,7 +751,7 @@ namespace Umbraco.Web.Search
public static void Execute(ExamineComponent examineComponent, IMember member)
{
var valueSet = examineComponent._memberValueSetBuilder.GetValueSets(member).ToList();
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
//filter the indexers
.Where(x => x.EnableDefaultEventHandler))
{
@@ -782,7 +781,7 @@ namespace Umbraco.Web.Search
public static void Execute(ExamineComponent examineComponent, int id, bool keepIfUnpublished)
{
var strId = id.ToString(CultureInfo.InvariantCulture);
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
.Where(x => (keepIfUnpublished && !x.PublishedValuesOnly) || !keepIfUnpublished)
.Where(x => x.EnableDefaultEventHandler))
@@ -33,7 +33,7 @@ namespace Umbraco.Web.Search
try
{
var searcher = _index.GetSearcher();
var result = searcher.Search("test", false);
var result = searcher.Search("test");
return Attempt<string>.Succeed(); //if we can search we'll assume it's healthy
}
catch (Exception e)
@@ -59,8 +59,7 @@ namespace Umbraco.Web.Search
{
var index = new UmbracoContentIndex(
Constants.UmbracoIndexes.InternalIndexName,
//fixme - how to deal with languages like in UmbracoContentIndexer.CreateFieldValueTypes
UmbracoExamineIndex.UmbracoIndexFieldDefinitions,
new UmbracoFieldDefinitionCollection(),
CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.InternalIndexPath),
new CultureInvariantWhitespaceAnalyzer(),
ProfilingLogger,
@@ -73,8 +72,7 @@ namespace Umbraco.Web.Search
{
var index = new UmbracoContentIndex(
Constants.UmbracoIndexes.ExternalIndexName,
//fixme - how to deal with languages like in UmbracoContentIndexer.CreateFieldValueTypes
UmbracoExamineIndex.UmbracoIndexFieldDefinitions,
new UmbracoFieldDefinitionCollection(),
CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.ExternalIndexPath),
new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30),
ProfilingLogger,
@@ -87,8 +85,7 @@ namespace Umbraco.Web.Search
{
var index = new UmbracoMemberIndex(
Constants.UmbracoIndexes.MembersIndexName,
//fixme - how to deal with languages like in UmbracoContentIndexer.CreateFieldValueTypes
UmbracoExamineIndex.UmbracoIndexFieldDefinitions,
new UmbracoFieldDefinitionCollection(),
CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.MembersIndexPath),
new CultureInvariantWhitespaceAnalyzer(),
ProfilingLogger,
@@ -109,11 +109,9 @@ namespace Umbraco.Web.Search
return Enumerable.Empty<SearchResultEntity>();
}
var raw = internalSearcher.CreateCriteria().RawQuery(sb.ToString());
var result = internalSearcher
var result = internalSearcher.CreateQuery().NativeQuery(sb.ToString())
//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, Convert.ToInt32(pageSize * (pageIndex + 1)));
.Execute(Convert.ToInt32(pageSize * (pageIndex + 1)));
totalFound = result.TotalItemCount;
@@ -263,6 +263,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
menu.Items.Add<ActionRestore>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
@@ -6,6 +6,7 @@ using System.Net.Http.Formatting;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
@@ -144,7 +145,8 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultEntity> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.DocumentType, pageIndex, pageSize, out totalFound, filter: query);
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.DocumentType, pageIndex, pageSize, out totalFound,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(query)));
return Mapper.Map<IEnumerable<SearchResultEntity>>(results);
}
}
@@ -5,6 +5,7 @@ using System.Net.Http.Formatting;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
@@ -144,7 +145,8 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultEntity> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.DataType, pageIndex, pageSize, out totalFound, filter: query);
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.DataType, pageIndex, pageSize, out totalFound,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(query)));
return Mapper.Map<IEnumerable<SearchResultEntity>>(results);
}
}
+15 -12
View File
@@ -121,24 +121,27 @@ namespace Umbraco.Web.Trees
return menu;
}
//return a normal node menu:
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionSort>(Services.TextService);
menu.Items.Add(new RefreshNode(Services.TextService, true));
//if the media item is in the recycle bin, don't have a default menu, just show the regular menu
//if the media item is in the recycle bin, we don't have a default menu and we need to show a limited menu
if (item.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Contains(RecycleBinId.ToInvariantString()))
{
menu.Items.Add<ActionRestore>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));
menu.DefaultMenuAlias = null;
menu.Items.Insert(2, new MenuItem(ActionRestore.ActionAlias, Services.TextService)
{
OpensDialog = true
});
}
else
{
//return a normal node menu:
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionSort>(Services.TextService);
menu.Items.Add(new RefreshNode(Services.TextService, true));
//set the default to create
menu.DefaultMenuAlias = ActionNew.ActionAlias;
}
@@ -171,6 +174,6 @@ namespace Umbraco.Web.Trees
// do not want to make public on the interface. Unfortunately also prevents this from being unit tested.
// See this issue for details on why we need this:
// https://github.com/umbraco/Umbraco-CMS/issues/3457
=> ((EntityService)Services.EntityService).GetMediaChildrenWithoutPropertyData(entityId).ToList();
=> ((EntityService)Services.EntityService).GetMediaChildrenWithoutPropertyData(entityId).ToList();
}
}
@@ -6,6 +6,8 @@ using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Services;
@@ -135,7 +137,8 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultEntity> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.MediaType, pageIndex, pageSize, out totalFound, filter: query);
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.MediaType, pageIndex, pageSize, out totalFound,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(query)));
return Mapper.Map<IEnumerable<SearchResultEntity>>(results);
}
}
@@ -135,7 +135,8 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultEntity> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.Template, pageIndex, pageSize, out totalFound, filter: query);
var results = Services.EntityService.GetPagedDescendants(UmbracoObjectTypes.Template, pageIndex, pageSize, out totalFound,
filter: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(query)));
return Mapper.Map<IEnumerable<SearchResultEntity>>(results);
}
}
+1 -1
View File
@@ -63,7 +63,7 @@
<PackageReference Include="AutoMapper" Version="7.0.1" />
<PackageReference Include="ClientDependency" Version="1.9.7" />
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
<PackageReference Include="Examine" Version="1.0.0-beta046" />
<PackageReference Include="Examine" Version="1.0.0-beta067" />
<PackageReference Include="HtmlAgilityPack" Version="1.8.9" />
<PackageReference Include="ImageProcessor">
<Version>2.6.2.25</Version>
-56
View File
@@ -775,62 +775,6 @@ namespace Umbraco.Web
#endregion
#region Search
/// <summary>
/// Searches content.
/// </summary>
/// <param name="term"></param>
/// <param name="useWildCards"></param>
/// <param name="indexName"></param>
/// <returns></returns>
public IEnumerable<PublishedSearchResult> Search(string term, bool useWildCards = true, string indexName = null)
{
return ContentQuery.Search(term, useWildCards, indexName);
}
/// <summary>
/// Searches content.
/// </summary>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="totalRecords"></param>
/// <param name="term"></param>
/// <param name="useWildCards"></param>
/// <param name="indexName"></param>
/// <returns></returns>
public IEnumerable<PublishedSearchResult> Search(int skip, int take, out long totalRecords, string term, bool useWildCards = true, string indexName = null)
{
return ContentQuery.Search(skip, take, out totalRecords, term, useWildCards, indexName);
}
/// <summary>
/// Searhes content.
/// </summary>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="totalRecords"></param>
/// <param name="criteria"></param>
/// <param name="searchProvider"></param>
/// <returns></returns>
public IEnumerable<PublishedSearchResult> Search(int skip, int take, out long totalRecords, Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null)
{
return ContentQuery.Search(skip, take, out totalRecords, criteria, searchProvider);
}
/// <summary>
/// Searhes content.
/// </summary>
/// <param name="criteria"></param>
/// <param name="searchProvider"></param>
/// <returns></returns>
public IEnumerable<PublishedSearchResult> Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null)
{
return ContentQuery.Search(criteria, searchProvider);
}
#endregion
#region Strings
/// <summary>