diff --git a/src/Umbraco.Examine/MediaValueSetBuilder.cs b/src/Umbraco.Examine/MediaValueSetBuilder.cs index 3839d008b3..03e7f4944b 100644 --- a/src/Umbraco.Examine/MediaValueSetBuilder.cs +++ b/src/Umbraco.Examine/MediaValueSetBuilder.cs @@ -1,9 +1,13 @@ -using Examine; +using System; +using Examine; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -13,14 +17,16 @@ namespace Umbraco.Examine { private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IUserService _userService; + private readonly ILogger _logger; public MediaValueSetBuilder(PropertyEditorCollection propertyEditors, UrlSegmentProviderCollection urlSegmentProviders, - IUserService userService) + IUserService userService, ILogger logger) : base(propertyEditors, false) { _urlSegmentProviders = urlSegmentProviders; _userService = userService; + _logger = logger; } /// @@ -29,6 +35,42 @@ namespace Umbraco.Examine foreach (var m in media) { var urlValue = m.GetUrlSegment(_urlSegmentProviders); + + var umbracoFilePath = string.Empty; + var umbracoFile = string.Empty; + + var umbracoFileSource = m.GetValue(Constants.Conventions.Media.File); + + if (umbracoFileSource.DetectIsJson()) + { + ImageCropperValue cropper = null; + try + { + cropper = JsonConvert.DeserializeObject( + m.GetValue(Constants.Conventions.Media.File)); + } + catch (Exception ex) + { + _logger.Error(ex, $"Could not Deserialize ImageCropperValue for item with key {m.Key} "); + } + + if (cropper != null) + { + umbracoFilePath = cropper.Src; + } + } + else + { + umbracoFilePath = umbracoFileSource; + } + + if (!string.IsNullOrEmpty(umbracoFilePath)) + { + // intentional dummy Uri + var uri = new Uri("https://localhost/" + umbracoFilePath); + umbracoFile = uri.Segments.Last(); + } + var values = new Dictionary> { {"icon", m.ContentType.Icon?.Yield() ?? Enumerable.Empty()}, @@ -44,7 +86,8 @@ namespace Umbraco.Examine {"urlName", urlValue?.Yield() ?? Enumerable.Empty()}, {"path", m.Path?.Yield() ?? Enumerable.Empty()}, {"nodeType", m.ContentType.Id.ToString().Yield() }, - {"creatorName", (m.GetCreatorProfile(_userService)?.Name ?? "??").Yield()} + {"creatorName", (m.GetCreatorProfile(_userService)?.Name ?? "??").Yield()}, + {UmbracoExamineIndex.UmbracoFileFieldName, umbracoFile.Yield()} }; foreach (var property in m.Properties) diff --git a/src/Umbraco.Examine/UmbracoExamineIndex.cs b/src/Umbraco.Examine/UmbracoExamineIndex.cs index 24952050da..e1dd77b994 100644 --- a/src/Umbraco.Examine/UmbracoExamineIndex.cs +++ b/src/Umbraco.Examine/UmbracoExamineIndex.cs @@ -32,6 +32,7 @@ namespace Umbraco.Examine /// public const string IndexPathFieldName = SpecialFieldPrefix + "Path"; public const string NodeKeyFieldName = SpecialFieldPrefix + "Key"; + public const string UmbracoFileFieldName = "umbracoFileSrc"; public const string IconFieldName = SpecialFieldPrefix + "Icon"; public const string PublishedFieldName = SpecialFieldPrefix + "Published"; diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index f7b1799d63..1653de827d 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -7,6 +7,7 @@ using Lucene.Net.Analysis; using Lucene.Net.Analysis.Standard; using Lucene.Net.Store; using Moq; +using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -44,11 +45,10 @@ namespace Umbraco.Tests.UmbracoExamine public static MediaIndexPopulator GetMediaIndexRebuilder(PropertyEditorCollection propertyEditors, IMediaService mediaService) { - var mediaValueSetBuilder = new MediaValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), GetMockUserService()); + var mediaValueSetBuilder = new MediaValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), GetMockUserService(), GetMockLogger()); var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder); return mediaIndexDataSource; } - public static IContentService GetMockContentService() { long longTotalRecs; @@ -146,6 +146,11 @@ namespace Umbraco.Tests.UmbracoExamine return mediaTypeServiceMock.Object; } + public static IProfilingLogger GetMockLogger() + { + return new ProfilingLogger(Mock.Of(), Mock.Of()); + } + public static UmbracoContentIndex GetUmbracoIndexer( IProfilingLogger profilingLogger, Directory luceneDir, diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs index 2e44f1327b..f2099f2554 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs @@ -177,6 +177,14 @@ namespace Umbraco.Web.Models.Mapping target.Name = source.Values.ContainsKey("nodeName") ? source.Values["nodeName"] : "[no name]"; + if (source.Values.TryGetValue(UmbracoExamineIndex.UmbracoFileFieldName, out var umbracoFile)) + { + if (umbracoFile != null) + { + target.Name = $"{target.Name} ({umbracoFile})"; + } + } + if (source.Values.ContainsKey(UmbracoExamineIndex.NodeKeyFieldName)) { if (Guid.TryParse(source.Values[UmbracoExamineIndex.NodeKeyFieldName], out var key)) diff --git a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs index b351cca972..463f4b09df 100644 --- a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs @@ -67,7 +67,7 @@ namespace Umbraco.Web.Search string type; var indexName = Constants.UmbracoIndexes.InternalIndexName; - var fields = new[] { "id", "__NodeId", "__Key" }; + var fields = new List { "id", "__NodeId", "__Key" }; // TODO: WE should try to allow passing in a lucene raw query, however we will still need to do some manual string // manipulation for things like start paths, member types, etc... @@ -87,7 +87,7 @@ namespace Umbraco.Web.Search case UmbracoEntityTypes.Member: indexName = Constants.UmbracoIndexes.MembersIndexName; type = "member"; - fields = new[] { "id", "__NodeId", "__Key", "email", "loginName" }; + fields.AddRange(new[]{ "email", "loginName"}); if (searchFrom != null && searchFrom != Constants.Conventions.MemberTypes.AllMembersListId && searchFrom.Trim() != "-1") { sb.Append("+__NodeTypeAlias:"); @@ -97,6 +97,7 @@ namespace Umbraco.Web.Search break; case UmbracoEntityTypes.Media: type = "media"; + fields.AddRange(new[] { UmbracoExamineIndex.UmbracoFileFieldName }); var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService); AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, ignoreUserStartNodes, _entityService); break; @@ -161,7 +162,7 @@ namespace Umbraco.Web.Search return _mapper.MapEnumerable(results); } - private bool BuildQuery(StringBuilder sb, string query, string searchFrom, string[] fields, string type) + private bool BuildQuery(StringBuilder sb, string query, string searchFrom, List fields, string type) { //build a lucene query: // the nodeName will be boosted 10x without wildcards @@ -234,11 +235,26 @@ namespace Umbraco.Web.Search foreach (var f in fields) { + var queryWordsReplaced = new string[querywords.Length]; + + // when searching file names containing hyphens we need to replace the hyphens with spaces + if (f.Equals(UmbracoExamineIndex.UmbracoFileFieldName)) + { + for (var index = 0; index < querywords.Length; index++) + { + queryWordsReplaced[index] = querywords[index].Replace("\\-", " ").Replace("_", " ").Trim(" "); + } + } + else + { + queryWordsReplaced = querywords; + } + //additional fields normally sb.Append(f); sb.Append(":"); sb.Append("("); - foreach (var w in querywords) + foreach (var w in queryWordsReplaced) { sb.Append(w.ToLower()); sb.Append("* ");