add support for visitor tracking

This commit is contained in:
sbwalker 2024-01-31 10:49:26 -05:00
parent e47690dd52
commit d0da1f43a9

View File

@ -1,7 +1,12 @@
@namespace Oqtane.Components
@using System.Net
@using System.Security.Claims
@using Microsoft.AspNetCore.Http
@using Microsoft.AspNetCore.Http.Extensions
@using Microsoft.AspNetCore.Antiforgery
@using Microsoft.AspNetCore.Localization
@using Microsoft.Net.Http.Headers
@using Microsoft.Extensions.Primitives
@using Oqtane.Client
@using Oqtane.Client.Utilities
@using Oqtane.Repository
@ -10,20 +15,20 @@
@using Oqtane.Models
@using Oqtane.Shared
@using Oqtane.Themes
@using System.Net
@using Microsoft.AspNetCore.Localization
@inject NavigationManager NavigationManager
@inject IAntiforgery Antiforgery;
@inject IConfigManager ConfigManager;
@inject ITenantManager TenantManager;
@inject ISiteRepository SiteRepository;
@inject IPageRepository PageRepository;
@inject IThemeRepository ThemeRepository;
@inject ILanguageRepository LanguageRepository;
@inject IServerStateManager ServerStateManager;
@inject ILocalizationManager LocalizationManager;
@inject IAliasRepository AliasRepository;
@inject IUrlMappingRepository UrlMappingRepository;
@inject IAntiforgery Antiforgery
@inject IConfigManager ConfigManager
@inject ITenantManager TenantManager
@inject ISiteRepository SiteRepository
@inject IPageRepository PageRepository
@inject IThemeRepository ThemeRepository
@inject ILanguageRepository LanguageRepository
@inject IServerStateManager ServerStateManager
@inject ILocalizationManager LocalizationManager
@inject IAliasRepository AliasRepository
@inject IUrlMappingRepository UrlMappingRepository
@inject ISettingRepository SettingRepository
@inject IVisitorRepository VisitorRepository
<!DOCTYPE html>
<html lang="@_language">
@ -56,11 +61,11 @@
{
@if (_renderMode == "Interactive")
{
<Routes AntiForgeryToken="@_antiForgeryToken" Runtime="Server" RenderMode="PreRendered" VisitorId="-1" RemoteIPAddress="@_remoteIPAddress" AuthorizationToken="" @rendermode="@RenderModes.GetInteractiveRenderMode((_renderMode + _interactiveRenderMode), _prerender)" />
<Routes AntiForgeryToken="@_antiForgeryToken" Runtime="Server" RenderMode="PreRendered" VisitorId="@_visitorId" RemoteIPAddress="@_remoteIPAddress" AuthorizationToken="" @rendermode="@RenderModes.GetInteractiveRenderMode((_renderMode + _interactiveRenderMode), _prerender)" />
}
else
{
<Routes AntiForgeryToken="@_antiForgeryToken" Runtime="Server" RenderMode="PreRendered" VisitorId="-1" RemoteIPAddress="@_remoteIPAddress" AuthorizationToken="" />
<Routes AntiForgeryToken="@_antiForgeryToken" Runtime="Server" RenderMode="PreRendered" VisitorId="@_visitorId" RemoteIPAddress="@_remoteIPAddress" AuthorizationToken="" />
}
<script src="js/interop.js"></script>
@ -96,6 +101,7 @@
private string _PWAScript = "";
private string _reconnectScript = "";
private string _message = "";
private int _visitorId = -1;
// CascadingParameter is required to access HttpContext
[CascadingParameter]
@ -143,10 +149,10 @@
HandlePageNotFound(site, page, route);
}
// if (site.VisitorTracking)
// {
// TrackVisitor(site.SiteId);
// }
if (site.VisitorTracking)
{
TrackVisitor(site.SiteId);
}
// get jwt token for downstream APIs
// if (User.Identity.IsAuthenticated)
@ -279,6 +285,137 @@
}
}
private void TrackVisitor(int SiteId)
{
try
{
// get request attributes
string useragent = (Context.Request.Headers[HeaderNames.UserAgent] != StringValues.Empty) ? Context.Request.Headers[HeaderNames.UserAgent] : "(none)";
useragent = (useragent.Length > 256) ? useragent.Substring(0, 256) : useragent;
string language = (Context.Request.Headers[HeaderNames.AcceptLanguage] != StringValues.Empty) ? Context.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 settings = SettingRepository.GetSettings(EntityNames.Site, SiteId);
if (settings.Any(item => item.SettingName == "VisitorFilter"))
{
filter = settings.First(item => item.SettingName == "VisitorFilter").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;
}
}
// get other request attributes
string url = Context.Request.GetEncodedUrl();
string referrer = (Context.Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Context.Request.Headers[HeaderNames.Referer] : "";
int? userid = null;
if (Context.User.HasClaim(item => item.Type == ClaimTypes.NameIdentifier))
{
userid = int.Parse(Context.User.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
}
// check if cookie already exists
Visitor visitor = null;
bool addcookie = false;
var VisitorCookie = Constants.VisitorCookiePrefix + SiteId.ToString();
if (!int.TryParse(Context.Request.Cookies[VisitorCookie], out _visitorId))
{
// if enabled use IP Address correlation
_visitorId = -1;
bool correlate = true;
if (settings.Any(item => item.SettingName == "VisitorCorrelation"))
{
correlate = bool.Parse(settings.First(item => item.SettingName == "VisitorCorrelation").SettingValue);
}
if (correlate)
{
visitor = VisitorRepository.GetVisitor(SiteId, _remoteIPAddress);
if (visitor != null)
{
_visitorId = visitor.VisitorId;
addcookie = true;
}
}
}
if (_visitorId == -1)
{
// create new visitor
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 = VisitorRepository.AddVisitor(visitor);
_visitorId = visitor.VisitorId;
addcookie = true;
}
else
{
if (visitor == null)
{
// get visitor if it was not previously loaded
visitor = VisitorRepository.GetVisitor(_visitorId);
}
if (visitor != null)
{
// update visitor
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;
VisitorRepository.UpdateVisitor(visitor);
}
else
{
// remove cookie if VisitorId does not exist
Context.Response.Cookies.Delete(VisitorCookie);
}
}
// append cookie
if (addcookie)
{
Context.Response.Cookies.Append(
VisitorCookie,
_visitorId.ToString(),
new CookieOptions()
{
Expires = DateTimeOffset.UtcNow.AddYears(1),
IsEssential = true
}
);
}
}
catch
{
// error tracking visitor
}
}
private string CreatePWAScript(Alias alias, Site site, Route route)
{
return