Updates latest examine + api updates + fixes tests, gets different validation working (valid, failed, filtered)

This commit is contained in:
Shannon
2018-12-03 22:10:56 +11:00
parent 6103832b8a
commit f8d203abff
26 changed files with 343 additions and 279 deletions

View File

@@ -12,7 +12,7 @@ namespace Umbraco.Examine
/// <summary>
/// Used to validate a ValueSet for content/media - based on permissions, parent id, etc....
/// </summary>
public class ContentValueSetValidator : ValueSetValidator
public class ContentValueSetValidator : ValueSetValidator, IContentValueSetValidator
{
private readonly IPublicAccessService _publicAccessService;
@@ -24,6 +24,46 @@ namespace Umbraco.Examine
public bool SupportProtectedContent { get; }
public int? ParentId { get; }
public bool ValidatePath(string path, string category)
{
//check if this document is a descendent of the parent
if (ParentId.HasValue && ParentId.Value > 0)
{
// we cannot return FAILED here because we need the value set to get into the indexer and then deal with it from there
// because we need to remove anything that doesn't pass by parent Id in the cases that umbraco data is moved to an illegal parent.
if (!path.Contains(string.Concat(",", ParentId.Value, ",")))
return false;
}
return true;
}
public bool ValidateRecycleBin(string path, string category)
{
var recycleBinId = category == IndexTypes.Content ? Constants.System.RecycleBinContent : Constants.System.RecycleBinMedia;
//check for recycle bin
if (!SupportUnpublishedContent)
{
if (path.Contains(string.Concat(",", recycleBinId, ",")))
return false;
}
return true;
}
public bool ValidateProtectedContent(string path, string category)
{
if (category == IndexTypes.Content
&& !SupportProtectedContent
//if the service is null we can't look this up so we'll return false
&& (_publicAccessService == null || _publicAccessService.IsProtected(path)))
{
return false;
}
return true;
}
public ContentValueSetValidator(bool supportUnpublishedContent, int? parentId = null,
IEnumerable<string> includeItemTypes = null, IEnumerable<string> excludeItemTypes = null)
: this(supportUnpublishedContent, true, null, parentId, includeItemTypes, excludeItemTypes)
@@ -41,19 +81,22 @@ namespace Umbraco.Examine
_publicAccessService = publicAccessService;
}
public override bool Validate(ValueSet valueSet)
public override ValueSetValidationResult Validate(ValueSet valueSet)
{
if (!base.Validate(valueSet))
return false;
var baseValidate = base.Validate(valueSet);
if (baseValidate == ValueSetValidationResult.Failed)
return ValueSetValidationResult.Failed;
var isFiltered = baseValidate == ValueSetValidationResult.Filtered;
//check for published content
if (valueSet.Category == IndexTypes.Content && !SupportUnpublishedContent)
{
if (!valueSet.Values.TryGetValue(UmbracoExamineIndexer.PublishedFieldName, out var published))
return false;
return ValueSetValidationResult.Failed;
if (!published[0].Equals(1))
return false;
return ValueSetValidationResult.Failed;
//deal with variants, if there are unpublished variants than we need to remove them from the value set
if (valueSet.Values.TryGetValue(UmbracoContentIndexer.VariesByCultureFieldName, out var variesByCulture)
@@ -69,6 +112,7 @@ namespace Umbraco.Examine
foreach (var cultureField in valueSet.Values.Where(x => x.Key.InvariantEndsWith(cultureSuffix)).ToList())
{
valueSet.Values.Remove(cultureField.Key);
isFiltered = true;
}
}
}
@@ -76,37 +120,21 @@ namespace Umbraco.Examine
}
//must have a 'path'
if (!valueSet.Values.TryGetValue(PathKey, out var pathValues)) return false;
if (pathValues.Count == 0) return false;
if (pathValues[0] == null) return false;
if (pathValues[0].ToString().IsNullOrWhiteSpace()) return false;
if (!valueSet.Values.TryGetValue(PathKey, out var pathValues)) return ValueSetValidationResult.Failed;
if (pathValues.Count == 0) return ValueSetValidationResult.Failed;
if (pathValues[0] == null) return ValueSetValidationResult.Failed;
if (pathValues[0].ToString().IsNullOrWhiteSpace()) return ValueSetValidationResult.Failed;
var path = pathValues[0].ToString();
// return nothing if we're not supporting protected content and it is protected, and we're not supporting unpublished content
if (valueSet.Category == IndexTypes.Content
&& !SupportProtectedContent
//if the service is null we can't look this up so we'll return false
&& (_publicAccessService == null || _publicAccessService.IsProtected(path)))
{
return false;
}
// We need to validate the path of the content based on ParentId, protected content and recycle bin rules.
// We cannot return FAILED here because we need the value set to get into the indexer and then deal with it from there
// because we need to remove anything that doesn't pass by protected content in the cases that umbraco data is moved to an illegal parent.
if (!ValidatePath(path, valueSet.Category)
|| !ValidateRecycleBin(path, valueSet.Category)
|| !ValidateProtectedContent(path, valueSet.Category))
return ValueSetValidationResult.Filtered;
//check if this document is a descendent of the parent
if (ParentId.HasValue && ParentId.Value > 0)
{
if (!path.Contains(string.Concat(",", ParentId.Value, ",")))
return false;
}
//check for recycle bin
if (!SupportUnpublishedContent)
{
var recycleBinId = valueSet.Category == IndexTypes.Content ? Constants.System.RecycleBinContent : Constants.System.RecycleBinMedia;
if (path.Contains(string.Concat(",", recycleBinId, ",")))
return false;
}
return true;
return isFiltered ? ValueSetValidationResult.Filtered: ValueSetValidationResult.Valid;
}
}
}

View File

