diff --git a/Oqtane.Client/Modules/Admin/Visitors/Index.razor b/Oqtane.Client/Modules/Admin/Visitors/Index.razor
index 16b5d1a8..11deb70f 100644
--- a/Oqtane.Client/Modules/Admin/Visitors/Index.razor
+++ b/Oqtane.Client/Modules/Admin/Visitors/Index.razor
@@ -81,6 +81,15 @@ else
+
+
+
+
+
+
@@ -96,6 +105,7 @@ else
private string _tracking;
private string _filter = "";
private string _retention = "";
+ private string _correlation = "true";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
@@ -120,6 +130,7 @@ else
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
_retention = SettingService.GetSetting(settings, "VisitorRetention", "30");
+ _correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
}
private async void TypeChanged(ChangeEventArgs e)
@@ -170,6 +181,7 @@ else
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention, true);
+ settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
diff --git a/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx
index f852194f..28bc46d1 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx
@@ -186,4 +186,10 @@
Retention (Days):
+
+ Indicate if new visitors to this site should be correlated based on their IP Address
+
+
+ Correlate Visitors?
+
\ No newline at end of file
diff --git a/Oqtane.Database.Sqlite/SqliteDatabase.cs b/Oqtane.Database.Sqlite/SqliteDatabase.cs
index a6b078c9..8b91ffba 100644
--- a/Oqtane.Database.Sqlite/SqliteDatabase.cs
+++ b/Oqtane.Database.Sqlite/SqliteDatabase.cs
@@ -30,6 +30,11 @@ namespace Oqtane.Database.Sqlite
return table.Column(name: name, nullable: false).Annotation("Sqlite:Autoincrement", true);
}
+ public override void DropColumn(MigrationBuilder builder, string name, string table)
+ {
+ // not implemented as SQLite does not support dropping columns
+ }
+
public override string ConcatenateSql(params string[] values)
{
var returnValue = String.Empty;
diff --git a/Oqtane.Server/Databases/DatabaseBase.cs b/Oqtane.Server/Databases/DatabaseBase.cs
index bad8ad6c..d9a25371 100644
--- a/Oqtane.Server/Databases/DatabaseBase.cs
+++ b/Oqtane.Server/Databases/DatabaseBase.cs
@@ -1,6 +1,7 @@
using System;
using System.Data;
using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
using Oqtane.Databases.Interfaces;
@@ -75,6 +76,11 @@ namespace Oqtane.Databases
}
+ public virtual void DropColumn(MigrationBuilder builder, string name, string table)
+ {
+ builder.DropColumn(name, table);
+ }
+
public abstract DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString);
}
}
diff --git a/Oqtane.Server/Databases/Interfaces/IDatabase.cs b/Oqtane.Server/Databases/Interfaces/IDatabase.cs
index 2a6c0999..8d80e39e 100644
--- a/Oqtane.Server/Databases/Interfaces/IDatabase.cs
+++ b/Oqtane.Server/Databases/Interfaces/IDatabase.cs
@@ -1,5 +1,6 @@
using System.Data;
using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
@@ -31,6 +32,8 @@ namespace Oqtane.Databases.Interfaces
public void UpdateIdentityStoreTableNames(ModelBuilder builder);
+ public void DropColumn(MigrationBuilder builder, string name, string table);
+
public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString);
}
}
diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
index d8693bd2..89f9895a 100644
--- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
+++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
@@ -17,6 +17,7 @@ using Oqtane.Infrastructure;
using Oqtane.Modules;
using Oqtane.Repository;
using Oqtane.Security;
+using Oqtane.Services;
using Oqtane.Shared;
namespace Microsoft.Extensions.DependencyInjection
@@ -222,12 +223,15 @@ namespace Microsoft.Extensions.DependencyInjection
}
}
- // register server startup services
- var startUps = assembly.GetInstances();
- foreach (var startup in startUps)
- {
- startup.ConfigureServices(services);
- }
+ // dynamically register server startup services
+ assembly.GetInstances()
+ .ToList()
+ .ForEach(x => x.ConfigureServices(services));
+
+ // dynamically register client startup services (these services will only be used when running on Blazor Server)
+ assembly.GetInstances()
+ .ToList()
+ .ForEach(x => x.ConfigureServices(services));
}
return services;
}
diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs
index 07c68631..d9275734 100644
--- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs
+++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs
@@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Net.NetworkInformation;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
using Oqtane.Databases.Interfaces;
-using Oqtane.Interfaces;
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
namespace Oqtane.Migrations.EntityBuilders
@@ -126,7 +124,7 @@ namespace Oqtane.Migrations.EntityBuilders
public void DropColumn(string name)
{
- _migrationBuilder.DropColumn(RewriteName(name), RewriteName(EntityTableName));
+ ActiveDatabase.DropColumn(_migrationBuilder, RewriteName(name), RewriteName(EntityTableName));
}
diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs
index 7c76e354..a5c89a9b 100644
--- a/Oqtane.Server/Pages/_Host.cshtml.cs
+++ b/Oqtane.Server/Pages/_Host.cshtml.cs
@@ -253,6 +253,35 @@ namespace Oqtane.Pages
var VisitorCookie = "APP_VISITOR_" + SiteId.ToString();
if (!int.TryParse(Request.Cookies[VisitorCookie], out VisitorId))
+ {
+ VisitorId = -1;
+ bool correlate = true;
+ setting = _settings.GetSetting(EntityNames.Site, SiteId, "VisitorCorrelation");
+ if (setting != null)
+ {
+ correlate = bool.Parse(setting.SettingValue);
+ }
+ if (correlate)
+ {
+ var visitor = _visitors.GetVisitor(SiteId, RemoteIPAddress);
+ if (visitor != null)
+ {
+ VisitorId = visitor.VisitorId;
+
+ Response.Cookies.Append(
+ VisitorCookie,
+ VisitorId.ToString(),
+ new CookieOptions()
+ {
+ Expires = DateTimeOffset.UtcNow.AddYears(1),
+ IsEssential = true
+ }
+ );
+ }
+ }
+ }
+
+ if (VisitorId == -1)
{
var visitor = new Visitor();
visitor.SiteId = SiteId;
diff --git a/Oqtane.Server/Repository/Interfaces/IVisitorRepository.cs b/Oqtane.Server/Repository/Interfaces/IVisitorRepository.cs
index 3b05ba90..d73a02ed 100644
--- a/Oqtane.Server/Repository/Interfaces/IVisitorRepository.cs
+++ b/Oqtane.Server/Repository/Interfaces/IVisitorRepository.cs
@@ -10,6 +10,7 @@ namespace Oqtane.Repository
Visitor AddVisitor(Visitor visitor);
Visitor UpdateVisitor(Visitor visitor);
Visitor GetVisitor(int visitorId);
+ Visitor GetVisitor(int siteId, string IPAddress);
void DeleteVisitor(int visitorId);
int DeleteVisitors(int age);
}
diff --git a/Oqtane.Server/Repository/VisitorRepository.cs b/Oqtane.Server/Repository/VisitorRepository.cs
index 6572d973..2f7c10dc 100644
--- a/Oqtane.Server/Repository/VisitorRepository.cs
+++ b/Oqtane.Server/Repository/VisitorRepository.cs
@@ -41,6 +41,11 @@ namespace Oqtane.Repository
return _db.Visitor.Find(visitorId);
}
+ public Visitor GetVisitor(int siteId, string IPAddress)
+ {
+ return _db.Visitor.FirstOrDefault(item => item.SiteId == siteId && item.IPAddress == IPAddress);
+ }
+
public void DeleteVisitor(int visitorId)
{
Visitor visitor = _db.Visitor.Find(visitorId);
diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak
index 461409ed..a4866e07 100644
Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak differ
diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak
index a99a0724..e5ebbf28 100644
Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak differ
diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak
index 859f8844..6f38671f 100644
Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak differ
diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak
index ad6c9b2a..acf13f1c 100644
Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak differ