diff --git a/Oqtane.Client/Modules/Admin/Logs/Index.razor b/Oqtane.Client/Modules/Admin/Logs/Index.razor
index cf2f7cbc..8d180f13 100644
--- a/Oqtane.Client/Modules/Admin/Logs/Index.razor
+++ b/Oqtane.Client/Modules/Admin/Logs/Index.razor
@@ -86,47 +86,48 @@ else
-
+
+
}
@code {
- private string _level = "-";
- private string _function = "-";
- private string _rows = "10";
- private int _page = 1;
- private List _logs;
- private int _retention = 30;
+ private string _level = "-";
+ private string _function = "-";
+ private string _rows = "10";
+ private int _page = 1;
+ private List _logs;
+ private int _retention = 30;
- public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
- public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
+ public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
+ public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
- protected override async Task OnParametersSetAsync()
- {
- try
- {
- if (UrlParameters.ContainsKey("level"))
- {
- _level = UrlParameters["level"];
- }
- if (UrlParameters.ContainsKey("function"))
- {
- _function = UrlParameters["function"];
- }
- if (UrlParameters.ContainsKey("rows"))
- {
- _rows = UrlParameters["rows"];
- }
- if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
- {
- _page = page;
- }
+ protected override async Task OnParametersSetAsync()
+ {
+ try
+ {
+ if (UrlParameters.ContainsKey("level"))
+ {
+ _level = UrlParameters["level"];
+ }
+ if (UrlParameters.ContainsKey("function"))
+ {
+ _function = UrlParameters["function"];
+ }
+ if (UrlParameters.ContainsKey("rows"))
+ {
+ _rows = UrlParameters["rows"];
+ }
+ if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
+ {
+ _page = page;
+ }
await GetLogs();
- var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
- _retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30"));
+ var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
+ _retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30"));
}
catch (Exception ex)
{
@@ -213,22 +214,37 @@ else
return classname;
}
- private async Task SaveSiteSettings()
- {
- try
- {
- var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
- settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true);
+ private async Task SaveSiteSettings()
+ {
+ try
+ {
+ var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
+ settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
- AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
- }
- catch (Exception ex)
- {
- await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
- AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
- }
- }
+ AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
+ }
+ }
+
+ private async Task ClearLogs()
+ {
+ try
+ {
+ await LogService.ClearLogsAsync(PageState.Site.SiteId);
+ await GetLogs();
+ StateHasChanged();
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Clearing Logs {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.ClearLogs"], MessageType.Error);
+ }
+ }
private void OnPageChange(int page)
{
diff --git a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx
index dfd55880..27b3c4c7 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx
@@ -210,4 +210,13 @@
Settings Saved Successfully
+
+ Clear Logs
+
+
+ Are you sure you wish to clear all the logs?
+
+
+ Error Clearing Logs
+
\ No newline at end of file
diff --git a/Oqtane.Client/Services/Interfaces/ILogService.cs b/Oqtane.Client/Services/Interfaces/ILogService.cs
index 2a821359..dea788bc 100644
--- a/Oqtane.Client/Services/Interfaces/ILogService.cs
+++ b/Oqtane.Client/Services/Interfaces/ILogService.cs
@@ -29,6 +29,13 @@ namespace Oqtane.Services
///
Task GetLogAsync(int logId);
+ ///
+ /// Clear the entire logs of the given site.
+ ///
+ ///
+ ///
+ Task ClearLogsAsync(int siteId);
+
///
/// Creates a new log entry
///
diff --git a/Oqtane.Client/Services/LogService.cs b/Oqtane.Client/Services/LogService.cs
index e575694e..26c37038 100644
--- a/Oqtane.Client/Services/LogService.cs
+++ b/Oqtane.Client/Services/LogService.cs
@@ -35,6 +35,11 @@ namespace Oqtane.Services
return await GetJsonAsync($"{Apiurl}/{logId}");
}
+ public async Task ClearLogsAsync(int siteId)
+ {
+ await DeleteAsync($"{Apiurl}?siteid={siteId}");
+ }
+
public async Task Log(int? pageId, int? moduleId, int? userId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args)
{
await Log(null, pageId, moduleId, userId, category, feature, function, level, exception, message, args);
diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs
index 34fc5b7c..c35bf6bf 100644
--- a/Oqtane.Server/Controllers/LogController.cs
+++ b/Oqtane.Server/Controllers/LogController.cs
@@ -76,5 +76,20 @@ namespace Oqtane.Controllers
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
}
}
+
+ [HttpDelete]
+ [Authorize(Roles = RoleNames.Admin)]
+ public void Delete(string siteId)
+ {
+ if (int.TryParse(siteId, out int parsedSiteId) && parsedSiteId == _alias.SiteId)
+ {
+ _logs.ClearLogs(parsedSiteId);
+ }
+ else
+ {
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Delete Attempt {SiteId}", siteId);
+ HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
+ }
+ }
}
}
diff --git a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs
index 918785f2..623e3a2d 100644
--- a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs
+++ b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs
@@ -9,5 +9,6 @@ namespace Oqtane.Repository
Log GetLog(int logId);
void AddLog(Log log);
int DeleteLogs(int siteId, int age);
+ void ClearLogs(int siteId);
}
}
diff --git a/Oqtane.Server/Repository/LogRepository.cs b/Oqtane.Server/Repository/LogRepository.cs
index 6c388f15..81d5813f 100644
--- a/Oqtane.Server/Repository/LogRepository.cs
+++ b/Oqtane.Server/Repository/LogRepository.cs
@@ -71,5 +71,19 @@ namespace Oqtane.Repository
}
return count;
}
+
+ public void ClearLogs(int siteId)
+ {
+ using var db = _dbContextFactory.CreateDbContext();
+ var getLogsForDelete = () => db.Log.Where(item => item.SiteId == siteId).Take(100).ToList();
+ // delete logs in batches of 100 records
+ var logs = getLogsForDelete();
+ while (logs.Count > 0)
+ {
+ db.Log.RemoveRange(logs);
+ db.SaveChanges();
+ logs = getLogsForDelete();
+ }
+ }
}
}
diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css
index 863d10d2..f5a65a80 100644
--- a/Oqtane.Server/wwwroot/css/app.css
+++ b/Oqtane.Server/wwwroot/css/app.css
@@ -35,6 +35,9 @@ app {
}
/* Action Dialog */
+.app-actiondialog{
+ position: absolute;
+}
.app-actiondialog .modal {
position: fixed; /* Stay in place */
z-index: 9999; /* Sit on top */