From 9ef73f84b0a2d29d4cb967d03c6440bf79f679c9 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Fri, 4 Jun 2010 14:45:18 -0700 Subject: [PATCH] Adding some admin UI for search index management. Not yet working end-to-end but it looks like it does * * Waiting on some pieces of the index manager/provider are being added and/or reworked then we'll get it all hooked up. --HG-- branch : dev --- .../Modules/Orchard.Search/AdminMenu.cs | 16 ++++++ .../Controllers/AdminController.cs | 49 +++++++++++++++++++ .../Orchard.Search/Orchard.Search.csproj | 6 +++ .../Modules/Orchard.Search/Permissions.cs | 29 +++++++++++ .../Orchard.Search/Services/ISearchService.cs | 3 ++ .../Orchard.Search/Services/SearchService.cs | 37 +++++++++++++- .../Modules/Orchard.Search/Styles/admin.css | 3 ++ .../ViewModels/SearchIndexViewModel.cs | 10 ++++ .../Orchard.Search/Views/Admin/Index.ascx | 16 ++++++ .../Orchard.Search/Views/Search/Index.ascx | 11 ++--- .../Themes/TheAdmin/Styles/site.css | 7 +-- src/Orchard/Mvc/Html/HtmlHelperExtensions.cs | 2 +- 12 files changed, 174 insertions(+), 15 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Search/AdminMenu.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Permissions.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Styles/admin.css create mode 100644 src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchIndexViewModel.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx diff --git a/src/Orchard.Web/Modules/Orchard.Search/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.Search/AdminMenu.cs new file mode 100644 index 000000000..369fcea1c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/AdminMenu.cs @@ -0,0 +1,16 @@ +using Orchard.Localization; +using Orchard.UI.Navigation; + +namespace Orchard.Search { + public class AdminMenu : INavigationProvider { + public Localizer T { get; set; } + public string MenuName { get { return "admin"; } } + + public void GetNavigation(NavigationBuilder builder) { + builder.Add(T("Site"), "11", + menu => menu + .Add(T("Search Index"), "10.0", item => item.Action("Index", "Admin", new {area = "Orchard.Search"}) + .Permission(Permissions.ManageSearchIndex))); + } + } +} \ 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 new file mode 100644 index 000000000..852509b81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs @@ -0,0 +1,49 @@ +using System.Web.Mvc; +using Orchard.Localization; +using Orchard.Search.Services; +using Orchard.Search.ViewModels; +using Orchard.UI.Notify; + +namespace Orchard.Search.Controllers { + public class AdminController : Controller { + private readonly ISearchService _searchService; + + public AdminController(ISearchService searchService, IOrchardServices services) { + _searchService = searchService; + Services = services; + T = NullLocalizer.Instance; + } + + public IOrchardServices Services { get; private set; } + public Localizer T { get; set; } + + public ActionResult Index() { + var viewModel = new SearchIndexViewModel {HasIndexToManage = _searchService.HasIndexToManage}; + + if (!viewModel.HasIndexToManage) + Services.Notifier.Information(T("There is not search index to manage for this site.")); + + return View(viewModel); + } + + [HttpPost] + public ActionResult Update() { + if (!Services.Authorizer.Authorize(Permissions.ManageSearchIndex, T("Not allowed to manage the search index."))) + return new HttpUnauthorizedResult(); + + _searchService.UpdateIndex(); + + return RedirectToAction("Index"); + } + + [HttpPost] + public ActionResult Rebuild() { + if (!Services.Authorizer.Authorize(Permissions.ManageSearchIndex, T("Not allowed to manage the search index."))) + return new HttpUnauthorizedResult(); + + _searchService.RebuildIndex(); + + return RedirectToAction("Index"); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj index 770b58c82..5ee797d6f 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj +++ b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj @@ -65,11 +65,15 @@ + + + + @@ -82,7 +86,9 @@ + + diff --git a/src/Orchard.Web/Modules/Orchard.Search/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Search/Permissions.cs new file mode 100644 index 000000000..901f4ae65 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Permissions.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Orchard.Security.Permissions; + +namespace Orchard.Search { + public class Permissions : IPermissionProvider { + public static readonly Permission ManageSearchIndex = new Permission { Description = "Manage Search Index", Name = "ManageSearchIndex" }; + + public string ModuleName { + get { + return "Search"; + } + } + + public IEnumerable GetPermissions() { + return new Permission[] { + ManageSearchIndex, + }; + } + + public IEnumerable GetDefaultStereotypes() { + return new[] { + new PermissionStereotype { + Name = "Administrator", + Permissions = new[] {ManageSearchIndex} + }, + }; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs b/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs index 490fcc31c..aba8ecdb0 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs @@ -3,6 +3,9 @@ using Orchard.Indexing; namespace Orchard.Search.Services { public interface ISearchService : IDependency { + bool HasIndexToManage { get; } IEnumerable Query(string term); + void RebuildIndex(); + void UpdateIndex(); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs b/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs index 27c7b6fc7..257be8946 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs @@ -1,25 +1,58 @@ using System.Collections.Generic; using System.Linq; using Orchard.Indexing; +using Orchard.Localization; +using Orchard.UI.Notify; namespace Orchard.Search.Services { public class SearchService : ISearchService { + private const string SearchIndexName = "search"; private readonly IIndexManager _indexManager; - public SearchService(IIndexManager indexManager) { + public SearchService(IOrchardServices services, IIndexManager indexManager) { + Services = services; _indexManager = indexManager; + T = NullLocalizer.Instance; + } + + public IOrchardServices Services { get; set; } + public Localizer T { get; set; } + + public bool HasIndexToManage { + get { return _indexManager.HasIndexProvider(); } } public IEnumerable Query(string term) { if (string.IsNullOrWhiteSpace(term) || !_indexManager.HasIndexProvider()) return Enumerable.Empty(); - return _indexManager.GetSearchIndexProvider().CreateSearchBuilder("search") + return _indexManager.GetSearchIndexProvider().CreateSearchBuilder(SearchIndexName) .WithField("title", term) .WithField("body", term) .Search(); } + + public void RebuildIndex() { + if (!_indexManager.HasIndexProvider()) { + Services.Notifier.Warning(T("There is no search index to rebuild.")); + return; + } + + var searchProvider = _indexManager.GetSearchIndexProvider(); + if (searchProvider.Exists(SearchIndexName)) + searchProvider.DeleteIndex(SearchIndexName); + + searchProvider.CreateIndex(SearchIndexName); // or just reset the updated date and let the background process recreate the index + Services.Notifier.Information(T("The search index has been rebuilt.")); + } + + public void UpdateIndex() { + //todo: this + //if (_indexManager.HasIndexProvider()) + // _indexManager.GetSearchIndexProvider().UpdateIndex(SearchIndexName); + Services.Notifier.Information(T("The search index has been updated.")); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Styles/admin.css b/src/Orchard.Web/Modules/Orchard.Search/Styles/admin.css new file mode 100644 index 000000000..057874152 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Styles/admin.css @@ -0,0 +1,3 @@ +#main button { + display:block; +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchIndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchIndexViewModel.cs new file mode 100644 index 000000000..2a0637cda --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchIndexViewModel.cs @@ -0,0 +1,10 @@ +using System; +using Orchard.Mvc.ViewModels; + +namespace Orchard.Search.ViewModels { + public class SearchIndexViewModel : BaseViewModel { + public bool HasIndexToManage { get; set; } + //todo: hang the index updated date off here to show in the admin UI (e.g. -> index updated: June 4, 2010 [update index]) + public DateTime IndexUpdatedUtc { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx b/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx new file mode 100644 index 000000000..7726c2ef2 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx @@ -0,0 +1,16 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<%@ Import Namespace="Orchard.Mvc.Html" %><% +Html.RegisterStyle("admin.css"); %> +