@@ -0,0 +1,18 @@
using Examine;
namespace Umbraco.Examine
{
/// <summary>
/// An extended <see cref="IValueSetValidator"/> for content indexes
/// </summary>
public interface IContentValueSetValidator : IValueSetValidator
{
bool SupportUnpublishedContent { get; }
bool SupportProtectedContent { get; }
int? ParentId { get; }
bool ValidatePath(string path, string category);
bool ValidateRecycleBin(string path, string category);
bool ValidateProtectedContent(string path, string category);
}
}

View File

@@ -21,8 +21,8 @@ namespace Umbraco.Examine
public void RebuildIndexes(bool onlyEmptyIndexes)
{
var indexes = (onlyEmptyIndexes
? ExamineManager.IndexProviders.Values.Where(x => !x.IndexExists())
: ExamineManager.IndexProviders.Values).ToArray();
? ExamineManager.Indexes.Where(x => !x.IndexExists())
: ExamineManager.Indexes).ToArray();
foreach(var index in indexes)
index.CreateIndex(); // clear the index

View File

@@ -48,7 +48,7 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Examine" Version="1.0.0-beta038" />
<PackageReference Include="Examine" Version="1.0.0-beta042" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NPoco" Version="3.9.4" />
</ItemGroup>
@@ -64,6 +64,7 @@
<Compile Include="ContentIndexPopulator.cs" />
<Compile Include="ContentValueSetBuilder.cs" />
<Compile Include="ExamineExtensions.cs" />
<Compile Include="IContentValueSetValidator.cs" />
<Compile Include="IIndexDiagnostics.cs" />
<Compile Include="IIndexPopulator.cs" />
<Compile Include="IndexPopulator.cs" />

View File

@@ -57,7 +57,7 @@ namespace Umbraco.Examine
Analyzer defaultAnalyzer,
ProfilingLogger profilingLogger,
ILocalizationService languageService,
IValueSetValidator validator,
IContentValueSetValidator validator,
IReadOnlyDictionary<string, Func<string, IIndexValueType>> indexValueTypes = null)
: base(name, fieldDefinitions, luceneDirectory, defaultAnalyzer, profilingLogger, validator, indexValueTypes)
{
@@ -121,14 +121,50 @@ namespace Umbraco.Examine
//Using a singleton here, we can't inject this when using config based providers and we don't use this
//anywhere else in this class
Current.Services.PublicAccessService,
parentId, ConfigIndexCriteria.IncludeItemTypes, ConfigIndexCriteria.ExcludeItemTypes);
parentId,
ConfigIndexCriteria.IncludeItemTypes, ConfigIndexCriteria.ExcludeItemTypes);
SupportSoftDelete = supportUnpublished;
}
#endregion
#region Public methods
/// <summary>
/// Special check for invalid paths
/// </summary>
/// <param name="values"></param>
/// <param name="onComplete"></param>
protected override void PerformIndexItems(IEnumerable<ValueSet> values, Action<IndexOperationEventArgs> onComplete)
{
var valid = true;
// ReSharper disable once PossibleMultipleEnumeration
foreach (var v in values)
{
if (v.Values.TryGetValue("path", out var paths) && paths.Count > 0 && paths[0] != null)
{
//we know this is an IContentValueSetValidator
var validator = (IContentValueSetValidator) ValueSetValidator;
var path = paths[0].ToString();
if (!validator.ValidatePath(path, v.Category)
|| !validator.ValidateRecycleBin(path, v.Category)
|| !validator.ValidateProtectedContent(path, v.Category))
{
//since the path is not valid we need to delete this item in case it exists in the index already and has now
//been moved to an invalid parent.
PerformDeleteFromIndex(v.Id, x => { /*noop*/ });
valid = false;
}
}
}
if (valid)
{
// ReSharper disable once PossibleMultipleEnumeration
base.PerformIndexItems(values, onComplete);
}
}
/// <inheritdoc />
/// <summary>
@@ -155,14 +191,11 @@ namespace Umbraco.Examine
//need to queue a delete item for each one found
foreach (var r in results)
{
QueueIndexOperation(new IndexOperation(new ValueSet(r.Id, null), IndexOperationType.Delete));
QueueIndexOperation(new IndexOperation(new ValueSet(r.Id), IndexOperationType.Delete));
}
base.PerformDeleteFromIndex(nodeId, onComplete);
}
#endregion
#region Protected
/// <summary>
/// Overridden to ensure that the variant system fields have the right value types
@@ -184,8 +217,6 @@ namespace Umbraco.Examine
return base.CreateFieldValueTypes(indexValueTypesFactory);
}
#endregion
}
}

View File

@@ -59,18 +59,20 @@ namespace Umbraco.Examine
/// </remarks>
public IEnumerable<string> ExcludeFields { get; }
public virtual bool Validate(ValueSet valueSet)
public virtual ValueSetValidationResult Validate(ValueSet valueSet)
{
if (ValidIndexCategories != null && !ValidIndexCategories.InvariantContains(valueSet.Category))
return false;
return ValueSetValidationResult.Failed;
//check if this document is of a correct type of node type alias
if (IncludeItemTypes != null && !IncludeItemTypes.InvariantContains(valueSet.ItemType))
return false;
return ValueSetValidationResult.Failed;
//if this node type is part of our exclusion list
if (ExcludeItemTypes != null && ExcludeItemTypes.InvariantContains(valueSet.ItemType))
return false;
return ValueSetValidationResult.Failed;
var isFiltered = false;
//filter based on the fields provided (if any)
if (IncludeFields != null || ExcludeFields != null)
@@ -78,15 +80,21 @@ namespace Umbraco.Examine
foreach (var key in valueSet.Values.Keys.ToList())
{
if (IncludeFields != null && !IncludeFields.InvariantContains(key))
{
valueSet.Values.Remove(key); //remove any value with a key that doesn't match the inclusion list
isFiltered = true;
}
if (ExcludeFields != null && ExcludeFields.InvariantContains(key))
{
valueSet.Values.Remove(key); //remove any value with a key that matches the exclusion list
isFiltered = true;
}
}
}
return true;
return isFiltered ? ValueSetValidationResult.Filtered : ValueSetValidationResult.Valid;
}
}
}

