Merge branch 'temp8' into temp8-migrations
This commit is contained in:
+2
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)" />
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+28
-12
@@ -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);
|
||||
|
||||
})();
|
||||
|
||||
+29
-23
@@ -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
|
||||
|
||||
+10
-10
@@ -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>
|
||||
|
||||
+10
-10
@@ -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>
|
||||
<i class="{{::contentType.icon}}"></i>
|
||||
|
||||
@@ -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 you’ll 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 you’ll 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 <your@email.here></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 <your@email.here></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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 + "' />");
|
||||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user