diff --git a/Oqtane.Client/Modules/Admin/Logs/Detail.razor b/Oqtane.Client/Modules/Admin/Logs/Detail.razor index e2623a02..356ac98a 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Detail.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Detail.razor @@ -9,86 +9,88 @@ @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- @if (_pageName != string.Empty) - { -
- -
- -
-
- } - @if (_moduleTitle != string.Empty) - { -
- -
- -
-
- } - @if (_username != string.Empty) - { -
- -
- -
-
- } -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- @if (!string.IsNullOrEmpty(_exception)) - { -
- +@if (_initialized) +{ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ @if (_pageName != string.Empty) + { +
+ +
+ +
+
+ } + @if (_moduleTitle != string.Empty) + { +
+ +
+ +
+
+ } + @if (_username != string.Empty) + { +
+ +
+ +
+
+ } +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ @if (!string.IsNullOrEmpty(_exception)) + { +
+
@@ -107,81 +109,83 @@
+} +@SharedLocalizer["Cancel"] - @SharedLocalizer["Cancel"] +@code { + private bool _initialized = false; + private int _logId; + private string _logDate = string.Empty; + private string _level = string.Empty; + private string _feature = string.Empty; + private string _function = string.Empty; + private string _category = string.Empty; + private string _pageName = string.Empty; + private string _moduleTitle = string.Empty; + private string _username = string.Empty; + private string _url = string.Empty; + private string _template = string.Empty; + private string _message = string.Empty; + private string _exception = string.Empty; + private string _properties = string.Empty; + private string _server = string.Empty; - @code { - private int _logId; - private string _logDate = string.Empty; - private string _level = string.Empty; - private string _feature = string.Empty; - private string _function = string.Empty; - private string _category = string.Empty; - private string _pageName = string.Empty; - private string _moduleTitle = string.Empty; - private string _username = string.Empty; - private string _url = string.Empty; - private string _template = string.Empty; - private string _message = string.Empty; - private string _exception = string.Empty; - private string _properties = string.Empty; - private string _server = string.Empty; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; - - protected override async Task OnInitializedAsync() + protected override async Task OnInitializedAsync() + { + try { - try + _logId = Int32.Parse(PageState.QueryString["id"]); + var log = await LogService.GetLogAsync(_logId); + if (log != null) { - _logId = Int32.Parse(PageState.QueryString["id"]); - var log = await LogService.GetLogAsync(_logId); - if (log != null) + _logDate = log.LogDate.ToString(CultureInfo.CurrentCulture); + _level = log.Level; + _feature = log.Feature; + _function = log.Function; + _category = log.Category; + + if (log.PageId != null) { - _logDate = log.LogDate.ToString(CultureInfo.CurrentCulture); - _level = log.Level; - _feature = log.Feature; - _function = log.Function; - _category = log.Category; - - if (log.PageId != null) + var page = await PageService.GetPageAsync(log.PageId.Value); + if (page != null) { - var page = await PageService.GetPageAsync(log.PageId.Value); - if (page != null) - { - _pageName = page.Name; - } + _pageName = page.Name; } - - if (log.PageId != null && log.ModuleId != null) - { - var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value); - if (pagemodule != null) - { - _moduleTitle = pagemodule.Title; - } - } - - if (log.UserId != null) - { - var user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId); - if (user != null) - { - _username = user.Username; - } - } - - _url = log.Url; - _template = log.MessageTemplate; - _message = log.Message; - _exception = log.Exception; - _properties = log.Properties; - _server = log.Server; } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Log {LogId} {Error}", _logId, ex.Message); - AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error); + + if (log.PageId != null && log.ModuleId != null) + { + var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value); + if (pagemodule != null) + { + _moduleTitle = pagemodule.Title; + } + } + + if (log.UserId != null) + { + var user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId); + if (user != null) + { + _username = user.Username; + } + } + + _url = log.Url; + _template = log.MessageTemplate; + _message = log.Message; + _exception = log.Exception; + _properties = log.Properties; + _server = log.Server; + _initialized = true; } } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Log {LogId} {Error}", _logId, ex.Message); + AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error); + } } +} diff --git a/Oqtane.Client/Modules/Admin/Logs/Index.razor b/Oqtane.Client/Modules/Admin/Logs/Index.razor index 853409cb..5bab1f8c 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Index.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Index.razor @@ -17,7 +17,7 @@ else


- @@ -29,7 +29,7 @@ else