View File

@@ -24,16 +24,20 @@ namespace Umbraco.Tests.TestHelpers.Stubs
//noop
}
public IIndex GetIndex(string indexerName)
public bool TryGetIndex(string indexName, out IIndex index)
{
return _indexers.TryGetValue(indexerName, out var indexer) ? indexer : null;
return _indexers.TryGetValue(indexName, out index);
}
public ISearcher GetSearcher(string searcherName)
public bool TryGetSearcher(string searcherName, out ISearcher searcher)
{
return _searchers.TryGetValue(searcherName, out var indexer) ? indexer : null;
return _searchers.TryGetValue(searcherName, out searcher);
}
public IEnumerable<IIndex> Indexes => _indexers.Values;
public IEnumerable<ISearcher> RegisteredSearchers => _searchers.Values;
public IReadOnlyDictionary<string, IIndex> IndexProviders => _indexers;
}
}

View File

@@ -77,7 +77,7 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="7.0.1" />
<PackageReference Include="Castle.Core" Version="4.2.1" />
<PackageReference Include="Examine" Version="1.0.0-beta038" />
<PackageReference Include="Examine" Version="1.0.0-beta042" />
<PackageReference Include="HtmlAgilityPack">
<Version>1.8.9</Version>
</PackageReference>

View File

@@ -151,7 +151,7 @@ namespace Umbraco.Tests.UmbracoExamine
Directory luceneDir,
Analyzer analyzer = null,
ILocalizationService languageService = null,
IValueSetValidator validator = null)
IContentValueSetValidator validator = null)
{
if (languageService == null)
languageService = GetMockLocalizationService();

View File

@@ -19,14 +19,14 @@ namespace Umbraco.Tests.UmbracoExamine
{
var validator = new ContentValueSetValidator(true, true, Mock.Of<IPublicAccessService>());
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
result = validator.Validate(new ValueSet("777", IndexTypes.Media, new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("777", IndexTypes.Media, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
result = validator.Validate(new ValueSet("555", "invalid-category", new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", "invalid-category", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
}
@@ -35,11 +35,11 @@ namespace Umbraco.Tests.UmbracoExamine
{
var validator = new ContentValueSetValidator(true, true, Mock.Of<IPublicAccessService>());
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
[Test]
@@ -47,17 +47,17 @@ namespace Umbraco.Tests.UmbracoExamine
{
var validator = new ContentValueSetValidator(true, true, Mock.Of<IPublicAccessService>(), 555);
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,444" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,444" }));
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555,777" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555,777" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555,777,999" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555,777,999" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
[Test]
@@ -67,9 +67,9 @@ namespace Umbraco.Tests.UmbracoExamine
new[] { "hello", "world" },
null);
var valueSet = new ValueSet("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" });
var valueSet = ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" });
var result = validator.Validate(valueSet);
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
Assert.IsFalse(valueSet.Values.ContainsKey("path"));
Assert.IsTrue(valueSet.Values.ContainsKey("hello"));
@@ -83,9 +83,9 @@ namespace Umbraco.Tests.UmbracoExamine
null,
new[] { "hello", "world" });
var valueSet = new ValueSet("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" });
var valueSet = ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" });
var result = validator.Validate(valueSet);
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
Assert.IsTrue(valueSet.Values.ContainsKey("path"));
Assert.IsFalse(valueSet.Values.ContainsKey("hello"));
@@ -99,9 +99,9 @@ namespace Umbraco.Tests.UmbracoExamine
new[] { "hello", "world" },
new[] { "world" });
var valueSet = new ValueSet("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" });
var valueSet = ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" });
var result = validator.Validate(valueSet);
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
Assert.IsFalse(valueSet.Values.ContainsKey("path"));
Assert.IsTrue(valueSet.Values.ContainsKey("hello"));
@@ -114,14 +114,14 @@ namespace Umbraco.Tests.UmbracoExamine
var validator = new ContentValueSetValidator(true, true, Mock.Of<IPublicAccessService>(),
includeItemTypes: new List<string> { "include-content" });
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, "include-content", new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "include-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
[Test]
@@ -130,14 +130,14 @@ namespace Umbraco.Tests.UmbracoExamine
var validator = new ContentValueSetValidator(true, true, Mock.Of<IPublicAccessService>(),
excludeItemTypes: new List<string> { "exclude-content" });
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, "exclude-content", new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "exclude-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
}
[Test]
@@ -147,17 +147,17 @@ namespace Umbraco.Tests.UmbracoExamine
includeItemTypes: new List<string> { "include-content", "exclude-content" },
excludeItemTypes: new List<string> { "exclude-content" });
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, "exclude-content", new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "exclude-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, "include-content", new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "include-content", new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
[Test]
@@ -165,14 +165,14 @@ namespace Umbraco.Tests.UmbracoExamine
{
var validator = new ContentValueSetValidator(false, false, Mock.Of<IPublicAccessService>());
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555,777" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555,777" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content,
new Dictionary<string, object>
@@ -181,7 +181,7 @@ namespace Umbraco.Tests.UmbracoExamine
["path"] = "-1,555",
[UmbracoExamineIndexer.PublishedFieldName] = 1
}));
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
[Test]
@@ -189,15 +189,15 @@ namespace Umbraco.Tests.UmbracoExamine
{
var validator = new ContentValueSetValidator(false, false, Mock.Of<IPublicAccessService>());
var result = validator.Validate(new ValueSet("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555" }));
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555,777" }));
Assert.IsFalse(result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555,777" }));
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Media, new { hello = "world", path = "-1,555" }));
Assert.IsTrue(result);
}
[Test]
@@ -205,8 +205,8 @@ namespace Umbraco.Tests.UmbracoExamine
{
var validator = new ContentValueSetValidator(false, true, Mock.Of<IPublicAccessService>());
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content,
new Dictionary<string, object>
@@ -215,7 +215,7 @@ namespace Umbraco.Tests.UmbracoExamine
["path"] = "-1,555",
[UmbracoExamineIndexer.PublishedFieldName] = 0
}));
Assert.IsFalse(result);
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content,
new Dictionary<string, object>
@@ -224,7 +224,7 @@ namespace Umbraco.Tests.UmbracoExamine
["path"] = "-1,555",
[UmbracoExamineIndexer.PublishedFieldName] = 1
}));
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
[Test]
@@ -240,7 +240,7 @@ namespace Umbraco.Tests.UmbracoExamine
[UmbracoContentIndexer.VariesByCultureFieldName] = 1,
[UmbracoExamineIndexer.PublishedFieldName] = 0
}));
Assert.IsFalse(result);
Assert.AreEqual(ValueSetValidationResult.Failed, result);
result = validator.Validate(new ValueSet("555", IndexTypes.Content,
new Dictionary<string, object>
@@ -250,7 +250,7 @@ namespace Umbraco.Tests.UmbracoExamine
[UmbracoContentIndexer.VariesByCultureFieldName] = 1,
[UmbracoExamineIndexer.PublishedFieldName] = 1
}));
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Valid, result);
var valueSet = new ValueSet("555", IndexTypes.Content,
new Dictionary<string, object>
@@ -272,7 +272,7 @@ namespace Umbraco.Tests.UmbracoExamine
Assert.IsTrue(valueSet.Values.ContainsKey("title_es-ES"));
result = validator.Validate(valueSet);
Assert.IsTrue(result);
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
Assert.AreEqual(7, valueSet.Values.Count()); //filtered to 7 values (removes es-es values)
Assert.IsFalse(valueSet.Values.ContainsKey($"{UmbracoExamineIndexer.PublishedFieldName}_es-es"));
@@ -290,11 +290,11 @@ namespace Umbraco.Tests.UmbracoExamine
.Returns(Attempt.Fail<PublicAccessEntry>());
var validator = new ContentValueSetValidator(true, false, publicAccessService.Object);
var result = validator.Validate(new ValueSet("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.IsFalse(result);
var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" }));
Assert.AreEqual(ValueSetValidationResult.Filtered, result);
result = validator.Validate(new ValueSet("777", IndexTypes.Content, new { hello = "world", path = "-1,777" }));
Assert.IsTrue(result);
result = validator.Validate(ValueSet.FromObject("777", IndexTypes.Content, new { hello = "world", path = "-1,777" }));
Assert.AreEqual(ValueSetValidationResult.Valid, result);
}
}
}

