From 66943406539c07df48949700d050b2529d7fb52a Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Wed, 8 Feb 2023 15:41:43 +0100 Subject: [PATCH 01/13] Rewrite to post to keep state on delete/pagechange --- .../Pages/Administer.cshtml.cs | 6 +- .../Pages/Components/Pager/Default.cshtml | 14 +- .../Components/Pager/PagerViewComponent.cs | 13 +- .../Pages/Deleted.cshtml | 4 +- .../Pages/Deleted.cshtml.cs | 21 +- .../Pages/Ignored.cshtml | 4 +- .../Pages/Ignored.cshtml.cs | 21 +- .../Pages/Index.cshtml | 13 +- .../Pages/Index.cshtml.cs | 60 +++--- .../Pages/Models/Paging.cs | 15 -- .../Pages/Suggestions.cshtml | 194 +++++++++--------- .../Pages/Suggestions.cshtml.cs | 19 +- .../Geta.NotFoundHandler.Admin.csproj | 4 - .../Views/Shared/_ShellLayout.cshtml | 1 + .../Core/CustomRedirectsResult.cs | 23 +++ .../Core/Redirects/DefaultRedirectsService.cs | 25 +-- .../Core/Redirects/IRedirectsService.cs | 14 +- .../Core/SuggestionRedirectsResult.cs | 23 +++ .../Suggestions/DefaultSuggestionService.cs | 5 +- .../Core/Suggestions/ISuggestionService.cs | 8 +- .../Data/IDataExecutor.cs | 12 +- .../Data/IRedirectLoader.cs | 7 +- .../Data/ISuggestionLoader.cs | 5 +- src/Geta.NotFoundHandler/Data/QueryParams.cs | 29 +++ .../Data/SqlDataExecutor.cs | 16 +- .../Data/SqlRedirectRepository.cs | 107 ++++++++-- .../Data/SqlSuggestionRepository.cs | 94 ++++++--- .../Geta.NotFoundHandler.csproj | 3 +- 28 files changed, 481 insertions(+), 279 deletions(-) delete mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Models/Paging.cs create mode 100644 src/Geta.NotFoundHandler/Core/CustomRedirectsResult.cs create mode 100644 src/Geta.NotFoundHandler/Core/SuggestionRedirectsResult.cs create mode 100644 src/Geta.NotFoundHandler/Data/QueryParams.cs diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Administer.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Administer.cshtml.cs index 9cacff9..29750e8 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Administer.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Administer.cshtml.cs @@ -49,7 +49,8 @@ public IActionResult OnPostDeleteAllIgnoredSuggestions() Message = $"All {count} ignored suggestions permanently removed"; CardType = CardType.Success; - return RedirectToPage(new { + return RedirectToPage(new + { Message, CardType }); @@ -168,7 +169,7 @@ public IActionResult OnPostImportDeletedRedirects() public IActionResult OnPostExportRedirects() { - var redirects = _redirectsService.GetSaved().ToList(); + var redirects = _redirectsService.GetRedirects(new Data.QueryParams() { QueryState = RedirectState.Saved }).Redirects.ToList(); var document = _redirectsXmlParser.Export(redirects); var memoryStream = new MemoryStream(); @@ -208,5 +209,6 @@ private CustomRedirectCollection ReadDeletedRedirectsFromImportFile() public class DeleteSuggestionsModel { public int MaxErrors { get; set; } = 5; + public int MinimumDays { get; set; } = 30; } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml index d6f6348..b604acc 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml @@ -3,19 +3,23 @@ \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewComponent.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewComponent.cs index eb3dd9c..cea3235 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewComponent.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewComponent.cs @@ -1,6 +1,6 @@ +using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using X.PagedList; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager { @@ -13,15 +13,16 @@ public PagerViewComponent(IHttpContextAccessor contextAccessor) _contextAccessor = contextAccessor; } - public IViewComponentResult Invoke(IPagedList items) + public IViewComponentResult Invoke(int page, int pageSize, int totalCount) { var context = _contextAccessor.HttpContext; + var pageCount = pageSize is int ps && ps > 0 ? (int)Math.Ceiling((decimal)totalCount / ps) : 1; return View(new PagerViewModel { - HasPreviousPage = items.HasPreviousPage, - HasNextPage = items.HasNextPage, - PageNumber = items.PageNumber, - PageCount = items.PageCount, + HasPreviousPage = page > 1, + HasNextPage = pageCount > page, + PageNumber = page, + PageCount = pageCount, QueryString = context.Request.QueryString.ToString() }); } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml index c60bbc9..c4a9fbc 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml @@ -27,7 +27,7 @@ - @foreach (var item in Model.Items) + @foreach (var item in Model.Results.Redirects) { @item.OldUrl @@ -43,6 +43,6 @@ } - @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Items }) + @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs index 6cd5cbe..38fc2d3 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs @@ -1,11 +1,11 @@ -using System.Linq; using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; +using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -using X.PagedList; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; @@ -21,13 +21,13 @@ public DeletedModel(IRedirectsService redirectsService) public string Message { get; set; } - public IPagedList Items { get; set; } = Enumerable.Empty().ToPagedList(); + public CustomRedirectsResult Results { get; set; } [BindProperty] public DeletedRedirectModel DeletedRedirect { get; set; } [BindProperty(SupportsGet = true)] - public Paging Paging { get; set; } + public QueryParams Params { get; set; } public void OnGet() { @@ -55,9 +55,16 @@ public IActionResult OnPostDelete(string oldUrl) private void Load() { - var items = _redirectsService.GetDeleted().ToPagedList(Paging.PageNumber, Paging.PageSize); + Params.QueryState = RedirectState.Deleted; + Params.PageSize ??= 50; + var results = _redirectsService.GetRedirects(Params); Message = - $"There are currently {items.TotalItemCount} URLs that return a Deleted response. This tells crawlers to remove these URLs from their index."; - Items = items; + $"There are currently {results.UnfilteredCount} URLs that return a Deleted response. This tells crawlers to remove these URLs from their index."; + + if (results.TotalCount < results.UnfilteredCount) + { + Message += $"Current filter gives {results.TotalCount}."; + } + Results = results; } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml index 3bb3ad0..f266696 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml @@ -13,7 +13,7 @@ - @foreach (var item in Model.Items) + @foreach (var item in Model.Results.Redirects) { @item.OldUrl @@ -29,6 +29,6 @@ } - @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Items }) + @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs index f7a6cf4..97177f6 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs @@ -1,11 +1,10 @@ -using System.Linq; -using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; +using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -using X.PagedList; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; @@ -21,10 +20,10 @@ public IgnoredModel(IRedirectsService redirectsService) public string Message { get; set; } - public IPagedList Items { get; set; } = Enumerable.Empty().ToPagedList(); + public CustomRedirectsResult Results { get; set; } [BindProperty(SupportsGet = true)] - public Paging Paging { get; set; } + public QueryParams Params { get; set; } public void OnGet() { @@ -40,8 +39,14 @@ public IActionResult OnPostUnignore(string oldUrl) private void Load() { - var items = _redirectsService.GetIgnored().ToPagedList(Paging.PageNumber, Paging.PageSize); - Message = $"There are currently {items.TotalItemCount} ignored suggestions stored."; - Items = items; + Params.QueryState = RedirectState.Ignored; + Params.PageSize ??= 50; + var results = _redirectsService.GetRedirects(Params); + Message = $"There are currently {results.UnfilteredCount} ignored suggestions stored. "; + if (results.TotalCount < results.UnfilteredCount) + { + Message += $"Current filter gives {results.TotalCount}."; + } + Results = results; } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml index 4b93209..ef89e0f 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml @@ -1,24 +1,23 @@ @page +@using Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Infrastructure; @using Geta.NotFoundHandler.Core.Redirects @model Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.IndexModel @await Component.InvokeAsync("Card", new { message = Model.Message }) -
+
- + -
-
-
@@ -58,7 +57,7 @@ - @foreach (var item in Model.Items) + @foreach (var item in Model.Results.Redirects) { @@ -79,6 +78,6 @@ }
@item.OldUrl
- @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Items }) + @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
\ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs index c4aa129..b6297ed 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs @@ -1,12 +1,11 @@ -using System.Collections.Generic; -using System.Linq; using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; +using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -using X.PagedList; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; @@ -22,57 +21,62 @@ public IndexModel(IRedirectsService redirectsService) public string Message { get; set; } - public IPagedList Items { get; set; } = Enumerable.Empty().ToPagedList(); + public CustomRedirectsResult Results { get; set; } [BindProperty] public RedirectModel CustomRedirect { get; set; } [BindProperty(SupportsGet = true)] - public Paging Paging { get; set; } - - [BindProperty(SupportsGet = true, Name = "q")] - public string Query { get; set; } - - public bool HasQuery => !string.IsNullOrEmpty(Query); + public QueryParams Params { get; set; } public void OnGet() { Load(); } + public IActionResult OnPost() + { + ModelState.Clear(); + return LoadPage(); + } + public IActionResult OnPostCreate() { - if (!ModelState.IsValid) + if (ModelState.IsValid) { - Load(); - return Page(); - } - - var customRedirect = new CustomRedirect(CustomRedirect.OldUrl, - CustomRedirect.NewUrl, - CustomRedirect.WildCardSkipAppend, - CustomRedirect.RedirectType); + var customRedirect = new CustomRedirect(CustomRedirect.OldUrl, + CustomRedirect.NewUrl, + CustomRedirect.WildCardSkipAppend, + CustomRedirect.RedirectType); - _redirectsService.AddOrUpdate(customRedirect); + _redirectsService.AddOrUpdate(customRedirect); + } - return RedirectToPage(); + return LoadPage(); } public IActionResult OnPostDelete(string oldUrl) { _redirectsService.DeleteByOldUrl(oldUrl); - return RedirectToPage(); + return LoadPage(); } - private void Load() + public IActionResult LoadPage() { - var items = FindRedirects().ToPagedList(Paging.PageNumber, Paging.PageSize); - Message = $"There are currently stored {items.TotalItemCount} custom redirects."; - Items = items; + Load(); + return Page(); } - private IEnumerable FindRedirects() + private void Load() { - return HasQuery ? _redirectsService.Search(Query) : _redirectsService.GetSaved(); + Params.QueryState = RedirectState.Saved; + Params.PageSize ??= 50; + var results = _redirectsService.GetRedirects(Params); + Message = $"There are currently stored {results.UnfilteredCount} custom redirects. "; + if (results.TotalCount < results.UnfilteredCount) + { + Message += $"Current filter gives {results.TotalCount}."; + } + Results = results; } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Models/Paging.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Models/Paging.cs deleted file mode 100644 index 3635713..0000000 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Models/Paging.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models -{ - public class Paging - { - public const int DefaultPageSize = 50; - - [FromQuery(Name = "page")] - public int PageNumber { get; set; } = 1; - - [FromQuery(Name = "page-size")] - public int PageSize { get; set; } = DefaultPageSize; - } -} diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml index 3a4033e..4c57426 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml @@ -3,105 +3,107 @@ @await Component.InvokeAsync("Card", new { message = Model.Message }) -
- - - - - - - - - - - - @for (var i = 0; i < Model.Items.Count; i++) - { - var item = Model.Items[i]; - var formId = $"redirect{i}"; - - - - - + + + } + +
Old URLNew URL
-
- -
- @item.OldUrl (@item.Count errors) -
- - - -
- -
-
- @{ - var referersModalId = $"referers{i}"; - var modalTitleId = $"modalTitle{i}"; - } - + @{ + var ignoreFormId = $"ignore{i}"; + } +
+
+ +
+
+
+ @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) +
+ \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs index 3282edf..1b6c54b 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using System.Linq; using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Suggestions; +using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -using X.PagedList; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; @@ -22,10 +23,12 @@ public SuggestionsModel(ISuggestionService suggestionService) public string Message { get; set; } - public IPagedList Items { get; set; } = Enumerable.Empty().ToPagedList(); + public SuggestionRedirectsResult Results { get; set; } + + public IList Items { get; set; } = Enumerable.Empty().ToList(); [BindProperty(SupportsGet = true)] - public Paging Paging { get; set; } + public QueryParams Params { get; set; } public void OnGet() { @@ -56,15 +59,17 @@ public IActionResult OnPostIgnore(string oldUrl) private void Load() { - var summaries = _suggestionService.GetSummaries(Paging.PageNumber, Paging.PageSize); - var redirectModels = summaries.Select(x => new SuggestionRedirectModel + Params.PageSize ??= 50; + var results = _suggestionService.GetSummaries(Params); + var redirectModels = results.Suggestions.Select(x => new SuggestionRedirectModel { OldUrl = x.OldUrl, Count = x.Count, Referers = x.Referers }); - Message = $"Based on the logged 404 errors, there are {summaries.TotalItemCount} custom redirect suggestions."; - Items = new StaticPagedList(redirectModels, summaries); + Message = $"Based on the logged 404 errors, there are {results.TotalCount} custom redirect suggestions."; + Results = results; + Items = redirectModels.ToList(); } } diff --git a/src/Geta.NotFoundHandler.Admin/Geta.NotFoundHandler.Admin.csproj b/src/Geta.NotFoundHandler.Admin/Geta.NotFoundHandler.Admin.csproj index 5daceb3..6372092 100644 --- a/src/Geta.NotFoundHandler.Admin/Geta.NotFoundHandler.Admin.csproj +++ b/src/Geta.NotFoundHandler.Admin/Geta.NotFoundHandler.Admin.csproj @@ -23,10 +23,6 @@ - - - - diff --git a/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml b/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml index c12a4b4..acce988 100644 --- a/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml +++ b/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml @@ -9,6 +9,7 @@ diff --git a/src/Geta.NotFoundHandler/Core/CustomRedirectsResult.cs b/src/Geta.NotFoundHandler/Core/CustomRedirectsResult.cs new file mode 100644 index 0000000..76512ab --- /dev/null +++ b/src/Geta.NotFoundHandler/Core/CustomRedirectsResult.cs @@ -0,0 +1,23 @@ +// Copyright (c) Geta Digital. All rights reserved. +// Licensed under Apache-2.0. See the LICENSE file in the project root for more information + +using System.Collections.Generic; +using Geta.NotFoundHandler.Core.Redirects; + +namespace Geta.NotFoundHandler.Core; + +public class CustomRedirectsResult +{ + public CustomRedirectsResult(IList redirects, int unfilteredCount, int totalCount) + { + Redirects = redirects; + UnfilteredCount = unfilteredCount; + TotalCount = totalCount; + } + + public IList Redirects { get; init; } + + public int UnfilteredCount { get; init; } + + public int TotalCount { get; init; } +} diff --git a/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs b/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs index 40f9703..e86bb80 100644 --- a/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs +++ b/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs @@ -29,24 +29,9 @@ public IEnumerable GetAll() return _redirectLoader.GetAll(); } - public IEnumerable GetSaved() + public CustomRedirectsResult GetRedirects(QueryParams query) { - return _redirectLoader.GetByState(RedirectState.Saved); - } - - public IEnumerable GetIgnored() - { - return _redirectLoader.GetByState(RedirectState.Ignored); - } - - public IEnumerable GetDeleted() - { - return _redirectLoader.GetByState(RedirectState.Deleted); - } - - public IEnumerable Search(string searchText) - { - return _redirectLoader.Find(searchText); + return _redirectLoader.GetRedirects(query); } public void AddOrUpdate(CustomRedirect redirect) @@ -91,7 +76,9 @@ public void AddDeletedRedirect(string oldUrl) { var redirect = new CustomRedirect { - OldUrl = oldUrl, NewUrl = string.Empty, State = Convert.ToInt32(RedirectState.Deleted) + OldUrl = oldUrl, + NewUrl = string.Empty, + State = Convert.ToInt32(RedirectState.Deleted) }; AddOrUpdate(redirect, notifyUpdated: true); } @@ -141,7 +128,7 @@ public int DeleteAll() public int DeleteAllIgnored() { // In order to avoid a database timeout, we delete the items one by one. - var ignoredRedirects = GetIgnored().ToList(); + var ignoredRedirects = GetRedirects(new QueryParams() { QueryState = RedirectState.Ignored }).Redirects.ToList(); foreach (var redirect in ignoredRedirects) { _repository.Delete(redirect); diff --git a/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs b/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs index 09c8598..af47d85 100644 --- a/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs +++ b/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs @@ -2,22 +2,28 @@ // Licensed under Apache-2.0. See the LICENSE file in the project root for more information using System.Collections.Generic; +using Geta.NotFoundHandler.Data; namespace Geta.NotFoundHandler.Core.Redirects { public interface IRedirectsService { IEnumerable GetAll(); - IEnumerable GetSaved(); - IEnumerable GetIgnored(); - IEnumerable GetDeleted(); - IEnumerable Search(string searchText); + + CustomRedirectsResult GetRedirects(QueryParams query); + void AddOrUpdate(CustomRedirect redirect); + void AddOrUpdate(IEnumerable redirects); + void AddDeletedRedirect(string oldUrl); + void DeleteByOldUrl(string oldUrl); + void DeleteByOldUrl(IEnumerable oldUrls); + int DeleteAll(); + int DeleteAllIgnored(); } } diff --git a/src/Geta.NotFoundHandler/Core/SuggestionRedirectsResult.cs b/src/Geta.NotFoundHandler/Core/SuggestionRedirectsResult.cs new file mode 100644 index 0000000..315b341 --- /dev/null +++ b/src/Geta.NotFoundHandler/Core/SuggestionRedirectsResult.cs @@ -0,0 +1,23 @@ +// Copyright (c) Geta Digital. All rights reserved. +// Licensed under Apache-2.0. See the LICENSE file in the project root for more information + +using System.Collections.Generic; +using Geta.NotFoundHandler.Core.Suggestions; + +namespace Geta.NotFoundHandler.Core; + +public class SuggestionRedirectsResult +{ + public SuggestionRedirectsResult(IList redirects, int unfilteredCount, int totalCount) + { + Suggestions = redirects; + UnfilteredCount = unfilteredCount; + TotalCount = totalCount; + } + + public IList Suggestions { get; init; } + + public int UnfilteredCount { get; init; } + + public int TotalCount { get; init; } +} diff --git a/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs b/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs index 47e60ca..f396807 100644 --- a/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs +++ b/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs @@ -3,7 +3,6 @@ using Geta.NotFoundHandler.Core.Redirects; using Geta.NotFoundHandler.Data; -using X.PagedList; namespace Geta.NotFoundHandler.Core.Suggestions { @@ -23,9 +22,9 @@ public DefaultSuggestionService( _suggestionRepository = suggestionRepository; } - public IPagedList GetSummaries(int page, int pageSize) + public SuggestionRedirectsResult GetSummaries(QueryParams query) { - return _suggestionLoader.GetSummaries(page, pageSize); + return _suggestionLoader.GetSummaries(query); } public void AddRedirect(SuggestionRedirect suggestionRedirect) diff --git a/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs b/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs index 6b73586..63e107b 100644 --- a/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs +++ b/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs @@ -1,16 +1,20 @@ // Copyright (c) Geta Digital. All rights reserved. // Licensed under Apache-2.0. See the LICENSE file in the project root for more information -using X.PagedList; +using Geta.NotFoundHandler.Data; namespace Geta.NotFoundHandler.Core.Suggestions { public interface ISuggestionService { - IPagedList GetSummaries(int page, int pageSize); + SuggestionRedirectsResult GetSummaries(QueryParams query); + void AddRedirect(SuggestionRedirect suggestionRedirect); + void IgnoreSuggestion(string oldUrl); + void DeleteAll(); + void Delete(int maxErrors, int minimumDays); } } diff --git a/src/Geta.NotFoundHandler/Data/IDataExecutor.cs b/src/Geta.NotFoundHandler/Data/IDataExecutor.cs index b2bb19d..4d076fe 100644 --- a/src/Geta.NotFoundHandler/Data/IDataExecutor.cs +++ b/src/Geta.NotFoundHandler/Data/IDataExecutor.cs @@ -10,15 +10,25 @@ namespace Geta.NotFoundHandler.Data public interface IDataExecutor { DataTable ExecuteQuery(string sqlCommand, params IDbDataParameter[] parameters); + bool ExecuteNonQuery(string sqlCommand, params IDbDataParameter[] parameters); - int ExecuteScalar(string sqlCommand); + + int ExecuteScalar(string sqlCommand, params IDbDataParameter[] parameters); + int ExecuteStoredProcedure(string sqlCommand, int defaultReturnValue = -1); + DbParameter CreateParameter(string parameterName, DbType dbType); + DbParameter CreateParameter(string parameterName, DbType dbType, int size); + DbParameter CreateGuidParameter(string name, Guid value); + DbParameter CreateStringParameter(string name, string value, int size = 2000); + DbParameter CreateIntParameter(string name, int value); + DbParameter CreateBoolParameter(string name, bool value); + DbParameter CreateDateTimeParameter(string name, DateTime value); } } diff --git a/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs b/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs index 0c95b98..56648cc 100644 --- a/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs +++ b/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; namespace Geta.NotFoundHandler.Data @@ -10,9 +11,11 @@ namespace Geta.NotFoundHandler.Data public interface IRedirectLoader { CustomRedirect GetByOldUrl(string oldUrl); + IEnumerable GetAll(); - IEnumerable GetByState(RedirectState state); - IEnumerable Find(string searchText); + + CustomRedirectsResult GetRedirects(QueryParams query); + CustomRedirect Get(Guid id); } } diff --git a/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs b/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs index 2ec9ae0..7eb2e9f 100644 --- a/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs +++ b/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs @@ -1,13 +1,12 @@ // Copyright (c) Geta Digital. All rights reserved. // Licensed under Apache-2.0. See the LICENSE file in the project root for more information -using Geta.NotFoundHandler.Core.Suggestions; -using X.PagedList; +using Geta.NotFoundHandler.Core; namespace Geta.NotFoundHandler.Data { public interface ISuggestionLoader { - IPagedList GetSummaries(int page, int pageSize); + SuggestionRedirectsResult GetSummaries(QueryParams query); } } diff --git a/src/Geta.NotFoundHandler/Data/QueryParams.cs b/src/Geta.NotFoundHandler/Data/QueryParams.cs new file mode 100644 index 0000000..fa818ed --- /dev/null +++ b/src/Geta.NotFoundHandler/Data/QueryParams.cs @@ -0,0 +1,29 @@ +// Copyright (c) Geta Digital. All rights reserved. +// Licensed under Apache-2.0. See the LICENSE file in the project root for more information + +using System.Data.SqlClient; +using Geta.NotFoundHandler.Core.Redirects; +using Microsoft.AspNetCore.Mvc; + +namespace Geta.NotFoundHandler.Data +{ + public class QueryParams + { + [FromForm(Name = "q")] + public string QueryText { get; set; } = string.Empty; + + public RedirectState? QueryState { get; set; } + + [FromForm(Name = "page")] + public int Page { get; set; } = 1; + + [FromForm(Name = "page-size")] + public int? PageSize { get; set; } + + [FromForm(Name = "sort-by")] + public string SortBy { get; set; } + + [FromForm(Name = "sort-direction")] + public SortOrder SortDirection { get; set; } = SortOrder.Ascending; + } +} diff --git a/src/Geta.NotFoundHandler/Data/SqlDataExecutor.cs b/src/Geta.NotFoundHandler/Data/SqlDataExecutor.cs index 66a22fe..072a543 100644 --- a/src/Geta.NotFoundHandler/Data/SqlDataExecutor.cs +++ b/src/Geta.NotFoundHandler/Data/SqlDataExecutor.cs @@ -4,9 +4,9 @@ using System; using System.Data; using System.Data.Common; +using System.Data.SqlClient; using System.Globalization; using Geta.NotFoundHandler.Infrastructure.Configuration; -using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -70,7 +70,7 @@ public bool ExecuteNonQuery(string sqlCommand, params IDbDataParameter[] paramet return success; } - public int ExecuteScalar(string sqlCommand) + public int ExecuteScalar(string sqlCommand, params IDbDataParameter[] parameters) { int result; try @@ -78,7 +78,7 @@ public int ExecuteScalar(string sqlCommand) using var connection = new SqlConnection(_connectionString); connection.Open(); - using var command = CreateCommand(connection, sqlCommand); + using var command = CreateCommand(connection, sqlCommand, parameters); var queryResult = command.ExecuteScalar(); if (queryResult == null) return 0; result = (int)queryResult; @@ -125,7 +125,9 @@ public DbParameter CreateParameter(string parameterName, DbType dbType) { var parameter = new SqlParameter { - ParameterName = parameterName, DbType = dbType, Direction = ParameterDirection.Input + ParameterName = parameterName, + DbType = dbType, + Direction = ParameterDirection.Input }; return parameter; } @@ -187,7 +189,9 @@ private static SqlParameter CreateReturnParameter() { var parameter = new SqlParameter { - ParameterName = "@ReturnValue", DbType = DbType.Int32, Direction = ParameterDirection.ReturnValue, + ParameterName = "@ReturnValue", + DbType = DbType.Int32, + Direction = ParameterDirection.ReturnValue, }; return parameter; } @@ -202,7 +206,7 @@ private static SqlCommand CreateCommand(SqlConnection connection, string sqlComm foreach (var dbDataParameter in parameters) { var parameter = (SqlParameter)dbDataParameter; - command.Parameters.Add(parameter); + command.Parameters.Add((parameter as ICloneable).Clone()); } } diff --git a/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs b/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs index 67c660a..b094c15 100644 --- a/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Data; +using System.Data.SqlClient; using System.Linq; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; namespace Geta.NotFoundHandler.Data @@ -104,36 +106,41 @@ public CustomRedirect GetByOldUrl(string oldUrl) public IEnumerable GetAll() { - var sqlCommand = $@"SELECT {AllFields} FROM {RedirectsTable}"; + var sqlCommand = $"SELECT {AllFields} FROM {RedirectsTable}"; var dataTable = _dataExecutor.ExecuteQuery(sqlCommand); return ToCustomRedirects(dataTable); } - public IEnumerable GetByState(RedirectState state) + public CustomRedirectsResult GetRedirects(QueryParams query) { - var sqlCommand = $@"SELECT {AllFields} FROM {RedirectsTable} - WHERE State = @state"; + var parameters = new List(); - var dataTable = _dataExecutor.ExecuteQuery( - sqlCommand, - _dataExecutor.CreateIntParameter("state", (int)state)); + var whereString = GetWhereString(query, parameters); - return ToCustomRedirects(dataTable); - } - - public IEnumerable Find(string searchText) - { - var sqlCommand = $@"SELECT {AllFields} FROM {RedirectsTable} - WHERE OldUrl like '%' + @searchText + '%' - OR NewUrl like '%' + @searchText + '%'"; + var suffixString = GetSuffixString(query, parameters, out var isPaginated); var dataTable = _dataExecutor.ExecuteQuery( - sqlCommand, - _dataExecutor.CreateStringParameter("searchText", searchText)); + $"SELECT {AllFields} FROM {RedirectsTable}{whereString}{suffixString}", + parameters.ToArray()); - return ToCustomRedirects(dataTable); + var items = ToCustomRedirects(dataTable); + var totalCount = items.Count; + if (isPaginated) + { + var whereState = query.QueryState != null ? @" + WHERE state = @state" : ""; + totalCount = _dataExecutor.ExecuteScalar($"SELECT COUNT(*) FROM {RedirectsTable}{whereState}", + _dataExecutor.CreateIntParameter("state", (int)query.QueryState)); + } + var filteredCount = totalCount; + if (!string.IsNullOrWhiteSpace(whereString)) + { + filteredCount = _dataExecutor.ExecuteScalar($"SELECT COUNT(*) FROM {RedirectsTable}{whereString}", parameters.ToArray()); + } + + return new CustomRedirectsResult(items, totalCount, filteredCount); } public CustomRedirect Get(Guid id) @@ -148,9 +155,9 @@ public CustomRedirect Get(Guid id) return ToCustomRedirects(dataTable).FirstOrDefault(); } - private static IEnumerable ToCustomRedirects(DataTable table) + private static IList ToCustomRedirects(DataTable table) { - return table.AsEnumerable().Select(ToCustomRedirect); + return table.AsEnumerable().Select(ToCustomRedirect).ToList(); } private static CustomRedirect ToCustomRedirect(DataRow x) @@ -159,7 +166,65 @@ private static CustomRedirect ToCustomRedirect(DataRow x) x.Field("OldUrl"), x.Field("NewUrl"), x.Field("WildCardSkipAppend"), - x.Field("RedirectType")) { Id = x.Field("Id"), State = x.Field("State") }; + x.Field("RedirectType")) + { Id = x.Field("Id"), State = x.Field("State") }; + } + + private string GetWhereString(QueryParams query, IList parameters) + { + var conditions = new List(); + if (!string.IsNullOrEmpty(query?.QueryText)) + { + parameters.Add(_dataExecutor.CreateStringParameter("searchText", query.QueryText)); + conditions.Add(@"(OldUrl like '%' + @searchText + '%' + OR NewUrl like '%' + @searchText + '%')"); + } + + if (query.QueryState != null) + { + parameters.Add(_dataExecutor.CreateIntParameter("state", (int)query.QueryState)); + conditions.Add("State = @state"); + } + + var hasFilter = conditions.Any(); + if (hasFilter) + { + return $@" + WHERE {string.Join(" AND ", conditions)}"; + } + + return ""; + } + + private string GetSuffixString(QueryParams query, IList parameters, out bool isPaginated) + { + var suffixString = ""; + var hasSortBy = !string.IsNullOrWhiteSpace(query.SortBy); + if (hasSortBy) + { + parameters.Add(_dataExecutor.CreateStringParameter("sortBy", query.SortBy)); + suffixString += $@" + ORDER BY @sortBy {(query.SortDirection == SortOrder.Ascending ? "ASC" : "DESC")}"; + } + + isPaginated = false; + if (query.PageSize is int ps && ps > 0) + { + isPaginated = true; + if (!hasSortBy) + { + // Adds dummy ORDER BY for pagination + suffixString += @" + ORDER BY(SELECT NULL)"; + } + parameters.Add(_dataExecutor.CreateIntParameter("pageSize", ps)); + parameters.Add(_dataExecutor.CreateIntParameter("skip", (query.Page - 1) * ps)); + suffixString += $@" + OFFSET {(query.Page - 1) * ps} ROWS + FETCH NEXT @pageSize ROWS ONLY"; + } + + return suffixString; } } } diff --git a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs index 120bebe..5cb607f 100644 --- a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs @@ -4,9 +4,10 @@ using System; using System.Collections.Generic; using System.Data; +using System.Data.SqlClient; using System.Linq; +using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Suggestions; -using X.PagedList; namespace Geta.NotFoundHandler.Data { @@ -21,16 +22,35 @@ public SqlSuggestionRepository(IDataExecutor dataExecutor) _dataExecutor = dataExecutor; } - public IPagedList GetSummaries(int page, int pageSize) + public SuggestionRedirectsResult GetSummaries(QueryParams query) { - var table = GetSuggestionsPaged(page, pageSize); - var summaries = CreateSuggestionSummaries(table); - var count = CountSummaries(); + var parameters = new List(); - return new StaticPagedList(summaries, page, pageSize, count); + var whereString = GetWhereString(query, parameters); + + var suffixString = GetSuffixString(query, parameters, out var isPaginated); + + var dataTable = _dataExecutor.ExecuteQuery( + $@"SELECT [OldUrl], COUNT(*) as Requests FROM {SuggestionsTable}{whereString} + GROUP BY [OldUrl]{suffixString}", + parameters.ToArray()); + + var items = CreateSuggestionSummaries(dataTable); + var totalCount = items.Count; + if (isPaginated) + { + totalCount = _dataExecutor.ExecuteScalar($"SELECT COUNT(*) FROM {SuggestionsTable}"); + } + var filteredCount = totalCount; + if (!string.IsNullOrWhiteSpace(whereString)) + { + filteredCount = _dataExecutor.ExecuteScalar($"SELECT COUNT(*) FROM {SuggestionsTable}{whereString}", parameters.ToArray()); + } + + return new SuggestionRedirectsResult(items, totalCount, filteredCount); } - private IEnumerable CreateSuggestionSummaries(DataTable table) + private IList CreateSuggestionSummaries(DataTable table) { var summaries = new List(); @@ -83,7 +103,7 @@ private IEnumerable GetReferers(string url) public void DeleteAll() { - var sqlCommand = $@"delete from {SuggestionsTable}"; + var sqlCommand = $"delete from {SuggestionsTable}"; _dataExecutor.ExecuteNonQuery(sqlCommand); } @@ -131,38 +151,58 @@ public void Save(string oldUrl, string referer, DateTime requestedOn) _dataExecutor.ExecuteNonQuery(sqlCommand, requestedParam, refererParam, oldUrlParam); } - private DataTable GetSuggestionsPaged(int? page, int? pageSize) + public DataTable GetSuggestionReferers(string url) { var sqlCommand = - $"SELECT [OldUrl], COUNT(*) as Requests FROM {SuggestionsTable} GROUP BY [OldUrl] order by Requests desc"; - - if (page.HasValue && pageSize.HasValue) - { - page = Math.Max(1, page.Value); - var skip = (page.Value - 1) * pageSize.Value; + $"SELECT [Referer], COUNT(*) as Requests FROM {SuggestionsTable} where [OldUrl] = @oldUrl GROUP BY [Referer] order by Requests desc"; - sqlCommand += $" OFFSET {skip} ROWS FETCH NEXT {pageSize.Value} ROWS ONLY"; - } + var oldUrlParam = _dataExecutor.CreateParameter("oldUrl", DbType.String, 2000); + oldUrlParam.Value = url; - return _dataExecutor.ExecuteQuery(sqlCommand); + return _dataExecutor.ExecuteQuery(sqlCommand, oldUrlParam); } - private int CountSummaries() + private string GetWhereString(QueryParams query, IList parameters) { - var sqlCommand = $"SELECT COUNT([ID]) FROM {SuggestionsTable}"; + if (!string.IsNullOrEmpty(query?.QueryText)) + { + parameters.Add(_dataExecutor.CreateStringParameter("searchText", query.QueryText)); + return @" + WHERE OldUrl like '%' + @searchText + '%'"; + } - return _dataExecutor.ExecuteScalar(sqlCommand); + return ""; } - public DataTable GetSuggestionReferers(string url) + private string GetSuffixString(QueryParams query, IList parameters, out bool isPaginated) { - var sqlCommand = - $"SELECT [Referer], COUNT(*) as Requests FROM {SuggestionsTable} where [OldUrl] = @oldUrl GROUP BY [Referer] order by Requests desc"; + var suffixString = ""; + var hasSortBy = !string.IsNullOrWhiteSpace(query.SortBy); + if (hasSortBy) + { + parameters.Add(_dataExecutor.CreateStringParameter("sortBy", query.SortBy)); + suffixString += $@" + ORDER BY @sortBy {(query.SortDirection == SortOrder.Ascending ? "ASC" : "DESC")}"; + } - var oldUrlParam = _dataExecutor.CreateParameter("oldUrl", DbType.String, 2000); - oldUrlParam.Value = url; + isPaginated = false; + if (query.PageSize is int ps && ps > 0) + { + isPaginated = true; + if (!hasSortBy) + { + // Adds dummy ORDER BY for pagination + suffixString += @" + ORDER BY(SELECT NULL)"; + } + parameters.Add(_dataExecutor.CreateIntParameter("pageSize", ps)); + parameters.Add(_dataExecutor.CreateIntParameter("skip", (query.Page - 1) * ps)); + suffixString += $@" + OFFSET {(query.Page - 1) * ps} ROWS + FETCH NEXT @pageSize ROWS ONLY"; + } - return _dataExecutor.ExecuteQuery(sqlCommand, oldUrlParam); + return suffixString; } } } diff --git a/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj b/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj index 742fcba..39d5700 100644 --- a/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj +++ b/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj @@ -26,8 +26,7 @@ - - + From e89d7d100c84f818aa66823a30884c2906911c34 Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Wed, 8 Feb 2023 17:01:58 +0100 Subject: [PATCH 02/13] Sortable columns --- .../Components/SortableHeader/Default.cshtml | 24 +++++ .../SortableHeaderViewComponent.cs | 13 +++ .../SortableHeader/SortableHeaderViewModel.cs | 23 +++++ .../Pages/Index.cshtml | 95 ++++++++++--------- .../Pages/Index.cshtml.cs | 1 + .../css/dashboard.css | 72 +++++++++----- .../GetaNotFoundHandlerAdmin/js/dashboard.js | 18 ++++ .../Data/SqlRedirectRepository.cs | 7 +- 8 files changed, 177 insertions(+), 76 deletions(-) create mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml create mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewComponent.cs create mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewModel.cs diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml new file mode 100644 index 0000000..3860da0 --- /dev/null +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml @@ -0,0 +1,24 @@ +@using System.Data.SqlClient; +@model Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Components.SortableHeader.SortableHeaderViewModel + +@{ + var sortBy = Model.InternalName; + var isCurrent = Model.Params.SortBy == Model.InternalName; + var nextSortDirection = isCurrent && Model.Params.SortDirection == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; +} + + + + @Model.DisplayName + + @if (nextSortDirection == SortOrder.Ascending) + { + + } + else + { + + } + + \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewComponent.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewComponent.cs new file mode 100644 index 0000000..af2a6c8 --- /dev/null +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewComponent.cs @@ -0,0 +1,13 @@ +using Geta.NotFoundHandler.Data; +using Microsoft.AspNetCore.Mvc; + +namespace Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Components.SortableHeader +{ + public class SortableHeaderViewComponent : ViewComponent + { + public IViewComponentResult Invoke(string displayName, string internalName, QueryParams @params, string additionalClass = null) + { + return View(new SortableHeaderViewModel(displayName, internalName, @params, additionalClass)); + } + } +} diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewModel.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewModel.cs new file mode 100644 index 0000000..8a29e07 --- /dev/null +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/SortableHeaderViewModel.cs @@ -0,0 +1,23 @@ +using Geta.NotFoundHandler.Data; + +namespace Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Components.SortableHeader +{ + public class SortableHeaderViewModel + { + public SortableHeaderViewModel(string displayName, string internalName, QueryParams @params, string additionalClass = null) + { + DisplayName = displayName; + InternalName = internalName; + Params = @params; + AdditionalClass = additionalClass; + } + + public string DisplayName { get; init; } + + public string InternalName { get; init; } + + public QueryParams Params { get; init; } + + public string AdditionalClass { get; } + } +} diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml index ef89e0f..546208b 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml @@ -1,11 +1,12 @@ @page -@using Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Infrastructure; @using Geta.NotFoundHandler.Core.Redirects @model Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.IndexModel @await Component.InvokeAsync("Card", new { message = Model.Message })
+ +
@@ -13,7 +14,7 @@ -
@@ -21,61 +22,61 @@
- - - - - - - + + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Old URL", InternalName = nameof(CustomRedirect.OldUrl), Model.Params }) + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "New URL", InternalName = nameof(CustomRedirect.NewUrl), Model.Params }) + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Wildcard", InternalName = nameof(CustomRedirect.WildCardSkipAppend), Model.Params, AdditionalClass = "col-1 text-center" }) + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Redirect type", InternalName = nameof(CustomRedirect.RedirectType), Model.Params, AdditionalClass = "col-1" }) + + - - - - - - - - @foreach (var item in Model.Results.Redirects) - { - - - + + + + - - } + @foreach (var item in Model.Results.Redirects) + { + + + + + + + + }
Old URLNew URLWildcardRedirect Type
- - - - - - - - - - -
- -
-
@item.OldUrl@item.NewUrl
+ + + + + + - @await Component.InvokeAsync("CheckboxReadonly", new { isChecked = item.WildCardSkipAppend }) + + + @item.RedirectType
-
@item.OldUrl@item.NewUrl + @await Component.InvokeAsync("CheckboxReadonly", new { isChecked = item.WildCardSkipAppend }) + @item.RedirectType +
+ +
+
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs index b6297ed..8a145ba 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs @@ -50,6 +50,7 @@ public IActionResult OnPostCreate() CustomRedirect.RedirectType); _redirectsService.AddOrUpdate(customRedirect); + CustomRedirect = new RedirectModel(); } return LoadPage(); diff --git a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css index aad2de6..5d9f508 100644 --- a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css +++ b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css @@ -13,56 +13,56 @@ */ .sidebar { - position: fixed; - top: 0; - /* rtl:raw: + position: fixed; + top: 0; + /* rtl:raw: right: 0; */ - bottom: 0; - /* rtl:remove */ - left: 0; - z-index: 100; /* Behind the navbar */ - padding: 48px 0 0; /* Height of navbar */ - box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); + bottom: 0; + /* rtl:remove */ + left: 0; + z-index: 100; /* Behind the navbar */ + padding: 48px 0 0; /* Height of navbar */ + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); } @media (max-width: 767.98px) { - .sidebar { - top: 5rem; - } + .sidebar { + top: 5rem; + } } .sidebar-sticky { - position: relative; - top: 0; - height: calc(100vh - 48px); - padding-top: .5rem; - overflow-x: hidden; - overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ + position: relative; + top: 0; + height: calc(100vh - 48px); + padding-top: .5rem; + overflow-x: hidden; + overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ } .sidebar .nav-link { - font-weight: 500; - color: #333; + font-weight: 500; + color: #333; } .sidebar .nav-link .feather { - margin-right: 4px; - color: #727272; + margin-right: 4px; + color: #727272; } .sidebar .nav-link.active { - color: #007bff; + color: #007bff; } .sidebar .nav-link:hover .feather, .sidebar .nav-link.active .feather { - color: inherit; + color: inherit; } .sidebar-heading { - font-size: .75rem; - text-transform: uppercase; + font-size: .75rem; + text-transform: uppercase; } /* @@ -114,3 +114,23 @@ .input-file { width: 450px; } + +/* + * Table + */ + +.sortable-header { + white-space: nowrap; +} + +.sortable-header svg { + color: gray; +} + +.sortable-header.current { + text-decoration: underline; +} + +.sortable-header.current svg { + color: black; +} diff --git a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js index 8b02046..9c31d41 100644 --- a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js +++ b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js @@ -36,6 +36,24 @@ }); } + function addSortableHeaders() { + var buttons = document.querySelectorAll('form .sortable-header a'); + buttons.forEach(function (button) { + button.addEventListener('click', + function (e) { + e.preventDefault(); + var header = button.closest(".sortable-header"); + var form = header.closest("form"); + var sortBy = form.querySelector("input[name='sort-by']"); + var sortDirection = form.querySelector("input[name='sort-direction']"); + if (sortBy) sortBy.value = header.dataset.sortBy; + if (sortDirection) sortDirection.value = header.dataset.sortDirection; + form.submit(); + }); + }); + } + clearInput(); confirmSubmit(); + addSortableHeaders(); })() \ No newline at end of file diff --git a/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs b/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs index b094c15..4d30050 100644 --- a/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs @@ -6,6 +6,7 @@ using System.Data; using System.Data.SqlClient; using System.Linq; +using System.Text.RegularExpressions; using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; @@ -199,12 +200,12 @@ private string GetWhereString(QueryParams query, IList paramet private string GetSuffixString(QueryParams query, IList parameters, out bool isPaginated) { var suffixString = ""; - var hasSortBy = !string.IsNullOrWhiteSpace(query.SortBy); + var safeSortBy = Regex.Replace(query.SortBy ?? string.Empty, "[^A-Za-z]", "", RegexOptions.IgnoreCase); + var hasSortBy = !string.IsNullOrWhiteSpace(safeSortBy); if (hasSortBy) { - parameters.Add(_dataExecutor.CreateStringParameter("sortBy", query.SortBy)); suffixString += $@" - ORDER BY @sortBy {(query.SortDirection == SortOrder.Ascending ? "ASC" : "DESC")}"; + ORDER BY [{safeSortBy}] {(query.SortDirection == SortOrder.Ascending ? "ASC" : "DESC")}"; } isPaginated = false; From a2633a28f6d061ac3e8ecd68ea905420b15ff9eb Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Wed, 8 Feb 2023 17:10:14 +0100 Subject: [PATCH 03/13] Fix sortby for suggestions as well --- src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs index 5cb607f..8e19b4e 100644 --- a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs @@ -6,6 +6,7 @@ using System.Data; using System.Data.SqlClient; using System.Linq; +using System.Text.RegularExpressions; using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Suggestions; @@ -177,12 +178,12 @@ private string GetWhereString(QueryParams query, IList paramet private string GetSuffixString(QueryParams query, IList parameters, out bool isPaginated) { var suffixString = ""; - var hasSortBy = !string.IsNullOrWhiteSpace(query.SortBy); + var safeSortBy = Regex.Replace(query.SortBy ?? string.Empty, "[^A-Za-z]", "", RegexOptions.IgnoreCase); + var hasSortBy = !string.IsNullOrWhiteSpace(safeSortBy); if (hasSortBy) { - parameters.Add(_dataExecutor.CreateStringParameter("sortBy", query.SortBy)); suffixString += $@" - ORDER BY @sortBy {(query.SortDirection == SortOrder.Ascending ? "ASC" : "DESC")}"; + ORDER BY [{safeSortBy}] {(query.SortDirection == SortOrder.Ascending ? "ASC" : "DESC")}"; } isPaginated = false; From a44fbc10d5b42f44eafb7d8e815a3c5bf9afed78 Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Wed, 8 Feb 2023 23:56:37 +0100 Subject: [PATCH 04/13] Fixes order on suggestions, deleted and ignored views Fixes iframe height calculation Fixes sortable hover-style --- .../Components/SortableHeader/Default.cshtml | 6 +-- .../Pages/Deleted.cshtml | 6 ++- .../Pages/Deleted.cshtml.cs | 51 +++--------------- .../Pages/Ignored.cshtml | 6 ++- .../Pages/Ignored.cshtml.cs | 41 ++------------ .../Pages/Index.cshtml | 5 +- .../Pages/Index.cshtml.cs | 54 +++---------------- .../BaseCustomRedirectPageModel.cs | 35 ++++++++++++ .../Infrastructure/BaseRedirectPageModel.cs | 36 +++++++++++++ .../Pages/Suggestions.cshtml | 33 +++++------- .../Pages/Suggestions.cshtml.cs | 40 +++++--------- .../css/dashboard.css | 6 +-- .../Views/Shared/_ShellLayout.cshtml | 7 ++- 13 files changed, 143 insertions(+), 183 deletions(-) create mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs create mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseRedirectPageModel.cs diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml index 3860da0..b07fe91 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml @@ -12,13 +12,13 @@ @Model.DisplayName - @if (nextSortDirection == SortOrder.Ascending) + @if (isCurrent && nextSortDirection == SortOrder.Ascending) { - + } else { - + } \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml index c4a9fbc..fed1934 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml @@ -1,4 +1,5 @@ @page +@using Geta.NotFoundHandler.Core.Redirects; @model Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.DeletedModel @await Component.InvokeAsync("Card", new { message = Model.Message }) @@ -8,7 +9,7 @@ - + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "URL", InternalName = nameof(CustomRedirect.OldUrl), Model.Params }) @@ -45,4 +46,7 @@
URL
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
+ + +
diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs index 38fc2d3..98734a9 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml.cs @@ -1,70 +1,35 @@ using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; -using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; -using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; [Authorize(Constants.PolicyName)] -public class DeletedModel : PageModel +public class DeletedModel : BaseCustomRedirectPageModel { - private readonly IRedirectsService _redirectsService; - - public DeletedModel(IRedirectsService redirectsService) + public DeletedModel(IRedirectsService redirectsService) : base(redirectsService, RedirectState.Deleted, + "There are currently {0} URLs that return a Deleted response.This tells crawlers to remove these URLs from their index. ") { - _redirectsService = redirectsService; } - public string Message { get; set; } - - public CustomRedirectsResult Results { get; set; } - [BindProperty] public DeletedRedirectModel DeletedRedirect { get; set; } - [BindProperty(SupportsGet = true)] - public QueryParams Params { get; set; } - - public void OnGet() - { - Load(); - } - public IActionResult OnPostCreate() { - if (!ModelState.IsValid) + if (ModelState.IsValid) { - Load(); - return Page(); + RedirectsService.AddDeletedRedirect(DeletedRedirect.OldUrl); } - _redirectsService.AddDeletedRedirect(DeletedRedirect.OldUrl); - - return RedirectToPage(); + return LoadPage(); } public IActionResult OnPostDelete(string oldUrl) { - _redirectsService.DeleteByOldUrl(oldUrl); - return RedirectToPage(); - } - - private void Load() - { - Params.QueryState = RedirectState.Deleted; - Params.PageSize ??= 50; - var results = _redirectsService.GetRedirects(Params); - Message = - $"There are currently {results.UnfilteredCount} URLs that return a Deleted response. This tells crawlers to remove these URLs from their index."; - - if (results.TotalCount < results.UnfilteredCount) - { - Message += $"Current filter gives {results.TotalCount}."; - } - Results = results; + RedirectsService.DeleteByOldUrl(oldUrl); + return LoadPage(true); } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml index f266696..29221b3 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml @@ -1,4 +1,5 @@ @page +@using Geta.NotFoundHandler.Core.Redirects; @model Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.IgnoredModel @await Component.InvokeAsync("Card", new { message = Model.Message }) @@ -8,7 +9,7 @@ - + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "URL", InternalName = nameof(CustomRedirect.OldUrl), Model.Params }) @@ -31,4 +32,7 @@
URL
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) + + + \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs index 97177f6..0e75fd8 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml.cs @@ -1,52 +1,21 @@ -using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; -using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; [Authorize(Constants.PolicyName)] -public class IgnoredModel : PageModel +public class IgnoredModel : BaseCustomRedirectPageModel { - private readonly IRedirectsService _redirectsService; - - public IgnoredModel(IRedirectsService redirectsService) + public IgnoredModel(IRedirectsService redirectsService) : base(redirectsService, RedirectState.Ignored, + "There are currently {0} ignored suggestions stored. ") { - _redirectsService = redirectsService; - } - - public string Message { get; set; } - - public CustomRedirectsResult Results { get; set; } - - [BindProperty(SupportsGet = true)] - public QueryParams Params { get; set; } - - public void OnGet() - { - Load(); } public IActionResult OnPostUnignore(string oldUrl) { - _redirectsService.DeleteByOldUrl(oldUrl); - - return RedirectToPage(); - } - - private void Load() - { - Params.QueryState = RedirectState.Ignored; - Params.PageSize ??= 50; - var results = _redirectsService.GetRedirects(Params); - Message = $"There are currently {results.UnfilteredCount} ignored suggestions stored. "; - if (results.TotalCount < results.UnfilteredCount) - { - Message += $"Current filter gives {results.TotalCount}."; - } - Results = results; + RedirectsService.DeleteByOldUrl(oldUrl); + return LoadPage(true); } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml index 546208b..375cb26 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml @@ -5,8 +5,6 @@ @await Component.InvokeAsync("Card", new { message = Model.Message })
- -
@@ -81,4 +79,7 @@ @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
+ + +
\ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs index 8a145ba..89a3653 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs @@ -1,45 +1,22 @@ using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; -using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Redirects; -using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; [Authorize(Constants.PolicyName)] -public class IndexModel : PageModel +public class IndexModel : BaseCustomRedirectPageModel { - private readonly IRedirectsService _redirectsService; - - public IndexModel(IRedirectsService redirectsService) + public IndexModel(IRedirectsService redirectsService) : base(redirectsService, RedirectState.Saved, + "There are currently stored {0} custom redirects. ") { - _redirectsService = redirectsService; } - public string Message { get; set; } - - public CustomRedirectsResult Results { get; set; } - [BindProperty] public RedirectModel CustomRedirect { get; set; } - [BindProperty(SupportsGet = true)] - public QueryParams Params { get; set; } - - public void OnGet() - { - Load(); - } - - public IActionResult OnPost() - { - ModelState.Clear(); - return LoadPage(); - } - public IActionResult OnPostCreate() { if (ModelState.IsValid) @@ -49,7 +26,7 @@ public IActionResult OnPostCreate() CustomRedirect.WildCardSkipAppend, CustomRedirect.RedirectType); - _redirectsService.AddOrUpdate(customRedirect); + RedirectsService.AddOrUpdate(customRedirect); CustomRedirect = new RedirectModel(); } @@ -58,26 +35,7 @@ public IActionResult OnPostCreate() public IActionResult OnPostDelete(string oldUrl) { - _redirectsService.DeleteByOldUrl(oldUrl); - return LoadPage(); - } - - public IActionResult LoadPage() - { - Load(); - return Page(); - } - - private void Load() - { - Params.QueryState = RedirectState.Saved; - Params.PageSize ??= 50; - var results = _redirectsService.GetRedirects(Params); - Message = $"There are currently stored {results.UnfilteredCount} custom redirects. "; - if (results.TotalCount < results.UnfilteredCount) - { - Message += $"Current filter gives {results.TotalCount}."; - } - Results = results; + RedirectsService.DeleteByOldUrl(oldUrl); + return LoadPage(true); } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs new file mode 100644 index 0000000..74bf95c --- /dev/null +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs @@ -0,0 +1,35 @@ +using Geta.NotFoundHandler.Core; +using Geta.NotFoundHandler.Core.Redirects; + +namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; + +public abstract class BaseCustomRedirectPageModel : BaseRedirectPageModel +{ + private readonly RedirectState _redirectState; + private readonly string _messageFormat; + + protected BaseCustomRedirectPageModel(IRedirectsService redirectsService, RedirectState redirectState, string messageFormat) + { + RedirectsService = redirectsService; + _redirectState = redirectState; + _messageFormat = messageFormat; + } + + protected IRedirectsService RedirectsService { get; } + + public CustomRedirectsResult Results { get; set; } + + protected override void Load() + { + Params.SortBy ??= nameof(CustomRedirect.OldUrl); + Params.QueryState = _redirectState; + Params.PageSize ??= 5; + var results = RedirectsService.GetRedirects(Params); + Message = string.Format(_messageFormat, results.UnfilteredCount); + if (results.TotalCount < results.UnfilteredCount) + { + Message += $"Current filter gives {results.TotalCount}."; + } + Results = results; + } +} diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseRedirectPageModel.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseRedirectPageModel.cs new file mode 100644 index 0000000..42c3a7a --- /dev/null +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseRedirectPageModel.cs @@ -0,0 +1,36 @@ +using Geta.NotFoundHandler.Data; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; + +public abstract class BaseRedirectPageModel : PageModel +{ + public string Message { get; set; } + + [BindProperty(SupportsGet = true)] + public QueryParams Params { get; set; } + + public void OnGet() + { + Load(); + } + + public IActionResult OnPost() + { + return LoadPage(true); + } + + protected virtual IActionResult LoadPage(bool clearModelState = false) + { + if (clearModelState) + { + ModelState.Clear(); + } + + Load(); + return Page(); + } + + protected abstract void Load(); +} diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml index 4c57426..2763a14 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml @@ -1,4 +1,5 @@ @page +@using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; @model Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.SuggestionsModel @await Component.InvokeAsync("Card", new { message = Model.Message }) @@ -8,7 +9,7 @@ - + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Old URL", InternalName = nameof(SuggestionRedirectModel.OldUrl), Model.Params }) @@ -19,22 +20,18 @@ @for (var i = 0; i < Model.Items.Count; i++) { var item = Model.Items[i]; - var formId = $"redirect{i}"; @@ -106,4 +98,7 @@
Old URLNew URL
-
- -
+ @item.OldUrl (@item.Count errors)
- - + +
-
@@ -82,22 +79,17 @@
-
- @{ - var ignoreFormId = $"ignore{i}"; - }
-
- -
+
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) + + + \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs index 1b6c54b..50129cd 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs @@ -3,16 +3,14 @@ using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Suggestions; -using Geta.NotFoundHandler.Data; using Geta.NotFoundHandler.Infrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; [Authorize(Constants.PolicyName)] -public class SuggestionsModel : PageModel +public class SuggestionsModel : BaseRedirectPageModel { private readonly ISuggestionService _suggestionService; @@ -21,45 +19,35 @@ public SuggestionsModel(ISuggestionService suggestionService) _suggestionService = suggestionService; } - public string Message { get; set; } - public SuggestionRedirectsResult Results { get; set; } public IList Items { get; set; } = Enumerable.Empty().ToList(); - [BindProperty(SupportsGet = true)] - public QueryParams Params { get; set; } - - public void OnGet() - { - Load(); - } - - public IActionResult OnPostCreate(Dictionary items) + public IActionResult OnPostCreate(Dictionary items, int index) { - if (!ModelState.IsValid) + ModelState.Clear(); + if (items.ContainsKey(index)) { - Load(); - return Page(); + var item = items[index]; + if (TryValidateModel(item, $"{nameof(items)}[{index}]")) + { + _suggestionService.AddRedirect(new SuggestionRedirect(item.OldUrl, item.NewUrl)); + } } - var item = items.First().Value; - - _suggestionService.AddRedirect(new SuggestionRedirect(item.OldUrl, item.NewUrl)); - - return RedirectToPage(); + return LoadPage(); } public IActionResult OnPostIgnore(string oldUrl) { _suggestionService.IgnoreSuggestion(oldUrl); - - return RedirectToPage(); + return LoadPage(true); } - private void Load() + protected override void Load() { - Params.PageSize ??= 50; + Params.SortBy ??= nameof(SuggestionRedirectModel.OldUrl); + Params.PageSize ??= 5; var results = _suggestionService.GetSummaries(Params); var redirectModels = results.Suggestions.Select(x => new SuggestionRedirectModel { diff --git a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css index 5d9f508..e1b4e19 100644 --- a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css +++ b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/css/dashboard.css @@ -124,13 +124,13 @@ } .sortable-header svg { - color: gray; + color: lightgray; } -.sortable-header.current { +.sortable-header.current, .sortable-header:hover { text-decoration: underline; } -.sortable-header.current svg { +.sortable-header.current svg, .sortable-header:hover svg { color: black; } diff --git a/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml b/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml index acce988..7e45bbc 100644 --- a/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml +++ b/src/Geta.NotFoundHandler.Optimizely/Geta.NotFoundHandler.Optimizely.Views/Views/Shared/_ShellLayout.cshtml @@ -10,7 +10,12 @@ NotFound handler From 377b3f8958da19ded8db00fde5133eefe62611bf Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Thu, 9 Feb 2023 00:01:19 +0100 Subject: [PATCH 05/13] Restore default page size --- .../Pages/Infrastructure/BaseCustomRedirectPageModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs index 74bf95c..c9c9b42 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/BaseCustomRedirectPageModel.cs @@ -23,7 +23,7 @@ protected override void Load() { Params.SortBy ??= nameof(CustomRedirect.OldUrl); Params.QueryState = _redirectState; - Params.PageSize ??= 5; + Params.PageSize ??= 50; var results = RedirectsService.GetRedirects(Params); Message = string.Format(_messageFormat, results.UnfilteredCount); if (results.TotalCount < results.UnfilteredCount) From 952de2ea14c58f7bda7e6b9245a082a636c081de Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Thu, 9 Feb 2023 09:45:31 +0100 Subject: [PATCH 06/13] #13 Added confirmation message --- .../Pages/Components/Pager/Default.cshtml | 6 +++--- .../Pages/Components/SortableHeader/Default.cshtml | 4 ++-- .../GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml | 4 ++-- .../Pages/Deleted.cshtml.cs | 4 ++++ .../GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml | 4 ++-- .../Pages/Ignored.cshtml.cs | 1 + .../GetaNotFoundHandlerAdmin/Pages/Index.cshtml | 4 ++-- .../GetaNotFoundHandlerAdmin/Pages/Index.cshtml.cs | 3 +++ .../Pages/Infrastructure/BaseRedirectPageModel.cs | 1 + .../Pages/Suggestions.cshtml | 4 ++-- .../Pages/Suggestions.cshtml.cs | 2 ++ .../Pages/_ViewImports.cshtml | 8 ++++++-- .../GetaNotFoundHandlerAdmin/css/dashboard.css | 10 +++++++++- .../GetaNotFoundHandlerAdmin/js/dashboard.js | 14 +++++++------- 14 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml index b604acc..bfeee13 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml @@ -3,7 +3,7 @@ \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml index 64ace5c..dd9ce45 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Deleted.cshtml @@ -5,6 +5,8 @@ @await Component.InvokeAsync("Card", new { message = Model.OperationMessage, cardType = CardType.Success }) + +
@@ -46,7 +48,4 @@
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
- - - diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml index 97deef6..8a20176 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Ignored.cshtml @@ -5,6 +5,8 @@ @await Component.InvokeAsync("Card", new { message = Model.OperationMessage, cardType = CardType.Success })
+ +
@@ -32,7 +34,4 @@
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
- - -
\ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml index d6f010c..85c56af 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml @@ -5,6 +5,8 @@ @await Component.InvokeAsync("Card", new { message = Model.OperationMessage, cardType = CardType.Success })
+ +
@@ -79,7 +81,4 @@ @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
- - -
\ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml index 459c7c0..5f9c925 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml @@ -5,6 +5,8 @@ @await Component.InvokeAsync("Card", new { message = Model.OperationMessage, cardType = CardType.Success })
+ +
@@ -98,7 +100,4 @@
@await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount })
- - -
\ No newline at end of file From 4f0443d837571c88a28fc85f6dada2fa6ab8b576 Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Tue, 14 Feb 2023 13:56:17 +0100 Subject: [PATCH 08/13] Fix pagination --- .../Data/SqlSuggestionRepository.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs index 8e19b4e..4e9e545 100644 --- a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs @@ -31,21 +31,23 @@ public SuggestionRedirectsResult GetSummaries(QueryParams query) var suffixString = GetSuffixString(query, parameters, out var isPaginated); + const string groupBy = @" + GROUP BY [OldUrl]"; + var dataTable = _dataExecutor.ExecuteQuery( - $@"SELECT [OldUrl], COUNT(*) as Requests FROM {SuggestionsTable}{whereString} - GROUP BY [OldUrl]{suffixString}", + $"SELECT [OldUrl], COUNT(*) as Requests FROM {SuggestionsTable}{whereString}{groupBy}{suffixString}", parameters.ToArray()); var items = CreateSuggestionSummaries(dataTable); var totalCount = items.Count; if (isPaginated) { - totalCount = _dataExecutor.ExecuteScalar($"SELECT COUNT(*) FROM {SuggestionsTable}"); + totalCount = _dataExecutor.ExecuteScalar($@"SELECT COUNT(*) FROM {SuggestionsTable}{groupBy}"); } var filteredCount = totalCount; if (!string.IsNullOrWhiteSpace(whereString)) { - filteredCount = _dataExecutor.ExecuteScalar($"SELECT COUNT(*) FROM {SuggestionsTable}{whereString}", parameters.ToArray()); + filteredCount = _dataExecutor.ExecuteScalar($@"SELECT COUNT(*) FROM {SuggestionsTable}{whereString}{groupBy}", parameters.ToArray()); } return new SuggestionRedirectsResult(items, totalCount, filteredCount); From 3fc6f10fa87f11fe26a4090278151f142548bb8b Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Tue, 14 Feb 2023 14:15:24 +0100 Subject: [PATCH 09/13] Fix pagination count + pagesize for suggestions --- .../GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs | 2 +- src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs index aba32fc..a96ac9c 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml.cs @@ -49,7 +49,7 @@ public IActionResult OnPostIgnore(string oldUrl) protected override void Load() { Params.SortBy ??= nameof(SuggestionRedirectModel.OldUrl); - Params.PageSize ??= 5; + Params.PageSize ??= 50; var results = _suggestionService.GetSummaries(Params); var redirectModels = results.Suggestions.Select(x => new SuggestionRedirectModel { diff --git a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs index 4e9e545..038f040 100644 --- a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs @@ -31,23 +31,23 @@ public SuggestionRedirectsResult GetSummaries(QueryParams query) var suffixString = GetSuffixString(query, parameters, out var isPaginated); - const string groupBy = @" + const string GroupByOldUrl = @" GROUP BY [OldUrl]"; var dataTable = _dataExecutor.ExecuteQuery( - $"SELECT [OldUrl], COUNT(*) as Requests FROM {SuggestionsTable}{whereString}{groupBy}{suffixString}", + $"SELECT [OldUrl], COUNT(*) as Requests FROM {SuggestionsTable}{whereString}{GroupByOldUrl}{suffixString}", parameters.ToArray()); var items = CreateSuggestionSummaries(dataTable); var totalCount = items.Count; if (isPaginated) { - totalCount = _dataExecutor.ExecuteScalar($@"SELECT COUNT(*) FROM {SuggestionsTable}{groupBy}"); + totalCount = _dataExecutor.ExecuteScalar($"SELECT DISTINCT COUNT(*) OVER () FROM {SuggestionsTable}{GroupByOldUrl}"); } var filteredCount = totalCount; if (!string.IsNullOrWhiteSpace(whereString)) { - filteredCount = _dataExecutor.ExecuteScalar($@"SELECT COUNT(*) FROM {SuggestionsTable}{whereString}{groupBy}", parameters.ToArray()); + filteredCount = _dataExecutor.ExecuteScalar($"SELECT DISTINCT COUNT(*) OVER () FROM {SuggestionsTable}{whereString}{GroupByOldUrl}", parameters.ToArray()); } return new SuggestionRedirectsResult(items, totalCount, filteredCount); From 6298f181e995e57c98695db439b5c5b1199a0771 Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Sat, 18 Feb 2023 20:59:24 +0100 Subject: [PATCH 10/13] Separate GET / POST --- .../Pages/Components/Pager/Default.cshtml | 9 +- .../Pages/Components/Pager/PagerViewModel.cs | 6 +- .../Components/SortableHeader/Default.cshtml | 2 +- .../Pages/Deleted.cshtml | 79 ++++---- .../Pages/Ignored.cshtml | 57 +++--- .../Pages/Index.cshtml | 117 ++++++------ .../Infrastructure/HtmlHelperExtensions.cs | 54 ++++++ .../Pages/Suggestions.cshtml | 174 +++++++++--------- .../Pages/_ViewImports.cshtml | 3 +- .../GetaNotFoundHandlerAdmin/js/dashboard.js | 48 +++-- src/Geta.NotFoundHandler/Data/QueryParams.cs | 10 +- 11 files changed, 320 insertions(+), 239 deletions(-) create mode 100644 src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/HtmlHelperExtensions.cs diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml index b9e5159..9fc4d04 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml @@ -3,24 +3,23 @@ \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewModel.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewModel.cs index 1ec85ce..0559660 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewModel.cs +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/PagerViewModel.cs @@ -5,15 +5,19 @@ namespace Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components public class PagerViewModel { public bool HasPreviousPage { get; set; } + public bool HasNextPage { get; set; } + public int PageNumber { get; set; } + public int PageCount { get; set; } + public string QueryString { get; set; } public string PageUrl(int page) { var qs = HttpUtility.ParseQueryString(QueryString); - qs["page"] = page.ToString(); + qs["p"] = page.ToString(); return $"?{qs}"; } } diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml index 8058368..4e4138b 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/SortableHeader/Default.cshtml @@ -9,7 +9,7 @@ - + + + + } + + + + @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) + \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml index 85c56af..1ba235b 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Index.cshtml @@ -1,12 +1,9 @@ @page @model IndexModel - @await Component.InvokeAsync("Card", new { message = Model.Message }) @await Component.InvokeAsync("Card", new { message = Model.OperationMessage, cardType = CardType.Success }) -
- - +
@@ -18,67 +15,69 @@ search
+ @Html.HiddenForQueryParams() +
-
- - - - @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Old URL", InternalName = nameof(CustomRedirect.OldUrl), Model.Params }) - @await Component.InvokeAsync("SortableHeader", new { DisplayName = "New URL", InternalName = nameof(CustomRedirect.NewUrl), Model.Params }) - @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Wildcard", InternalName = nameof(CustomRedirect.WildCardSkipAppend), Model.Params, AdditionalClass = "col-1 text-center" }) - @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Redirect type", InternalName = nameof(CustomRedirect.RedirectType), Model.Params, AdditionalClass = "col-1" }) - - - - - - - +
+
- - - - - -
+ + + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Old URL", InternalName = nameof(CustomRedirect.OldUrl), Model.Params }) + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "New URL", InternalName = nameof(CustomRedirect.NewUrl), Model.Params }) + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Wildcard", InternalName = nameof(CustomRedirect.WildCardSkipAppend), Model.Params, AdditionalClass = "col-1 text-center" }) + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Redirect type", InternalName = nameof(CustomRedirect.RedirectType), Model.Params, AdditionalClass = "col-1" }) + + + + + @Html.HiddenForQueryParams() + + + + + + + + + @foreach (var item in Model.Results.Redirects) + { + + + - + - @foreach (var item in Model.Results.Redirects) - { - - - - - - - - } - -
+ + + + + + + + + + +
+ +
+
@item.OldUrl@item.NewUrl - - - + @await Component.InvokeAsync("CheckboxReadonly", new { isChecked = item.WildCardSkipAppend }) @item.RedirectType
-
@item.OldUrl@item.NewUrl - @await Component.InvokeAsync("CheckboxReadonly", new { isChecked = item.WildCardSkipAppend }) - @item.RedirectType -
- -
-
- @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) -
- \ No newline at end of file + } + + + + @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) + \ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/HtmlHelperExtensions.cs b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/HtmlHelperExtensions.cs new file mode 100644 index 0000000..eae9ee0 --- /dev/null +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Infrastructure/HtmlHelperExtensions.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Linq.Expressions; +using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; +using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.Extensions.DependencyInjection; + +namespace Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Infrastructure +{ + public static class HtmlHelperExtensions + { + private static readonly ConcurrentDictionary<(Type, string), string> QueryNameDictionary = new(); + + public static IHtmlContent HiddenForQueryParams(this IHtmlHelper htmlHelper) + where T : BaseRedirectPageModel + { + var htmlContentBuilder = new HtmlContentBuilder(); + htmlContentBuilder.AppendHiddenInputFor(htmlHelper, x => x.Params.QueryText); + htmlContentBuilder.AppendHiddenInputFor(htmlHelper, x => x.Params.Page); + htmlContentBuilder.AppendHiddenInputFor(htmlHelper, x => x.Params.SortBy); + htmlContentBuilder.AppendHiddenInputFor(htmlHelper, x => x.Params.SortDirection); + return htmlContentBuilder; + } + + public static string NameQueryFor(this IHtmlHelper html, Expression> expression) + { + ArgumentNullException.ThrowIfNull(html); + ArgumentNullException.ThrowIfNull(expression); + + return QueryNameDictionary.GetOrAdd((typeof(TModel), expression.ToString()), _ => + { + var modelExpression = html.ViewContext.HttpContext.RequestServices.GetRequiredService().CreateModelExpression(html.ViewData, expression); + + if (modelExpression.Metadata is DefaultModelMetadata defaultMetadata && defaultMetadata.Attributes.Attributes.OfType().FirstOrDefault() is IModelNameProvider attribute + && attribute.Name is string queryName && !string.IsNullOrEmpty(queryName)) + { + return queryName; + } + + return html.NameFor(expression); + }); + } + + private static void AppendHiddenInputFor(this IHtmlContentBuilder htmlContentBuilder, IHtmlHelper htmlHelper, Expression> expression) + { + htmlContentBuilder.AppendHtml(htmlHelper.Hidden(htmlHelper.NameQueryFor(expression), htmlHelper.DisplayTextFor(expression))); + } + } +} diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml index 5f9c925..cb6ac4f 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Suggestions.cshtml @@ -4,100 +4,102 @@ @await Component.InvokeAsync("Card", new { message = Model.Message }) @await Component.InvokeAsync("Card", new { message = Model.OperationMessage, cardType = CardType.Success }) -
- - -
- - - - @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Old URL", InternalName = nameof(SuggestionRedirectModel.OldUrl), Model.Params }) - - - - - - - - @for (var i = 0; i < Model.Items.Count; i++) - { - var item = Model.Items[i]; - - + + + } + + +
New URL
- + + @Html.HiddenForQueryParams() + + +
+ + + + @await Component.InvokeAsync("SortableHeader", new { DisplayName = "Old URL", InternalName = nameof(SuggestionRedirectModel.OldUrl), Model.Params }) + + + + + + + + @Html.HiddenForQueryParams() + + @for (var i = 0; i < Model.Items.Count; i++) + { + var item = Model.Items[i]; + + - - - + + + - - - } - -
New URL
+ @item.OldUrl (@item.Count errors) - - - - -
- -
-
- @{ - var referersModalId = $"referers{i}"; - var modalTitleId = $"modalTitle{i}"; - } - + + + +
+ +
+
+ @{ + var referersModalId = $"referers{i}"; + var modalTitleId = $"modalTitle{i}"; + } + -
- -
-
-
- -
-
- @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) -
- \ No newline at end of file + +
+ +
+
+
+ +
+
+ @await Component.InvokeAsync(typeof(Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Pager.PagerViewComponent), new { Model.Params.Page, Model.Params.PageSize, Model.Results.TotalCount }) +
\ No newline at end of file diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/_ViewImports.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/_ViewImports.cshtml index b19742d..7b204be 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/_ViewImports.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/_ViewImports.cshtml @@ -1,4 +1,5 @@ -@using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Card; +@using Geta.NotFoundHandler.Admin.Areas.GetaNotFoundHandlerAdmin.Pages.Infrastructure; +@using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Components.Card; @using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin.Models; @using Geta.NotFoundHandler.Admin.Pages.Geta.NotFoundHandler.Admin; @using Geta.NotFoundHandler.Core.Redirects diff --git a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js index f7873a7..5d97761 100644 --- a/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js +++ b/src/Geta.NotFoundHandler.Admin/wwwroot/GetaNotFoundHandlerAdmin/js/dashboard.js @@ -35,25 +35,43 @@ }); } - function addSortableHeaders() { - var buttons = document.querySelectorAll('form .sortable-header button'); + function addFormTriggers() { + var form = document.getElementById("tableQueryState"); + if (!form) { return; } + + var buttons = form.parentElement.querySelectorAll('.sortable-header button'); buttons.forEach(function (button) { - button.addEventListener('click', - function (e) { - e.preventDefault(); - var header = button.closest(".sortable-header"); - var form = header.closest("form"); - var sortBy = form.querySelector("input[name='sort-by']"); - var sortDirection = form.querySelector("input[name='sort-direction']"); - if (sortBy) sortBy.value = header.dataset.sortBy; - if (sortDirection) sortDirection.value = header.dataset.sortDirection; - form.action = button.formAction; - form.submit(); - }); + button.addEventListener('click', function (e) { + e.preventDefault(); + var header = button.closest(".sortable-header"); + var sortBy = form.querySelector("input[name='sb']"); + var sortDirection = form.querySelector("input[name='sd']"); + if (sortBy) sortBy.value = header.dataset.sortBy; + if (sortDirection) sortDirection.value = header.dataset.sortDirection; + form.submit(); + }); }); + + var pageLinks = form.parentElement.querySelectorAll('.page-link[name="p"]'); + pageLinks.forEach(function (pageLink) { + pageLink.addEventListener('click', function (e) { + e.preventDefault(); + var page = form.querySelector("input[name='p']"); + if (page) page.value = pageLink.value; + form.submit(); + }); + }); + + var searchButton = form.querySelector(".search-button"); + if (searchButton) { + var page = form.querySelector("input[name='p']"); + if (page) { + page.value = 1; + } + } } clearInput(); confirmSubmit(); - addSortableHeaders(); + addFormTriggers(); })() diff --git a/src/Geta.NotFoundHandler/Data/QueryParams.cs b/src/Geta.NotFoundHandler/Data/QueryParams.cs index fa818ed..bb4137a 100644 --- a/src/Geta.NotFoundHandler/Data/QueryParams.cs +++ b/src/Geta.NotFoundHandler/Data/QueryParams.cs @@ -9,21 +9,21 @@ namespace Geta.NotFoundHandler.Data { public class QueryParams { - [FromForm(Name = "q")] + [BindProperty(Name = "q", SupportsGet = true)] public string QueryText { get; set; } = string.Empty; public RedirectState? QueryState { get; set; } - [FromForm(Name = "page")] + [BindProperty(Name = "p", SupportsGet = true)] public int Page { get; set; } = 1; - [FromForm(Name = "page-size")] + [BindProperty(Name = "ps", SupportsGet = true)] public int? PageSize { get; set; } - [FromForm(Name = "sort-by")] + [BindProperty(Name = "sb", SupportsGet = true)] public string SortBy { get; set; } - [FromForm(Name = "sort-direction")] + [BindProperty(Name = "sd", SupportsGet = true)] public SortOrder SortDirection { get; set; } = SortOrder.Ascending; } } From 716587300091292360e4e7537abc6832436fa0dc Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Sat, 18 Feb 2023 21:43:19 +0100 Subject: [PATCH 11/13] Keep public interfaces --- .../Core/Redirects/DefaultRedirectsService.cs | 20 +++++++++++++++++++ .../Core/Redirects/IRedirectsService.cs | 13 ++++++++++++ .../Suggestions/DefaultSuggestionService.cs | 6 ++++++ .../Core/Suggestions/ISuggestionService.cs | 4 +--- .../Data/IRedirectLoader.cs | 6 ++++++ .../Data/ISuggestionLoader.cs | 6 ++++++ .../Data/SqlRedirectRepository.cs | 10 ++++++++++ .../Data/SqlSuggestionRepository.cs | 7 +++++++ .../Geta.NotFoundHandler.csproj | 1 + 9 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs b/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs index e86bb80..25b2cbe 100644 --- a/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs +++ b/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs @@ -29,6 +29,26 @@ public IEnumerable GetAll() return _redirectLoader.GetAll(); } + public IEnumerable GetSaved() + { + return GetRedirects(new QueryParams() { QueryState = RedirectState.Saved }).Redirects; + } + + public IEnumerable GetIgnored() + { + return GetRedirects(new QueryParams() { QueryState = RedirectState.Ignored }).Redirects; + } + + public IEnumerable GetDeleted() + { + return GetRedirects(new QueryParams() { QueryState = RedirectState.Deleted }).Redirects; + } + + public IEnumerable Search(string searchText) + { + return GetRedirects(new QueryParams() { QueryText = searchText }).Redirects; + } + public CustomRedirectsResult GetRedirects(QueryParams query) { return _redirectLoader.GetRedirects(query); diff --git a/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs b/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs index af47d85..c949587 100644 --- a/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs +++ b/src/Geta.NotFoundHandler/Core/Redirects/IRedirectsService.cs @@ -1,6 +1,7 @@ // Copyright (c) Geta Digital. All rights reserved. // Licensed under Apache-2.0. See the LICENSE file in the project root for more information +using System; using System.Collections.Generic; using Geta.NotFoundHandler.Data; @@ -10,6 +11,18 @@ public interface IRedirectsService { IEnumerable GetAll(); + [Obsolete($"Use {nameof(GetRedirects)} instead")] + IEnumerable GetSaved(); + + [Obsolete($"Use {nameof(GetRedirects)} instead")] + IEnumerable GetIgnored(); + + [Obsolete($"Use {nameof(GetRedirects)} instead")] + IEnumerable GetDeleted(); + + [Obsolete($"Use {nameof(GetRedirects)} instead")] + IEnumerable Search(string searchText); + CustomRedirectsResult GetRedirects(QueryParams query); void AddOrUpdate(CustomRedirect redirect); diff --git a/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs b/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs index f396807..1fc25b0 100644 --- a/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs +++ b/src/Geta.NotFoundHandler/Core/Suggestions/DefaultSuggestionService.cs @@ -3,6 +3,7 @@ using Geta.NotFoundHandler.Core.Redirects; using Geta.NotFoundHandler.Data; +using X.PagedList; namespace Geta.NotFoundHandler.Core.Suggestions { @@ -22,6 +23,11 @@ public DefaultSuggestionService( _suggestionRepository = suggestionRepository; } + public IPagedList GetSummaries(int page, int pageSize) + { + return _suggestionLoader.GetSummaries(page, pageSize); + } + public SuggestionRedirectsResult GetSummaries(QueryParams query) { return _suggestionLoader.GetSummaries(query); diff --git a/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs b/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs index 63e107b..1e68b61 100644 --- a/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs +++ b/src/Geta.NotFoundHandler/Core/Suggestions/ISuggestionService.cs @@ -5,10 +5,8 @@ namespace Geta.NotFoundHandler.Core.Suggestions { - public interface ISuggestionService + public interface ISuggestionService : ISuggestionLoader { - SuggestionRedirectsResult GetSummaries(QueryParams query); - void AddRedirect(SuggestionRedirect suggestionRedirect); void IgnoreSuggestion(string oldUrl); diff --git a/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs b/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs index 56648cc..a954344 100644 --- a/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs +++ b/src/Geta.NotFoundHandler/Data/IRedirectLoader.cs @@ -14,6 +14,12 @@ public interface IRedirectLoader IEnumerable GetAll(); + [Obsolete($"Use {nameof(GetRedirects)} instead")] + IEnumerable GetByState(RedirectState state); + + [Obsolete($"Use {nameof(GetRedirects)} instead")] + IEnumerable Find(string searchText); + CustomRedirectsResult GetRedirects(QueryParams query); CustomRedirect Get(Guid id); diff --git a/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs b/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs index 7eb2e9f..62fdc30 100644 --- a/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs +++ b/src/Geta.NotFoundHandler/Data/ISuggestionLoader.cs @@ -1,12 +1,18 @@ // Copyright (c) Geta Digital. All rights reserved. // Licensed under Apache-2.0. See the LICENSE file in the project root for more information +using System; using Geta.NotFoundHandler.Core; +using Geta.NotFoundHandler.Core.Suggestions; +using X.PagedList; namespace Geta.NotFoundHandler.Data { public interface ISuggestionLoader { + [Obsolete($"Please use other overload for {nameof(GetSummaries)}")] + IPagedList GetSummaries(int page, int pageSize); + SuggestionRedirectsResult GetSummaries(QueryParams query); } } diff --git a/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs b/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs index 4d30050..507c90a 100644 --- a/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlRedirectRepository.cs @@ -114,6 +114,16 @@ public IEnumerable GetAll() return ToCustomRedirects(dataTable); } + public IEnumerable GetByState(RedirectState state) + { + return GetRedirects(new QueryParams() { QueryState = state }).Redirects; + } + + public IEnumerable Find(string searchText) + { + return GetRedirects(new QueryParams() { QueryText = searchText }).Redirects; + } + public CustomRedirectsResult GetRedirects(QueryParams query) { var parameters = new List(); diff --git a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs index 038f040..783495a 100644 --- a/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs +++ b/src/Geta.NotFoundHandler/Data/SqlSuggestionRepository.cs @@ -9,6 +9,7 @@ using System.Text.RegularExpressions; using Geta.NotFoundHandler.Core; using Geta.NotFoundHandler.Core.Suggestions; +using X.PagedList; namespace Geta.NotFoundHandler.Data { @@ -23,6 +24,12 @@ public SqlSuggestionRepository(IDataExecutor dataExecutor) _dataExecutor = dataExecutor; } + public IPagedList GetSummaries(int page, int pageSize) + { + var result = GetSummaries(new QueryParams() { Page = page, PageSize = pageSize }); + return new StaticPagedList(result.Suggestions, page, pageSize, result.TotalCount); + } + public SuggestionRedirectsResult GetSummaries(QueryParams query) { var parameters = new List(); diff --git a/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj b/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj index 39d5700..5ae51fb 100644 --- a/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj +++ b/src/Geta.NotFoundHandler/Geta.NotFoundHandler.csproj @@ -27,6 +27,7 @@ + From a24fec0518119dc0b2d6514258e35594f84f0ac1 Mon Sep 17 00:00:00 2001 From: Magnus Ellinge Date: Sat, 18 Feb 2023 22:08:42 +0100 Subject: [PATCH 12/13] Keep previous functions with querystrings for page/pagesize --- .../Pages/Components/Pager/Default.cshtml | 8 ++++---- .../Pages/Components/Pager/PagerViewModel.cs | 9 --------- .../Pages/Infrastructure/BaseRedirectPageModel.cs | 6 +----- .../GetaNotFoundHandlerAdmin/js/dashboard.js | 12 ++++++------ src/Geta.NotFoundHandler/Data/QueryParams.cs | 12 ++++++------ .../Web/FromFormOrQueryAttribute.cs | 15 +++++++++++++++ 6 files changed, 32 insertions(+), 30 deletions(-) create mode 100644 src/Geta.NotFoundHandler/Infrastructure/Web/FromFormOrQueryAttribute.cs diff --git a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml index 9fc4d04..e644243 100644 --- a/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml +++ b/src/Geta.NotFoundHandler.Admin/Areas/GetaNotFoundHandlerAdmin/Pages/Components/Pager/Default.cshtml @@ -3,21 +3,21 @@