Merge pull request #1912 from sbwalker/dev
include purge job for maintaining event logs and visitor logs
This commit is contained in:
commit
65ba6423b1
@ -1,6 +1,7 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Logs
|
@namespace Oqtane.Modules.Admin.Logs
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject ILogService LogService
|
@inject ILogService LogService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -10,67 +11,83 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="container g-0">
|
<TabStrip>
|
||||||
<div class="row mb-1 align-items-center">
|
<TabPanel Name="Events" Heading="Events" ResourceKey="Events">
|
||||||
<div class="col-sm-4">
|
<div class="container g-0">
|
||||||
<Label For="level" HelpText="Select the log level for event log items" ResourceKey="Level">Level: </Label><br /><br />
|
<div class="row mb-1 align-items-center">
|
||||||
<select id="level" class="form-select" @onchange="(e => LevelChanged(e))">
|
<div class="col-sm-4">
|
||||||
<option value="-"><@Localizer["AllLevels"]></option>
|
<Label For="level" HelpText="Select the log level for event log items" ResourceKey="Level">Level: </Label><br /><br />
|
||||||
<option value="Trace">@Localizer["Trace"]</option>
|
<select id="level" class="form-select" @onchange="(e => LevelChanged(e))">
|
||||||
<option value="Debug">@Localizer["Debug"]</option>
|
<option value="-"><@Localizer["AllLevels"]></option>
|
||||||
<option value="Information">@Localizer["Information"]</option>
|
<option value="Trace">@Localizer["Trace"]</option>
|
||||||
<option value="Warning">@Localizer["Warning"]</option>
|
<option value="Debug">@Localizer["Debug"]</option>
|
||||||
<option value="Error">@Localizer["Error"]</option>
|
<option value="Information">@Localizer["Information"]</option>
|
||||||
<option value="Critical">@Localizer["Critical"]</option>
|
<option value="Warning">@Localizer["Warning"]</option>
|
||||||
</select>
|
<option value="Error">@Localizer["Error"]</option>
|
||||||
</div>
|
<option value="Critical">@Localizer["Critical"]</option>
|
||||||
<div class="col-sm-4">
|
</select>
|
||||||
<Label For="function" HelpText="Select the function for event log items" ResourceKey="Function">Function: </Label><br /><br />
|
</div>
|
||||||
<select id="function" class="form-select" @onchange="(e => FunctionChanged(e))">
|
<div class="col-sm-4">
|
||||||
<option value="-"><@Localizer["AllFunctions"]></option>
|
<Label For="function" HelpText="Select the function for event log items" ResourceKey="Function">Function: </Label><br /><br />
|
||||||
<option value="Create">@Localizer["Create"]</option>
|
<select id="function" class="form-select" @onchange="(e => FunctionChanged(e))">
|
||||||
<option value="Read">@Localizer["Read"]</option>
|
<option value="-"><@Localizer["AllFunctions"]></option>
|
||||||
<option value="Update">@SharedLocalizer["Update"]</option>
|
<option value="Create">@Localizer["Create"]</option>
|
||||||
<option value="Delete">@SharedLocalizer["Delete"]</option>
|
<option value="Read">@Localizer["Read"]</option>
|
||||||
<option value="Security">@Localizer["Security"]</option>
|
<option value="Update">@SharedLocalizer["Update"]</option>
|
||||||
<option value="Other">@Localizer["Other"]</option>
|
<option value="Delete">@SharedLocalizer["Delete"]</option>
|
||||||
</select>
|
<option value="Security">@Localizer["Security"]</option>
|
||||||
</div>
|
<option value="Other">@Localizer["Other"]</option>
|
||||||
<div class="col-sm-4">
|
</select>
|
||||||
<Label For="rows" HelpText="Select the maximum number of event log items to review. Please note that if you choose more than 10 items the information will be split into pages." ResourceKey="Rows">Maximum Items: </Label><br /><br />
|
</div>
|
||||||
<select id="rows" class="form-select" @onchange="(e => RowsChanged(e))">
|
<div class="col-sm-4">
|
||||||
<option value="10">10</option>
|
<Label For="rows" HelpText="Select the maximum number of event log items to review. Please note that if you choose more than 10 items the information will be split into pages." ResourceKey="Rows">Maximum Items: </Label><br /><br />
|
||||||
<option value="50">50</option>
|
<select id="rows" class="form-select" @onchange="(e => RowsChanged(e))">
|
||||||
<option value="100">100</option>
|
<option value="10">10</option>
|
||||||
</select>
|
<option value="50">50</option>
|
||||||
</div>
|
<option value="100">100</option>
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
|
||||||
@if (_logs.Any())
|
@if (_logs.Any())
|
||||||
{
|
{
|
||||||
<Pager Items="@_logs">
|
<Pager Items="@_logs">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["Date"]</th>
|
<th>@Localizer["Date"]</th>
|
||||||
<th>@Localizer["Level"]</th>
|
<th>@Localizer["Level"]</th>
|
||||||
<th>@Localizer["Feature"]</th>
|
<th>@Localizer["Feature"]</th>
|
||||||
<th>@Localizer["Function"]</th>
|
<th>@Localizer["Function"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" ResourceKey="LogDetails" /></td>
|
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" ResourceKey="LogDetails" /></td>
|
||||||
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Level</td>
|
<td class="@GetClass(context.Function)">@context.Level</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Feature</td>
|
<td class="@GetClass(context.Function)">@context.Feature</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Function</td>
|
<td class="@GetClass(context.Function)">@context.Function</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<p><em>@Localizer["NoLogs"]</em></p>
|
<p><em>@Localizer["NoLogs"]</em></p>
|
||||||
}
|
}
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="retention" HelpText="Number of days of events to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="retention" class="form-control" @bind="@_retention" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
|
</TabPanel>
|
||||||
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@ -78,6 +95,7 @@ else
|
|||||||
private string _function = "-";
|
private string _function = "-";
|
||||||
private string _rows = "10";
|
private string _rows = "10";
|
||||||
private List<Log> _logs;
|
private List<Log> _logs;
|
||||||
|
private string _retention = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
@ -86,6 +104,7 @@ else
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await GetLogs();
|
await GetLogs();
|
||||||
|
_retention = SettingService.GetSetting(PageState.Site.Settings, "LogRetention", "30");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -171,4 +190,22 @@ else
|
|||||||
}
|
}
|
||||||
return classname;
|
return classname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SaveSiteSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = PageState.Site.Settings;
|
||||||
|
settings = SettingService.SetSetting(settings, "LogRetention", _retention);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject IVisitorService VisitorService
|
@inject IVisitorService VisitorService
|
||||||
@inject ISiteService SiteService
|
@inject ISiteService SiteService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -56,18 +57,30 @@ else
|
|||||||
<td>@context.CreatedOn</td>
|
<td>@context.CreatedOn</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="visitortracking" HelpText="Specify if visitor tracking is enabled" ResourceKey="VisitorTracking">Visitor Tracking Enabled? </Label>
|
<Label Class="col-sm-3" For="tracking" HelpText="Specify if visitor tracking is enabled" ResourceKey="Tracking">Tracking Enabled? </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="visitortracking" class="form-select" @bind="@_visitortracking" >
|
<select id="tracking" class="form-select" @bind="@_tracking" >
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="filter" HelpText="Comma delimited list of terms which may exist in IP addresses, user agents, or languages which identify visitors which should not be tracked (ie. bots)" ResourceKey="Filter">Filter: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="filter" class="form-control" @bind="@_filter" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="retention" class="form-control" @bind="@_retention" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
@ -79,14 +92,18 @@ else
|
|||||||
private bool _users = false;
|
private bool _users = false;
|
||||||
private int _days = 1;
|
private int _days = 1;
|
||||||
private List<Visitor> _visitors;
|
private List<Visitor> _visitors;
|
||||||
private string _visitortracking;
|
private string _tracking;
|
||||||
|
private string _filter = "";
|
||||||
|
private string _retention = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
await GetVisitors();
|
await GetVisitors();
|
||||||
_visitortracking = PageState.Site.VisitorTracking.ToString();
|
_tracking = PageState.Site.VisitorTracking.ToString();
|
||||||
|
_filter = SettingService.GetSetting(PageState.Site.Settings, "VisitorFilter", "");
|
||||||
|
_retention = SettingService.GetSetting(PageState.Site.Settings, "VisitorRetention", "30");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void TypeChanged(ChangeEventArgs e)
|
private async void TypeChanged(ChangeEventArgs e)
|
||||||
@ -124,15 +141,21 @@ else
|
|||||||
{
|
{
|
||||||
_visitors = _visitors.Where(item => item.UserId != null).ToList();
|
_visitors = _visitors.Where(item => item.UserId != null).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveSiteSettings()
|
private async Task SaveSiteSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var site = PageState.Site;
|
var site = PageState.Site;
|
||||||
site.VisitorTracking = bool.Parse(_visitortracking);
|
site.VisitorTracking = bool.Parse(_tracking);
|
||||||
await SiteService.UpdateSiteAsync(site);
|
await SiteService.UpdateSiteAsync(site);
|
||||||
|
|
||||||
|
var settings = PageState.Site.Settings;
|
||||||
|
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter);
|
||||||
|
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -192,4 +192,22 @@
|
|||||||
<data name="LogDetails.Text" xml:space="preserve">
|
<data name="LogDetails.Text" xml:space="preserve">
|
||||||
<value>Details</value>
|
<value>Details</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||||
|
<value>Error Saving Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Events.Heading" xml:space="preserve">
|
||||||
|
<value>Events</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.HelpText" xml:space="preserve">
|
||||||
|
<value>Number of days of events to retain</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
|
<value>Retention (Days):</value>
|
||||||
|
</data>
|
||||||
|
<data name="Settings.Heading" xml:space="preserve">
|
||||||
|
<value>Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||||
|
<value>Settings Saved Successfully</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -156,11 +156,11 @@
|
|||||||
<data name="Visitors.Heading" xml:space="preserve">
|
<data name="Visitors.Heading" xml:space="preserve">
|
||||||
<value>Visitors</value>
|
<value>Visitors</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="VisitorTracking.HelpText" xml:space="preserve">
|
<data name="Tracking.HelpText" xml:space="preserve">
|
||||||
<value>Specify if visitor tracking is enabled</value>
|
<value>Specify if visitor tracking is enabled</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="VisitorTracking.Text" xml:space="preserve">
|
<data name="Tracking.Text" xml:space="preserve">
|
||||||
<value>Visitor Tracking Enabled?</value>
|
<value>Tracking Enabled?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IP" xml:space="preserve">
|
<data name="IP" xml:space="preserve">
|
||||||
<value>IP</value>
|
<value>IP</value>
|
||||||
@ -174,4 +174,16 @@
|
|||||||
<data name="Details.Text" xml:space="preserve">
|
<data name="Details.Text" xml:space="preserve">
|
||||||
<value>Details</value>
|
<value>Details</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Filter.HelpText" xml:space="preserve">
|
||||||
|
<value>Comma delimited list of terms which may exist in IP addresses, user agents, or languages which identify visitors which should not be tracked (ie. bots)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Filter.Text" xml:space="preserve">
|
||||||
|
<value>Filter:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.HelpText" xml:space="preserve">
|
||||||
|
<value>Number of days of visitor activity to retain</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
|
<value>Retention (Days):</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -218,188 +218,189 @@
|
|||||||
|
|
||||||
@code{
|
@code{
|
||||||
|
|
||||||
private bool _deleteConfirmation = false;
|
private bool _deleteConfirmation = false;
|
||||||
private List<string> _categories = new List<string>();
|
private List<string> _categories = new List<string>();
|
||||||
private List<ModuleDefinition> _allModuleDefinitions;
|
private List<ModuleDefinition> _allModuleDefinitions;
|
||||||
private List<ModuleDefinition> _moduleDefinitions;
|
private List<ModuleDefinition> _moduleDefinitions;
|
||||||
private List<Page> _pages = new List<Page>();
|
private List<Page> _pages = new List<Page>();
|
||||||
private List<Module> _modules = new List<Module>();
|
private List<Module> _modules = new List<Module>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _category = "Common";
|
private string _category = "Common";
|
||||||
|
|
||||||
protected string PageId { get; private set; } = "-";
|
protected string PageId { get; private set; } = "-";
|
||||||
protected string ModuleId { get; private set; } = "-";
|
protected string ModuleId { get; private set; } = "-";
|
||||||
protected string ModuleType { get; private set; } = "new";
|
protected string ModuleType { get; private set; } = "new";
|
||||||
protected string ModuleDefinitionName { get; private set; } = "-";
|
protected string ModuleDefinitionName { get; private set; } = "-";
|
||||||
|
|
||||||
protected string Category
|
protected string Category
|
||||||
{
|
{
|
||||||
get => _category;
|
get => _category;
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
if (_category != value)
|
if (_category != value)
|
||||||
{
|
{
|
||||||
_category = value;
|
_category = value;
|
||||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||||
ModuleDefinitionName = "-";
|
ModuleDefinitionName = "-";
|
||||||
Description = "";
|
Description = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
_ = UpdateSettingsAsync();
|
_ = UpdateSettingsAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string Pane
|
protected string Pane
|
||||||
{
|
{
|
||||||
get => _pane;
|
get => _pane;
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
if (_pane != value)
|
if (_pane != value)
|
||||||
{
|
{
|
||||||
_pane = value;
|
_pane = value;
|
||||||
_ = UpdateSettingsAsync();
|
_ = UpdateSettingsAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected string Description { get; private set; } = "";
|
protected string Description { get; private set; } = "";
|
||||||
|
|
||||||
protected string Title { get; private set; } = "";
|
protected string Title { get; private set; } = "";
|
||||||
protected string ContainerType { get; private set; } = "";
|
protected string ContainerType { get; private set; } = "";
|
||||||
protected string Message { get; private set; } = "";
|
protected string Message { get; private set; } = "";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string HeaderClass { get; set; } = "offcanvas-header";
|
public string HeaderClass { get; set; } = "offcanvas-header";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowLanguageSwitcher { get; set; } = true;
|
public bool ShowLanguageSwitcher { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||||
{
|
{
|
||||||
_pages?.Clear();
|
_pages?.Clear();
|
||||||
|
|
||||||
foreach (Page p in PageState.Pages)
|
foreach (Page p in PageState.Pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||||
{
|
{
|
||||||
_pages.Add(p);
|
_pages.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await LoadSettingsAsync();
|
await LoadSettingsAsync();
|
||||||
|
|
||||||
var themes = await ThemeService.GetThemesAsync();
|
var themes = await ThemeService.GetThemesAsync();
|
||||||
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
||||||
ContainerType = PageState.Site.DefaultContainerType;
|
ContainerType = PageState.Site.DefaultContainerType;
|
||||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CategoryChanged(ChangeEventArgs e)
|
private void CategoryChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
Category = (string)e.Value;
|
Category = (string)e.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModuleChanged(ChangeEventArgs e)
|
private void ModuleChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = (string)e.Value;
|
ModuleDefinitionName = (string)e.Value;
|
||||||
if (ModuleDefinitionName != "-")
|
if (ModuleDefinitionName != "-")
|
||||||
{
|
{
|
||||||
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
|
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
|
||||||
Description = "<br /><div class=\"alert alert-info\" role=\"alert\">" + moduleDefinition.Description + "</div>";
|
Description = "<br /><div class=\"alert alert-info\" role=\"alert\">" + moduleDefinition.Description + "</div>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Description = "";
|
Description = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PageChanged(ChangeEventArgs e)
|
private void PageChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
PageId = (string)e.Value;
|
PageId = (string)e.Value;
|
||||||
if (PageId != "-")
|
if (PageId != "-")
|
||||||
{
|
{
|
||||||
_modules = PageState.Modules
|
_modules = PageState.Modules
|
||||||
.Where(module => module.PageId == int.Parse(PageId)
|
.Where(module => module.PageId == int.Parse(PageId)
|
||||||
&& !module.IsDeleted
|
&& !module.IsDeleted
|
||||||
&& UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
&& UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
ModuleId = "-";
|
ModuleId = "-";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddModule()
|
private async Task AddModule()
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||||
{
|
{
|
||||||
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
||||||
{
|
{
|
||||||
if (ModuleType == "new")
|
if (ModuleType == "new")
|
||||||
{
|
{
|
||||||
Module module = new Module();
|
Module module = new Module();
|
||||||
module.SiteId = PageState.Site.SiteId;
|
module.SiteId = PageState.Site.SiteId;
|
||||||
module.PageId = PageState.Page.PageId;
|
module.PageId = PageState.Page.PageId;
|
||||||
module.ModuleDefinitionName = ModuleDefinitionName;
|
module.ModuleDefinitionName = ModuleDefinitionName;
|
||||||
module.AllPages = false;
|
module.AllPages = false;
|
||||||
|
|
||||||
// set module view permissions to page edit permissions
|
// set module view permissions to page edit permissions
|
||||||
List<PermissionString> permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions);
|
List<PermissionString> permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions);
|
||||||
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions;
|
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions;
|
||||||
module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
||||||
|
|
||||||
module = await ModuleService.AddModuleAsync(module);
|
module = await ModuleService.AddModuleAsync(module);
|
||||||
ModuleId = module.ModuleId.ToString();
|
ModuleId = module.ModuleId.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
var pageModule = new PageModule
|
var pageModule = new PageModule
|
||||||
{
|
{
|
||||||
PageId = PageState.Page.PageId,
|
PageId = PageState.Page.PageId,
|
||||||
ModuleId = int.Parse(ModuleId),
|
ModuleId = int.Parse(ModuleId),
|
||||||
Title = Title
|
Title = Title
|
||||||
};
|
};
|
||||||
if (pageModule.Title == "")
|
if (pageModule.Title == "")
|
||||||
{
|
{
|
||||||
if (ModuleType == "new")
|
if (ModuleType == "new")
|
||||||
{
|
{
|
||||||
pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
|
pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
|
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pageModule.Pane = Pane;
|
pageModule.Pane = Pane;
|
||||||
pageModule.Order = int.MaxValue;
|
pageModule.Order = int.MaxValue;
|
||||||
pageModule.ContainerType = ContainerType;
|
pageModule.ContainerType = ContainerType;
|
||||||
|
|
||||||
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
||||||
{
|
{
|
||||||
pageModule.ContainerType = "";
|
pageModule.ContainerType = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
await PageModuleService.AddPageModuleAsync(pageModule);
|
await PageModuleService.AddPageModuleAsync(pageModule);
|
||||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||||
|
|
||||||
Message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
Message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
Title = "";
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
76
Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs
Normal file
76
Oqtane.Server/Infrastructure/Jobs/PurgeJob.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class PurgeJob : HostedServiceBase
|
||||||
|
{
|
||||||
|
// JobType = "Oqtane.Infrastructure.PurgeJob, Oqtane.Server"
|
||||||
|
|
||||||
|
public PurgeJob(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
|
||||||
|
{
|
||||||
|
Name = "Purge Job";
|
||||||
|
Frequency = "d"; // daily
|
||||||
|
Interval = 1;
|
||||||
|
StartDate = DateTime.ParseExact("03:00", "H:mm", null, System.Globalization.DateTimeStyles.None); // 3 AM
|
||||||
|
IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// job is executed for each tenant in installation
|
||||||
|
public override string ExecuteJob(IServiceProvider provider)
|
||||||
|
{
|
||||||
|
string log = "";
|
||||||
|
|
||||||
|
// get services
|
||||||
|
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||||
|
var settingRepository = provider.GetRequiredService<ISettingRepository>();
|
||||||
|
var logRepository = provider.GetRequiredService<ILogRepository>();
|
||||||
|
var visitorRepository = provider.GetRequiredService<IVisitorRepository>();
|
||||||
|
|
||||||
|
// iterate through sites for current tenant
|
||||||
|
List<Site> sites = siteRepository.GetSites().ToList();
|
||||||
|
foreach (Site site in sites)
|
||||||
|
{
|
||||||
|
log += "Processing Site: " + site.Name + "<br />";
|
||||||
|
|
||||||
|
// get site settings
|
||||||
|
Dictionary<string, string> settings = GetSettings(settingRepository.GetSettings(EntityNames.Site, site.SiteId).ToList());
|
||||||
|
|
||||||
|
// purge event log
|
||||||
|
int logretention = 30;
|
||||||
|
if (settings.ContainsKey("LogRetention") && settings["LogRetention"] != "")
|
||||||
|
{
|
||||||
|
logretention = int.Parse(settings["LogRetention"]);
|
||||||
|
}
|
||||||
|
int count = logRepository.DeleteLogs(logretention);
|
||||||
|
log += count.ToString() + " Event Logs Purged<br />";
|
||||||
|
|
||||||
|
// purge visitors
|
||||||
|
int visitorrention = 30;
|
||||||
|
if (settings.ContainsKey("VisitorRetention") && settings["VisitorRetention"] != "")
|
||||||
|
{
|
||||||
|
visitorrention = int.Parse(settings["VisitorRetention"]);
|
||||||
|
}
|
||||||
|
count = visitorRepository.DeleteVisitors(visitorrention);
|
||||||
|
log += count.ToString() + " Visitors Purged<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, string> GetSettings(List<Setting> settings)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> dictionary = new Dictionary<string, string>();
|
||||||
|
foreach (Setting setting in settings.OrderBy(item => item.SettingName).ToList())
|
||||||
|
{
|
||||||
|
dictionary.Add(setting.SettingName, setting.SettingValue);
|
||||||
|
}
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,8 +35,9 @@ namespace Oqtane.Pages
|
|||||||
private readonly IUrlMappingRepository _urlMappings;
|
private readonly IUrlMappingRepository _urlMappings;
|
||||||
private readonly IVisitorRepository _visitors;
|
private readonly IVisitorRepository _visitors;
|
||||||
private readonly IAliasRepository _aliases;
|
private readonly IAliasRepository _aliases;
|
||||||
|
private readonly ISettingRepository _settings;
|
||||||
|
|
||||||
public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases)
|
public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
@ -48,6 +49,7 @@ namespace Oqtane.Pages
|
|||||||
_urlMappings = urlMappings;
|
_urlMappings = urlMappings;
|
||||||
_visitors = visitors;
|
_visitors = visitors;
|
||||||
_aliases = aliases;
|
_aliases = aliases;
|
||||||
|
_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string AntiForgeryToken = "";
|
public string AntiForgeryToken = "";
|
||||||
@ -198,6 +200,20 @@ namespace Oqtane.Pages
|
|||||||
language = (language.Contains(",")) ? language.Substring(0, language.IndexOf(",")) : language;
|
language = (language.Contains(",")) ? language.Substring(0, language.IndexOf(",")) : language;
|
||||||
language = (language.Contains(";")) ? language.Substring(0, language.IndexOf(";")) : language;
|
language = (language.Contains(";")) ? language.Substring(0, language.IndexOf(";")) : language;
|
||||||
language = (language.Trim().Length == 0) ? "*" : language;
|
language = (language.Trim().Length == 0) ? "*" : language;
|
||||||
|
|
||||||
|
// filter
|
||||||
|
var filter = _settings.GetSetting(EntityNames.Site, SiteId, "VisitorFilter");
|
||||||
|
if (filter != null && !string.IsNullOrEmpty(filter.SettingValue))
|
||||||
|
{
|
||||||
|
foreach (string term in filter.SettingValue.ToLower().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
||||||
|
{
|
||||||
|
if (ip.ToLower().Contains(term) || useragent.ToLower().Contains(term) || language.ToLower().Contains(term))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string url = Request.GetEncodedUrl();
|
string url = Request.GetEncodedUrl();
|
||||||
string referrer = (Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Request.Headers[HeaderNames.Referer] : "";
|
string referrer = (Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Request.Headers[HeaderNames.Referer] : "";
|
||||||
int? userid = null;
|
int? userid = null;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
@ -8,5 +8,6 @@ namespace Oqtane.Repository
|
|||||||
IEnumerable<Log> GetLogs(int siteId, string level, string function, int rows);
|
IEnumerable<Log> GetLogs(int siteId, string level, string function, int rows);
|
||||||
Log GetLog(int logId);
|
Log GetLog(int logId);
|
||||||
void AddLog(Log log);
|
void AddLog(Log log);
|
||||||
|
int DeleteLogs(int age);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ namespace Oqtane.Repository
|
|||||||
Setting AddSetting(Setting setting);
|
Setting AddSetting(Setting setting);
|
||||||
Setting UpdateSetting(Setting setting);
|
Setting UpdateSetting(Setting setting);
|
||||||
Setting GetSetting(string entityName, int settingId);
|
Setting GetSetting(string entityName, int settingId);
|
||||||
|
Setting GetSetting(string entityName, int entityId, string settingName);
|
||||||
void DeleteSetting(string entityName, int settingId);
|
void DeleteSetting(string entityName, int settingId);
|
||||||
void DeleteSettings(string entityName, int entityId);
|
void DeleteSettings(string entityName, int entityId);
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,6 @@ namespace Oqtane.Repository
|
|||||||
Visitor UpdateVisitor(Visitor visitor);
|
Visitor UpdateVisitor(Visitor visitor);
|
||||||
Visitor GetVisitor(int visitorId);
|
Visitor GetVisitor(int visitorId);
|
||||||
void DeleteVisitor(int visitorId);
|
void DeleteVisitor(int visitorId);
|
||||||
|
int DeleteVisitors(int age);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
@ -47,5 +48,23 @@ namespace Oqtane.Repository
|
|||||||
_db.Log.Add(log);
|
_db.Log.Add(log);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int DeleteLogs(int age)
|
||||||
|
{
|
||||||
|
// delete logs in batches of 100 records
|
||||||
|
int count = 0;
|
||||||
|
var purgedate = DateTime.Now.AddDays(-age);
|
||||||
|
var logs = _db.Log.Where(item => item.Level != "Error" && item.LogDate < purgedate)
|
||||||
|
.OrderBy(item => item.LogDate).Take(100).ToList();
|
||||||
|
while (logs.Count > 0)
|
||||||
|
{
|
||||||
|
count += logs.Count;
|
||||||
|
_db.Log.RemoveRange(logs);
|
||||||
|
_db.SaveChanges();
|
||||||
|
logs = _db.Log.Where(item => item.Level != "Error" && item.LogDate < purgedate)
|
||||||
|
.OrderBy(item => item.LogDate).Take(100).ToList();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,18 @@ namespace Oqtane.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Setting GetSetting(string entityName, int entityId, string settingName)
|
||||||
|
{
|
||||||
|
if (IsMaster(entityName))
|
||||||
|
{
|
||||||
|
return _master.Setting.Where(item => item.EntityName == entityName && item.EntityId == entityId && item.SettingName == settingName).FirstOrDefault();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _tenant.Setting.Where(item => item.EntityName == entityName && item.EntityId == entityId && item.SettingName == settingName).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteSetting(string entityName, int settingId)
|
public void DeleteSetting(string entityName, int settingId)
|
||||||
{
|
{
|
||||||
if (IsMaster(entityName))
|
if (IsMaster(entityName))
|
||||||
|
@ -47,5 +47,23 @@ namespace Oqtane.Repository
|
|||||||
_db.Visitor.Remove(visitor);
|
_db.Visitor.Remove(visitor);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int DeleteVisitors(int age)
|
||||||
|
{
|
||||||
|
// delete visitors in batches of 100 records
|
||||||
|
int count = 0;
|
||||||
|
var purgedate = DateTime.Now.AddDays(-age);
|
||||||
|
var visitors = _db.Visitor.Where(item => item.Visits <= 1 && item.VisitedOn < purgedate)
|
||||||
|
.OrderBy(item => item.VisitedOn).Take(100).ToList();
|
||||||
|
while (visitors.Count > 0)
|
||||||
|
{
|
||||||
|
count += visitors.Count;
|
||||||
|
_db.Visitor.RemoveRange(visitors);
|
||||||
|
_db.SaveChanges();
|
||||||
|
visitors = _db.Visitor.Where(item => item.Visits < 2 && item.VisitedOn < purgedate)
|
||||||
|
.OrderBy(item => item.VisitedOn).Take(100).ToList();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user