- @@ -41,7 +41,7 @@ else


- @@ -53,7 +53,7 @@ else @if (_logs.Any()) { - +
  @Localizer["Date"] @@ -62,7 +62,7 @@ else @Localizer["Function"]
- + @context.LogDate @context.Level @context.Feature @@ -94,6 +94,7 @@ else private string _level = "-"; private string _function = "-"; private string _rows = "10"; + private int _page = 1; private List _logs; private string _retention = ""; @@ -103,8 +104,27 @@ else { try { + if (PageState.QueryString.ContainsKey("level")) + { + _level = PageState.QueryString["level"]; + } + if (PageState.QueryString.ContainsKey("function")) + { + _function = PageState.QueryString["function"]; + } + if (PageState.QueryString.ContainsKey("rows")) + { + _rows = PageState.QueryString["rows"]; + } + if (PageState.QueryString.ContainsKey("page") && int.TryParse(PageState.QueryString["page"], out int page)) + { + _page = page; + } + await GetLogs(); - _retention = SettingService.GetSetting(PageState.Site.Settings, "LogRetention", "30"); + + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + _retention = SettingService.GetSetting(settings, "LogRetention", "30"); } catch (Exception ex) { @@ -208,4 +228,9 @@ else } } + private void OnPageChange(int page) + { + _page = page; + } + } diff --git a/Oqtane.Client/Modules/Admin/Visitors/Detail.razor b/Oqtane.Client/Modules/Admin/Visitors/Detail.razor index 58a7cefa..cff56939 100644 --- a/Oqtane.Client/Modules/Admin/Visitors/Detail.razor +++ b/Oqtane.Client/Modules/Admin/Visitors/Detail.razor @@ -7,69 +7,73 @@ @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- @if (_user != string.Empty) - { -
- -
- -
-
- } -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
+@if (_initialized) +{ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ @if (_user != string.Empty) + { +
+ +
+ +
+
+ } +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+} @SharedLocalizer["Cancel"] @code { + private bool _initialized = false; private int _visitorId; private string _ip = string.Empty; private string _language = string.Empty; @@ -108,6 +112,7 @@ _user = user.DisplayName; } } + _initialized = true; } else { @@ -120,4 +125,4 @@ AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error); } } - } +} diff --git a/Oqtane.Client/Modules/Admin/Visitors/Index.razor b/Oqtane.Client/Modules/Admin/Visitors/Index.razor index 5fbdb3b2..16b5d1a8 100644 --- a/Oqtane.Client/Modules/Admin/Visitors/Index.razor +++ b/Oqtane.Client/Modules/Admin/Visitors/Index.razor @@ -70,7 +70,7 @@ else
- +
@@ -117,8 +117,9 @@ else await GetVisitors(); _tracking = PageState.Site.VisitorTracking.ToString(); - _filter = SettingService.GetSetting(PageState.Site.Settings, "VisitorFilter", ""); - _retention = SettingService.GetSetting(PageState.Site.Settings, "VisitorRetention", "30"); + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + _filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter); + _retention = SettingService.GetSetting(settings, "VisitorRetention", "30"); } private async void TypeChanged(ChangeEventArgs e) diff --git a/Oqtane.Client/Modules/Controls/Pager.razor b/Oqtane.Client/Modules/Controls/Pager.razor index 61ffac0a..114e9028 100644 --- a/Oqtane.Client/Modules/Controls/Pager.razor +++ b/Oqtane.Client/Modules/Controls/Pager.razor @@ -57,12 +57,12 @@
- @Header + @Header @foreach (var item in ItemList) { - @Row(item) + @Row(item) @if (Detail != null) { @Detail(item) @@ -93,23 +93,19 @@ } }
- @if (Header != null) - { -
@Header
- } @for (int row = 0; row < rows; row++) { -
+
@for (int col = 0; col < cols; col++) { int index = (row * _columns) + col; if (index < ItemList.Count()) { -
@Row(ItemList.ElementAt(index))
+
@Row(ItemList.ElementAt(index))
} else { -
 
+
 
} }
@@ -182,10 +178,10 @@ public string Toolbar { get; set; } // Top, Bottom or Both [Parameter] - public RenderFragment Header { get; set; } = null; + public RenderFragment Header { get; set; } = null; // only applicable to Table layouts [Parameter] - public RenderFragment Row { get; set; } = null; + public RenderFragment Row { get; set; } = null; // required [Parameter] public RenderFragment Detail { get; set; } = null; // only applicable to Table layouts @@ -197,19 +193,25 @@ public string PageSize { get; set; } // number of items to display on a page [Parameter] - public string Columns { get; set; } // only applicable to Grid layouts + public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior [Parameter] - public string CurrentPage { get; set; } // optional property to set the initial page to display + public string CurrentPage { get; set; } // sets the initial page to display [Parameter] public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection [Parameter] - public string Class { get; set; } + public string Class { get; set; } // class for the containing element - ie.
for Table or
for Grid [Parameter] - public Action OnPageChange { get; set; } // optional - executes a method in the calling component when the page changes + public string RowClass { get; set; } // class for row element - ie.
for Table or
for Grid + + [Parameter] + public string ColumnClass { get; set; } // class for column element - only applicable to Grid format + + [Parameter] + public Action OnPageChange { get; set; } // a method to be executed in the calling component when the page changes private IEnumerable ItemList { get; set; } @@ -233,11 +235,35 @@ } else { - Class = "container-fluid px-0"; + Class = "container-fluid"; } } - if (!string.IsNullOrEmpty(PageSize)) + if (string.IsNullOrEmpty(RowClass)) + { + if (Format == "Table") + { + RowClass = ""; + } + else + { + RowClass = "row"; + } + } + + if (string.IsNullOrEmpty(ColumnClass)) + { + if (Format == "Table") + { + ColumnClass = ""; + } + else + { + ColumnClass = "col"; + } + } + + if (!string.IsNullOrEmpty(PageSize)) { _maxItems = int.Parse(PageSize); } diff --git a/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx index a6e25bbc..f852194f 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx @@ -175,7 +175,7 @@ Details - 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) + Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked Filter: diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index 0185a5c2..86827eba 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -6,7 +6,7 @@ - + @Model.Title diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 1a882402..1c6259b8 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -5,7 +5,6 @@ using Oqtane.Modules; using Oqtane.Models; using Oqtane.Themes; using System; -using System.Globalization; using System.Linq; using System.Reflection; using Oqtane.Repository; @@ -20,6 +19,7 @@ using Microsoft.AspNetCore.Http; using System.Security.Claims; using System.Net; using Microsoft.Extensions.Primitives; +using Oqtane.Enums; namespace Oqtane.Pages { @@ -36,8 +36,9 @@ namespace Oqtane.Pages private readonly IVisitorRepository _visitors; private readonly IAliasRepository _aliases; private readonly ISettingRepository _settings; + private readonly ILogManager _logger; - public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings) + public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ILogManager logger) { _configuration = configuration; _tenantManager = tenantManager; @@ -50,6 +51,7 @@ namespace Oqtane.Pages _visitors = visitors; _aliases = aliases; _settings = settings; + _logger = logger; } public string Language = "en"; @@ -206,86 +208,95 @@ namespace Oqtane.Pages private void TrackVisitor(int SiteId) { - // get request attributes - string useragent = (Request.Headers[HeaderNames.UserAgent] != StringValues.Empty) ? Request.Headers[HeaderNames.UserAgent] : "(none)"; - string language = (Request.Headers[HeaderNames.AcceptLanguage] != StringValues.Empty) ? Request.Headers[HeaderNames.AcceptLanguage] : ""; - language = (language.Contains(",")) ? language.Substring(0, language.IndexOf(",")) : language; - language = (language.Contains(";")) ? language.Substring(0, language.IndexOf(";")) : language; - language = (language.Trim().Length == 0) ? "??" : language; - - // filter - var filter = _settings.GetSetting(EntityNames.Site, SiteId, "VisitorFilter"); - if (filter != null && !string.IsNullOrEmpty(filter.SettingValue)) + try { - foreach (string term in filter.SettingValue.ToLower().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray()) + // get request attributes + string useragent = (Request.Headers[HeaderNames.UserAgent] != StringValues.Empty) ? Request.Headers[HeaderNames.UserAgent] : "(none)"; + string language = (Request.Headers[HeaderNames.AcceptLanguage] != StringValues.Empty) ? Request.Headers[HeaderNames.AcceptLanguage] : ""; + language = (language.Contains(",")) ? language.Substring(0, language.IndexOf(",")) : language; + language = (language.Contains(";")) ? language.Substring(0, language.IndexOf(";")) : language; + language = (language.Trim().Length == 0) ? "??" : language; + + // filter + string filter = Constants.DefaultVisitorFilter; + var setting = _settings.GetSetting(EntityNames.Site, SiteId, "VisitorFilter"); + if (setting != null) + { + filter = setting.SettingValue; + } + foreach (string term in filter.ToLower().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray()) { if (RemoteIPAddress.ToLower().Contains(term) || useragent.ToLower().Contains(term) || language.ToLower().Contains(term)) { return; } } - } - string url = Request.GetEncodedUrl(); - string referrer = (Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Request.Headers[HeaderNames.Referer] : ""; - int? userid = null; - if (User.HasClaim(item => item.Type == ClaimTypes.PrimarySid)) - { - userid = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.PrimarySid).Value); - } - - var VisitorCookie = "APP_VISITOR_" + SiteId.ToString(); - if (!int.TryParse(Request.Cookies[VisitorCookie], out VisitorId)) - { - var visitor = new Visitor(); - visitor.SiteId = SiteId; - visitor.IPAddress = RemoteIPAddress; - visitor.UserAgent = useragent; - visitor.Language = language; - visitor.Url = url; - visitor.Referrer = referrer; - visitor.UserId = userid; - visitor.Visits = 1; - visitor.CreatedOn = DateTime.UtcNow; - visitor.VisitedOn = DateTime.UtcNow; - visitor = _visitors.AddVisitor(visitor); - - Response.Cookies.Append( - VisitorCookie, - visitor.VisitorId.ToString(), - new CookieOptions() - { - Expires = DateTimeOffset.UtcNow.AddYears(1), - IsEssential = true - } - ); - } - else - { - var visitor = _visitors.GetVisitor(VisitorId); - if (visitor != null) + string url = Request.GetEncodedUrl(); + string referrer = (Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Request.Headers[HeaderNames.Referer] : ""; + int? userid = null; + if (User.HasClaim(item => item.Type == ClaimTypes.PrimarySid)) { + userid = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.PrimarySid).Value); + } + + var VisitorCookie = "APP_VISITOR_" + SiteId.ToString(); + if (!int.TryParse(Request.Cookies[VisitorCookie], out VisitorId)) + { + var visitor = new Visitor(); + visitor.SiteId = SiteId; visitor.IPAddress = RemoteIPAddress; visitor.UserAgent = useragent; visitor.Language = language; visitor.Url = url; - if (!string.IsNullOrEmpty(referrer)) - { - visitor.Referrer = referrer; - } - if (userid != null) - { - visitor.UserId = userid; - } - visitor.Visits += 1; + visitor.Referrer = referrer; + visitor.UserId = userid; + visitor.Visits = 1; + visitor.CreatedOn = DateTime.UtcNow; visitor.VisitedOn = DateTime.UtcNow; - _visitors.UpdateVisitor(visitor); + visitor = _visitors.AddVisitor(visitor); + + Response.Cookies.Append( + VisitorCookie, + visitor.VisitorId.ToString(), + new CookieOptions() + { + Expires = DateTimeOffset.UtcNow.AddYears(1), + IsEssential = true + } + ); } else { - Response.Cookies.Delete(VisitorCookie); + var visitor = _visitors.GetVisitor(VisitorId); + if (visitor != null) + { + visitor.IPAddress = RemoteIPAddress; + visitor.UserAgent = useragent; + visitor.Language = language; + visitor.Url = url; + if (!string.IsNullOrEmpty(referrer)) + { + visitor.Referrer = referrer; + } + if (userid != null) + { + visitor.UserId = userid; + } + visitor.Visits += 1; + visitor.VisitedOn = DateTime.UtcNow; + _visitors.UpdateVisitor(visitor); + } + else + { + Response.Cookies.Delete(VisitorCookie); + } } } + catch (Exception ex) + { + _logger.Log(LogLevel.Error, this, LogFunction.Other, "Error Tracking Visitor {Error}", ex.Message); + } } private string CreatePWAScript(Alias alias, Site site, Route route) diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index aa70e703..57ccc0ca 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -83,5 +83,7 @@ namespace Oqtane.Shared { public static readonly string RequestVerificationToken = "__RequestVerificationToken"; public static readonly string AntiForgeryTokenHeaderName = "X-XSRF-TOKEN-HEADER"; public static readonly string AntiForgeryTokenCookieName = "X-XSRF-TOKEN-COOKIE"; + + public static readonly string DefaultVisitorFilter = "bot,crawler,slurp,spider,(none),??"; } }