From 87ee6980e6f820f6acacd30bc22bf081892d8b01 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 28 Jul 2014 11:45:46 -0700 Subject: [PATCH] Adding Admin Search specific index settings --- .../DefinitionTemplates/TypeIndexing.cshtml | 24 +++--- .../Controllers/AdminController.cs | 8 +- .../Drivers/AdminSearchSettingsPartDriver.cs | 83 +++++++++++++++++++ .../AdminSearchSettingsPartHandler.cs | 30 +++++++ .../Modules/Orchard.Search/Migrations.cs | 19 +++++ .../Models/AdminSearchSettingsPart.cs | 23 +++++ .../Orchard.Search/Orchard.Search.csproj | 6 ++ .../Modules/Orchard.Search/Placement.info | 1 + .../Parts/AdminSearch.SiteSettings.cshtml | 78 +++++++++++++++++ 9 files changed, 256 insertions(+), 16 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Drivers/AdminSearchSettingsPartDriver.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Handlers/AdminSearchSettingsPartHandler.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Models/AdminSearchSettingsPart.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/AdminSearch.SiteSettings.cshtml diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml index d9d6fdbde..36d638eff 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml @@ -7,16 +7,16 @@ } @if (indexProvider != null) { -
- @T("Index this content type in:") - @{ var i = 0;} - -
+ var i = 0; + foreach (var index in indexProvider.List()) { +
+ @T("{0} index", @index) + +
+ i++; + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs index 65b55c02d..72f849c59 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs @@ -37,13 +37,13 @@ namespace Orchard.Search.Controllers { public ActionResult Index(PagerParameters pagerParameters, string searchText = "") { var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); - var searchSettingsPart = Services.WorkContext.CurrentSite.As(); + var searchSettingsPart = Services.WorkContext.CurrentSite.As(); IPageOfItems searchHits = new PageOfItems(new ISearchHit[] { }); try { searchHits = _searchService.Query(searchText, pager.Page, pager.PageSize, - Services.WorkContext.CurrentSite.As().FilterCulture, + Services.WorkContext.CurrentSite.As().FilterCulture, searchSettingsPart.SearchIndex, searchSettingsPart.SearchedFields, searchHit => searchHit); @@ -54,8 +54,8 @@ namespace Orchard.Search.Controllers { } var list = Services.New.List(); - foreach (var contentItem in Services.ContentManager.GetMany(searchHits.Select(x => x.ContentItemId), VersionOptions.Published, QueryHints.Empty)) { - // ignore search results which content item has been removed or unpublished + foreach (var contentItem in Services.ContentManager.GetMany(searchHits.Select(x => x.ContentItemId), VersionOptions.Latest, QueryHints.Empty)) { + // ignore search results which content item has been removed if (contentItem == null) { searchHits.TotalItemCount--; continue; diff --git a/src/Orchard.Web/Modules/Orchard.Search/Drivers/AdminSearchSettingsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Search/Drivers/AdminSearchSettingsPartDriver.cs new file mode 100644 index 000000000..41b288286 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Drivers/AdminSearchSettingsPartDriver.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; +using Orchard.Environment.Extensions; +using Orchard.Indexing; +using Orchard.Localization; +using Orchard.Search.Models; +using Orchard.Search.ViewModels; + +namespace Orchard.Search.Drivers { + + [OrchardFeature("Orchard.Search.Content")] + public class AdminSearchSettingsPartDriver : ContentPartDriver { + private readonly IIndexManager _indexManager; + + public AdminSearchSettingsPartDriver(IIndexManager indexManager) { + _indexManager = indexManager; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + protected override string Prefix { get { return "AdminSearchSettings"; } } + + protected override DriverResult Editor(AdminSearchSettingsPart part, dynamic shapeHelper) { + return Editor(part, null, shapeHelper); + + } + + protected override DriverResult Editor(AdminSearchSettingsPart part, IUpdateModel updater, dynamic shapeHelper) { + return ContentShape("Parts_AdminSearch_SiteSettings", () => { + var model = new SearchSettingsViewModel(); + String[] searchedFields = part.SearchedFields; + + if (updater != null) { + // submitting: rebuild model from form data + if (updater.TryUpdateModel(model, Prefix, null, null)) { + // update part if successful + part.SearchIndex = model.SelectedIndex; + part.SearchedFields = model.Entries.First(e => e.Index == model.SelectedIndex).Fields.Where(e => e.Selected).Select(e => e.Field).ToArray(); + part.FilterCulture = model.FilterCulture; + } + } + else if (_indexManager.HasIndexProvider()) { + // viewing editor: build model from part + model.FilterCulture = part.FilterCulture; + model.SelectedIndex = part.SearchIndex; + model.Entries = _indexManager.GetSearchIndexProvider().List().Select(x => { + var indexSettings = new IndexSettingsEntry { + Index = x, + Fields = new List() + }; + foreach (var field in _indexManager.GetSearchIndexProvider().GetFields(x)) { + indexSettings.Fields.Add(new SearchSettingsEntry {Field = field, Selected = (x == part.SearchIndex && searchedFields.Contains(field))}); + } + + return indexSettings; + }).ToList(); + } + + return shapeHelper.EditorTemplate(TemplateName: "Parts/AdminSearch.SiteSettings", Model: model, Prefix: Prefix); + }).OnGroup("admin search"); + } + + protected override void Exporting(AdminSearchSettingsPart part, ExportContentContext context) { + context.Element(part.PartDefinition.Name).Add(new XAttribute("SearchedFields", string.Join(",", part.SearchedFields))); + } + + protected override void Importing(AdminSearchSettingsPart part, ImportContentContext context) { + var xElement = context.Data.Element(part.PartDefinition.Name); + if (xElement == null) return; + + var searchedFields = xElement.Attribute("SearchedFields"); + searchedFields.Remove(); + + part.SearchedFields = searchedFields.Value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Handlers/AdminSearchSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Search/Handlers/AdminSearchSettingsPartHandler.cs new file mode 100644 index 000000000..9c51bcb8f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Handlers/AdminSearchSettingsPartHandler.cs @@ -0,0 +1,30 @@ +using Orchard.ContentManagement; +using Orchard.Localization; +using Orchard.Search.Models; +using Orchard.Data; +using Orchard.ContentManagement.Handlers; +using Orchard.Environment.Extensions; + +namespace Orchard.Search.Handlers { + [OrchardFeature("Orchard.Search.Content")] + public class AdminSearchSettingsPartHandler : ContentHandler { + public AdminSearchSettingsPartHandler() { + T = NullLocalizer.Instance; + Filters.Add(new ActivatingFilter("Site")); + + OnInitializing((context, part) => { + part.FilterCulture = false; + part.SearchedFields = new [] {"body, title"}; + }); + } + + public Localizer T { get; set; } + + protected override void GetItemMetadata(GetContentItemMetadataContext context) { + if (context.ContentItem.ContentType != "Site") + return; + base.GetItemMetadata(context); + context.Metadata.EditorGroupInfo.Add(new GroupInfo(T("Admin Search"))); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs index 383c13214..639569c41 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs @@ -57,4 +57,23 @@ namespace Orchard.Search { return 1; } } + + + [OrchardFeature("Orchard.Search.Content")] + public class AdminSearchMigration : DataMigrationImpl { + private readonly IIndexManager _indexManager; + + public AdminSearchMigration(IIndexManager indexManager) { + _indexManager = indexManager; + } + + public int Create() { + + _indexManager.GetSearchIndexProvider().CreateIndex("Admin"); + + ContentDefinitionManager.AlterTypeDefinition("Page", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Page:latest")); + + return 1; + } + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Models/AdminSearchSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Search/Models/AdminSearchSettingsPart.cs new file mode 100644 index 000000000..e82ce05d7 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Models/AdminSearchSettingsPart.cs @@ -0,0 +1,23 @@ +using System; +using Orchard.ContentManagement; +using Orchard.Environment.Extensions; + +namespace Orchard.Search.Models { + [OrchardFeature("Orchard.Search.Content")] + public class AdminSearchSettingsPart : ContentPart { + public string[] SearchedFields { + get { return (Retrieve("SearchedFields") ?? "").Split(new[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries); } + set { Store("SearchedFields", String.Join(", ", value)); } + } + + public bool FilterCulture { + get { return this.Retrieve(x => x.FilterCulture); } + set { this.Store(x => x.FilterCulture, value); } + } + + public string SearchIndex { + get { return this.Retrieve(x => x.SearchIndex); } + set { this.Store(x => x.SearchIndex, value); } + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj index b56de30c1..9a9866313 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj +++ b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj @@ -72,7 +72,10 @@ + + + @@ -146,6 +149,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.Search/Placement.info b/src/Orchard.Web/Modules/Orchard.Search/Placement.info index 559f4bf95..d2f515e83 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.Search/Placement.info @@ -1,4 +1,5 @@  + diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/AdminSearch.SiteSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/AdminSearch.SiteSettings.cshtml new file mode 100644 index 000000000..bbee1d446 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/AdminSearch.SiteSettings.cshtml @@ -0,0 +1,78 @@ +@using Orchard.Search.ViewModels +@model SearchSettingsViewModel +@{ + Script.Require("jQuery"); + +} +
+ @T("Admin Search") +
+ + + @if (Model.Entries != null && Model.Entries.Any()) { + if (String.IsNullOrWhiteSpace(Model.SelectedIndex)) { + Model.Entries.Insert(0, new IndexSettingsEntry { Index = "" }); + } + + + @T("Select which index to use in search queries.") + + +
    + @{var entryIndex = 0;} + @foreach(var modelEntry in Model.Entries) { + @Html.HiddenFor(m => m.Entries[entryIndex].Index) +
  • + @if (modelEntry.Fields != null && modelEntry.Fields.Any()) { +
      + @{ var fieldIndex = 0;} + @foreach (var fieldEntry in Model.Entries[entryIndex].Fields) { +
    • + @Html.EditorFor(m => m.Entries[entryIndex].Fields[fieldIndex].Selected) + @Html.HiddenFor(m => m.Entries[entryIndex].Fields[fieldIndex].Field) + +
    • + fieldIndex++; + } +
    + } +
  • + entryIndex++; + } +
+ @T("Check any property which should be used for search queries.") + + } + else { + @T("There is currently no index to search from. Please update your index, and check if some indexable content exists.") + } +
+
+ + @Html.EditorFor(m => m.FilterCulture) + + @T("If checked, search results will only include content items localized in the current culture of the request.") +
+ +
+ +@using (Script.Foot()) { + +} \ No newline at end of file