Merge branch 'dev' into MissingRes-3.0.1
This commit is contained in:
commit
ec9686cfb8
|
@ -10,100 +10,32 @@
|
|||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="dateTime" class="form-control" @bind="@_logDate" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="level" HelpText="The level of this log" ResourceKey="Level">Level: </Label>
|
||||
<Label Class="col-sm-3" For="level" HelpText="The level of this log" ResourceKey="Level">Level: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="level" class="form-control" @bind="@_level" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="feature" HelpText="The feature that was affected" ResourceKey="Feature">Feature: </Label>
|
||||
<Label Class="col-sm-3" For="feature" HelpText="The feature that was affected" ResourceKey="Feature">Feature: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="feature" class="form-control" @bind="@_feature" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="function" HelpText="The function that was performed" ResourceKey="Function">Function: </Label>
|
||||
<Label Class="col-sm-3" For="function" HelpText="The function that was performed" ResourceKey="Function">Function: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="function" class="form-control" @bind="@_function" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="category" class="form-control" @bind="@_category" readonly />
|
||||
</div>
|
||||
|
@ -111,7 +43,7 @@
|
|||
@if (_pageName != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that was affected" ResourceKey="Page">Page: </Label>
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that was affected" ResourceKey="Page">Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="page" class="form-control" @bind="@_pageName" readonly />
|
||||
</div>
|
||||
|
@ -120,7 +52,7 @@
|
|||
@if (_moduleTitle != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="module" HelpText="The module that was affected" ResourceKey="Module">Module: </Label>
|
||||
<Label Class="col-sm-3" For="module" HelpText="The module that was affected" ResourceKey="Module">Module: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" class="form-control" @bind="@_moduleTitle" readonly />
|
||||
</div>
|
||||
|
@ -129,26 +61,26 @@
|
|||
@if (_username != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The user that caused this log" ResourceKey="User">User: </Label>
|
||||
<Label Class="col-sm-3" For="user" HelpText="The user that caused this log" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_username" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The url the log comes from" ResourceKey="Url">Url: </Label>
|
||||
<Label Class="col-sm-3" For="url" HelpText="The url the log comes from" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="What the log is about" ResourceKey="Template">Template: </Label>
|
||||
<Label Class="col-sm-3" For="template" HelpText="What the log is about" ResourceKey="Template">Template: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="template" class="form-control" @bind="@_template" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="message" HelpText="The message that the system generated" ResourceKey="Message">Message: </Label>
|
||||
<Label Class="col-sm-3" For="message" HelpText="The message that the system generated" ResourceKey="Message">Message: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="message" class="form-control" @bind="@_message" rows="5" readonly></textarea>
|
||||
</div>
|
||||
|
@ -156,24 +88,25 @@
|
|||
@if (!string.IsNullOrEmpty(_exception))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="exception" HelpText="The exceptions generated by the system" ResourceKey="Exception">Exception: </Label>
|
||||
<div class="col-sm-9">
|
||||
<Label Class="col-sm-3" For="exception" HelpText="The exceptions generated by the system" ResourceKey="Exception">Exception: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="exception" class="form-control" @bind="@_exception" rows="5" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="properties" HelpText="The properties that were affected" ResourceKey="Properties">Properties: </Label>
|
||||
<Label Class="col-sm-3" For="properties" HelpText="The properties that were affected" ResourceKey="Properties">Properties: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="properties" class="form-control" @bind="@_properties" rows="5" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="server" HelpText="The server that was affected" ResourceKey="Server">Server: </Label>
|
||||
<div class="col-sm-9">
|
||||
<Label Class="col-sm-3" For="server" HelpText="The server that was affected" ResourceKey="Server">Server: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="server" class="form-control" @bind="@_server" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
|
|
|
@ -51,11 +51,11 @@ else
|
|||
{
|
||||
<Pager Items="@_logs">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
<th>@Localizer["Level"]</th>
|
||||
<th>@Localizer["Feature"]</th>
|
||||
<th>@Localizer["Function"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
<th>@Localizer["Level"]</th>
|
||||
<th>@Localizer["Feature"]</th>
|
||||
<th>@Localizer["Function"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" ResourceKey="LogDetails" /></td>
|
||||
|
|
123
Oqtane.Client/Modules/Admin/Visitors/Detail.razor
Normal file
123
Oqtane.Client/Modules/Admin/Visitors/Detail.razor
Normal file
|
@ -0,0 +1,123 @@
|
|||
@namespace Oqtane.Modules.Admin.Visitors
|
||||
@using System.Globalization
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IVisitorService VisitorService
|
||||
@inject IUserService UserService
|
||||
@inject IStringLocalizer<Detail> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="ip" HelpText="The last recorded IP address for this visitor" ResourceKey="IP">IP Address: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="ip" class="form-control" @bind="@_ip" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="language" HelpText="The last recorded language for this visitor" ResourceKey="Language">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="language" class="form-control" @bind="@_language" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="useragent" HelpText="The last recorded user agent for this visitor" ResourceKey="UserAgent">User Agent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="useragent" class="form-control" @bind="@_useragent" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The last recorded url for this visitor" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="referrer" HelpText="The last recorded referrer for this visitor" ResourceKey="Referrer">Referrer: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="referrer" class="form-control" @bind="@_referrer" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_user != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The last recorded user associated with this visitor" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_user" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visits" HelpText="The total number of visits by this visitor all time" ResourceKey="Visits">Visits: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visits" class="form-control" @bind="@_visits" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visited" HelpText="The last recorded date/time when the visitor visited the site" ResourceKey="Visited">Visited: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visited" class="form-control" @bind="@_visited" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="created" HelpText="The first recorded date/time when this visitor visited the site" ResourceKey="Created">Created: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="created" class="form-control" @bind="@_created" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private int _visitorId;
|
||||
private string _ip = string.Empty;
|
||||
private string _language = string.Empty;
|
||||
private string _useragent = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _referrer = string.Empty;
|
||||
private string _user = string.Empty;
|
||||
private string _visits = string.Empty;
|
||||
private string _visited = string.Empty;
|
||||
private string _created = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_visitorId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var visitor = await VisitorService.GetVisitorAsync(_visitorId);
|
||||
if (visitor != null)
|
||||
{
|
||||
_ip = visitor.IPAddress;
|
||||
_language = visitor.Language;
|
||||
_useragent = visitor.UserAgent;
|
||||
_url = visitor.Url;
|
||||
_referrer = visitor.Referrer;
|
||||
_visits = visitor.Visits.ToString();
|
||||
_visited = visitor.VisitedOn.ToString(CultureInfo.CurrentCulture);
|
||||
_created = visitor.CreatedOn.ToString(CultureInfo.CurrentCulture);
|
||||
|
||||
if (visitor.UserId != null)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(visitor.UserId.Value, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_user = user.DisplayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Visitor {VisitorId} {Error}", _visitorId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,13 +33,16 @@ else
|
|||
<br/>
|
||||
<Pager Items="@_visitors">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["IP"]</th>
|
||||
<th>@Localizer["User"]</th>
|
||||
<th>@Localizer["Language"]</th>
|
||||
<th>@Localizer["Visits"]</th>
|
||||
<th>@Localizer["Visited"]</th>
|
||||
<th>@Localizer["Created"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Detail" Parameters="@($"id=" + context.VisitorId.ToString())" ResourceKey="Details" /></td>
|
||||
<td>@context.IPAddress</td>
|
||||
<td>
|
||||
@if (context.UserId != null)
|
||||
|
@ -50,6 +53,7 @@ else
|
|||
<td>@context.Language</td>
|
||||
<td>@context.Visits</td>
|
||||
<td>@context.VisitedOn</td>
|
||||
<td>@context.CreatedOn</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
|
|
|
@ -34,10 +34,6 @@
|
|||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="System.Runtime" />
|
||||
<TrimmerRootAssembly Include="System.Linq.Parallel" />
|
||||
|
|
|
@ -132,11 +132,11 @@
|
|||
<data name="User" xml:space="preserve">
|
||||
<value>User</value>
|
||||
</data>
|
||||
<data name="Visited" xml:space="preserve">
|
||||
<value>Visited</value>
|
||||
<data name="Requested" xml:space="preserve">
|
||||
<value>Requested</value>
|
||||
</data>
|
||||
<data name="Visits" xml:space="preserve">
|
||||
<value>Visits</value>
|
||||
<data name="Requests" xml:space="preserve">
|
||||
<value>Requests</value>
|
||||
</data>
|
||||
<data name="Mapped" xml:space="preserve">
|
||||
<value>Mapped Urls</value>
|
||||
|
|
177
Oqtane.Client/Resources/Modules/Admin/Visitors/Detail.resx
Normal file
177
Oqtane.Client/Resources/Modules/Admin/Visitors/Detail.resx
Normal file
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="IP.Text" xml:space="preserve">
|
||||
<value>IP Address:</value>
|
||||
</data>
|
||||
<data name="IP.HelpText" xml:space="preserve">
|
||||
<value>The last recorded IP address for this visitor</value>
|
||||
</data>
|
||||
<data name="Language.HelpText" xml:space="preserve">
|
||||
<value>The last recorded language for this visitor</value>
|
||||
</data>
|
||||
<data name="Language.Text" xml:space="preserve">
|
||||
<value>Language:</value>
|
||||
</data>
|
||||
<data name="Error.LoadVisitor" xml:space="preserve">
|
||||
<value>Error Loading Visitor</value>
|
||||
</data>
|
||||
<data name="Created.HelpText" xml:space="preserve">
|
||||
<value>The frst recorded date/time when the visitor visited the site</value>
|
||||
</data>
|
||||
<data name="Created.Text" xml:space="preserve">
|
||||
<value>Created:</value>
|
||||
</data>
|
||||
<data name="Referrer.HelpText" xml:space="preserve">
|
||||
<value>The last recorded referrer for this visitor</value>
|
||||
</data>
|
||||
<data name="Referrer.Text" xml:space="preserve">
|
||||
<value>Referrer:</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>The last recorded Url for this visitor</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
</data>
|
||||
<data name="User.HelpText" xml:space="preserve">
|
||||
<value>The last recorded user associated with this visitor</value>
|
||||
</data>
|
||||
<data name="User.Text" xml:space="preserve">
|
||||
<value>User:</value>
|
||||
</data>
|
||||
<data name="UserAgent.HelpText" xml:space="preserve">
|
||||
<value>The last recorded user agent for this visitor</value>
|
||||
</data>
|
||||
<data name="UserAgent.Text" xml:space="preserve">
|
||||
<value>User Agent:</value>
|
||||
</data>
|
||||
<data name="Visited.HelpText" xml:space="preserve">
|
||||
<value>The last recorded date/time when the visitor visited the site</value>
|
||||
</data>
|
||||
<data name="Visited.Text" xml:space="preserve">
|
||||
<value>Visited:</value>
|
||||
</data>
|
||||
<data name="Visits.HelpText" xml:space="preserve">
|
||||
<value>The total number of visits by this visitor all time</value>
|
||||
</data>
|
||||
<data name="Visits.Text" xml:space="preserve">
|
||||
<value>Visits:</value>
|
||||
</data>
|
||||
</root>
|
|
@ -120,11 +120,11 @@
|
|||
<data name="Url" xml:space="preserve">
|
||||
<value>Url</value>
|
||||
</data>
|
||||
<data name="Requested" xml:space="preserve">
|
||||
<value>Requested</value>
|
||||
<data name="Visited" xml:space="preserve">
|
||||
<value>Visited</value>
|
||||
</data>
|
||||
<data name="Requests" xml:space="preserve">
|
||||
<value>Requests</value>
|
||||
<data name="Visits" xml:space="preserve">
|
||||
<value>Visits</value>
|
||||
</data>
|
||||
<data name="AllVisitors" xml:space="preserve">
|
||||
<value>All Visitors</value>
|
||||
|
@ -168,10 +168,7 @@
|
|||
<data name="User" xml:space="preserve">
|
||||
<value>User</value>
|
||||
</data>
|
||||
<data name="Visited" xml:space="preserve">
|
||||
<value>Visited</value>
|
||||
</data>
|
||||
<data name="Visits" xml:space="preserve">
|
||||
<value>Visits</value>
|
||||
<data name="Created" xml:space="preserve">
|
||||
<value>Created</value>
|
||||
</data>
|
||||
</root>
|
|
@ -17,5 +17,13 @@ namespace Oqtane.Services
|
|||
/// <param name="siteId">ID-reference of a <see cref="Site"/></param>
|
||||
/// <returns></returns>
|
||||
Task<List<Visitor>> GetVisitorsAsync(int siteId, DateTime fromDate);
|
||||
|
||||
/// <summary>
|
||||
/// Get a specific <see cref="Visitor"/> of this <see cref="Site"/>.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="visitorId">ID-reference of a <see cref="Visitor"/></param>
|
||||
/// <returns></returns>
|
||||
Task<Visitor> GetVisitorAsync(int visitorId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,5 +28,10 @@ namespace Oqtane.Services
|
|||
List<Visitor> visitors = await GetJsonAsync<List<Visitor>>($"{Apiurl}?siteid={siteId}&fromdate={fromDate.ToString("dd-MMM-yyyy")}");
|
||||
return visitors.OrderByDescending(item => item.VisitedOn).ToList();
|
||||
}
|
||||
|
||||
public async Task<Visitor> GetVisitorAsync(int visitorId)
|
||||
{
|
||||
return await GetJsonAsync<Visitor>($"{Apiurl}/{visitorId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,12 +204,15 @@ namespace Oqtane.Controllers
|
|||
}
|
||||
break;
|
||||
case EntityNames.Visitor:
|
||||
authorized = false;
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
{
|
||||
authorized = (visitorId == entityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return authorized;
|
||||
|
|
|
@ -42,5 +42,33 @@ namespace Oqtane.Controllers
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
public Visitor Get(int id)
|
||||
{
|
||||
bool authorized;
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
{
|
||||
authorized = (visitorId == id);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
}
|
||||
|
||||
var visitor = _visitors.GetVisitor(id);
|
||||
if (authorized && visitor != null && visitor.SiteId == _alias.SiteId)
|
||||
{
|
||||
return visitor;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Visitor Get Attempt {VisitorId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.03.00.01.05")]
|
||||
public class AddVisitorReferrer : MultiDatabaseMigration
|
||||
{
|
||||
public AddVisitorReferrer(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var visitorEntityBuilder = new VisitorEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
|
||||
visitorEntityBuilder.AddStringColumn("Referrer", 500, true);
|
||||
visitorEntityBuilder.AddStringColumn("Url", 500, true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var visitorEntityBuilder = new VisitorEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
|
||||
visitorEntityBuilder.DropColumn("Referrer");
|
||||
visitorEntityBuilder.DropColumn("Url");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -189,19 +189,33 @@ namespace Oqtane.Pages
|
|||
|
||||
private void TrackVisitor(int SiteId)
|
||||
{
|
||||
// get request attributes
|
||||
string ip = HttpContext.Connection.RemoteIpAddress.ToString();
|
||||
string useragent = Request.Headers[HeaderNames.UserAgent];
|
||||
string language = Request.Headers[HeaderNames.AcceptLanguage];
|
||||
if (language.Contains(","))
|
||||
{
|
||||
language = language.Substring(0, language.IndexOf(","));
|
||||
}
|
||||
string url = Request.GetEncodedUrl();
|
||||
string referrer = 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 = HttpContext.Connection.RemoteIpAddress.ToString();
|
||||
visitor.UserAgent = Request.Headers[HeaderNames.UserAgent];
|
||||
visitor.Language = Request.Headers[HeaderNames.AcceptLanguage];
|
||||
if (visitor.Language.Contains(","))
|
||||
{
|
||||
visitor.Language = visitor.Language.Substring(0, visitor.Language.IndexOf(","));
|
||||
}
|
||||
visitor.UserId = null;
|
||||
visitor.IPAddress = ip;
|
||||
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;
|
||||
|
@ -222,16 +236,17 @@ namespace Oqtane.Pages
|
|||
var visitor = _visitors.GetVisitor(VisitorId);
|
||||
if (visitor != null)
|
||||
{
|
||||
visitor.IPAddress = HttpContext.Connection.RemoteIpAddress.ToString();
|
||||
visitor.UserAgent = Request.Headers[HeaderNames.UserAgent];
|
||||
visitor.Language = Request.Headers[HeaderNames.AcceptLanguage];
|
||||
if (visitor.Language.Contains(","))
|
||||
visitor.IPAddress = ip;
|
||||
visitor.UserAgent = useragent;
|
||||
visitor.Language = language;
|
||||
visitor.Url = url;
|
||||
if (!string.IsNullOrEmpty(referrer))
|
||||
{
|
||||
visitor.Language = visitor.Language.Substring(0, visitor.Language.IndexOf(","));
|
||||
visitor.Referrer = referrer;
|
||||
}
|
||||
if (User.HasClaim(item => item.Type == ClaimTypes.PrimarySid))
|
||||
if (userid != null)
|
||||
{
|
||||
visitor.UserId = int.Parse(User.Claims.First(item => item.Type == ClaimTypes.PrimarySid).Value);
|
||||
visitor.UserId = userid;
|
||||
}
|
||||
visitor.Visits += 1;
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
|
|
|
@ -29,20 +29,30 @@ namespace Oqtane.Models
|
|||
public int Visits { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IP Address of visitor
|
||||
/// Last recorded IP Address of visitor
|
||||
/// </summary>
|
||||
public string IPAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User agent of visitor
|
||||
/// Last recorded user agent of visitor
|
||||
/// </summary>
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Language of visitor
|
||||
/// Last recorded language of visitor
|
||||
/// </summary>
|
||||
public string Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Last recorded Url of visitor
|
||||
/// </summary>
|
||||
public string Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Last recorded Referrer of visitor
|
||||
/// </summary>
|
||||
public string Referrer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date the visitor first visited the site
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in New Issue
Block a user