<%=Html.TitleForPage(T("Search Index Mangement").ToString()) %>

<% +using (Html.BeginForm("update", "admin", FormMethod.Post, new {area = "Orchard.Search"})) { %> +
+

<%=T("The search index was last updated {0}. ", Html.DateTimeRelative(Model.IndexUpdatedUtc))%>

+ <%=Html.AntiForgeryTokenOrchard() %> +
<% +} +using (Html.BeginForm("rebuild", "admin", FormMethod.Post, new {area = "Orchard.Search"})) { %> +
+

<%=T("Rebuild the search index for a fresh start. ") %>

+ <%=Html.AntiForgeryTokenOrchard() %> +
<% +} %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/Search/Index.ascx b/src/Orchard.Web/Modules/Orchard.Search/Views/Search/Index.ascx index 415dab029..e0f8681ba 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Views/Search/Index.ascx +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/Search/Index.ascx @@ -1,14 +1,11 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Mvc.Html" %><% Html.RegisterStyle("search.css"); %> -

<%=Html.TitleForPage(T("Search"))%>

-<% -Html.Zone("search"); %><% - +

<%=Html.TitleForPage(T("Search"))%>

<% +Html.Zone("search"); if (!string.IsNullOrWhiteSpace(Model.Query)) { %> -

<%=T("{0} results", Model.Results.Count()) %>

<% +

<%=T("{0} results", Model.Results.Count()) %>

<% } - if (Model.Results.Count() > 0) { %> - <%=Html.UnorderedList(Model.Results, (r, i) => Html.DisplayForItem(r.Content).ToHtmlString(), "search-results contentItems") %><% +<%=Html.UnorderedList(Model.Results, (r, i) => Html.DisplayForItem(r.Content).ToHtmlString(), "search-results contentItems") %><% } %> \ No newline at end of file diff --git a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css index 59cb915bd..e692f8aeb 100644 --- a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css +++ b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css @@ -57,7 +57,6 @@ body { } button { font-family:Segoe UI,Trebuchet,Arial,Sans-Serif; - font-size:1.01em; } body#preview { min-width:0; @@ -157,6 +156,7 @@ table.items th, table.items td, table.items caption { font-size:1.4em; line-heig table.items p, table.items label, table.items input, table.items .button { font-size:1em; line-height:1em; } p .button { font-size:inherit; } .meta, .hint { font-size:1.2em; } /* 12px */ +form.link button { font-size:1.01em; } /* Links ----------------------------------------------------------*/ @@ -450,9 +450,6 @@ button, .button, .button:link, .button:visited { text-align:center; padding:0 .8em .1em; } -button { - padding-top:.08em; -} form.link button { background:inherit; border:0; @@ -681,7 +678,7 @@ table .button { .contentItems .properties .icon { margin:0 .2em -.2em; } -.contentItems .related{ +.contentItems .related { float:right; font-size:1.4em; text-align:right; diff --git a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs index 8615286b2..aabadcfb4 100644 --- a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs +++ b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs @@ -111,7 +111,7 @@ namespace Orchard.Mvc.Html { TimeSpan time = htmlHelper.Resolve().UtcNow - value; if (time.TotalDays > 7) - return "at " + htmlHelper.DateTime(value); + return "on " + htmlHelper.DateTime(value, "MMM d yyyy 'at' h:mm tt"); if (time.TotalHours > 24) return string.Format("{0} day{1} ago", time.Days, time.Days == 1 ? "" : "s"); if (time.TotalMinutes > 60)