View File

@@ -88,10 +88,9 @@
<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-beta038" />
<PackageReference Include="Examine" Version="1.0.0-beta042" />
<PackageReference Include="ImageProcessor.Web" Version="4.9.3.25" />
<PackageReference Include="ImageProcessor.Web.Config" Version="2.4.1.19" />
<PackageReference Include="Lucene.Net.Contrib" Version="3.0.3" />
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.6" />
<PackageReference Include="Microsoft.AspNet.WebApi" Version="5.2.6" />

View File

@@ -15,6 +15,7 @@ using Umbraco.Core.Models;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using System.Web.Http.Controllers;
using Examine;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Xml;
using Umbraco.Web.Models.Mapping;
@@ -53,12 +54,13 @@ namespace Umbraco.Web.Editors
}
}
private readonly UmbracoTreeSearcher _treeSearcher = new UmbracoTreeSearcher();
private readonly UmbracoTreeSearcher _treeSearcher;
private readonly SearchableTreeCollection _searchableTreeCollection;
public EntityController(SearchableTreeCollection searchableTreeCollection)
public EntityController(SearchableTreeCollection searchableTreeCollection, UmbracoTreeSearcher treeSearcher)
{
_searchableTreeCollection = searchableTreeCollection;
_treeSearcher = treeSearcher;
}
/// <summary>
@@ -410,22 +412,18 @@ namespace Umbraco.Web.Editors
Direction orderDirection = Direction.Ascending,
string filter = "")
{
int intId;
if (int.TryParse(id, out intId))
if (int.TryParse(id, out var intId))
{
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter);
}
Guid guidId;
if (Guid.TryParse(id, out guidId))
if (Guid.TryParse(id, out _))
{
//Not supported currently
throw new HttpResponseException(HttpStatusCode.NotFound);
}
Udi udiId;
if (Udi.TryParse(id, out udiId))
if (Udi.TryParse(id, out _))
{
//Not supported currently
throw new HttpResponseException(HttpStatusCode.NotFound);
@@ -443,8 +441,7 @@ namespace Umbraco.Web.Editors
//the EntityService cannot search members of a certain type, this is currently not supported and would require
//quite a bit of plumbing to do in the Services/Repository, we'll revert to a paged search
long total;
var searchResult = _treeSearcher.ExamineSearch(Umbraco, filter ?? "", type, pageSize, pageNumber - 1, out total, id);
var searchResult = _treeSearcher.ExamineSearch(filter ?? "", type, pageSize, pageNumber - 1, out long total, id);
return new PagedResult<EntityBasic>(total, pageNumber, pageSize)
{
@@ -480,8 +477,7 @@ namespace Umbraco.Web.Editors
var objectType = ConvertToObjectType(type);
if (objectType.HasValue)
{
long totalRecords;
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out var totalRecords, orderBy, orderDirection, filter);
if (totalRecords == 0)
{
@@ -596,13 +592,9 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
private IEnumerable<SearchResultItem> ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null)
{
long total;
return _treeSearcher.ExamineSearch(Umbraco, query, entityType, 200, 0, out total, searchFrom);
return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, searchFrom);
}
private IEnumerable<EntityBasic> GetResultForChildren(int id, UmbracoEntityTypes entityType)
{
var objectType = ConvertToObjectType(entityType);

View File

@@ -43,7 +43,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
public IEnumerable<ExamineIndexModel> GetIndexerDetails()
{
return _examineManager.IndexProviders.Select(CreateModel).OrderBy(x => x.Name.TrimEnd("Indexer"));
return _examineManager.Indexes.Select(CreateModel).OrderBy(x => x.Name.TrimEnd("Indexer"));
}
/// <summary>
@@ -53,32 +53,8 @@ namespace Umbraco.Web.Editors
public IEnumerable<ExamineSearcherModel> GetSearcherDetails()
{
var model = new List<ExamineSearcherModel>(
_examineManager.IndexProviders.Select(indexer =>
{
var searcher = indexer.Value.GetSearcher();
var searcherName = (searcher as BaseLuceneSearcher)?.Name ?? string.Concat(indexer.Key, "Searcher");
var indexerModel = new ExamineSearcherModel
{
Name = searcherName
};
var props = TypeHelper.CachedDiscoverableProperties(searcher.GetType(), mustWrite: false)
//ignore these properties
.Where(x => new[] { "Description" }.InvariantContains(x.Name) == false)
.Where(x => x.GetCustomAttribute<EditorBrowsableAttribute>()
?.State != EditorBrowsableState.Never)
.OrderBy(x => x.Name);
foreach (var p in props)
{
indexerModel.ProviderProperties.Add(p.Name, p.GetValue(searcher, null)?.ToString());
}
return indexerModel;
}).OrderBy(x =>
{
//order by name , but strip the "Searcher" from the end if it exists
return x.Name.TrimEnd("Searcher");
}));
_examineManager.RegisteredSearchers.Select(searcher => new ExamineSearcherModel{Name = searcher.Name})
.OrderBy(x => x.Name.TrimEnd("Searcher"))); //order by name , but strip the "Searcher" from the end if it exists
return model;
}
@@ -138,7 +114,7 @@ namespace Umbraco.Web.Editors
//if its still there then it's not done
return found != null
? null
: CreateModel(new KeyValuePair<string, IIndex>(indexName, index));
: CreateModel(index);
}
@@ -197,13 +173,12 @@ namespace Umbraco.Web.Editors
private ExamineIndexModel CreateModel(KeyValuePair<string, IIndex> indexerKeyVal)
private ExamineIndexModel CreateModel(IIndex index)
{
var indexer = indexerKeyVal.Value;
var indexName = indexerKeyVal.Key;
var indexName = index.Name;
if (!(indexer is IIndexDiagnostics indexDiag))
indexDiag = new GenericIndexDiagnostics(indexer);
if (!(index is IIndexDiagnostics indexDiag))
indexDiag = new GenericIndexDiagnostics(index);
var isHealth = indexDiag.IsHealthy();
@@ -229,10 +204,10 @@ namespace Umbraco.Web.Editors
private HttpResponseMessage ValidateLuceneSearcher(string searcherName, out LuceneSearcher searcher)
{
foreach (var indexer in _examineManager.IndexProviders)
foreach (var indexer in _examineManager.Indexes)
{
var s = indexer.Value.GetSearcher();
var sName = (s as BaseLuceneSearcher)?.Name ?? string.Concat(indexer.Key, "Searcher");
var s = indexer.GetSearcher();
var sName = (s as BaseLuceneSearcher)?.Name ?? string.Concat(indexer.Name, "Searcher");
if (sName != searcherName)
{
continue;
@@ -277,10 +252,9 @@ namespace Umbraco.Web.Editors
{
index = null;
if (_examineManager.IndexProviders.ContainsKey(indexName))
if (_examineManager.TryGetIndex(indexName, out index))
{
//return Ok!
index = _examineManager.GetIndex(indexName);
return Request.CreateResponse(HttpStatusCode.OK);
}

View File

@@ -49,6 +49,6 @@ namespace Umbraco.Web
/// <summary>
/// Searches content.
/// </summary>
IEnumerable<PublishedSearchResult> Search(int skip, int take, out int totalRecords, Examine.SearchCriteria.ISearchCriteria criteria, Examine.ISearcher searchProvider = null);
IEnumerable<PublishedSearchResult> Search(int skip, int take, out int totalRecords, Examine.SearchCriteria.ISearchCriteria criteria, Examine.ISearcher searcher = null);
}
}

View File

@@ -240,8 +240,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
try
{
//by default use the internal index
return eMgr.GetSearcher(Constants.Examine.InternalIndexer);
if (eMgr.TryGetIndex(Constants.Examine.InternalIndexer, out var index))
return index.GetSearcher();
throw new InvalidOperationException($"No index found by name {Constants.Examine.InternalIndexer}");
}
catch (FileNotFoundException)
{

View File

@@ -282,16 +282,15 @@ namespace Umbraco.Web
#region Search
public static IEnumerable<PublishedSearchResult> Search(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
public static IEnumerable<PublishedSearchResult> SearchDescendants(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
{
//TODO: we should pass in the IExamineManager?
//fixme: pass in the IExamineManager
var searcher = string.IsNullOrEmpty(indexName)
? ExamineManager.Instance.GetSearcher(Constants.Examine.ExternalIndexer)
: ExamineManager.Instance.GetSearcher(indexName);
indexName = string.IsNullOrEmpty(indexName) ? Constants.Examine.ExternalIndexer : indexName;
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index))
throw new InvalidOperationException("No index found with name " + indexName);
if (searcher == null)
throw new InvalidOperationException("No searcher found for index " + indexName);
var searcher = index.GetSearcher();
var t = term.Escape().Value;
if (useWildCards)
@@ -303,21 +302,15 @@ namespace Umbraco.Web
return content.Search(crit, searcher);
}
public static IEnumerable<PublishedSearchResult> SearchDescendants(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
{
return content.Search(term, useWildCards, indexName);
}
public static IEnumerable<PublishedSearchResult> SearchChildren(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
{
//TODO: we should pass in the IExamineManager?
//fixme: pass in the IExamineManager
var searcher = string.IsNullOrEmpty(indexName)
? ExamineManager.Instance.GetSearcher(Constants.Examine.ExternalIndexer)
: ExamineManager.Instance.GetSearcher(indexName);
indexName = string.IsNullOrEmpty(indexName) ? Constants.Examine.ExternalIndexer : indexName;
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index))
throw new InvalidOperationException("No index found with name " + indexName);
if (searcher == null)
throw new InvalidOperationException("No searcher found for index " + indexName);
var searcher = index.GetSearcher();
var t = term.Escape().Value;
if (useWildCards)
@@ -329,13 +322,17 @@ namespace Umbraco.Web
return content.Search(crit, searcher);
}
public static IEnumerable<PublishedSearchResult> Search(this IPublishedContent content, Examine.SearchCriteria.ISearchCriteria criteria, Examine.ISearcher searchProvider = null)
public static IEnumerable<PublishedSearchResult> Search(this IPublishedContent content, Examine.SearchCriteria.ISearchCriteria criteria, ISearcher searchProvider = null)
{
//TODO: we should pass in the IExamineManager?
//fixme: pass in the IExamineManager
var s = searchProvider ?? ExamineManager.Instance.GetSearcher(Constants.Examine.ExternalIndexer);
var results = s.Search(criteria);
if (searchProvider == null)
{
if (!ExamineManager.Instance.TryGetIndex(Constants.Examine.ExternalIndexer, out var index))
throw new InvalidOperationException("No index found with name " + Constants.Examine.ExternalIndexer);
searchProvider = index.GetSearcher();
}
var results = searchProvider.Search(criteria);
return results.ToPublishedSearchResults(UmbracoContext.Current.ContentCache);
}

View File

@@ -229,17 +229,18 @@ namespace Umbraco.Web
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(int skip, int take, out int totalRecords, string term, bool useWildCards = true, string indexName = null)
{
//TODO: Can we inject IExamineManager?
//fixme: inject IExamineManager
if (_query != null) return _query.Search(skip, take, out totalRecords, term, useWildCards, indexName);
var indexer = string.IsNullOrEmpty(indexName)
? Examine.ExamineManager.Instance.GetIndex(Constants.Examine.ExternalIndexer)
: Examine.ExamineManager.Instance.GetIndex(indexName);
indexName = string.IsNullOrEmpty(indexName)
? Constants.Examine.ExternalIndexer
: indexName;
if (indexer == null) throw new InvalidOperationException("No index found by name " + indexName);
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index))
throw new InvalidOperationException($"No index found by name {indexName}");
var searcher = indexer.GetSearcher();
var searcher = index.GetSearcher();
if (skip == 0 && take == 0)
{
@@ -248,24 +249,28 @@ namespace Umbraco.Web
return results.ToPublishedSearchResults(_contentCache);
}
var criteria = SearchAllFields(term, useWildCards, searcher, indexer);
var criteria = SearchAllFields(term, useWildCards, searcher, index);
return Search(skip, take, out totalRecords, criteria, searcher);
}
/// <inheritdoc />
public IEnumerable<PublishedSearchResult> Search(ISearchCriteria criteria, Examine.ISearcher searchProvider = null)
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 int totalRecords, ISearchCriteria criteria, Examine.ISearcher searchProvider = null)
public IEnumerable<PublishedSearchResult> Search(int skip, int take, out int totalRecords, ISearchCriteria criteria, ISearcher searcher = null)
{
if (_query != null) return _query.Search(skip, take, out totalRecords, criteria, searchProvider);
if (_query != null) return _query.Search(skip, take, out totalRecords, criteria, searcher);
//TODO: Can we inject IExamineManager?
var searcher = searchProvider ?? Examine.ExamineManager.Instance.GetSearcher(Constants.Examine.ExternalIndexer);
//fixme: inject IExamineManager
if (searcher == null)
{
if (!ExamineManager.Instance.TryGetIndex(Constants.Examine.ExternalIndexer, out var index))
throw new InvalidOperationException($"No index found by name {Constants.Examine.ExternalIndexer}");
searcher = index.GetSearcher();
}
var results = skip == 0 && take == 0
? searcher.Search(criteria)
@@ -278,7 +283,7 @@ namespace Umbraco.Web
/// <summary>
/// Creates an ISearchCriteria for searching all fields in a <see cref="BaseLuceneSearcher"/>.
/// </summary>
private ISearchCriteria SearchAllFields(string searchText, bool useWildcards, Examine.ISearcher searcher, Examine.IIndex indexer)
private ISearchCriteria SearchAllFields(string searchText, bool useWildcards, ISearcher searcher, IIndex indexer)
{
var sc = searcher.CreateCriteria();

View File

@@ -129,6 +129,8 @@ namespace Umbraco.Web.Runtime
composition.Container.RegisterCollectionBuilder<SearchableTreeCollectionBuilder>()
.Add(() => typeLoader.GetTypes<ISearchableTree>()); // fixme which searchable trees?!
composition.Container.Register<UmbracoTreeSearcher>(new PerRequestLifeTime());
composition.Container.RegisterCollectionBuilder<EditorValidatorCollectionBuilder>()
.Add(() => typeLoader.GetTypes<IEditorValidator>());

View File

@@ -125,13 +125,11 @@ namespace Umbraco.Web.Search
//create the indexes and register them with the manager
foreach(var index in indexCreator.Create())
{
_examineManager.AddIndex(index);
}
profilingLogger.Logger.Debug<ExamineComponent>("Examine shutdown registered with MainDom");
var registeredIndexers = examineManager.IndexProviders.Values.OfType<IUmbracoIndexer>().Count(x => x.EnableDefaultEventHandler);
var registeredIndexers = examineManager.Indexes.OfType<IUmbracoIndexer>().Count(x => x.EnableDefaultEventHandler);
profilingLogger.Logger.Info<ExamineComponent>("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers);
@@ -205,7 +203,7 @@ namespace Umbraco.Web.Search
_isConfigured = true;
foreach (var luceneIndexer in examineManager.IndexProviders.Values.OfType<LuceneIndex>())
foreach (var luceneIndexer in examineManager.Indexes.OfType<LuceneIndex>())
{
//We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending
//indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because
@@ -377,7 +375,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.IndexProviders.Values.OfType<IUmbracoIndexer>())
foreach (var index in _examineManager.Indexes.OfType<IUmbracoIndexer>())
{
var searcher = index.GetSearcher();
@@ -707,7 +705,7 @@ namespace Umbraco.Web.Search
{
var valueSet = examineComponent._contentValueSetBuilder.GetValueSets(content).ToList();
foreach (var index in examineComponent._examineManager.IndexProviders.Values.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
// only for the specified indexers
.Where(x => supportUnpublished.HasValue == false || supportUnpublished.Value == x.SupportSoftDelete)
.Where(x => x.EnableDefaultEventHandler))
@@ -739,7 +737,7 @@ namespace Umbraco.Web.Search
{
var valueSet = examineComponent._mediaValueSetBuilder.GetValueSets(media).ToList();
foreach (var index in examineComponent._examineManager.IndexProviders.Values.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
// index this item for all indexers if the media is not trashed, otherwise if the item is trashed
// then only index this for indexers supporting unpublished media
.Where(x => isPublished || (x.SupportSoftDelete))
@@ -769,7 +767,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.IndexProviders.Values.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
//ensure that only the providers are flagged to listen execute
.Where(x => x.EnableDefaultEventHandler))
{
@@ -799,7 +797,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.IndexProviders.Values.OfType<IUmbracoIndexer>()
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndexer>()
// if keepIfUnpublished == true then only delete this item from indexes not supporting unpublished content,
// otherwise if keepIfUnpublished == false then remove from all indexes
.Where(x => keepIfUnpublished == false || x.SupportSoftDelete == false)

View File

@@ -11,26 +11,11 @@ namespace Umbraco.Web.Search
{
public ExamineSearcherModel()
{
ProviderProperties = new Dictionary<string, string>();
}
/// <summary>
/// If the index is not healthy this represents the index error state
/// </summary>
[DataMember(Name = "error")]
public string Error { get; set; }
/// <summary>
/// If the index can be open/read
/// </summary>
[DataMember(Name = "isHealthy")]
public bool IsHealthy { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "providerProperties")]
public IDictionary<string, string> ProviderProperties { get; private set; }
}
}

View File

@@ -110,12 +110,12 @@ namespace Umbraco.Web.Search
return luceneDir;
}
public virtual IValueSetValidator GetContentValueSetValidator()
public virtual IContentValueSetValidator GetContentValueSetValidator()
{
return new ContentValueSetValidator(true, true, PublicAccessService);
}
public virtual IValueSetValidator GetPublishedContentValueSetValidator()
public virtual IContentValueSetValidator GetPublishedContentValueSetValidator()
{
return new ContentValueSetValidator(false, false, PublicAccessService);
}

View File

@@ -11,15 +11,27 @@ using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Search
{
internal class UmbracoTreeSearcher
/// <summary>
/// Used for internal Umbraco implementations of <see cref="ISearchableTree"/>
/// </summary>
public class UmbracoTreeSearcher
{
private readonly IExamineManager _examineManager;
private readonly UmbracoHelper _umbracoHelper;
public UmbracoTreeSearcher(IExamineManager examineManager, UmbracoHelper umbracoHelper)
{
_examineManager = examineManager ?? throw new ArgumentNullException(nameof(examineManager));
_umbracoHelper = umbracoHelper ?? throw new ArgumentNullException(nameof(umbracoHelper));
}
/// <summary>
/// Searches for results based on the entity type
/// </summary>
/// <param name="umbracoHelper"></param>
/// <param name="query"></param>
/// <param name="entityType"></param>
/// <param name="totalFound"></param>
@@ -30,7 +42,6 @@ namespace Umbraco.Web.Search
/// <param name="pageIndex"></param>
/// <returns></returns>
public IEnumerable<SearchResultItem> ExamineSearch(
UmbracoHelper umbracoHelper,
string query,
UmbracoEntityTypes entityType,
int pageSize,
@@ -39,16 +50,16 @@ namespace Umbraco.Web.Search
var sb = new StringBuilder();
string type;
var indexer = Constants.Examine.InternalIndexer;
var indexName = Constants.Examine.InternalIndexer;
var fields = new[] { "id", "__NodeId" };
var umbracoContext = umbracoHelper.UmbracoContext;
var umbracoContext = _umbracoHelper.UmbracoContext;
//TODO: WE should really just allow passing in a lucene raw query
switch (entityType)
{
case UmbracoEntityTypes.Member:
indexer = Constants.Examine.InternalMemberIndexer;
indexName = Constants.Examine.InternalMemberIndexer;
type = "member";
fields = new[] { "id", "__NodeId", "email", "loginName" };
if (searchFrom != null && searchFrom != Constants.Conventions.MemberTypes.AllMembersListId && searchFrom.Trim() != "-1")
@@ -72,7 +83,10 @@ namespace Umbraco.Web.Search
throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType);
}
var internalSearcher = ExamineManager.Instance.GetSearcher(indexer);
if (!_examineManager.TryGetIndex(indexName, out var index))
throw new InvalidOperationException("No index found by name " + indexName);
var internalSearcher = index.GetSearcher();
//build a lucene query:
// the __nodeName will be boosted 10x without wildcards
@@ -197,7 +211,7 @@ namespace Umbraco.Web.Search
case UmbracoEntityTypes.Media:
return MediaFromSearchResults(pagedResult);
case UmbracoEntityTypes.Document:
return ContentFromSearchResults(umbracoHelper, pagedResult);
return ContentFromSearchResults(pagedResult);
default:
throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType);
}
@@ -205,15 +219,13 @@ namespace Umbraco.Web.Search
private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[] startNodeIds, string searchFrom, IEntityService entityService)
{
if (sb == null) throw new ArgumentNullException("sb");
if (entityService == null) throw new ArgumentNullException("entityService");
if (sb == null) throw new ArgumentNullException(nameof(sb));
if (entityService == null) throw new ArgumentNullException(nameof(entityService));
Udi udi;
Udi.TryParse(searchFrom, true, out udi);
Udi.TryParse(searchFrom, true, out var udi);
searchFrom = udi == null ? searchFrom : entityService.GetId(udi).Result.ToString();
int searchFromId;
var entityPath = int.TryParse(searchFrom, out searchFromId) && searchFromId > 0
var entityPath = int.TryParse(searchFrom, out var searchFromId) && searchFromId > 0
? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault()
: null;
if (entityPath != null)
@@ -284,8 +296,7 @@ namespace Umbraco.Web.Search
}
if (searchResult.Values.ContainsKey("__key") && searchResult.Values["__key"] != null)
{
Guid key;
if (Guid.TryParse(searchResult.Values["__key"], out key))
if (Guid.TryParse(searchResult.Values["__key"], out var key))
{
m.Key = key;
}
@@ -317,10 +328,9 @@ namespace Umbraco.Web.Search
/// <summary>
/// Returns a collection of entities for content based on search results
/// </summary>
/// <param name="umbracoHelper"></param>
/// <param name="results"></param>
/// <returns></returns>
private IEnumerable<SearchResultItem> ContentFromSearchResults(UmbracoHelper umbracoHelper, IEnumerable<SearchResult> results)
private IEnumerable<SearchResultItem> ContentFromSearchResults(IEnumerable<SearchResult> results)
{
var mapped = Mapper.Map<IEnumerable<SearchResultItem>>(results).ToArray();
//add additional data
@@ -329,7 +339,7 @@ namespace Umbraco.Web.Search
var intId = m.Id.TryConvertTo<int>();
if (intId.Success)
{
m.AdditionalData["Url"] = umbracoHelper.Url(intId.Result);
m.AdditionalData["Url"] = _umbracoHelper.Url(intId.Result);
}
}
return mapped;

View File

@@ -35,7 +35,12 @@ namespace Umbraco.Web.Trees
[SearchableTree("searchResultFormatter", "configureContentResult")]
public class ContentTreeController : ContentTreeControllerBase, ISearchableTree
{
private readonly UmbracoTreeSearcher _treeSearcher = new UmbracoTreeSearcher();
private readonly UmbracoTreeSearcher _treeSearcher;
public ContentTreeController(UmbracoTreeSearcher treeSearcher)
{
_treeSearcher = treeSearcher;
}
protected override int RecycleBinId => Constants.System.RecycleBinContent;
@@ -316,7 +321,7 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultItem> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
return _treeSearcher.ExamineSearch(Umbraco, query, UmbracoEntityTypes.Document, pageSize, pageIndex, out totalFound, searchFrom);
return _treeSearcher.ExamineSearch(query, UmbracoEntityTypes.Document, pageSize, pageIndex, out totalFound, searchFrom);
}
}
}

View File

@@ -35,7 +35,12 @@ namespace Umbraco.Web.Trees
[SearchableTree("searchResultFormatter", "configureMediaResult")]
public class MediaTreeController : ContentTreeControllerBase, ISearchableTree
{
private readonly UmbracoTreeSearcher _treeSearcher = new UmbracoTreeSearcher();
private readonly UmbracoTreeSearcher _treeSearcher;
public MediaTreeController(UmbracoTreeSearcher treeSearcher)
{
_treeSearcher = treeSearcher;
}
protected override int RecycleBinId => Constants.System.RecycleBinMedia;
@@ -161,7 +166,7 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultItem> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
return _treeSearcher.ExamineSearch(Umbraco, query, UmbracoEntityTypes.Media, pageSize, pageIndex, out totalFound, searchFrom);
return _treeSearcher.ExamineSearch(query, UmbracoEntityTypes.Media, pageSize, pageIndex, out totalFound, searchFrom);
}
internal override IEnumerable<IEntitySlim> GetChildrenFromEntityService(int entityId)

View File

@@ -33,13 +33,14 @@ namespace Umbraco.Web.Trees
[SearchableTree("searchResultFormatter", "configureMemberResult")]
public class MemberTreeController : TreeController, ISearchableTree
{
public MemberTreeController()
public MemberTreeController(UmbracoTreeSearcher treeSearcher)
{
_treeSearcher = treeSearcher;
_provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
_isUmbracoProvider = _provider.IsUmbracoMembershipProvider();
}
private readonly UmbracoTreeSearcher _treeSearcher = new UmbracoTreeSearcher();
private readonly UmbracoTreeSearcher _treeSearcher;
private readonly MembershipProvider _provider;
private readonly bool _isUmbracoProvider;
@@ -193,7 +194,7 @@ namespace Umbraco.Web.Trees
public IEnumerable<SearchResultItem> Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null)
{
return _treeSearcher.ExamineSearch(Umbraco, query, UmbracoEntityTypes.Member, pageSize, pageIndex, out totalFound, searchFrom);
return _treeSearcher.ExamineSearch(query, UmbracoEntityTypes.Member, pageSize, pageIndex, out totalFound, searchFrom);
}
}
}

View File

@@ -62,7 +62,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-beta038" />
<PackageReference Include="Examine" Version="1.0.0-beta042" />
<PackageReference Include="HtmlAgilityPack" Version="1.8.9" />
<PackageReference Include="ImageProcessor">
<Version>2.6.2.25</Version>