From ed353461dad78bab6b0e004d27bdeaabc47d1b0d Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sun, 9 Feb 2025 13:02:07 -0500 Subject: [PATCH] enhance purge job to trim broken urls based on retention policy --- .../Modules/Admin/UrlMappings/Index.razor | 22 ++++++++++++++++--- .../Modules/Admin/UrlMappings/Index.resx | 6 +++++ Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs | 17 ++++++++++++++ .../Interfaces/IUrlMappingRepository.cs | 1 + .../Repository/UrlMappingRepository.cs | 19 ++++++++++++++++ 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor b/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor index bae495fb..75a4c845 100644 --- a/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor +++ b/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor @@ -3,6 +3,7 @@ @inject NavigationManager NavigationManager @inject IUrlMappingService UrlMappingService @inject ISiteService SiteService +@inject ISettingService SettingService @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer @@ -62,7 +63,13 @@ else - +
+ +
+ +
+
+
@@ -73,6 +80,7 @@ else private bool _mapped = true; private List _urlMappings; private string _capturebrokenurls; + private int _retention = 30; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; @@ -80,7 +88,10 @@ else { await GetUrlMappings(); _capturebrokenurls = PageState.Site.CaptureBrokenUrls.ToString(); - } + + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + _retention = int.Parse(SettingService.GetSetting(settings, "UrlMappingRetention", "30")); + } private async void MappedChanged(ChangeEventArgs e) { @@ -124,7 +135,12 @@ else var site = PageState.Site; site.CaptureBrokenUrls = bool.Parse(_capturebrokenurls); await SiteService.UpdateSiteAsync(site); - AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); + + var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); + settings = SettingService.SetSetting(settings, "UrlMappingRetention", _retention.ToString(), true); + await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); + + AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); } catch (Exception ex) { diff --git a/Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx b/Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx index 188c09e3..49b517db 100644 --- a/Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx @@ -162,4 +162,10 @@ Edit + + Retention (Days): + + + Number of days of broken urls to retain + \ No newline at end of file diff --git a/Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs b/Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs index 28a13387..07504f1e 100644 --- a/Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs +++ b/Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs @@ -32,6 +32,7 @@ namespace Oqtane.Infrastructure var logRepository = provider.GetRequiredService(); var visitorRepository = provider.GetRequiredService(); var notificationRepository = provider.GetRequiredService(); + var urlMappingRepository = provider.GetRequiredService(); var installationManager = provider.GetRequiredService(); // iterate through sites for current tenant @@ -95,6 +96,22 @@ namespace Oqtane.Infrastructure { log += $"Error Purging Notifications - {ex.Message}
"; } + + // purge broken urls + retention = 30; // 30 days + if (settings.ContainsKey("UrlMappingRetention") && !string.IsNullOrEmpty(settings["UrlMappingRetention"])) + { + retention = int.Parse(settings["UrlMappingRetention"]); + } + try + { + count = urlMappingRepository.DeleteUrlMappings(site.SiteId, retention); + log += count.ToString() + " Broken Urls Purged
"; + } + catch (Exception ex) + { + log += $"Error Purging Broken Urls - {ex.Message}
"; + } } // register assemblies diff --git a/Oqtane.Server/Repository/Interfaces/IUrlMappingRepository.cs b/Oqtane.Server/Repository/Interfaces/IUrlMappingRepository.cs index f954d87b..ca056484 100644 --- a/Oqtane.Server/Repository/Interfaces/IUrlMappingRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IUrlMappingRepository.cs @@ -13,5 +13,6 @@ namespace Oqtane.Repository UrlMapping GetUrlMapping(int urlMappingId, bool tracking); UrlMapping GetUrlMapping(int siteId, string url); void DeleteUrlMapping(int urlMappingId); + int DeleteUrlMappings(int siteId, int age); } } diff --git a/Oqtane.Server/Repository/UrlMappingRepository.cs b/Oqtane.Server/Repository/UrlMappingRepository.cs index 71c80e7c..a4086b32 100644 --- a/Oqtane.Server/Repository/UrlMappingRepository.cs +++ b/Oqtane.Server/Repository/UrlMappingRepository.cs @@ -101,5 +101,24 @@ namespace Oqtane.Repository db.UrlMapping.Remove(urlMapping); db.SaveChanges(); } + + public int DeleteUrlMappings(int siteId, int age) + { + using var db = _dbContextFactory.CreateDbContext(); + // delete notifications in batches of 100 records + var count = 0; + var purgedate = DateTime.UtcNow.AddDays(-age); + var urlMappings = db.UrlMapping.Where(item => item.SiteId == siteId && string.IsNullOrEmpty(item.MappedUrl) && item.RequestedOn < purgedate) + .OrderBy(item => item.RequestedOn).Take(100).ToList(); + while (urlMappings.Count > 0) + { + count += urlMappings.Count; + db.UrlMapping.RemoveRange(urlMappings); + db.SaveChanges(); + urlMappings = db.UrlMapping.Where(item => item.SiteId == siteId && string.IsNullOrEmpty(item.MappedUrl) && item.RequestedOn < purgedate) + .OrderBy(item => item.RequestedOn).Take(100).ToList(); + } + return count; + } } }