From d8b717a879024455741f8340f95f533758257e52 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 25 Jan 2024 15:08:56 -0500 Subject: [PATCH 001/280] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ba4b8f49..18226e276 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Latest Release -[5.0.1](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.1) was released on Dec 21, 2023 and is a major release targeted at .NET 8. This release includes 67 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 4400. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. +[5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) was released on Jan 25, 2024 and is a stabilization release targeted at .NET 8. This release includes 51 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 4600. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json) @@ -66,6 +66,9 @@ Backlog (TBD) 5.1.0 (Q1 2024) - [ ] Full Stack Blazor (Static Server-Side Rendering) +[5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024) +- [x] Stabilization improvements + [5.0.1](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.1) (Dec 21, 2023) - [x] Stabilization improvements From c6f65debcff97dbc68b87ab2b2086a4e7a9ddca7 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Sun, 28 Jan 2024 11:56:55 +0100 Subject: [PATCH 002/280] Menu theme fix #3680 Added white-space: nowrap; to the .app-menu .nav-item --- .../wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css index 654247d49..b1536f7b6 100644 --- a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css @@ -50,6 +50,7 @@ body { .app-menu .nav-item { font-size: 0.9rem; padding-bottom: 0.5rem; + white-space: nowrap; } .app-menu .nav-item a { @@ -98,7 +99,7 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu @media (max-width: 767px) { .app-menu { - width: 100% + width: 100% ; } .navbar { From 8bf29528e3945b7fc44bae59ccd3152b5aea788f Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Mon, 29 Jan 2024 07:19:30 +0100 Subject: [PATCH 003/280] Updated Theme Template Template updated with white-space: nowrap; and corrected the app-menu class --- .../Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css index fa0bd479c..e78e77d17 100644 --- a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css @@ -1,4 +1,4 @@ -/* Oqtane Styles */ +/* Oqtane Styles */ body { padding-top: 7rem; @@ -48,6 +48,7 @@ body { .app-menu .nav-item { font-size: 0.9rem; padding-bottom: 0.5rem; + white-space: nowrap; } .app-menu .nav-item a { @@ -92,7 +93,7 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu @media (max-width: 767px) { .app-menu { - width: 100% + width: 100%; } .navbar { From ea04c7d5eb56a5e1c53e81fe07b0ce0e344877a6 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 29 Jan 2024 12:55:39 -0500 Subject: [PATCH 004/280] bump version to 5.0.3 --- Oqtane.Client/Oqtane.Client.csproj | 4 ++-- Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj | 4 ++-- .../Oqtane.Database.PostgreSQL.csproj | 4 ++-- Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj | 4 ++-- Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj | 4 ++-- Oqtane.Maui/Oqtane.Maui.csproj | 6 +++--- Oqtane.Package/Oqtane.Client.nuspec | 4 ++-- Oqtane.Package/Oqtane.Framework.nuspec | 6 +++--- Oqtane.Package/Oqtane.Server.nuspec | 4 ++-- Oqtane.Package/Oqtane.Shared.nuspec | 4 ++-- Oqtane.Package/Oqtane.Updater.nuspec | 4 ++-- Oqtane.Package/install.ps1 | 2 +- Oqtane.Package/upgrade.ps1 | 2 +- Oqtane.Server/Oqtane.Server.csproj | 4 ++-- Oqtane.Shared/Oqtane.Shared.csproj | 4 ++-- Oqtane.Shared/Shared/Constants.cs | 4 ++-- Oqtane.Updater/Oqtane.Updater.csproj | 4 ++-- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index c825a93e3..2d1d0703b 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -4,7 +4,7 @@ net8.0 Exe Debug;Release - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -12,7 +12,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj index 4edcb747b..b09daf658 100644 --- a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj +++ b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj index 431db75a8..a1107d0b9 100644 --- a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj +++ b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj index a06d14b68..361d671b8 100644 --- a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj +++ b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj index 5de3d4094..17abd6c98 100644 --- a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj +++ b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index 7f924fab7..03c6e1f0b 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -6,7 +6,7 @@ Exe - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -14,7 +14,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git Oqtane.Maui @@ -31,7 +31,7 @@ 0E29FC31-1B83-48ED-B6E0-9F3C67B775D4 - 5.0.2 + 5.0.3 1 14.2 diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index 06250592f..e4c87763a 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -2,7 +2,7 @@ Oqtane.Client - 5.0.2 + 5.0.3 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Framework.nuspec b/Oqtane.Package/Oqtane.Framework.nuspec index 671ba15a1..a96b5382a 100644 --- a/Oqtane.Package/Oqtane.Framework.nuspec +++ b/Oqtane.Package/Oqtane.Framework.nuspec @@ -2,7 +2,7 @@ Oqtane.Framework - 5.0.2 + 5.0.3 Shaun Walker .NET Foundation Oqtane Framework @@ -11,8 +11,8 @@ .NET Foundation false MIT - https://github.com/oqtane/oqtane.framework/releases/download/v5.0.2/Oqtane.Framework.5.0.2.Upgrade.zip - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/download/v5.0.3/Oqtane.Framework.5.0.3.Upgrade.zip + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 icon.png oqtane framework diff --git a/Oqtane.Package/Oqtane.Server.nuspec b/Oqtane.Package/Oqtane.Server.nuspec index 1b87c6099..7577ef974 100644 --- a/Oqtane.Package/Oqtane.Server.nuspec +++ b/Oqtane.Package/Oqtane.Server.nuspec @@ -2,7 +2,7 @@ Oqtane.Server - 5.0.2 + 5.0.3 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index 294d5c5c2..800186c6d 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -2,7 +2,7 @@ Oqtane.Shared - 5.0.2 + 5.0.3 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Updater.nuspec b/Oqtane.Package/Oqtane.Updater.nuspec index e16b7bd9a..2abc25a1c 100644 --- a/Oqtane.Package/Oqtane.Updater.nuspec +++ b/Oqtane.Package/Oqtane.Updater.nuspec @@ -2,7 +2,7 @@ Oqtane.Updater - 5.0.2 + 5.0.3 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 icon.png oqtane diff --git a/Oqtane.Package/install.ps1 b/Oqtane.Package/install.ps1 index 3f9861701..eeafbdc38 100644 --- a/Oqtane.Package/install.ps1 +++ b/Oqtane.Package/install.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.0.2.Install.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.0.3.Install.zip" -Force \ No newline at end of file diff --git a/Oqtane.Package/upgrade.ps1 b/Oqtane.Package/upgrade.ps1 index f1fe650ee..d86753f0f 100644 --- a/Oqtane.Package/upgrade.ps1 +++ b/Oqtane.Package/upgrade.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.0.2.Upgrade.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.0.3.Upgrade.zip" -Force \ No newline at end of file diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 70f595322..34f52a179 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index d2b161f9c..acdb88187 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index efef37e36..0b38b07b0 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -4,8 +4,8 @@ namespace Oqtane.Shared { public class Constants { - public static readonly string Version = "5.0.2"; - public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2"; + public static readonly string Version = "5.0.3"; + public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3"; public const string PackageId = "Oqtane.Framework"; public const string ClientId = "Oqtane.Client"; public const string UpdaterPackageId = "Oqtane.Updater"; diff --git a/Oqtane.Updater/Oqtane.Updater.csproj b/Oqtane.Updater/Oqtane.Updater.csproj index 616bc2b95..27e608177 100644 --- a/Oqtane.Updater/Oqtane.Updater.csproj +++ b/Oqtane.Updater/Oqtane.Updater.csproj @@ -3,7 +3,7 @@ net8.0 Exe - 5.0.2 + 5.0.3 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 https://github.com/oqtane/oqtane.framework Git Oqtane From 7fcfffba6f1c4bacc8200030516cfcbdc17bfa04 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 30 Jan 2024 13:13:49 -0500 Subject: [PATCH 005/280] add IDisposable declaration to accompany existing Dispose() method --- Oqtane.Client/Head.razor | 1 + Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor | 1 + Oqtane.Client/UI/ContainerBuilder.razor | 1 + Oqtane.Client/UI/SiteRouter.razor | 1 + .../HostedServices/EventDistributorHostedService .cs | 2 +- Oqtane.Server/Infrastructure/Logging/FileLoggerProvider.cs | 4 +++- 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Head.razor b/Oqtane.Client/Head.razor index 182071782..88f5c6a78 100644 --- a/Oqtane.Client/Head.razor +++ b/Oqtane.Client/Head.razor @@ -1,6 +1,7 @@ @using System.ComponentModel @using Oqtane.Shared @inject SiteState SiteState +@implements IDisposable @if (!string.IsNullOrEmpty(_title)) { diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor b/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor index c79e43257..d67baf3a1 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor +++ b/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor @@ -4,6 +4,7 @@ @attribute [OqtaneIgnore] @inject IStringLocalizer SharedLocalizer @inject IStringLocalizerFactory LocalizerFactory +@implements IDisposable @((MarkupString)title) diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 893dafd1a..6a769aed9 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -1,6 +1,7 @@ @using System.ComponentModel @namespace Oqtane.UI @inject SiteState SiteState +@implements IDisposable @if (ComponentType != null && _visible) { diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 1da8a8cda..d04e44693 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -13,6 +13,7 @@ @inject ILogService LogService @inject IJSRuntime JSRuntime @implements IHandleAfterRender +@implements IDisposable @if (!string.IsNullOrEmpty(_error)) { diff --git a/Oqtane.Server/Infrastructure/HostedServices/EventDistributorHostedService .cs b/Oqtane.Server/Infrastructure/HostedServices/EventDistributorHostedService .cs index 5c0ffa1c2..2b52e5e17 100644 --- a/Oqtane.Server/Infrastructure/HostedServices/EventDistributorHostedService .cs +++ b/Oqtane.Server/Infrastructure/HostedServices/EventDistributorHostedService .cs @@ -12,7 +12,7 @@ namespace Oqtane.Infrastructure { - public class EventDistributorHostedService : IHostedService + public class EventDistributorHostedService : IHostedService, IDisposable { private readonly IServiceProvider _serviceProvider; private readonly ISyncManager _syncManager; diff --git a/Oqtane.Server/Infrastructure/Logging/FileLoggerProvider.cs b/Oqtane.Server/Infrastructure/Logging/FileLoggerProvider.cs index 11c4ff481..fad1b294b 100644 --- a/Oqtane.Server/Infrastructure/Logging/FileLoggerProvider.cs +++ b/Oqtane.Server/Infrastructure/Logging/FileLoggerProvider.cs @@ -1,10 +1,11 @@ +using System; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Logging; namespace Oqtane.Infrastructure { /// - /// FileLogger should only be used in scenarios where a database is not available or tenant/site cannot be determined ( ie. during startup ) + /// FileLogger should only be used in scenarios where a database is not available or tenant/site cannot be determined (ie. during startup) /// [ProviderAlias("FileLogger")] public class FileLoggerProvider : ILoggerProvider @@ -25,6 +26,7 @@ public ILogger CreateLogger(string categoryName) public void Dispose() { + // nothing to dispose } } } From 82d7b9cf05fe713764a1cf83852c6c5b58812137 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 30 Jan 2024 16:03:50 -0500 Subject: [PATCH 006/280] initial changes to migrate to new Blazor approach in .NET 8 --- Oqtane.Client/{App.razor => Routes.razor} | 0 Oqtane.Client/Utilities/RenderModes.cs | 22 + Oqtane.Server/Components/App.razor | 386 +++++++++++++ ...ComponentEndpointRouteBuilderExtensions.cs | 29 + Oqtane.Server/Pages/_Host.cshtml | 67 --- Oqtane.Server/Pages/_Host.cshtml.cs | 525 ------------------ .../AutoValidateAntiforgeryTokenFilter.cs | 2 + Oqtane.Server/Startup.cs | 53 +- 8 files changed, 479 insertions(+), 605 deletions(-) rename Oqtane.Client/{App.razor => Routes.razor} (100%) create mode 100644 Oqtane.Client/Utilities/RenderModes.cs create mode 100644 Oqtane.Server/Components/App.razor create mode 100644 Oqtane.Server/Extensions/ComponentEndpointRouteBuilderExtensions.cs delete mode 100644 Oqtane.Server/Pages/_Host.cshtml delete mode 100644 Oqtane.Server/Pages/_Host.cshtml.cs diff --git a/Oqtane.Client/App.razor b/Oqtane.Client/Routes.razor similarity index 100% rename from Oqtane.Client/App.razor rename to Oqtane.Client/Routes.razor diff --git a/Oqtane.Client/Utilities/RenderModes.cs b/Oqtane.Client/Utilities/RenderModes.cs new file mode 100644 index 000000000..820dec37b --- /dev/null +++ b/Oqtane.Client/Utilities/RenderModes.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components; + +namespace Oqtane.Client.Utilities +{ + public static class RenderModes + { + public static IComponentRenderMode GetRenderMode(string renderMode) + { + switch (renderMode) + { + case "InteractiveServer": + return RenderMode.InteractiveServer; + case "InteractiveWebAssembly": + return RenderMode.InteractiveWebAssembly; + case "InteractiveAuto": + return RenderMode.InteractiveAuto; + } + return null; + } + } +} diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor new file mode 100644 index 000000000..0d0f69e36 --- /dev/null +++ b/Oqtane.Server/Components/App.razor @@ -0,0 +1,386 @@ +@namespace Oqtane.Components +@using Microsoft.AspNetCore.Http +@using Microsoft.AspNetCore.Http.Extensions +@using Oqtane.Client +@using Oqtane.Client.Utilities +@using Oqtane.Repository +@using Oqtane.Infrastructure +@using Oqtane.Security +@using Oqtane.Models +@using Oqtane.Shared +@using Oqtane.Themes +@using System.Net +@using Microsoft.AspNetCore.Localization +@inject IConfigManager ConfigManager; +@inject ITenantManager TenantManager; +@inject ILocalizationManager LocalizationManager; +@inject ISiteRepository SiteRepository; +@inject IPageRepository PageRepository; +@inject IThemeRepository ThemeRepository; +@inject ILanguageRepository LanguageRepository; +@inject IServerStateManager ServerStateManager; + + + + + + + + + + + @if (!string.IsNullOrEmpty(_PWAScript)) + { + + } + @((MarkupString)_styleSheets) + + + + @((MarkupString)_headResources) + + + @if (string.IsNullOrEmpty(_message)) + { + + + + + + @if (!string.IsNullOrEmpty(_reconnectScript)) + { + @((MarkupString)_reconnectScript) + } + @if (!string.IsNullOrEmpty(_PWAScript)) + { + @((MarkupString)_PWAScript) + } + @((MarkupString)_bodyResources) + } + else + { +
@_message
+ } + + + +@code { + private string _interactiveRenderMode = "InteractiveServer"; + private string _language = "en"; + private string _remoteIPAddress = ""; + private string _headResources = ""; + private string _bodyResources = ""; + private string _styleSheets = ""; + private string _PWAScript = ""; + private string _reconnectScript = ""; + private string _message = ""; + + // CascadingParameter is required to access HttpContext + [CascadingParameter] + HttpContext Context { get; set; } + + protected override void OnInitialized() + { + _remoteIPAddress = Context.Connection.RemoteIpAddress?.ToString() ?? ""; + + // if framework is installed + if (ConfigManager.IsInstalled()) + { + var alias = TenantManager.GetAlias(); + if (alias != null) + { + var url = WebUtility.UrlDecode(Context.Request.GetEncodedUrl()); + + // redirect non-default alias unless you are trying to access site settings + // if (!alias.IsDefault && !url.Contains("admin/site")) + // { + // var aliases = AliasRepository.GetAliases().Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId); + // if (aliases.Where(item => item.IsDefault).FirstOrDefault() != null) + // { + // return RedirectPermanent(url.Replace(alias.Name, aliases.Where(item => item.IsDefault).FirstOrDefault().Name)); + // } + // else // no default specified - use first alias + // { + // if (alias.Name.Trim() != aliases.First().Name.Trim()) + // { + // return RedirectPermanent(url.Replace(alias.Name, aliases.First().Name)); + // } + // } + // } + + var site = SiteRepository.GetSite(alias.SiteId); + if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") + { + // if (!string.IsNullOrEmpty(site.Runtime)) + // { + // Runtime = site.Runtime; + // } + // if (!string.IsNullOrEmpty(site.RenderMode)) + // { + // RenderMode = site.RenderMode; + // } + + Route route = new Route(url, alias.Path); + var page = PageRepository.GetPage(route.PagePath, site.SiteId); + if (page == null && route.PagePath == "" && site.HomePageId != null) + { + page = PageRepository.GetPage(site.HomePageId.Value); + } + + // if (page == null || page.IsDeleted) + // { + // // page not found - look for url mapping + // var urlMapping = _urlMappings.GetUrlMapping(site.SiteId, route.PagePath); + // if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) + // { + // url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl; + // return RedirectPermanent(url); + // } + // else + // { + // if (route.PagePath != "404") + // { + // return RedirectPermanent(route.SiteUrl + "/404"); + // } + // } + // } + + // if (site.VisitorTracking) + // { + // TrackVisitor(site.SiteId); + // } + + // get jwt token for downstream APIs + // if (User.Identity.IsAuthenticated) + // { + // var sitesettings = HttpContext.GetSiteSettings(); + // var secret = sitesettings.GetValue("JwtOptions:Secret", ""); + // if (!string.IsNullOrEmpty(secret)) + // { + // AuthorizationToken = _jwtManager.GenerateToken(alias, (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20"))); + // } + // } + + // stylesheets + var themes = ThemeRepository.GetThemes().ToList(); + var resources = new List(); + if (string.IsNullOrEmpty(page.ThemeType)) + { + page.ThemeType = site.DefaultThemeType; + } + var theme = themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType)); + if (theme?.Resources != null) + { + resources.AddRange(theme.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); + } + var type = Type.GetType(page.ThemeType); + if (type != null) + { + var obj = Activator.CreateInstance(type) as IThemeControl; + if (obj?.Resources != null) + { + resources.AddRange(obj.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); + } + } + ManageStyleSheets(resources, alias, theme.ThemeName); + + // scripts + if (_interactiveRenderMode == "InteractiveServer") + { + _reconnectScript = CreateReconnectScript(); + } + if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null) + { + _PWAScript = CreatePWAScript(alias, site, route); + } + _headResources += ParseScripts(site.HeadContent); + _bodyResources += ParseScripts(site.BodyContent); + var scripts = ServerStateManager.GetServerState(alias.SiteKey).Scripts; + foreach (var script in scripts) + { + AddScript(script, alias); + } + + // set culture if not specified + string culture = Context.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName]; + if (culture == null) + { + // get default language for site + var languages = LanguageRepository.GetLanguages(alias.SiteId); + if (languages.Any()) + { + // use default language if specified otherwise use first language in collection + culture = (languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First()).Code; + } + else + { + culture = LocalizationManager.GetDefaultCulture(); + } + SetLocalizationCookie(culture); + } + + // set language for page + if (!string.IsNullOrEmpty(culture)) + { + // localization cookie value in form of c=en|uic=en + _language = culture.Split('|')[0]; + _language = _language.Replace("c=", ""); + } + } + else + { + _message = "Site Is Disabled"; + } + } + else + { + _message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name"; + } + } + } + + private string CreatePWAScript(Alias alias, Site site, Route route) + { + return + "" + Environment.NewLine + + ""; + } + + private string CreateReconnectScript() + { + return + ""; + } + + private string ParseScripts(string content) + { + // iterate scripts + var scripts = ""; + if (!string.IsNullOrEmpty(content)) + { + var index = content.IndexOf("= 0) + { + scripts += content.Substring(index, content.IndexOf("", index) + 9 - index); + index = content.IndexOf(""; + } + else + { + // inline script + return ""; + } + } + + private void SetLocalizationCookie(string culture) + { + Context.Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture))); + } + + private void ManageStyleSheets(List resources, Alias alias, string name) + { + if (resources != null) + { + int count = 0; + foreach (var resource in resources) + { + if (resource.Url.StartsWith("~")) + { + resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(name) + "/").Replace("//", "/"); + } + if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl)) + { + resource.Url = alias.BaseUrl + resource.Url; + } + + if (!_styleSheets.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) + { + count++; + string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + count.ToString("00") + "\" "; + _styleSheets += "" + Environment.NewLine; + } + } + } + } +} diff --git a/Oqtane.Server/Extensions/ComponentEndpointRouteBuilderExtensions.cs b/Oqtane.Server/Extensions/ComponentEndpointRouteBuilderExtensions.cs new file mode 100644 index 000000000..b464e81d4 --- /dev/null +++ b/Oqtane.Server/Extensions/ComponentEndpointRouteBuilderExtensions.cs @@ -0,0 +1,29 @@ +#nullable enable +using Oqtane.Components; +using Microsoft.AspNetCore.Components.Endpoints; +using Microsoft.AspNetCore.Routing; +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace OqtaneSSR.Extensions +{ + public static class ComponentEndpointRouteBuilderExtensions + { + public static void MapFallback(this IEndpointRouteBuilder endpoints) + { + ArgumentNullException.ThrowIfNull(endpoints); + + endpoints.MapFallback((ctx) => + { + var invoker = ctx.RequestServices.GetRequiredService(); + return invoker.Render(ctx); + }) + .Add(routeEndpointBuilder => + { + routeEndpointBuilder.Metadata.Add(new RootComponentMetadata(typeof(App))); + routeEndpointBuilder.Metadata.Add(new ComponentTypeMetadata(typeof(App))); + }); + } + } +} diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml deleted file mode 100644 index af8444f80..000000000 --- a/Oqtane.Server/Pages/_Host.cshtml +++ /dev/null @@ -1,67 +0,0 @@ -@page "/" -@namespace Oqtane.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@model Oqtane.Pages.HostModel - - - - - - - - - - @if (!string.IsNullOrEmpty(Model.PWAScript)) - { - - } - @Html.Raw(Model.StyleSheets) - - - - @Html.Raw(Model.HeadResources) - - - @if (string.IsNullOrEmpty(Model.Message)) - { - @(Html.AntiForgeryToken()) - - - -
- - An error has occurred. This application may no longer respond until reloaded. - - - An unhandled exception has occurred. See browser dev tools for details. - - Reload - 🗙 -
- - - - @if (Model.Runtime == "WebAssembly") - { - - } - @if (Model.Runtime == "Server") - { - - } - @if (!string.IsNullOrEmpty(Model.ReconnectScript)) - { - @Html.Raw(Model.ReconnectScript) - } - @if (!string.IsNullOrEmpty(Model.PWAScript)) - { - @Html.Raw(Model.PWAScript) - } - @Html.Raw(Model.BodyResources) - } - else - { -
@Model.Message
- } - - diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs deleted file mode 100644 index a451f5a08..000000000 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ /dev/null @@ -1,525 +0,0 @@ -using Microsoft.AspNetCore.Mvc.RazorPages; -using Oqtane.Infrastructure; -using Oqtane.Shared; -using Oqtane.Models; -using System; -using System.Linq; -using Oqtane.Repository; -using Microsoft.AspNetCore.Localization; -using Microsoft.Extensions.Configuration; -using Microsoft.AspNetCore.Antiforgery; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Net.Http.Headers; -using Microsoft.AspNetCore.Http; -using System.Security.Claims; -using System.Net; -using Microsoft.Extensions.Primitives; -using Oqtane.Enums; -using Oqtane.Security; -using Oqtane.Extensions; -using Oqtane.Themes; -using System.Collections.Generic; - -namespace Oqtane.Pages -{ - public class HostModel : PageModel - { - private IConfigManager _configuration; - private readonly ITenantManager _tenantManager; - private readonly ILocalizationManager _localizationManager; - private readonly ILanguageRepository _languages; - private readonly IAntiforgery _antiforgery; - private readonly IJwtManager _jwtManager; - private readonly ISiteRepository _sites; - private readonly IPageRepository _pages; - private readonly IUrlMappingRepository _urlMappings; - private readonly IVisitorRepository _visitors; - private readonly IAliasRepository _aliases; - private readonly ISettingRepository _settings; - private readonly IThemeRepository _themes; - private readonly IServerStateManager _serverState; - private readonly ILogManager _logger; - - public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, IJwtManager jwtManager, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, IThemeRepository themes, IServerStateManager serverState, ILogManager logger) - { - _configuration = configuration; - _tenantManager = tenantManager; - _localizationManager = localizationManager; - _languages = languages; - _antiforgery = antiforgery; - _jwtManager = jwtManager; - _sites = sites; - _pages = pages; - _urlMappings = urlMappings; - _visitors = visitors; - _aliases = aliases; - _settings = settings; - _themes = themes; - _serverState = serverState; - _logger = logger; - } - - public string Language = "en"; - public string AntiForgeryToken = ""; - public string AuthorizationToken = ""; - public string Runtime = "Server"; - public string RenderMode = "ServerPrerendered"; - public int VisitorId = -1; - public string RemoteIPAddress = ""; - public string HeadResources = ""; - public string BodyResources = ""; - public string StyleSheets = ""; - public string PWAScript = ""; - public string ReconnectScript = ""; - public string Message = ""; - - public IActionResult OnGet() - { - AntiForgeryToken = _antiforgery.GetAndStoreTokens(HttpContext).RequestToken; - RemoteIPAddress = HttpContext.Connection.RemoteIpAddress?.ToString() ?? ""; - - if (_configuration.GetSection("Runtime").Exists()) - { - Runtime = _configuration.GetSection("Runtime").Value; - } - - if (_configuration.GetSection("RenderMode").Exists()) - { - RenderMode = _configuration.GetSection("RenderMode").Value; - } - - // if framework is installed - if (_configuration.IsInstalled()) - { - var alias = _tenantManager.GetAlias(); - if (alias != null) - { - var url = WebUtility.UrlDecode(HttpContext.Request.GetEncodedUrl()); - - // redirect non-default alias unless you are trying to access site settings - if (!alias.IsDefault && !url.Contains("admin/site")) - { - var aliases = _aliases.GetAliases().Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId); - if (aliases.Where(item => item.IsDefault).FirstOrDefault() != null) - { - return RedirectPermanent(url.Replace(alias.Name, aliases.Where(item => item.IsDefault).FirstOrDefault().Name)); - } - else // no default specified - use first alias - { - if (alias.Name.Trim() != aliases.First().Name.Trim()) - { - return RedirectPermanent(url.Replace(alias.Name, aliases.First().Name)); - } - } - } - - var site = _sites.GetSite(alias.SiteId); - if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") - { - Route route = new Route(url, alias.Path); - - if (!string.IsNullOrEmpty(site.Runtime)) - { - Runtime = site.Runtime; - } - if (!string.IsNullOrEmpty(site.RenderMode)) - { - RenderMode = site.RenderMode; - } - - var page = _pages.GetPage(route.PagePath, site.SiteId); - if (page == null && route.PagePath == "" && site.HomePageId != null) - { - page = _pages.GetPage(site.HomePageId.Value); - } - if (page == null || page.IsDeleted) - { - // page not found - look for url mapping - var urlMapping = _urlMappings.GetUrlMapping(site.SiteId, route.PagePath); - if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) - { - url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl; - return RedirectPermanent(url); - } - else - { - if (route.PagePath != "404") - { - return RedirectPermanent(route.SiteUrl + "/404"); - } - } - } - - if (site.VisitorTracking) - { - TrackVisitor(site.SiteId); - } - - // get jwt token for downstream APIs - if (User.Identity.IsAuthenticated) - { - var sitesettings = HttpContext.GetSiteSettings(); - var secret = sitesettings.GetValue("JwtOptions:Secret", ""); - if (!string.IsNullOrEmpty(secret)) - { - AuthorizationToken = _jwtManager.GenerateToken(alias, (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20"))); - } - } - - // stylesheets - var themes = _themes.GetThemes().ToList(); - var resources = new List(); - if (string.IsNullOrEmpty(page.ThemeType)) - { - page.ThemeType = site.DefaultThemeType; - } - var theme = themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType)); - if (theme?.Resources != null) - { - resources.AddRange(theme.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); - } - var type = Type.GetType(page.ThemeType); - if (type != null) - { - var obj = Activator.CreateInstance(type) as IThemeControl; - if (obj?.Resources != null) - { - resources.AddRange(obj.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); - } - } - ManageStyleSheets(resources, alias, theme.ThemeName); - - // scripts - if (Runtime == "Server") - { - ReconnectScript = CreateReconnectScript(); - } - if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null) - { - PWAScript = CreatePWAScript(alias, site, route); - } - HeadResources += ParseScripts(site.HeadContent); - BodyResources += ParseScripts(site.BodyContent); - var scripts = _serverState.GetServerState(alias.SiteKey).Scripts; - foreach (var script in scripts) - { - AddScript(script, alias); - } - - // set culture if not specified - string culture = HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName]; - if (culture == null) - { - // get default language for site - var languages = _languages.GetLanguages(alias.SiteId); - if (languages.Any()) - { - // use default language if specified otherwise use first language in collection - culture = (languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First()).Code; - } - else - { - culture = _localizationManager.GetDefaultCulture(); - } - SetLocalizationCookie(culture); - } - - // set language for page - if (!string.IsNullOrEmpty(culture)) - { - // localization cookie value in form of c=en|uic=en - Language = culture.Split('|')[0]; - Language = Language.Replace("c=", ""); - } - } - else - { - Message = "Site Is Disabled"; - } - } - else - { - Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name"; - } - } - return Page(); - } - - private void TrackVisitor(int SiteId) - { - try - { - // get request attributes - string useragent = (Request.Headers[HeaderNames.UserAgent] != StringValues.Empty) ? Request.Headers[HeaderNames.UserAgent] : "(none)"; - useragent = (useragent.Length > 256) ? useragent.Substring(0, 256) : useragent; - 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 settings = _settings.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 = Request.GetEncodedUrl(); - string referrer = (Request.Headers[HeaderNames.Referer] != StringValues.Empty) ? Request.Headers[HeaderNames.Referer] : ""; - int? userid = null; - if (User.HasClaim(item => item.Type == ClaimTypes.NameIdentifier)) - { - userid = int.Parse(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(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 = _visitors.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 = _visitors.AddVisitor(visitor); - VisitorId = visitor.VisitorId; - addcookie = true; - } - else - { - if (visitor == null) - { - // get visitor if it was not previously loaded - visitor = _visitors.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; - _visitors.UpdateVisitor(visitor); - } - else - { - // remove cookie if VisitorId does not exist - Response.Cookies.Delete(VisitorCookie); - } - } - - // append cookie - if (addcookie) - { - Response.Cookies.Append( - VisitorCookie, - VisitorId.ToString(), - new CookieOptions() - { - Expires = DateTimeOffset.UtcNow.AddYears(1), - IsEssential = true - } - ); - } - } - 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) - { - return - "" + Environment.NewLine + - ""; - } - - private string CreateReconnectScript() - { - return - ""; - } - - private string ParseScripts(string content) - { - // iterate scripts - var scripts = ""; - if (!string.IsNullOrEmpty(content)) - { - var index = content.IndexOf("= 0) - { - scripts += content.Substring(index, content.IndexOf("", index) + 9 - index); - index = content.IndexOf(""; - } - else - { - // inline script - return ""; - } - } - - private void SetLocalizationCookie(string culture) - { - HttpContext.Response.Cookies.Append( - CookieRequestCultureProvider.DefaultCookieName, - CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture))); - } - - private void ManageStyleSheets(List resources, Alias alias, string name) - { - if (resources != null) - { - int count = 0; - foreach (var resource in resources) - { - if (resource.Url.StartsWith("~")) - { - resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(name) + "/").Replace("//", "/"); - } - if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl)) - { - resource.Url = alias.BaseUrl + resource.Url; - } - - if (!StyleSheets.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) - { - count++; - string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + count.ToString("00") + "\" "; - StyleSheets += "" + Environment.NewLine; - } - } - } - } - } -} diff --git a/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs b/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs index f6fb29cfc..2740ed33e 100644 --- a/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs +++ b/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs @@ -50,6 +50,8 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) protected virtual bool ShouldValidate(AuthorizationFilterContext context) { + return false; + // ignore antiforgery validation if a bearer token was provided if (context.HttpContext.Request.Headers.ContainsKey("Authorization")) { diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index e777f4ede..f79561e21 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -17,6 +17,9 @@ using Oqtane.Shared; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Logging; +using Oqtane.Components; +using Oqtane.UI; +using OqtaneSSR.Extensions; namespace Oqtane { @@ -36,6 +39,7 @@ public Startup(IWebHostEnvironment env, ILocalizationManager localizationManager .AddJsonFile("appsettings.json", false, true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true) .AddEnvironmentVariables(); + Configuration = builder.Build(); _installedCultures = localizationManager.GetInstalledCultures(); @@ -64,17 +68,17 @@ public void ConfigureServices(IServiceCollection services) services.AddOptions>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection)); services.Configure(opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(10)); // increase from default of 5 seconds - services.AddServerSideBlazor() - .AddCircuitOptions(options => - { - if (_env.IsDevelopment()) - { - options.DetailedErrors = true; - } - }) - .AddHubOptions(options => { - options.MaximumReceiveMessageSize = null; // no limit (for large amnounts of data ie. textarea components) - }); + //services.AddServerSideBlazor() + // .AddCircuitOptions(options => + // { + // if (_env.IsDevelopment()) + // { + // options.DetailedErrors = true; + // } + // }) + // .AddHubOptions(options => { + // options.MaximumReceiveMessageSize = null; // no limit (for large amnounts of data ie. textarea components) + // }); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) services.AddHttpClients(); @@ -148,6 +152,10 @@ public void ConfigureServices(IServiceCollection services) .AddOqtaneApplicationParts() // register any Controllers from custom modules .ConfigureOqtaneMvc(); // any additional configuration from IStartup classes + services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + services.AddSwaggerGen(options => { options.CustomSchemaIds(type => type.ToString()); // Handle SchemaId already used for different type @@ -200,11 +208,30 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/" + Constants.Version + "/swagger.json", Constants.PackageId + " " + Constants.Version); }); } + //app.UseEndpoints(endpoints => + //{ + // endpoints.MapBlazorHub(); + // endpoints.MapControllers(); + // endpoints.MapFallbackToPage("/_Host"); + //}); + + app.UseAntiforgery(); app.UseEndpoints(endpoints => { - endpoints.MapBlazorHub(); endpoints.MapControllers(); - endpoints.MapFallbackToPage("/_Host"); + }); + + app.UseEndpoints(endpoints => + { + endpoints.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(SiteRouter).Assembly); + }); + + app.UseEndpoints(endpoints => + { + endpoints.MapFallback(); }); // create a global sync event to identify server application startup From 23b68bd9f979ced256d1222590864b46e8ff8298 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 30 Jan 2024 15:48:40 -0800 Subject: [PATCH 007/280] Removed unnecessary space. --- .../wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css index b1536f7b6..9eec314f9 100644 --- a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css @@ -99,7 +99,7 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu @media (max-width: 767px) { .app-menu { - width: 100% ; + width: 100%; } .navbar { From 7e817a5808436b574f7f744ba82e8a35efc11df1 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 07:33:52 -0500 Subject: [PATCH 008/280] resolve antiforgery issue --- Oqtane.Server/Components/App.razor | 6 +++++- .../Security/AutoValidateAntiforgeryTokenFilter.cs | 2 -- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 0d0f69e36..e41c5d2ef 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -1,6 +1,7 @@ @namespace Oqtane.Components @using Microsoft.AspNetCore.Http @using Microsoft.AspNetCore.Http.Extensions +@using Microsoft.AspNetCore.Antiforgery @using Oqtane.Client @using Oqtane.Client.Utilities @using Oqtane.Repository @@ -11,6 +12,7 @@ @using Oqtane.Themes @using System.Net @using Microsoft.AspNetCore.Localization +@inject IAntiforgery Antiforgery; @inject IConfigManager ConfigManager; @inject ITenantManager TenantManager; @inject ILocalizationManager LocalizationManager; @@ -42,7 +44,7 @@ @if (string.IsNullOrEmpty(_message)) { - + @@ -67,6 +69,7 @@ @code { private string _interactiveRenderMode = "InteractiveServer"; private string _language = "en"; + private string _antiForgeryToken = ""; private string _remoteIPAddress = ""; private string _headResources = ""; private string _bodyResources = ""; @@ -81,6 +84,7 @@ protected override void OnInitialized() { + _antiForgeryToken = Antiforgery.GetAndStoreTokens(Context).RequestToken; _remoteIPAddress = Context.Connection.RemoteIpAddress?.ToString() ?? ""; // if framework is installed diff --git a/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs b/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs index 2740ed33e..f6fb29cfc 100644 --- a/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs +++ b/Oqtane.Server/Security/AutoValidateAntiforgeryTokenFilter.cs @@ -50,8 +50,6 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) protected virtual bool ShouldValidate(AuthorizationFilterContext context) { - return false; - // ignore antiforgery validation if a bearer token was provided if (context.HttpContext.Request.Headers.ContainsKey("Authorization")) { From fdfbf548082b306b3cc11d8ad867610837d61d70 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 08:18:56 -0500 Subject: [PATCH 009/280] implement non-default alias redirect --- Oqtane.Server/Components/App.razor | 47 +++++++++++++++++++----------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index e41c5d2ef..5ac4e664b 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -12,15 +12,17 @@ @using Oqtane.Themes @using System.Net @using Microsoft.AspNetCore.Localization +@inject NavigationManager NavigationManager @inject IAntiforgery Antiforgery; @inject IConfigManager ConfigManager; @inject ITenantManager TenantManager; -@inject ILocalizationManager LocalizationManager; @inject ISiteRepository SiteRepository; @inject IPageRepository PageRepository; @inject IThemeRepository ThemeRepository; @inject ILanguageRepository LanguageRepository; @inject IServerStateManager ServerStateManager; +@inject ILocalizationManager LocalizationManager; +@inject IAliasRepository AliasRepository; @@ -95,22 +97,7 @@ { var url = WebUtility.UrlDecode(Context.Request.GetEncodedUrl()); - // redirect non-default alias unless you are trying to access site settings - // if (!alias.IsDefault && !url.Contains("admin/site")) - // { - // var aliases = AliasRepository.GetAliases().Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId); - // if (aliases.Where(item => item.IsDefault).FirstOrDefault() != null) - // { - // return RedirectPermanent(url.Replace(alias.Name, aliases.Where(item => item.IsDefault).FirstOrDefault().Name)); - // } - // else // no default specified - use first alias - // { - // if (alias.Name.Trim() != aliases.First().Name.Trim()) - // { - // return RedirectPermanent(url.Replace(alias.Name, aliases.First().Name)); - // } - // } - // } + HandleDefaultAliasRedirect(alias, url); var site = SiteRepository.GetSite(alias.SiteId); if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") @@ -243,6 +230,32 @@ } } + private void HandleDefaultAliasRedirect(Alias alias, string url) + { + // redirect non-default alias + if (!alias.IsDefault) + { + // get aliases for site and tenant + var aliases = AliasRepository.GetAliases().Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId); + // get first default alias + var defaultAlias = aliases.Where(item => item.IsDefault).FirstOrDefault(); + if (defaultAlias != null) + { + // redirect to default alias + NavigationManager.NavigateTo(url.Replace(alias.Name, defaultAlias.Name), true); + } + else // no default alias specified - use first alias + { + defaultAlias = aliases.FirstOrDefault(); + if (defaultAlias != null && alias.Name.Trim() != defaultAlias.Name.Trim()) + { + // redirect to first alias + NavigationManager.NavigateTo(url.Replace(alias.Name, defaultAlias.Name), true); + } + } + } + } + private string CreatePWAScript(Alias alias, Site site, Route route) { return From 50e179f7a884b6128cd3fb314989264a9be1297d Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 09:40:47 -0500 Subject: [PATCH 010/280] add support for Render Modes and Prerendering --- Oqtane.Client/Utilities/RenderModes.cs | 10 +++---- Oqtane.Server/Components/App.razor | 38 ++++++++++++++++++-------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Oqtane.Client/Utilities/RenderModes.cs b/Oqtane.Client/Utilities/RenderModes.cs index 820dec37b..4809e238d 100644 --- a/Oqtane.Client/Utilities/RenderModes.cs +++ b/Oqtane.Client/Utilities/RenderModes.cs @@ -5,16 +5,16 @@ namespace Oqtane.Client.Utilities { public static class RenderModes { - public static IComponentRenderMode GetRenderMode(string renderMode) + public static IComponentRenderMode GetInteractiveRenderMode(string interactiveRenderMode, bool prerender) { - switch (renderMode) + switch (interactiveRenderMode) { case "InteractiveServer": - return RenderMode.InteractiveServer; + return new InteractiveServerRenderMode(prerender); case "InteractiveWebAssembly": - return RenderMode.InteractiveWebAssembly; + return new InteractiveWebAssemblyRenderMode(prerender); case "InteractiveAuto": - return RenderMode.InteractiveAuto; + return new InteractiveAutoRenderMode(prerender); } return null; } diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 5ac4e664b..170db48d4 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -40,13 +40,27 @@ @((MarkupString)_styleSheets) - + @if (_renderMode == "Interactive") + { + + } + else + { + + } @((MarkupString)_headResources) @if (string.IsNullOrEmpty(_message)) { - + @if (_renderMode == "Interactive") + { + + } + else + { + + } @@ -69,7 +83,9 @@ @code { - private string _interactiveRenderMode = "InteractiveServer"; + private string _renderMode = "Interactive"; + private string _interactiveRenderMode = "Server"; + private bool _prerender = true; private string _language = "en"; private string _antiForgeryToken = ""; private string _remoteIPAddress = ""; @@ -102,14 +118,14 @@ var site = SiteRepository.GetSite(alias.SiteId); if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") { - // if (!string.IsNullOrEmpty(site.Runtime)) - // { - // Runtime = site.Runtime; - // } - // if (!string.IsNullOrEmpty(site.RenderMode)) - // { - // RenderMode = site.RenderMode; - // } + if (!string.IsNullOrEmpty(site.Runtime)) + { + _interactiveRenderMode = site.Runtime; + } + if (!string.IsNullOrEmpty(site.RenderMode)) + { + _prerender = (site.RenderMode.Replace(site.Runtime, "")) == "Prerendered"; + } Route route = new Route(url, alias.Path); var page = PageRepository.GetPage(route.PagePath, site.SiteId); From e47690dd52ac7113f108af0f61cd4b0247d99ff7 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 10:03:25 -0500 Subject: [PATCH 011/280] add support for page not found functionality --- Oqtane.Server/Components/App.razor | 75 ++++++++++++++++-------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 170db48d4..72b9924e8 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -23,6 +23,7 @@ @inject IServerStateManager ServerStateManager; @inject ILocalizationManager LocalizationManager; @inject IAliasRepository AliasRepository; +@inject IUrlMappingRepository UrlMappingRepository; @@ -113,7 +114,10 @@ { var url = WebUtility.UrlDecode(Context.Request.GetEncodedUrl()); - HandleDefaultAliasRedirect(alias, url); + if (!alias.IsDefault) + { + HandleDefaultAliasRedirect(alias, url); + } var site = SiteRepository.GetSite(alias.SiteId); if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") @@ -134,23 +138,10 @@ page = PageRepository.GetPage(site.HomePageId.Value); } - // if (page == null || page.IsDeleted) - // { - // // page not found - look for url mapping - // var urlMapping = _urlMappings.GetUrlMapping(site.SiteId, route.PagePath); - // if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) - // { - // url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl; - // return RedirectPermanent(url); - // } - // else - // { - // if (route.PagePath != "404") - // { - // return RedirectPermanent(route.SiteUrl + "/404"); - // } - // } - // } + if (page == null || page.IsDeleted) + { + HandlePageNotFound(site, page, route); + } // if (site.VisitorTracking) // { @@ -248,29 +239,45 @@ private void HandleDefaultAliasRedirect(Alias alias, string url) { - // redirect non-default alias - if (!alias.IsDefault) + // get aliases for site and tenant + var aliases = AliasRepository.GetAliases().Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId); + // get first default alias + var defaultAlias = aliases.Where(item => item.IsDefault).FirstOrDefault(); + if (defaultAlias != null) + { + // redirect to default alias + NavigationManager.NavigateTo(url.Replace(alias.Name, defaultAlias.Name), true); + } + else // no default alias specified - use first alias { - // get aliases for site and tenant - var aliases = AliasRepository.GetAliases().Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId); - // get first default alias - var defaultAlias = aliases.Where(item => item.IsDefault).FirstOrDefault(); - if (defaultAlias != null) + defaultAlias = aliases.FirstOrDefault(); + if (defaultAlias != null && alias.Name.Trim() != defaultAlias.Name.Trim()) { - // redirect to default alias + // redirect to first alias NavigationManager.NavigateTo(url.Replace(alias.Name, defaultAlias.Name), true); } - else // no default alias specified - use first alias + } + } + + private void HandlePageNotFound(Site site, Page page, Route route) + { + // page not found - look for url mapping + var urlMapping = UrlMappingRepository.GetUrlMapping(site.SiteId, route.PagePath); + if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) + { + // redirect to mapped url + var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl; + NavigationManager.NavigateTo(url, true); + } + else // no url mapping exists + { + if (route.PagePath != "404") { - defaultAlias = aliases.FirstOrDefault(); - if (defaultAlias != null && alias.Name.Trim() != defaultAlias.Name.Trim()) - { - // redirect to first alias - NavigationManager.NavigateTo(url.Replace(alias.Name, defaultAlias.Name), true); - } + // redirect to 404 page + NavigationManager.NavigateTo(route.SiteUrl + "/404", true); } } - } + } private string CreatePWAScript(Alias alias, Site site, Route route) { From d0da1f43a9c7919dfea47c8070d3a31d85654e0e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 10:49:26 -0500 Subject: [PATCH 012/280] add support for visitor tracking --- Oqtane.Server/Components/App.razor | 177 +++++++++++++++++++++++++---- 1 file changed, 157 insertions(+), 20 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 72b9924e8..67d743d51 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -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 @@ -56,11 +61,11 @@ { @if (_renderMode == "Interactive") { - + } else { - + } @@ -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) @@ -277,7 +283,138 @@ NavigationManager.NavigateTo(route.SiteUrl + "/404", true); } } - } + } + + 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) { From 5e82700871fea867799fe604e2737c169f805829 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 10:58:28 -0500 Subject: [PATCH 013/280] remove unnecessary database call to GetSettings() --- Oqtane.Server/Components/App.razor | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 67d743d51..6da8bb8a6 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -15,6 +15,7 @@ @using Oqtane.Models @using Oqtane.Shared @using Oqtane.Themes +@using Oqtane.Extensions @inject NavigationManager NavigationManager @inject IAntiforgery Antiforgery @inject IConfigManager ConfigManager @@ -27,7 +28,6 @@ @inject ILocalizationManager LocalizationManager @inject IAliasRepository AliasRepository @inject IUrlMappingRepository UrlMappingRepository -@inject ISettingRepository SettingRepository @inject IVisitorRepository VisitorRepository @@ -299,10 +299,10 @@ // filter string filter = Constants.DefaultVisitorFilter; - var settings = SettingRepository.GetSettings(EntityNames.Site, SiteId); - if (settings.Any(item => item.SettingName == "VisitorFilter")) + var settings = Context.GetSiteSettings(); + if (settings.ContainsKey("VisitorFilter") && !string.IsNullOrEmpty(settings["VisitorFilter"])) { - filter = settings.First(item => item.SettingName == "VisitorFilter").SettingValue; + filter = settings["VisitorFilter"]; } foreach (string term in filter.ToLower().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray()) { @@ -330,9 +330,9 @@ // if enabled use IP Address correlation _visitorId = -1; bool correlate = true; - if (settings.Any(item => item.SettingName == "VisitorCorrelation")) + if (settings.ContainsKey("VisitorCorrelation") && !string.IsNullOrEmpty(settings["VisitorCorrelation"])) { - correlate = bool.Parse(settings.First(item => item.SettingName == "VisitorCorrelation").SettingValue); + correlate = bool.Parse(settings["VisitorCorrelation"]); } if (correlate) { From 69e4fcfc76a3a2756acbf46af62a855593fa98f9 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 11:11:40 -0500 Subject: [PATCH 014/280] add support for Jwt Token creation --- Oqtane.Server/Components/App.razor | 51 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 6da8bb8a6..6083f8955 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -29,6 +29,7 @@ @inject IAliasRepository AliasRepository @inject IUrlMappingRepository UrlMappingRepository @inject IVisitorRepository VisitorRepository +@inject IJwtManager JwtManager @@ -48,7 +49,7 @@ @if (_renderMode == "Interactive") { - + } else { @@ -61,11 +62,11 @@ { @if (_renderMode == "Interactive") { - + } else { - + } @@ -91,17 +92,18 @@ @code { private string _renderMode = "Interactive"; private string _interactiveRenderMode = "Server"; - private bool _prerender = true; + private string _prerender = "Prerendered"; + private int _visitorId = -1; + private string _remoteIPAddress = ""; + private string _authorizationToken = ""; private string _language = "en"; private string _antiForgeryToken = ""; - private string _remoteIPAddress = ""; private string _headResources = ""; private string _bodyResources = ""; private string _styleSheets = ""; private string _PWAScript = ""; private string _reconnectScript = ""; private string _message = ""; - private int _visitorId = -1; // CascadingParameter is required to access HttpContext [CascadingParameter] @@ -134,7 +136,7 @@ } if (!string.IsNullOrEmpty(site.RenderMode)) { - _prerender = (site.RenderMode.Replace(site.Runtime, "")) == "Prerendered"; + _prerender = site.RenderMode; } Route route = new Route(url, alias.Path); @@ -155,15 +157,10 @@ } // get jwt token for downstream APIs - // if (User.Identity.IsAuthenticated) - // { - // var sitesettings = HttpContext.GetSiteSettings(); - // var secret = sitesettings.GetValue("JwtOptions:Secret", ""); - // if (!string.IsNullOrEmpty(secret)) - // { - // AuthorizationToken = _jwtManager.GenerateToken(alias, (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20"))); - // } - // } + if (Context.User.Identity.IsAuthenticated) + { + CreateJwtToken(alias); + } // stylesheets var themes = ThemeRepository.GetThemes().ToList(); @@ -298,12 +295,8 @@ language = (language.Trim().Length == 0) ? "??" : language; // filter - string filter = Constants.DefaultVisitorFilter; var settings = Context.GetSiteSettings(); - if (settings.ContainsKey("VisitorFilter") && !string.IsNullOrEmpty(settings["VisitorFilter"])) - { - filter = settings["VisitorFilter"]; - } + var filter = settings.GetValue("VisitorFilter", Constants.DefaultVisitorFilter); 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)) @@ -329,11 +322,7 @@ { // if enabled use IP Address correlation _visitorId = -1; - bool correlate = true; - if (settings.ContainsKey("VisitorCorrelation") && !string.IsNullOrEmpty(settings["VisitorCorrelation"])) - { - correlate = bool.Parse(settings["VisitorCorrelation"]); - } + var correlate = bool.Parse(settings.GetValue("VisitorCorrelation", "true")); if (correlate) { visitor = VisitorRepository.GetVisitor(SiteId, _remoteIPAddress); @@ -416,6 +405,16 @@ } } + private void CreateJwtToken(Alias alias) + { + var sitesettings = Context.GetSiteSettings(); + var secret = sitesettings.GetValue("JwtOptions:Secret", ""); + if (!string.IsNullOrEmpty(secret)) + { + _authorizationToken = JwtManager.GenerateToken(alias, (ClaimsIdentity)Context.User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20"))); + } + } + private string CreatePWAScript(Alias alias, Site site, Route route) { return From 8e499d164ada693cecdcd6207e37366dd5ed8763 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 15:22:21 -0500 Subject: [PATCH 015/280] render mode integration --- Oqtane.Client/Installer/Installer.razor | 3 +- Oqtane.Client/Modules/Admin/Site/Index.razor | 53 ++++++++++--------- Oqtane.Client/Modules/Admin/Sites/Add.razor | 25 +++------ .../Resources/Modules/Admin/Site/Index.resx | 10 ++-- .../Resources/Modules/Admin/Sites/Add.resx | 10 ++-- Oqtane.Client/Resources/SharedResources.resx | 15 +++--- Oqtane.Client/Routes.razor | 5 +- Oqtane.Client/UI/PageState.cs | 1 + .../RenderModes.cs => UI/RenderMode.cs} | 11 ++-- Oqtane.Client/UI/Runtime.cs | 11 ---- Oqtane.Client/UI/SiteRouter.razor | 6 +-- Oqtane.Server/Components/App.razor | 33 +++++------- .../Controllers/InstallationController.cs | 4 +- Oqtane.Server/Controllers/SiteController.cs | 2 +- .../Infrastructure/DatabaseManager.cs | 4 +- .../05010001_AddPageEffectiveExpiryDate.cs | 1 + ...010002_AddPageModuleEffectiveExpiryDate.cs | 1 + .../Tenant/05010003_AddProfileAutocomplete.cs | 1 + .../Tenant/05010004_AddSitePrerender.cs | 39 ++++++++++++++ Oqtane.Shared/Enums/Runtime.cs | 3 +- Oqtane.Shared/Models/Site.cs | 10 ++-- Oqtane.Shared/Shared/InstallConfig.cs | 1 - Oqtane.Shared/Shared/RenderModes.cs | 8 +++ 23 files changed, 143 insertions(+), 114 deletions(-) rename Oqtane.Client/{Utilities/RenderModes.cs => UI/RenderMode.cs} (69%) delete mode 100644 Oqtane.Client/UI/Runtime.cs create mode 100644 Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs create mode 100644 Oqtane.Shared/Shared/RenderModes.cs diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index 7e223ca03..2cbc4d44f 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -260,7 +260,8 @@ IsNewTenant = true, SiteName = Constants.DefaultSite, Register = _register, - SiteTemplate = _template + SiteTemplate = _template, + RenderMode = RenderModes.InteractiveServer }; var installation = await InstallationService.Install(config); diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 01a6bba3c..ca8edc1c5 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -311,27 +311,32 @@
- +
- + + + +
-
- -
- + @if (_rendermode != "Static") + { +
+ +
+ +
-
+ }
- +
- @@ -414,9 +419,9 @@ private int _aliasid = -1; private string _aliasname; private string _defaultalias; - private string _runtime = ""; - private string _prerender = ""; - private string _hybridenabled = ""; + private string _rendermode = RenderModes.InteractiveServer; + private string _prerender = "True"; + private string _hybrid = "False"; private string _tenant = string.Empty; private string _database = string.Empty; private string _connectionstring = string.Empty; @@ -500,9 +505,9 @@ await GetAliases(); // hosting model - _runtime = site.Runtime; - _prerender = site.RenderMode.Replace(_runtime, ""); - _hybridenabled = site.HybridEnabled.ToString(); + _rendermode = site.RenderMode; + _prerender = site.Prerender.ToString(); + _hybrid = site.Hybrid.ToString(); // database if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) @@ -640,11 +645,11 @@ // hosting model if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { - if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender || site.HybridEnabled != bool.Parse(_hybridenabled)) + if (site.RenderMode != _rendermode || site.Prerender != bool.Parse(_prerender) || site.Hybrid != bool.Parse(_hybrid)) { - site.Runtime = _runtime; - site.RenderMode = _runtime + _prerender; - site.HybridEnabled = bool.Parse(_hybridenabled); + site.RenderMode = _rendermode; + site.Prerender = bool.Parse(_prerender); + site.Hybrid = bool.Parse(_hybrid); reload = true; // needs to be reloaded on serve } } diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 2471ed63a..889b496fa 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -71,20 +71,13 @@ else
- +
- -
-
-
- -
- + + + +
@@ -201,8 +194,7 @@ else private string _themetype = "-"; private string _containertype = "-"; private string _sitetemplatetype = "-"; - private string _runtime = "Server"; - private string _prerender = "Prerendered"; + private string _rendermode = RenderModes.InteractiveServer; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; @@ -399,8 +391,7 @@ else config.DefaultContainer = _containertype; config.DefaultAdminContainer = ""; config.SiteTemplate = _sitetemplatetype; - config.Runtime = _runtime; - config.RenderMode = _runtime + _prerender; + config.RenderMode = _rendermode; ShowProgressIndicator(); diff --git a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx index 8d8efaf86..65a918e78 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx @@ -277,16 +277,16 @@ Hosting Model - Specifies if the site should be prerendered (for search crawlers, etc...) + Specifies if the site supports prerendering Prerender? - - The Blazor runtime hosting model for the site + + The default render mode for the site - - Runtime: + + Render Mode: Browse diff --git a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx index fed4bd6af..903dc147c 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx @@ -223,16 +223,16 @@ Error loading Database Configuration Control - Specifies if the site should be prerendered (for search crawlers, etc...) + Specifies if the site supports prerendering Prerender? - - The Blazor runtime hosting model + + The default render mode for the site - - Runtime: + + Render Mode: Enter a complete connection string including all parameters and delimiters diff --git a/Oqtane.Client/Resources/SharedResources.resx b/Oqtane.Client/Resources/SharedResources.resx index 6152a0666..464732c44 100644 --- a/Oqtane.Client/Resources/SharedResources.resx +++ b/Oqtane.Client/Resources/SharedResources.resx @@ -312,14 +312,14 @@ Not Specified - - Blazor Server + + Interactive Server Rendering - - Blazor WebAssembly + + Interactive WebAssembly Rendering - - Blazor Hybrid + + Static Server Rendering Settings @@ -441,4 +441,7 @@ Effective Date cannot be after Expiry Date. + + Interactive Auto Rendering + \ No newline at end of file diff --git a/Oqtane.Client/Routes.razor b/Oqtane.Client/Routes.razor index fa1d4e8d9..24d19a919 100644 --- a/Oqtane.Client/Routes.razor +++ b/Oqtane.Client/Routes.razor @@ -16,7 +16,7 @@
- +
@@ -34,9 +34,6 @@ [Parameter] public string AntiForgeryToken { get; set; } - [Parameter] - public string Runtime { get; set; } - [Parameter] public string RenderMode { get; set; } diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index 7de88d962..c9025622e 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -19,6 +19,7 @@ public class PageState public bool EditMode { get; set; } public DateTime LastSyncDate { get; set; } public Shared.Runtime Runtime { get; set; } + public string RenderMode { get; set; } public int VisitorId { get; set; } public string RemoteIPAddress { get; set; } public string ReturnUrl { get; set; } diff --git a/Oqtane.Client/Utilities/RenderModes.cs b/Oqtane.Client/UI/RenderMode.cs similarity index 69% rename from Oqtane.Client/Utilities/RenderModes.cs rename to Oqtane.Client/UI/RenderMode.cs index 4809e238d..fa41f3c11 100644 --- a/Oqtane.Client/Utilities/RenderModes.cs +++ b/Oqtane.Client/UI/RenderMode.cs @@ -1,19 +1,20 @@ using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components; +using Oqtane.Shared; -namespace Oqtane.Client.Utilities +namespace Oqtane.UI { - public static class RenderModes + public static class RenderMode { public static IComponentRenderMode GetInteractiveRenderMode(string interactiveRenderMode, bool prerender) { switch (interactiveRenderMode) { - case "InteractiveServer": + case RenderModes.InteractiveServer: return new InteractiveServerRenderMode(prerender); - case "InteractiveWebAssembly": + case RenderModes.InteractiveWebAssembly: return new InteractiveWebAssemblyRenderMode(prerender); - case "InteractiveAuto": + case RenderModes.InteractiveAuto: return new InteractiveAutoRenderMode(prerender); } return null; diff --git a/Oqtane.Client/UI/Runtime.cs b/Oqtane.Client/UI/Runtime.cs deleted file mode 100644 index 2d7e6b005..000000000 --- a/Oqtane.Client/UI/Runtime.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Oqtane.UI -{ - [Obsolete("This enum is deprecated and will be removed in the upcoming major release, please use Oqtane.Shared.Runtime instead.")] - public enum Runtime - { - Server, - WebAssembly - } -} diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index d04e44693..8bd12aa27 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -100,7 +100,6 @@ var editmode = false; var refresh = false; var lastsyncdate = DateTime.MinValue; - var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime); _error = ""; Route route = new Route(_absoluteUri, SiteState.Alias.Path); @@ -286,7 +285,8 @@ Action = action, EditMode = editmode, LastSyncDate = lastsyncdate, - Runtime = runtime, + Runtime = Shared.Runtime.Hybrid, + RenderMode = RenderMode, VisitorId = VisitorId, RemoteIPAddress = SiteState.RemoteIPAddress, ReturnUrl = returnurl, @@ -425,7 +425,7 @@ { var typename = Constants.ErrorModule; - if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime))) + if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(RenderMode))) { typename = module.ModuleDefinition.ControlTypeTemplate; diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 6083f8955..8bf473cca 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -8,7 +8,7 @@ @using Microsoft.Net.Http.Headers @using Microsoft.Extensions.Primitives @using Oqtane.Client -@using Oqtane.Client.Utilities +@using Oqtane.UI @using Oqtane.Repository @using Oqtane.Infrastructure @using Oqtane.Security @@ -47,26 +47,26 @@ @((MarkupString)_styleSheets) - @if (_renderMode == "Interactive") + @if (_renderMode == RenderModes.StaticServer) { - + } else { - + } @((MarkupString)_headResources) @if (string.IsNullOrEmpty(_message)) { - @if (_renderMode == "Interactive") + @if (_renderMode == RenderModes.StaticServer) { - + } else { - + } @@ -90,9 +90,8 @@ @code { - private string _renderMode = "Interactive"; - private string _interactiveRenderMode = "Server"; - private string _prerender = "Prerendered"; + private string _renderMode = RenderModes.InteractiveServer; + private bool _prerender = true; private int _visitorId = -1; private string _remoteIPAddress = ""; private string _authorizationToken = ""; @@ -128,16 +127,10 @@ } var site = SiteRepository.GetSite(alias.SiteId); - if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") + if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && !site.Hybrid) { - if (!string.IsNullOrEmpty(site.Runtime)) - { - _interactiveRenderMode = site.Runtime; - } - if (!string.IsNullOrEmpty(site.RenderMode)) - { - _prerender = site.RenderMode; - } + _renderMode = site.RenderMode; + _prerender = site.Prerender; Route route = new Route(url, alias.Path); var page = PageRepository.GetPage(route.PagePath, site.SiteId); @@ -186,7 +179,7 @@ ManageStyleSheets(resources, alias, theme.ThemeName); // scripts - if (_interactiveRenderMode == "InteractiveServer") + if (_renderMode == RenderModes.InteractiveServer) { _reconnectScript = CreateReconnectScript(); } diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index b070fce60..39ef38aab 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -119,7 +119,7 @@ private List GetAssemblyList() var assemblyList = new List(); var site = _sites.GetSite(alias.SiteId); - if (site != null && (site.Runtime == "WebAssembly" || site.HybridEnabled)) + if (site != null && (site.RenderMode == "InteractiveWebAssembly" || site.Hybrid)) { var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); @@ -201,7 +201,7 @@ private byte[] GetAssemblies(string list) private byte[] GetZIP(string list, Alias alias) { var site = _sites.GetSite(alias.SiteId); - if (site != null && (site.Runtime == "WebAssembly" || site.HybridEnabled)) + if (site != null && (site.RenderMode == "InteractiveWebAssembly" || site.Hybrid)) { var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index df0384c18..daa904c6a 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -212,7 +212,7 @@ public Site Put(int id, [FromBody] Site site) site = _sites.UpdateSite(site); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); string action = SyncEventActions.Refresh; - if (current.Runtime != site.Runtime || current.RenderMode != site.RenderMode) + if (current.RenderMode != site.RenderMode) { action = SyncEventActions.Reload; } diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index d05524ca1..189860167 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -556,9 +556,9 @@ private Installation CreateSite(InstallConfig install) DefaultContainerType = (!string.IsNullOrEmpty(install.DefaultContainer)) ? install.DefaultContainer : Constants.DefaultContainer, AdminContainerType = (!string.IsNullOrEmpty(install.DefaultAdminContainer)) ? install.DefaultAdminContainer : Constants.DefaultAdminContainer, SiteTemplateType = install.SiteTemplate, - Runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value, RenderMode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value, - HybridEnabled = false + Prerender = true, + Hybrid = false }; site = sites.AddSite(site); diff --git a/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs b/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs index bed22cd25..6111e09ee 100644 --- a/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs +++ b/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs @@ -8,6 +8,7 @@ namespace Oqtane.Migrations.Tenant { [DbContext(typeof(TenantDBContext))] + // note that the following migration was actually for version 5.0.2 (ie. "Tenant.05.00.02.01") [Migration("Tenant.05.01.00.01")] public class AddPageEffectiveExpiryDate : MultiDatabaseMigration { diff --git a/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs b/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs index f0b9147d2..e17f3387e 100644 --- a/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs +++ b/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs @@ -8,6 +8,7 @@ namespace Oqtane.Migrations.Tenant { [DbContext(typeof(TenantDBContext))] + // note that the following migration was actually for version 5.0.2 (ie. "Tenant.05.00.02.02") [Migration("Tenant.05.01.00.02")] public class AddPageModuleEffectiveExpiryDate : MultiDatabaseMigration { diff --git a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs index 6ec001568..2c2f45a52 100644 --- a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs +++ b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs @@ -7,6 +7,7 @@ namespace Oqtane.Migrations.Tenant { [DbContext(typeof(TenantDBContext))] + // note that the following migration was actually for version 5.0.2 (ie. "Tenant.05.00.02.03") [Migration("Tenant.05.01.00.03")] public class AddProfileAutocomplete : MultiDatabaseMigration { diff --git a/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs b/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs new file mode 100644 index 000000000..f0194dfcf --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; +using Oqtane.Shared; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.05.01.00.04")] + public class AddSitePrerender : MultiDatabaseMigration + { + public AddSitePrerender(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); + + siteEntityBuilder.UpdateColumn("RenderMode", $"'{RenderModes.InteractiveServer}'"); + + siteEntityBuilder.AddBooleanColumn("Prerender", true); + siteEntityBuilder.UpdateColumn("Prerender", "1", "bool", ""); + + siteEntityBuilder.AddBooleanColumn("Hybrid", true); + siteEntityBuilder.UpdateColumn("Hybrid", "0", "bool", ""); + + siteEntityBuilder.DropColumn("Runtime"); + siteEntityBuilder.DropColumn("HybridEnabled"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + // not implemented + } + } +} diff --git a/Oqtane.Shared/Enums/Runtime.cs b/Oqtane.Shared/Enums/Runtime.cs index 3758b765b..a755b7c12 100644 --- a/Oqtane.Shared/Enums/Runtime.cs +++ b/Oqtane.Shared/Enums/Runtime.cs @@ -2,8 +2,7 @@ namespace Oqtane.Shared { public enum Runtime { - Server, - WebAssembly, + Web, Hybrid } } diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index 30c5c02f1..fc1109c99 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -69,19 +69,19 @@ public class Site : ModelBase, IDeletable public string SiteGuid { get; set; } /// - /// The hosting model for the site (ie. Server or WebAssembly ). + /// The default render mode for the site (ie. Static,InteractiveServer,InteractiveWebAssembly,InteractiveAuto) /// - public string Runtime { get; set; } + public string RenderMode { get; set; } /// - /// The render mode for the site (ie. Server, ServerPrerendered, WebAssembly, WebAssemblyPrerendered ). + /// If the site supports prerendering (only applies to Interactive rendering) /// - public string RenderMode { get; set; } + public bool Prerender { get; set; } /// /// Indicates if a site can be integrated with an external .NET MAUI hybrid application /// - public bool HybridEnabled { get; set; } + public bool Hybrid { get; set; } /// /// Keeps track of site configuration changes and is used by the ISiteMigration interface diff --git a/Oqtane.Shared/Shared/InstallConfig.cs b/Oqtane.Shared/Shared/InstallConfig.cs index f4e7d0539..e5371867f 100644 --- a/Oqtane.Shared/Shared/InstallConfig.cs +++ b/Oqtane.Shared/Shared/InstallConfig.cs @@ -17,7 +17,6 @@ public class InstallConfig public string DefaultTheme { get; set; } public string DefaultContainer { get; set; } public string DefaultAdminContainer { get; set; } - public string Runtime { get; set; } public string RenderMode { get; set; } public bool Register { get; set; } } diff --git a/Oqtane.Shared/Shared/RenderModes.cs b/Oqtane.Shared/Shared/RenderModes.cs new file mode 100644 index 000000000..bb0aaa889 --- /dev/null +++ b/Oqtane.Shared/Shared/RenderModes.cs @@ -0,0 +1,8 @@ +namespace Oqtane.Shared { + public class RenderModes { + public const string StaticServer = "StaticServer"; + public const string InteractiveServer = "InteractiveServer"; + public const string InteractiveWebAssembly = "InteractiveWebAssembly"; + public const string InteractiveAuto = "InteractiveAuto"; + } +} From c5de56790ad6890886dd5597b01de106fdfff355 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 15:30:07 -0500 Subject: [PATCH 016/280] remove Runtime from System Info --- Oqtane.Server/Controllers/SystemController.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Oqtane.Server/Controllers/SystemController.cs b/Oqtane.Server/Controllers/SystemController.cs index 471fd81ec..d0eacf27c 100644 --- a/Oqtane.Server/Controllers/SystemController.cs +++ b/Oqtane.Server/Controllers/SystemController.cs @@ -46,8 +46,7 @@ public Dictionary Get(string type) break; case "configuration": systeminfo.Add("InstallationId", _configManager.GetInstallationId()); - systeminfo.Add("Runtime", _configManager.GetSetting("Runtime", "Server")); - systeminfo.Add("RenderMode", _configManager.GetSetting("RenderMode", "ServerPrerendered")); + systeminfo.Add("RenderMode", _configManager.GetSetting("RenderMode", RenderModes.InteractiveServer)); systeminfo.Add("DetailedErrors", _configManager.GetSetting("DetailedErrors", "false")); systeminfo.Add("Logging:LogLevel:Default", _configManager.GetSetting("Logging:LogLevel:Default", "Information")); systeminfo.Add("Logging:LogLevel:Notify", _configManager.GetSetting("Logging:LogLevel:Notify", "Error")); From 155cd31ced9d7d7a42a90937beec467a19680523 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 31 Jan 2024 15:30:48 -0500 Subject: [PATCH 017/280] Update appsettings.json --- Oqtane.Server/appsettings.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index ccf00c5c7..ca229d7fd 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -1,6 +1,5 @@ { - "Runtime": "Server", - "RenderMode": "ServerPrerendered", + "RenderMode": "InteractiveServer", "Database": { "DefaultDBType": "" }, From a88be30c3fe7ddd7fcf3691e34377d24931f2d77 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 31 Jan 2024 15:31:12 -0500 Subject: [PATCH 018/280] Update appsettings.release.json --- Oqtane.Server/appsettings.release.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Oqtane.Server/appsettings.release.json b/Oqtane.Server/appsettings.release.json index 8549fa0b7..091bf1a75 100644 --- a/Oqtane.Server/appsettings.release.json +++ b/Oqtane.Server/appsettings.release.json @@ -1,6 +1,5 @@ { - "Runtime": "Server", - "RenderMode": "ServerPrerendered", + "RenderMode": "InteractiveServer", "Database": { "DefaultDBType": "" }, From c66982c9bc063efcc452cc21e7764d6f2faed9f3 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 15:43:17 -0500 Subject: [PATCH 019/280] fix .NET MAUI integration --- Oqtane.Client/Routes.razor | 5 ++++- Oqtane.Client/UI/SiteRouter.razor | 2 +- Oqtane.Maui/Main.razor | 2 +- Oqtane.Server/Components/App.razor | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/Routes.razor b/Oqtane.Client/Routes.razor index 24d19a919..fa1d4e8d9 100644 --- a/Oqtane.Client/Routes.razor +++ b/Oqtane.Client/Routes.razor @@ -16,7 +16,7 @@
- +
@@ -34,6 +34,9 @@ [Parameter] public string AntiForgeryToken { get; set; } + [Parameter] + public string Runtime { get; set; } + [Parameter] public string RenderMode { get; set; } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 8bd12aa27..8f7aa1204 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -285,7 +285,7 @@ Action = action, EditMode = editmode, LastSyncDate = lastsyncdate, - Runtime = Shared.Runtime.Hybrid, + Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime), RenderMode = RenderMode, VisitorId = VisitorId, RemoteIPAddress = SiteState.RemoteIPAddress, diff --git a/Oqtane.Maui/Main.razor b/Oqtane.Maui/Main.razor index f8b8069c7..89ce5c8c3 100644 --- a/Oqtane.Maui/Main.razor +++ b/Oqtane.Maui/Main.razor @@ -11,7 +11,7 @@ else } @code { - Type ComponentType = Type.GetType("Oqtane.App, Oqtane.Client"); + Type ComponentType = Type.GetType("Oqtane.Routes, Oqtane.Client"); private IDictionary Parameters { get; set; } private string message = ""; diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 8bf473cca..77463e782 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -62,11 +62,11 @@ { @if (_renderMode == RenderModes.StaticServer) { - + } else { - + } From 9fe54c5d21b525b41cb59d40cea510db5f683efe Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 16:12:53 -0500 Subject: [PATCH 020/280] remove commented code and add SignalR options --- Oqtane.Server/Startup.cs | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index f79561e21..f4576ee9a 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -68,18 +68,6 @@ public void ConfigureServices(IServiceCollection services) services.AddOptions>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection)); services.Configure(opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(10)); // increase from default of 5 seconds - //services.AddServerSideBlazor() - // .AddCircuitOptions(options => - // { - // if (_env.IsDevelopment()) - // { - // options.DetailedErrors = true; - // } - // }) - // .AddHubOptions(options => { - // options.MaximumReceiveMessageSize = null; // no limit (for large amnounts of data ie. textarea components) - // }); - // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) services.AddHttpClients(); @@ -153,7 +141,16 @@ public void ConfigureServices(IServiceCollection services) .ConfigureOqtaneMvc(); // any additional configuration from IStartup classes services.AddRazorComponents() - .AddInteractiveServerComponents() + .AddInteractiveServerComponents(options => + { + if (_env.IsDevelopment()) + { + options.DetailedErrors = false; + } + }).AddHubOptions(options => + { + options.MaximumReceiveMessageSize = null; // no limit (for large amnounts of data ie. textarea components) + }) .AddInteractiveWebAssemblyComponents(); services.AddSwaggerGen(options => @@ -208,14 +205,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/" + Constants.Version + "/swagger.json", Constants.PackageId + " " + Constants.Version); }); } - //app.UseEndpoints(endpoints => - //{ - // endpoints.MapBlazorHub(); - // endpoints.MapControllers(); - // endpoints.MapFallbackToPage("/_Host"); - //}); - - app.UseAntiforgery(); + //app.UseAntiforgery(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); @@ -225,8 +215,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan { endpoints.MapRazorComponents() .AddInteractiveServerRenderMode() - .AddInteractiveWebAssemblyRenderMode() - .AddAdditionalAssemblies(typeof(SiteRouter).Assembly); + .AddInteractiveWebAssemblyRenderMode(); }); app.UseEndpoints(endpoints => From 44c088c96d0306e9321305638df67eaaf462c150 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 16:15:57 -0500 Subject: [PATCH 021/280] document CORS policy --- Oqtane.Server/Startup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index f4576ee9a..1622efcdf 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -128,6 +128,7 @@ public void ConfigureServices(IServiceCollection services) options.AddPolicy(Constants.MauiCorsPolicy, policy => { + // allow .NET MAUI client cross origin calls policy.WithOrigins("https://0.0.0.0", "http://0.0.0.0", "app://0.0.0.0") .AllowAnyHeader().AllowCredentials(); }); From 177d015fc63a6a63cf355f322c032cd92a4de371 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 16:21:23 -0500 Subject: [PATCH 022/280] remove app.UseAntiForgery as it is handled by the IAntiforgery service --- Oqtane.Server/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 1622efcdf..c0b485751 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -206,7 +206,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/" + Constants.Version + "/swagger.json", Constants.PackageId + " " + Constants.Version); }); } - //app.UseAntiforgery(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); @@ -219,6 +218,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan .AddInteractiveWebAssemblyRenderMode(); }); + // simulate the fallback routing approach of traditional Blazor - allowing the custom SiteRouter to handle all routing concerns app.UseEndpoints(endpoints => { endpoints.MapFallback(); From 9a4594227eaebf936b0e507f7f53cbf6fa38b9df Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 16:26:35 -0500 Subject: [PATCH 023/280] use new RenderModes constant --- Oqtane.Client/Modules/Admin/Site/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index ca8edc1c5..d22d498dc 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -321,7 +321,7 @@
- @if (_rendermode != "Static") + @if (_rendermode != RenderModes.StaticServer) {
From 97762712e64411967573a68e137293e99f78be07 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 31 Jan 2024 16:39:46 -0500 Subject: [PATCH 024/280] fix site Hybrid behavior --- Oqtane.Client/UI/SiteRouter.razor | 6 ++++++ Oqtane.Server/Components/App.razor | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 8f7aa1204..3be458580 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -220,6 +220,12 @@ if (site != null) { + if (Runtime == "Hybrid" && !site.Hybrid) + { + _error = "Hybrid Integration Is Not Enabled For This Site"; + return; + } + if (PageState == null || refresh || PageState.Page.Path != route.PagePath) { page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 77463e782..6770c849a 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -127,7 +127,7 @@ } var site = SiteRepository.GetSite(alias.SiteId); - if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && !site.Hybrid) + if (site != null && (!site.IsDeleted || url.Contains("admin/site"))) { _renderMode = site.RenderMode; _prerender = site.Prerender; From 1e332ed075f3aec5a869784bea68d87b91459c02 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 09:08:39 -0500 Subject: [PATCH 025/280] split RenderMode and Runtime configuration --- Oqtane.Client/Installer/Installer.razor | 5 +- Oqtane.Client/Modules/Admin/Site/Index.razor | 26 +- Oqtane.Client/Modules/Admin/Sites/Add.razor | 248 +++++++++--------- .../Resources/Modules/Admin/Site/Index.resx | 6 + .../Resources/Modules/Admin/Sites/Add.resx | 6 + Oqtane.Client/Resources/SharedResources.resx | 21 +- Oqtane.Client/Routes.razor | 6 +- Oqtane.Client/UI/PageState.cs | 2 +- Oqtane.Client/UI/RenderMode.cs | 10 +- Oqtane.Client/UI/SiteRouter.razor | 6 +- Oqtane.Server/Components/App.razor | 18 +- .../Controllers/InstallationController.cs | 4 +- Oqtane.Server/Controllers/SiteController.cs | 4 +- Oqtane.Server/Controllers/SystemController.cs | 3 +- .../Infrastructure/DatabaseManager.cs | 1 + .../Infrastructure/UpgradeManager.cs | 21 +- .../Tenant/05010004_AddSitePrerender.cs | 4 +- Oqtane.Shared/Enums/Runtime.cs | 4 +- Oqtane.Shared/Models/Site.cs | 9 +- Oqtane.Shared/Shared/InstallConfig.cs | 1 + Oqtane.Shared/Shared/RenderModes.cs | 7 +- Oqtane.Shared/Shared/Runtimes.cs | 8 + 22 files changed, 251 insertions(+), 169 deletions(-) create mode 100644 Oqtane.Shared/Shared/Runtimes.cs diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index 2cbc4d44f..a37da1d83 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -261,8 +261,9 @@ SiteName = Constants.DefaultSite, Register = _register, SiteTemplate = _template, - RenderMode = RenderModes.InteractiveServer - }; + RenderMode = RenderModes.Interactive, + Runtime = Runtimes.Server + }; var installation = await InstallationService.Install(config); if (installation.Success) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index d22d498dc..f879f0280 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -314,15 +314,24 @@
- @if (_rendermode != RenderModes.StaticServer) + @if (_rendermode == RenderModes.Interactive) { +
+ +
+ +
+
@@ -419,7 +428,8 @@ private int _aliasid = -1; private string _aliasname; private string _defaultalias; - private string _rendermode = RenderModes.InteractiveServer; + private string _rendermode = RenderModes.Interactive; + private string _runtime = Runtimes.Server; private string _prerender = "True"; private string _hybrid = "False"; private string _tenant = string.Empty; @@ -506,6 +516,7 @@ // hosting model _rendermode = site.RenderMode; + _runtime = site.Runtime; _prerender = site.Prerender.ToString(); _hybrid = site.Hybrid.ToString(); @@ -645,9 +656,10 @@ // hosting model if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { - if (site.RenderMode != _rendermode || site.Prerender != bool.Parse(_prerender) || site.Hybrid != bool.Parse(_hybrid)) + if (site.RenderMode != _rendermode || site.Runtime != _runtime || site.Prerender != bool.Parse(_prerender) || site.Hybrid != bool.Parse(_hybrid)) { site.RenderMode = _rendermode; + site.Runtime = _runtime; site.Prerender = bool.Parse(_prerender); site.Hybrid = bool.Parse(_hybrid); reload = true; // needs to be reloaded on serve diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 889b496fa..e9ee4a1c7 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -74,13 +74,25 @@ else
+ @if (_rendermode == RenderModes.Interactive) + { +
+ +
+ +
+
+ }
@@ -194,7 +206,8 @@ else private string _themetype = "-"; private string _containertype = "-"; private string _sitetemplatetype = "-"; - private string _rendermode = RenderModes.InteractiveServer; + private string _rendermode = RenderModes.Interactive; + private string _runtime = Runtimes.Server; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; @@ -220,137 +233,137 @@ else _sitetemplatetype = Constants.DefaultSiteTemplate; } - _databases = await DatabaseService.GetDatabasesAsync(); - if (_databases.Exists(item => item.IsDefault)) - { - _databaseName = _databases.Find(item => item.IsDefault).Name; - } - else - { - _databaseName = "LocalDB"; - } - LoadDatabaseConfigComponent(); - } + _databases = await DatabaseService.GetDatabasesAsync(); + if (_databases.Exists(item => item.IsDefault)) + { + _databaseName = _databases.Find(item => item.IsDefault).Name; + } + else + { + _databaseName = "LocalDB"; + } + LoadDatabaseConfigComponent(); + } - private void DatabaseChanged(ChangeEventArgs eventArgs) - { - try - { - _databaseName = (string)eventArgs.Value; - _showConnectionString = false; - LoadDatabaseConfigComponent(); - } - catch - { - AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error); - } - } + private void DatabaseChanged(ChangeEventArgs eventArgs) + { + try + { + _databaseName = (string)eventArgs.Value; + _showConnectionString = false; + LoadDatabaseConfigComponent(); + } + catch + { + AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error); + } + } - private void LoadDatabaseConfigComponent() - { - var database = _databases.SingleOrDefault(d => d.Name == _databaseName); - if (database != null) - { - _databaseConfigType = Type.GetType(database.ControlType); - DatabaseConfigComponent = builder => - { - builder.OpenComponent(0, _databaseConfigType); - builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); }); - builder.CloseComponent(); - }; - } - } + private void LoadDatabaseConfigComponent() + { + var database = _databases.SingleOrDefault(d => d.Name == _databaseName); + if (database != null) + { + _databaseConfigType = Type.GetType(database.ControlType); + DatabaseConfigComponent = builder => + { + builder.OpenComponent(0, _databaseConfigType); + builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); }); + builder.CloseComponent(); + }; + } + } - private void TenantChanged(ChangeEventArgs e) - { - _tenantid = (string)e.Value; - if (string.IsNullOrEmpty(_tenantName)) - { - _tenantName = _name; - } - StateHasChanged(); - } + private void TenantChanged(ChangeEventArgs e) + { + _tenantid = (string)e.Value; + if (string.IsNullOrEmpty(_tenantName)) + { + _tenantName = _name; + } + StateHasChanged(); + } - private async void ThemeChanged(ChangeEventArgs e) - { - try - { - _themetype = (string)e.Value; - if (_themetype != "-") - { - _containers = ThemeService.GetContainerControls(_themeList, _themetype); + private async void ThemeChanged(ChangeEventArgs e) + { + try + { + _themetype = (string)e.Value; + if (_themetype != "-") + { + _containers = ThemeService.GetContainerControls(_themeList, _themetype); _containertype = _containers.First().TypeName; } - else - { - _containers = new List(); + else + { + _containers = new List(); _containertype = "-"; } - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message); - AddModuleMessage(Localizer["Error.Theme.LoadContainers"], MessageType.Error); - } - } + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message); + AddModuleMessage(Localizer["Error.Theme.LoadContainers"], MessageType.Error); + } + } - private async Task SaveSite() - { - validated = true; - var interop = new Interop(JSRuntime); - if (await interop.FormValid(form)) - { - if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-") - { - _urls = Regex.Replace(_urls, @"\r\n?|\n", ","); - var duplicates = new List(); - var aliases = await AliasService.GetAliasesAsync(); - foreach (string name in _urls.Split(',', StringSplitOptions.RemoveEmptyEntries)) - { - if (aliases.Exists(item => item.Name == name)) - { - duplicates.Add(name); - } - } + private async Task SaveSite() + { + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(form)) + { + if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-") + { + _urls = Regex.Replace(_urls, @"\r\n?|\n", ","); + var duplicates = new List(); + var aliases = await AliasService.GetAliasesAsync(); + foreach (string name in _urls.Split(',', StringSplitOptions.RemoveEmptyEntries)) + { + if (aliases.Exists(item => item.Name == name)) + { + duplicates.Add(name); + } + } - if (duplicates.Count == 0) - { - InstallConfig config = new InstallConfig(); + if (duplicates.Count == 0) + { + InstallConfig config = new InstallConfig(); - if (_tenantid == "+") - { - if (!string.IsNullOrEmpty(_tenantName) && !_tenants.Exists(item => item.Name == _tenantName)) - { - // validate host credentials - var user = new User(); - user.SiteId = PageState.Site.SiteId; - user.Username = _hostusername; - user.Password = _hostpassword; - user.LastIPAddress = PageState.RemoteIPAddress; - user = await UserService.LoginUserAsync(user, false, false); + if (_tenantid == "+") + { + if (!string.IsNullOrEmpty(_tenantName) && !_tenants.Exists(item => item.Name == _tenantName)) + { + // validate host credentials + var user = new User(); + user.SiteId = PageState.Site.SiteId; + user.Username = _hostusername; + user.Password = _hostpassword; + user.LastIPAddress = PageState.RemoteIPAddress; + user = await UserService.LoginUserAsync(user, false, false); if (user.IsAuthenticated) { - var database = _databases.SingleOrDefault(d => d.Name == _databaseName); - var connectionString = String.Empty; - if (_showConnectionString) - { - connectionString = _connectionString; - } - else - { - if (_databaseConfig is IDatabaseConfigControl databaseConfigControl) - { - connectionString = databaseConfigControl.GetConnectionString(); - } - } + var database = _databases.SingleOrDefault(d => d.Name == _databaseName); + var connectionString = String.Empty; + if (_showConnectionString) + { + connectionString = _connectionString; + } + else + { + if (_databaseConfig is IDatabaseConfigControl databaseConfigControl) + { + connectionString = databaseConfigControl.GetConnectionString(); + } + } if (connectionString != "") { config.TenantName = _tenantName; config.DatabaseType = database.DBType; config.ConnectionString = connectionString; - config.HostUsername = _hostusername; + config.HostUsername = _hostusername; config.HostPassword = _hostpassword; config.HostEmail = user.Email; config.HostName = user.DisplayName; @@ -392,6 +405,7 @@ else config.DefaultAdminContainer = ""; config.SiteTemplate = _sitetemplatetype; config.RenderMode = _rendermode; + config.Runtime = _runtime; ShowProgressIndicator(); diff --git a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx index 65a918e78..1e4609a7f 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx @@ -423,4 +423,10 @@ Hybrid Enabled? + + The interactive render mode for the site + + + Interactivity: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx index 903dc147c..64f8fb7cf 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx @@ -246,4 +246,10 @@ Enter Connection String + + The interactive render mode for the site + + + Interactivity: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/SharedResources.resx b/Oqtane.Client/Resources/SharedResources.resx index 464732c44..cc721f5bf 100644 --- a/Oqtane.Client/Resources/SharedResources.resx +++ b/Oqtane.Client/Resources/SharedResources.resx @@ -312,11 +312,11 @@ Not Specified - - Interactive Server Rendering + + Server Rendering - - Interactive WebAssembly Rendering + + WebAssembly Rendering Static Server Rendering @@ -441,7 +441,16 @@ Effective Date cannot be after Expiry Date. - - Interactive Auto Rendering + + Auto Rendering + + + Headless API (No Rendering) + + + Global Interactivity + + + Static Server Rendering \ No newline at end of file diff --git a/Oqtane.Client/Routes.razor b/Oqtane.Client/Routes.razor index fa1d4e8d9..16c99c527 100644 --- a/Oqtane.Client/Routes.razor +++ b/Oqtane.Client/Routes.razor @@ -16,7 +16,7 @@
- +
@@ -35,10 +35,10 @@ public string AntiForgeryToken { get; set; } [Parameter] - public string Runtime { get; set; } + public string RenderMode { get; set; } [Parameter] - public string RenderMode { get; set; } + public string Runtime { get; set; } [Parameter] public int VisitorId { get; set; } diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index c9025622e..7d8a59589 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -18,8 +18,8 @@ public class PageState public string Action { get; set; } public bool EditMode { get; set; } public DateTime LastSyncDate { get; set; } - public Shared.Runtime Runtime { get; set; } public string RenderMode { get; set; } + public Shared.Runtime Runtime { get; set; } public int VisitorId { get; set; } public string RemoteIPAddress { get; set; } public string ReturnUrl { get; set; } diff --git a/Oqtane.Client/UI/RenderMode.cs b/Oqtane.Client/UI/RenderMode.cs index fa41f3c11..c9cd35579 100644 --- a/Oqtane.Client/UI/RenderMode.cs +++ b/Oqtane.Client/UI/RenderMode.cs @@ -6,15 +6,15 @@ namespace Oqtane.UI { public static class RenderMode { - public static IComponentRenderMode GetInteractiveRenderMode(string interactiveRenderMode, bool prerender) + public static IComponentRenderMode GetInteractiveRenderMode(string runtime, bool prerender) { - switch (interactiveRenderMode) + switch (runtime) { - case RenderModes.InteractiveServer: + case Runtimes.Server: return new InteractiveServerRenderMode(prerender); - case RenderModes.InteractiveWebAssembly: + case Runtimes.WebAssembly: return new InteractiveWebAssemblyRenderMode(prerender); - case RenderModes.InteractiveAuto: + case Runtimes.Auto: return new InteractiveAutoRenderMode(prerender); } return null; diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 3be458580..a378e6376 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -30,10 +30,10 @@ private string _error = ""; [Parameter] - public string Runtime { get; set; } + public string RenderMode { get; set; } [Parameter] - public string RenderMode { get; set; } + public string Runtime { get; set; } [Parameter] public int VisitorId { get; set; } @@ -291,8 +291,8 @@ Action = action, EditMode = editmode, LastSyncDate = lastsyncdate, - Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime), RenderMode = RenderMode, + Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime), VisitorId = VisitorId, RemoteIPAddress = SiteState.RemoteIPAddress, ReturnUrl = returnurl, diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 6770c849a..f7526324c 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -47,26 +47,26 @@ @((MarkupString)_styleSheets) - @if (_renderMode == RenderModes.StaticServer) + @if (_renderMode == RenderModes.Static) { } else { - + } @((MarkupString)_headResources) @if (string.IsNullOrEmpty(_message)) { - @if (_renderMode == RenderModes.StaticServer) + @if (_renderMode == RenderModes.Static) { - + } else { - + } @@ -90,7 +90,8 @@ @code { - private string _renderMode = RenderModes.InteractiveServer; + private string _renderMode = RenderModes.Interactive; + private string _runtime = Runtimes.Server; private bool _prerender = true; private int _visitorId = -1; private string _remoteIPAddress = ""; @@ -127,9 +128,10 @@ } var site = SiteRepository.GetSite(alias.SiteId); - if (site != null && (!site.IsDeleted || url.Contains("admin/site"))) + if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.RenderMode != RenderModes.Headless) { _renderMode = site.RenderMode; + _runtime = site.Runtime; _prerender = site.Prerender; Route route = new Route(url, alias.Path); @@ -179,7 +181,7 @@ ManageStyleSheets(resources, alias, theme.ThemeName); // scripts - if (_renderMode == RenderModes.InteractiveServer) + if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server) { _reconnectScript = CreateReconnectScript(); } diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 39ef38aab..92e5b289b 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -119,7 +119,7 @@ private List GetAssemblyList() var assemblyList = new List(); var site = _sites.GetSite(alias.SiteId); - if (site != null && (site.RenderMode == "InteractiveWebAssembly" || site.Hybrid)) + if (site != null && (site.Runtime == Runtimes.WebAssembly || site.Hybrid)) { var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); @@ -201,7 +201,7 @@ private byte[] GetAssemblies(string list) private byte[] GetZIP(string list, Alias alias) { var site = _sites.GetSite(alias.SiteId); - if (site != null && (site.RenderMode == "InteractiveWebAssembly" || site.Hybrid)) + if (site != null && (site.Runtime == Runtimes.WebAssembly || site.Hybrid)) { var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index daa904c6a..81df67bb3 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -13,8 +13,6 @@ using Microsoft.Extensions.Caching.Memory; using Oqtane.Extensions; using System; -using Oqtane.UI; -using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Oqtane.Controllers { @@ -212,7 +210,7 @@ public Site Put(int id, [FromBody] Site site) site = _sites.UpdateSite(site); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); string action = SyncEventActions.Refresh; - if (current.RenderMode != site.RenderMode) + if (current.RenderMode != site.RenderMode || current.Runtime != site.Runtime) { action = SyncEventActions.Reload; } diff --git a/Oqtane.Server/Controllers/SystemController.cs b/Oqtane.Server/Controllers/SystemController.cs index d0eacf27c..8c0dce624 100644 --- a/Oqtane.Server/Controllers/SystemController.cs +++ b/Oqtane.Server/Controllers/SystemController.cs @@ -46,7 +46,8 @@ public Dictionary Get(string type) break; case "configuration": systeminfo.Add("InstallationId", _configManager.GetInstallationId()); - systeminfo.Add("RenderMode", _configManager.GetSetting("RenderMode", RenderModes.InteractiveServer)); + systeminfo.Add("RenderMode", _configManager.GetSetting("RenderMode", RenderModes.Interactive)); + systeminfo.Add("Runtime", _configManager.GetSetting("Runtime", Runtimes.Server)); systeminfo.Add("DetailedErrors", _configManager.GetSetting("DetailedErrors", "false")); systeminfo.Add("Logging:LogLevel:Default", _configManager.GetSetting("Logging:LogLevel:Default", "Information")); systeminfo.Add("Logging:LogLevel:Notify", _configManager.GetSetting("Logging:LogLevel:Notify", "Error")); diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 189860167..043d7aa23 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -557,6 +557,7 @@ private Installation CreateSite(InstallConfig install) AdminContainerType = (!string.IsNullOrEmpty(install.DefaultAdminContainer)) ? install.DefaultAdminContainer : Constants.DefaultAdminContainer, SiteTemplateType = install.SiteTemplate, RenderMode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value, + Runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value, Prerender = true, Hybrid = false }; diff --git a/Oqtane.Server/Infrastructure/UpgradeManager.cs b/Oqtane.Server/Infrastructure/UpgradeManager.cs index 3af4b4b7f..a81b5ca0e 100644 --- a/Oqtane.Server/Infrastructure/UpgradeManager.cs +++ b/Oqtane.Server/Infrastructure/UpgradeManager.cs @@ -63,6 +63,9 @@ public void Upgrade(Tenant tenant, string version) case "3.3.0": Upgrade_3_3_0(tenant, scope); break; + case "5.1.0": + Upgrade_5_1_0(tenant, scope); + break; } } } @@ -111,7 +114,11 @@ private void Upgrade_2_1_0(Tenant tenant, IServiceScope scope) _configManager.RemoveSetting("Localization:SupportedCultures", true); if (_configManager.GetSetting("RenderMode", "") == "") { - _configManager.AddOrUpdateSetting("RenderMode", "ServerPrerendered", true); + _configManager.AddOrUpdateSetting("RenderMode", RenderModes.Interactive, true); + } + if (_configManager.GetSetting("Runtime", "") == "") + { + _configManager.AddOrUpdateSetting("Runtime", Runtimes.Server, true); } } } @@ -349,5 +356,17 @@ private void Upgrade_3_3_0(Tenant tenant, IServiceScope scope) Debug.WriteLine($"Oqtane Error: Error In 3.3.0 Upgrade Logic - {ex}"); } } + + private void Upgrade_5_1_0(Tenant tenant, IServiceScope scope) + { + if (tenant.Name == TenantNames.Master) + { + var rendermode = _configManager.GetSetting("RenderMode", ""); + if (rendermode.Contains("Prerendered")) + { + _configManager.AddOrUpdateSetting("RenderMode", rendermode.Replace("Prerendered", ""), true); + } + } + } } } diff --git a/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs b/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs index f0194dfcf..997798cad 100644 --- a/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs +++ b/Oqtane.Server/Migrations/Tenant/05010004_AddSitePrerender.cs @@ -19,15 +19,13 @@ protected override void Up(MigrationBuilder migrationBuilder) { var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); - siteEntityBuilder.UpdateColumn("RenderMode", $"'{RenderModes.InteractiveServer}'"); + siteEntityBuilder.UpdateColumn("RenderMode", $"'{RenderModes.Interactive}'"); siteEntityBuilder.AddBooleanColumn("Prerender", true); siteEntityBuilder.UpdateColumn("Prerender", "1", "bool", ""); siteEntityBuilder.AddBooleanColumn("Hybrid", true); siteEntityBuilder.UpdateColumn("Hybrid", "0", "bool", ""); - - siteEntityBuilder.DropColumn("Runtime"); siteEntityBuilder.DropColumn("HybridEnabled"); } diff --git a/Oqtane.Shared/Enums/Runtime.cs b/Oqtane.Shared/Enums/Runtime.cs index a755b7c12..2043e7436 100644 --- a/Oqtane.Shared/Enums/Runtime.cs +++ b/Oqtane.Shared/Enums/Runtime.cs @@ -2,7 +2,9 @@ namespace Oqtane.Shared { public enum Runtime { - Web, + Server, + WebAssembly, + Auto, Hybrid } } diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index fc1109c99..aa2f29001 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -69,12 +69,17 @@ public class Site : ModelBase, IDeletable public string SiteGuid { get; set; } /// - /// The default render mode for the site (ie. Static,InteractiveServer,InteractiveWebAssembly,InteractiveAuto) + /// The default render mode for the site ie. Static,Interactive,Headless /// public string RenderMode { get; set; } /// - /// If the site supports prerendering (only applies to Interactive rendering) + /// The interactive render mode for the site ie. Server,WebAssembly,Auto (only applies to Interactive rendermode) + /// + public string Runtime { get; set; } + + /// + /// If the site supports prerendering (only applies to Interactive rendermode) /// public bool Prerender { get; set; } diff --git a/Oqtane.Shared/Shared/InstallConfig.cs b/Oqtane.Shared/Shared/InstallConfig.cs index e5371867f..64747d4fe 100644 --- a/Oqtane.Shared/Shared/InstallConfig.cs +++ b/Oqtane.Shared/Shared/InstallConfig.cs @@ -18,6 +18,7 @@ public class InstallConfig public string DefaultContainer { get; set; } public string DefaultAdminContainer { get; set; } public string RenderMode { get; set; } + public string Runtime { get; set; } public bool Register { get; set; } } } diff --git a/Oqtane.Shared/Shared/RenderModes.cs b/Oqtane.Shared/Shared/RenderModes.cs index bb0aaa889..864cf05c8 100644 --- a/Oqtane.Shared/Shared/RenderModes.cs +++ b/Oqtane.Shared/Shared/RenderModes.cs @@ -1,8 +1,7 @@ namespace Oqtane.Shared { public class RenderModes { - public const string StaticServer = "StaticServer"; - public const string InteractiveServer = "InteractiveServer"; - public const string InteractiveWebAssembly = "InteractiveWebAssembly"; - public const string InteractiveAuto = "InteractiveAuto"; + public const string Static = "Static"; + public const string Interactive = "Interactive"; + public const string Headless = "Headless"; } } diff --git a/Oqtane.Shared/Shared/Runtimes.cs b/Oqtane.Shared/Shared/Runtimes.cs new file mode 100644 index 000000000..8ab73d1ea --- /dev/null +++ b/Oqtane.Shared/Shared/Runtimes.cs @@ -0,0 +1,8 @@ +namespace Oqtane.Shared { + public class Runtimes { + public const string Server = "Server"; + public const string WebAssembly = "WebAssembly"; + public const string Auto = "Auto"; + public const string Hybrid = "Hybrid"; + } +} From e0587ad17bf8c6f2ded30ebab75857169522d8e0 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 1 Feb 2024 09:09:58 -0500 Subject: [PATCH 026/280] Update appsettings.json --- Oqtane.Server/appsettings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index ca229d7fd..28270babe 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -1,5 +1,6 @@ { - "RenderMode": "InteractiveServer", + "RenderMode": "Interactive", + "Runtime": "Server", "Database": { "DefaultDBType": "" }, From a39968868f31e7e66a3061705de6b69715a21d9f Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 1 Feb 2024 09:10:13 -0500 Subject: [PATCH 027/280] Update appsettings.release.json --- Oqtane.Server/appsettings.release.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/appsettings.release.json b/Oqtane.Server/appsettings.release.json index 091bf1a75..3b74ae043 100644 --- a/Oqtane.Server/appsettings.release.json +++ b/Oqtane.Server/appsettings.release.json @@ -1,5 +1,6 @@ { - "RenderMode": "InteractiveServer", + "RenderMode": "Interactive", + "Runtime": "Server", "Database": { "DefaultDBType": "" }, From 156d39490ec8d87e3e37fee25807ec443dca3fd0 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 09:47:46 -0500 Subject: [PATCH 028/280] use new contants in .NET MAUI --- Oqtane.Maui/Main.razor | 5 +++-- Oqtane.Shared/Shared/RenderModes.cs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Oqtane.Maui/Main.razor b/Oqtane.Maui/Main.razor index 89ce5c8c3..52c20dd50 100644 --- a/Oqtane.Maui/Main.razor +++ b/Oqtane.Maui/Main.razor @@ -1,5 +1,6 @@ @using System.Text.Json; @using System.Text.Json.Nodes; +@using Oqtane.Shared; @if (string.IsNullOrEmpty(message)) { @@ -19,8 +20,8 @@ else { Parameters = new Dictionary(); Parameters.Add(new KeyValuePair("AntiForgeryToken", "")); - Parameters.Add(new KeyValuePair("Runtime", "Hybrid")); - Parameters.Add(new KeyValuePair("RenderMode", "Hybrid")); + Parameters.Add(new KeyValuePair("RenderMode", RenderModes.Hybrid)); + Parameters.Add(new KeyValuePair("Runtime", Runtimes.Hybrid)); Parameters.Add(new KeyValuePair("VisitorId", -1)); Parameters.Add(new KeyValuePair("RemoteIPAddress", "")); Parameters.Add(new KeyValuePair("AuthorizationToken", "")); diff --git a/Oqtane.Shared/Shared/RenderModes.cs b/Oqtane.Shared/Shared/RenderModes.cs index 864cf05c8..19c3e54cd 100644 --- a/Oqtane.Shared/Shared/RenderModes.cs +++ b/Oqtane.Shared/Shared/RenderModes.cs @@ -3,5 +3,6 @@ public class RenderModes { public const string Static = "Static"; public const string Interactive = "Interactive"; public const string Headless = "Headless"; + public const string Hybrid = "Hybrid"; // used at runtime by .NET MAUI clients } } From abd235f332998c633d06f1dc447e05e3a65e68c1 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 09:59:28 -0500 Subject: [PATCH 029/280] add RenderMode to IModuleControl --- Oqtane.Client/Modules/ModuleBase.cs | 2 ++ Oqtane.Client/UI/SiteRouter.razor | 2 ++ Oqtane.Maui/Main.razor | 2 +- Oqtane.Shared/Interfaces/IModuleControl.cs | 5 +++++ Oqtane.Shared/Models/Module.cs | 2 ++ Oqtane.Shared/Shared/RenderModes.cs | 1 - 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 052818446..e2769ed7d 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -50,6 +50,8 @@ public abstract class ModuleBase : ComponentBase, IModuleControl public virtual List Resources { get; set; } + public virtual string RenderMode { get { return RenderModes.Interactive; } } + // url parameters public virtual string UrlParametersTemplate { get; set; } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index a378e6376..a25d6d8e2 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -478,6 +478,8 @@ { // retrieve module component resources var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl; + module.RenderMode = moduleobject.RenderMode; + page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace); if (action.ToLower() == "settings" && module.ModuleDefinition != null) { diff --git a/Oqtane.Maui/Main.razor b/Oqtane.Maui/Main.razor index 52c20dd50..1adc989ea 100644 --- a/Oqtane.Maui/Main.razor +++ b/Oqtane.Maui/Main.razor @@ -20,7 +20,7 @@ else { Parameters = new Dictionary(); Parameters.Add(new KeyValuePair("AntiForgeryToken", "")); - Parameters.Add(new KeyValuePair("RenderMode", RenderModes.Hybrid)); + Parameters.Add(new KeyValuePair("RenderMode", RenderModes.Interactive)); Parameters.Add(new KeyValuePair("Runtime", Runtimes.Hybrid)); Parameters.Add(new KeyValuePair("VisitorId", -1)); Parameters.Add(new KeyValuePair("RemoteIPAddress", "")); diff --git a/Oqtane.Shared/Interfaces/IModuleControl.cs b/Oqtane.Shared/Interfaces/IModuleControl.cs index 7d9dd5c75..1d442931d 100644 --- a/Oqtane.Shared/Interfaces/IModuleControl.cs +++ b/Oqtane.Shared/Interfaces/IModuleControl.cs @@ -30,5 +30,10 @@ public interface IModuleControl /// Identifies all resources in a module /// List Resources { get; } + + /// + /// Specifies the required render mode for the module control ie. Static,Interactive + /// + string RenderMode { get; } } } diff --git a/Oqtane.Shared/Models/Module.cs b/Oqtane.Shared/Models/Module.cs index c0d37b3a9..bae7a0caa 100644 --- a/Oqtane.Shared/Models/Module.cs +++ b/Oqtane.Shared/Models/Module.cs @@ -115,6 +115,8 @@ public class Module : ModelBase public string Actions { get; set; } [NotMapped] public bool UseAdminContainer { get; set; } + [NotMapped] + public string RenderMode{ get; set; } #endregion diff --git a/Oqtane.Shared/Shared/RenderModes.cs b/Oqtane.Shared/Shared/RenderModes.cs index 19c3e54cd..864cf05c8 100644 --- a/Oqtane.Shared/Shared/RenderModes.cs +++ b/Oqtane.Shared/Shared/RenderModes.cs @@ -3,6 +3,5 @@ public class RenderModes { public const string Static = "Static"; public const string Interactive = "Interactive"; public const string Headless = "Headless"; - public const string Hybrid = "Hybrid"; // used at runtime by .NET MAUI clients } } From 7640dab3806e81cdec985e96497dafd3970f6a24 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 10:08:41 -0500 Subject: [PATCH 030/280] fix Runtimes property behavior --- Oqtane.Client/Modules/ModuleBase.cs | 2 +- Oqtane.Client/UI/SiteRouter.razor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index e2769ed7d..403f7fb39 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -50,7 +50,7 @@ public abstract class ModuleBase : ComponentBase, IModuleControl public virtual List Resources { get; set; } - public virtual string RenderMode { get { return RenderModes.Interactive; } } + public virtual string RenderMode { get { return RenderModes.Interactive; } } // interactive by default // url parameters public virtual string UrlParametersTemplate { get; set; } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index a25d6d8e2..d8ac51e91 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -431,7 +431,7 @@ { var typename = Constants.ErrorModule; - if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(RenderMode))) + if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime))) { typename = module.ModuleDefinition.ControlTypeTemplate; From 7c0479277750e99bb4f5617cd73f7c0c86bbd313 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 10:45:52 -0500 Subject: [PATCH 031/280] remove unnecessary constants --- Oqtane.Client/UI/Pane.razor | 2 +- Oqtane.Client/UI/SiteRouter.razor | 2 +- Oqtane.Shared/Shared/Constants.cs | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 0b5a2b9be..3412d9598 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -123,7 +123,7 @@ else private void CreateComponent(RenderTreeBuilder builder, Module module, int key) { - builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent)); + builder.OpenComponent(0, typeof(ContainerBuilder)); builder.AddAttribute(1, "ModuleState", module); if (key != -1) { diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index d8ac51e91..bc3da9912 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -55,7 +55,7 @@ { if (PageState != null) { - builder.OpenComponent(0, Type.GetType(Constants.PageComponent)); + builder.OpenComponent(0, typeof(ThemeBuilder)); builder.CloseComponent(); } }; diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 0b38b07b0..795e2d81b 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -14,9 +14,6 @@ public class Constants public const string DataDirectory = "DataDirectory"; public const string DefaultDBType = "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer"; - public const string PageComponent = "Oqtane.UI.ThemeBuilder, Oqtane.Client"; - public const string ContainerComponent = "Oqtane.UI.ContainerBuilder, Oqtane.Client"; - public const string DefaultTheme = "Oqtane.Themes.OqtaneTheme.Default, Oqtane.Client"; public const string DefaultContainer = "Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client"; public const string DefaultAdminContainer = "Oqtane.Themes.AdminContainer, Oqtane.Client"; @@ -35,7 +32,6 @@ public class Constants public const string AdminDashboardModule = "Oqtane.Modules.Admin.Dashboard, Oqtane.Client"; public const string PageManagementModule = "Oqtane.Modules.Admin.Pages, Oqtane.Client"; public const string ErrorModule = "Oqtane.Modules.Admin.Error.{Action}, Oqtane.Client"; - public const string ModuleMessageComponent = "Oqtane.Modules.Controls.ModuleMessage, Oqtane.Client"; public const string DefaultSiteTemplate = "Oqtane.SiteTemplates.DefaultSiteTemplate, Oqtane.Server"; From f0e2247f067fd95b1b0fab0e998bc6e3911d48e7 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 15:19:15 -0500 Subject: [PATCH 032/280] remove unused NavigationManager reference --- .../Providers/IdentityAuthenticationStateProvider.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs b/Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs index 146df8d4b..49ff4643d 100644 --- a/Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs +++ b/Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs @@ -1,10 +1,8 @@ using System; -using System.Net; using System.Net.Http; using System.Net.Http.Json; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.DependencyInjection; using Oqtane.Models; @@ -16,12 +14,10 @@ namespace Oqtane.Providers public class IdentityAuthenticationStateProvider : AuthenticationStateProvider { private readonly IServiceProvider _serviceProvider; - private readonly NavigationManager _navigationManager; - public IdentityAuthenticationStateProvider(IServiceProvider serviceProvider, NavigationManager navigationManager) + public IdentityAuthenticationStateProvider(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; - _navigationManager = navigationManager; } public override async Task GetAuthenticationStateAsync() From 1f65d47811c26c67e5067502b66c7d03211cb367 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 15:47:03 -0500 Subject: [PATCH 033/280] use new Cascading Authentication State Services --- .../Extensions/OqtaneServiceCollectionExtensions.cs | 1 + Oqtane.Client/Routes.razor | 8 +++----- Oqtane.Server/Startup.cs | 3 +++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs index bc1d4780c..ce563a13b 100644 --- a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -10,6 +10,7 @@ public static class OqtaneServiceCollectionExtensions public static IServiceCollection AddOqtaneAuthorization(this IServiceCollection services) { services.AddAuthorizationCore(); + services.AddCascadingAuthenticationState(); services.AddScoped(); services.AddScoped(s => s.GetRequiredService()); diff --git a/Oqtane.Client/Routes.razor b/Oqtane.Client/Routes.razor index 16c99c527..932b957e4 100644 --- a/Oqtane.Client/Routes.razor +++ b/Oqtane.Client/Routes.razor @@ -14,11 +14,9 @@ @if (string.IsNullOrEmpty(_installation.Message)) {
- - - - - + + +
} else diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index c0b485751..eb625a52d 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -108,6 +108,9 @@ public void ConfigureServices(IServiceCollection services) services.ConfigureOqtaneIdentityOptions(Configuration); + services.AddCascadingAuthenticationState(); + services.AddAuthorization(); + services.AddAuthentication(options => { options.DefaultScheme = Constants.AuthenticationScheme; From 033c85fc4bbb2224bf33eb01d787c88ee612ebb1 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 1 Feb 2024 16:49:29 -0500 Subject: [PATCH 034/280] add support for Razor Pages --- Oqtane.Server/Startup.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index eb625a52d..fcd22e8b2 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -144,6 +144,8 @@ public void ConfigureServices(IServiceCollection services) .AddOqtaneApplicationParts() // register any Controllers from custom modules .ConfigureOqtaneMvc(); // any additional configuration from IStartup classes + services.AddRazorPages(); + services.AddRazorComponents() .AddInteractiveServerComponents(options => { @@ -209,11 +211,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/" + Constants.Version + "/swagger.json", Constants.PackageId + " " + Constants.Version); }); } - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - app.UseEndpoints(endpoints => { endpoints.MapRazorComponents() @@ -224,6 +221,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan // simulate the fallback routing approach of traditional Blazor - allowing the custom SiteRouter to handle all routing concerns app.UseEndpoints(endpoints => { + endpoints.MapControllers(); + endpoints.MapRazorPages(); endpoints.MapFallback(); }); From 8500f5b4377b62b31bd71bdff78c4903a9c1ca18 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 1 Feb 2024 14:36:14 -0800 Subject: [PATCH 035/280] Fix refresh() conditional check for page --- Oqtane.Client/UI/SiteRouter.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index bc3da9912..4fd9cb338 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -324,7 +324,7 @@ } else // not mapped { - if (user == null && Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) + if (user == null) { // redirect to login page if user not logged in as they may need to be authenticated NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery))); From 71125f07cc5075032e28109412fdf51073b933a4 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 2 Feb 2024 08:54:01 -0500 Subject: [PATCH 036/280] change extension method name to reflect actual purpose --- Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs | 2 +- Oqtane.Client/Program.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs index ce563a13b..0062e399a 100644 --- a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - public static IServiceCollection AddOqtaneAuthorization(this IServiceCollection services) + public static IServiceCollection AddOqtaneAuthentication(this IServiceCollection services) { services.AddAuthorizationCore(); services.AddCascadingAuthenticationState(); diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 0c5f80d7e..3a40b0552 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -41,7 +41,7 @@ public static async Task Main(string[] args) builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); // register auth services - builder.Services.AddOqtaneAuthorization(); + builder.Services.AddOqtaneAuthentication(); // register scoped core services builder.Services.AddOqtaneScopedServices(); From bb02a17e444063264d76dc61f6b8899531862089 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 2 Feb 2024 09:06:51 -0500 Subject: [PATCH 037/280] Fix #3723 - cancel from login not redirecting properly --- Oqtane.Client/Modules/Admin/Login/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index b152a5d11..64c1d93f6 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -255,7 +255,7 @@ private void Cancel() { - NavigationManager.NavigateTo(_returnUrl); + NavigationManager.NavigateTo(WebUtility.UrlDecode(_returnUrl)); } private async Task Forgot() From 21b9b090f9efb900a24f94d9478b4ce6ffa49f4a Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 2 Feb 2024 10:38:16 -0500 Subject: [PATCH 038/280] move root UI components to UI namespace --- Oqtane.Client/{ => UI}/Head.razor | 1 + Oqtane.Client/{ => UI}/Routes.razor | 1 + 2 files changed, 2 insertions(+) rename Oqtane.Client/{ => UI}/Head.razor (98%) rename Oqtane.Client/{ => UI}/Routes.razor (99%) diff --git a/Oqtane.Client/Head.razor b/Oqtane.Client/UI/Head.razor similarity index 98% rename from Oqtane.Client/Head.razor rename to Oqtane.Client/UI/Head.razor index 88f5c6a78..75a6101f8 100644 --- a/Oqtane.Client/Head.razor +++ b/Oqtane.Client/UI/Head.razor @@ -1,3 +1,4 @@ +@namespace Oqtane.UI @using System.ComponentModel @using Oqtane.Shared @inject SiteState SiteState diff --git a/Oqtane.Client/Routes.razor b/Oqtane.Client/UI/Routes.razor similarity index 99% rename from Oqtane.Client/Routes.razor rename to Oqtane.Client/UI/Routes.razor index 932b957e4..954e16981 100644 --- a/Oqtane.Client/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -1,3 +1,4 @@ +@namespace Oqtane.UI @using Microsoft.AspNetCore.Http @inject IInstallationService InstallationService @inject IJSRuntime JSRuntime From b7dbed5cd4a436af15a5d4deedb917ffdb38368b Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 2 Feb 2024 10:56:24 -0500 Subject: [PATCH 039/280] update .NET MAUI client to reflect changes --- Oqtane.Maui/Main.razor | 2 +- Oqtane.Maui/MauiProgram.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Maui/Main.razor b/Oqtane.Maui/Main.razor index 1adc989ea..a00a2e9b5 100644 --- a/Oqtane.Maui/Main.razor +++ b/Oqtane.Maui/Main.razor @@ -12,7 +12,7 @@ else } @code { - Type ComponentType = Type.GetType("Oqtane.Routes, Oqtane.Client"); + Type ComponentType = Type.GetType("Oqtane.UI.Routes, Oqtane.Client"); private IDictionary Parameters { get; set; } private string message = ""; diff --git a/Oqtane.Maui/MauiProgram.cs b/Oqtane.Maui/MauiProgram.cs index 95a421179..fe147872b 100644 --- a/Oqtane.Maui/MauiProgram.cs +++ b/Oqtane.Maui/MauiProgram.cs @@ -44,7 +44,7 @@ public static MauiApp CreateMauiApp() builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); // register auth services - builder.Services.AddOqtaneAuthorization(); + builder.Services.AddOqtaneAuthentication(); // register scoped core services builder.Services.AddOqtaneScopedServices(); From 310772d7fe7d9ebdbacbd6529996972baf9b1bae Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 2 Feb 2024 13:08:05 -0500 Subject: [PATCH 040/280] changes for static rendering --- Oqtane.Client/UI/Routes.razor | 9 +++++++-- Oqtane.Client/UI/ThemeBuilder.razor | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index 954e16981..449d63577 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -52,13 +52,18 @@ HttpContext HttpContext { get; set; } private bool _initialized = false; - private string _display = "display: none;"; + private string _display = ""; private Installation _installation = new Installation { Success = false, Message = "" }; private PageState PageState { get; set; } protected override async Task OnParametersSetAsync() { + if (RenderMode == RenderModes.Interactive) + { + _display = "display: none;"; + } + SiteState.RemoteIPAddress = RemoteIPAddress; SiteState.AntiForgeryToken = AntiForgeryToken; SiteState.AuthorizationToken = AuthorizationToken; @@ -76,7 +81,7 @@ { if (firstRender) { - // prevents flash on initial page load + // prevents flash on initial interactive page load _display = ""; StateHasChanged(); } diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 9432e2ac4..262a919a2 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -57,8 +57,7 @@ DynamicComponent = builder => { - var themeType = Type.GetType(PageState.Page.ThemeType); - builder.OpenComponent(0, themeType); + builder.OpenComponent(0, Type.GetType(PageState.Page.ThemeType)); builder.CloseComponent(); }; } From e7a48f39091d8e3205e3d4f7598b8d038f1d14de Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 2 Feb 2024 14:38:37 -0500 Subject: [PATCH 041/280] use Runtimes constant --- Oqtane.Client/UI/SiteRouter.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 4fd9cb338..3a0081a39 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -220,7 +220,7 @@ if (site != null) { - if (Runtime == "Hybrid" && !site.Hybrid) + if (Runtime == Runtimes.Hybrid && !site.Hybrid) { _error = "Hybrid Integration Is Not Enabled For This Site"; return; From 6345335be27461bac46442a2e52cefa61a8bfa66 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 6 Feb 2024 11:26:31 -0500 Subject: [PATCH 042/280] optrimization to eliminate file lookup in Logo control --- Oqtane.Client/Themes/Controls/Theme/Logo.razor | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/Logo.razor b/Oqtane.Client/Themes/Controls/Theme/Logo.razor index 89483bd0b..594649f16 100644 --- a/Oqtane.Client/Themes/Controls/Theme/Logo.razor +++ b/Oqtane.Client/Themes/Controls/Theme/Logo.razor @@ -1,24 +1,11 @@ @namespace Oqtane.Themes.Controls @inherits ThemeControlBase -@inject IFileService FileService -@if (file != null) +@if (PageState.Site.LogoFileId != null) { -} - -@code { - private File file = null; - - protected override async Task OnParametersSetAsync() - { - if (PageState.Site.LogoFileId != null && file?.FileId != PageState.Site.LogoFileId.Value) - { - file = await FileService.GetFileAsync(PageState.Site.LogoFileId.Value); - } - } } \ No newline at end of file From a7a5fdb7f54133d676f21f47a378f263be78eac0 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 6 Feb 2024 11:28:37 -0500 Subject: [PATCH 043/280] temporary hack to allow Static rendering to (sort of) work - this will need to be removed later --- Oqtane.Client/UI/Routes.razor | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index 449d63577..ff1756b36 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -69,11 +69,13 @@ SiteState.AuthorizationToken = AuthorizationToken; SiteState.IsPrerendering = (HttpContext != null) ? true : false; - _installation = await InstallationService.IsInstalled(); - if (_installation.Alias != null) - { - SiteState.Alias = _installation.Alias; - } + _installation = new Installation { Success = true }; + SiteState.Alias = new Alias { AliasId = 1, SiteId = 1, TenantId = 1, Name = "localhost:44357", IsDefault = true, BaseUrl = "", Protocol = "http://" }; + // _installation = await InstallationService.IsInstalled(); + // if (_installation.Alias != null) + // { + // SiteState.Alias = _installation.Alias; + // } _initialized = true; } From c9c8e20511453c550c9df5278392dcc80d78c16d Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 6 Feb 2024 11:40:44 -0500 Subject: [PATCH 044/280] update project files to make consistent with Blazor template --- Oqtane.Client/Oqtane.Client.csproj | 2 -- Oqtane.Server/Oqtane.Server.csproj | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 2d1d0703b..b59b39097 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -22,11 +22,9 @@ - - diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 34f52a179..39a232b40 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -17,7 +17,6 @@ Oqtane true $(DefineConstants);OQTANE;OQTANE3 - true none @@ -35,7 +34,7 @@ - + all From 3d49ab2ae0c26959da14d201a131b0b6200168dd Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 6 Feb 2024 12:42:31 -0500 Subject: [PATCH 045/280] remove UseBlazorFrameworkFiles as no longer needed --- Oqtane.Server/Startup.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index fcd22e8b2..d162e62cb 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -68,9 +68,6 @@ public void ConfigureServices(IServiceCollection services) services.AddOptions>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection)); services.Configure(opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(10)); // increase from default of 5 seconds - // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) - services.AddHttpClients(); - // register scoped core services services.AddScoped() .AddOqtaneScopedServices() @@ -78,6 +75,9 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); + // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) + services.AddHttpClients(); + // register singleton scoped core services services.AddSingleton(Configuration) .AddOqtaneSingletonServices(); @@ -199,7 +199,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan app.UseStaticFiles(); app.UseTenantResolution(); app.UseJwtAuthorization(); - app.UseBlazorFrameworkFiles(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); From 07bd5c633e4c62c8188fd293c647e341d9a065e7 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 8 Feb 2024 09:25:31 -0500 Subject: [PATCH 046/280] add @attribute [StreamRendering] attribute to Routes.razor and remove #3739 --- Oqtane.Client/UI/Routes.razor | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index ff1756b36..3b0f51917 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -3,6 +3,7 @@ @inject IInstallationService InstallationService @inject IJSRuntime JSRuntime @inject SiteState SiteState +@attribute [StreamRendering] @if (_initialized) { @@ -69,13 +70,11 @@ SiteState.AuthorizationToken = AuthorizationToken; SiteState.IsPrerendering = (HttpContext != null) ? true : false; - _installation = new Installation { Success = true }; - SiteState.Alias = new Alias { AliasId = 1, SiteId = 1, TenantId = 1, Name = "localhost:44357", IsDefault = true, BaseUrl = "", Protocol = "http://" }; - // _installation = await InstallationService.IsInstalled(); - // if (_installation.Alias != null) - // { - // SiteState.Alias = _installation.Alias; - // } + _installation = await InstallationService.IsInstalled(); + if (_installation.Alias != null) + { + SiteState.Alias = _installation.Alias; + } _initialized = true; } From a40b49f2ede6c2a6ec1697a7c0dd02c27d5fcdbb Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 8 Feb 2024 15:47:25 -0500 Subject: [PATCH 047/280] implement RenderModeBoundary --- .../Modules/Admin/RecycleBin/Index.razor | 12 +- .../Modules/Admin/UserProfile/Index.razor | 6 +- .../Modules/Controls/ModuleMessage.razor | 6 +- Oqtane.Client/Modules/HtmlText/Settings.razor | 4 +- Oqtane.Client/Modules/ModuleBase.cs | 10 +- .../Themes/Controls/Theme/Login.razor | 15 +- .../Themes/Controls/Theme/LoginBase.cs | 71 ++++++--- .../Themes/Controls/Theme/UserProfile.razor | 14 +- .../Containers/ContainerSettings.razor | 4 +- Oqtane.Client/UI/ModuleInstance.razor | 118 +------------- Oqtane.Client/UI/RenderModeBoundary.razor | 149 ++++++++++++++++++ Oqtane.Server/Components/App.razor | 4 +- 12 files changed, 241 insertions(+), 172 deletions(-) create mode 100644 Oqtane.Client/UI/RenderModeBoundary.razor diff --git a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor index 1d88dcf89..91cf36692 100644 --- a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor +++ b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor @@ -140,7 +140,7 @@ else { try { - ModuleInstance.ShowProgressIndicator(); + ShowProgressIndicator(); foreach (Page page in _pages.Where(item => item.IsDeleted)) { await PageService.DeletePageAsync(page.PageId); @@ -149,7 +149,7 @@ else await logger.LogInformation("Pages Permanently Deleted"); await Load(); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); StateHasChanged(); NavigationManager.NavigateTo(NavigateUrl()); } @@ -157,7 +157,7 @@ else { await logger.LogError(ex, "Error Permanently Deleting Pages {Error}", ex.Message); AddModuleMessage(ex.Message, MessageType.Error); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); } } @@ -199,21 +199,21 @@ else { try { - ModuleInstance.ShowProgressIndicator(); + ShowProgressIndicator(); foreach (Module module in _modules.Where(item => item.IsDeleted).ToList()) { await PageModuleService.DeletePageModuleAsync(module.PageModuleId); } await logger.LogInformation("Modules Permanently Deleted"); await Load(); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); StateHasChanged(); } catch (Exception ex) { await logger.LogError(ex, "Error Permanently Deleting Modules {Error}", ex.Message); AddModuleMessage(Localizer["Error.Modules.Delete"], MessageType.Error); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); } } private void OnPageChangePage(int page) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 0f5dad7b0..24d5cf6af 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -596,7 +596,7 @@ { try { - ModuleInstance.ShowProgressIndicator(); + ShowProgressIndicator(); foreach(var Notification in notifications) { if (!Notification.IsDeleted) @@ -612,7 +612,7 @@ } await logger.LogInformation("Notifications Permanently Deleted"); await LoadNotificationsAsync(); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); StateHasChanged(); } @@ -620,7 +620,7 @@ { await logger.LogError(ex, "Error Deleting Notifications {Error}", ex.Message); AddModuleMessage(ex.Message, MessageType.Error); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); } } diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index f4f000277..820341659 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -10,7 +10,10 @@ { @((MarkupString)"  ")View Details } - +
+ + +
} @@ -58,6 +61,5 @@ private void DismissModal() { _message = ""; - StateHasChanged(); } } diff --git a/Oqtane.Client/Modules/HtmlText/Settings.razor b/Oqtane.Client/Modules/HtmlText/Settings.razor index bc1004a37..f08074c14 100644 --- a/Oqtane.Client/Modules/HtmlText/Settings.razor +++ b/Oqtane.Client/Modules/HtmlText/Settings.razor @@ -40,7 +40,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } @@ -55,7 +55,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 403f7fb39..e6582ffdb 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -37,7 +37,7 @@ public abstract class ModuleBase : ComponentBase, IModuleControl protected Module ModuleState { get; set; } [Parameter] - public ModuleInstance ModuleInstance { get; set; } + public RenderModeBoundary RenderModeBoundary { get; set; } // optional interface properties public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security @@ -274,22 +274,22 @@ public void AddModuleMessage(string message, MessageType type) public void AddModuleMessage(string message, MessageType type, string position) { ClearModuleMessage(); - ModuleInstance.AddModuleMessage(message, type, position); + RenderModeBoundary.AddModuleMessage(message, type, position); } public void ClearModuleMessage() { - ModuleInstance.AddModuleMessage("", MessageType.Undefined); + RenderModeBoundary.AddModuleMessage("", MessageType.Undefined); } public void ShowProgressIndicator() { - ModuleInstance.ShowProgressIndicator(); + RenderModeBoundary.ShowProgressIndicator(); } public void HideProgressIndicator() { - ModuleInstance.HideProgressIndicator(); + RenderModeBoundary.HideProgressIndicator(); } public void SetModuleTitle(string title) diff --git a/Oqtane.Client/Themes/Controls/Theme/Login.razor b/Oqtane.Client/Themes/Controls/Theme/Login.razor index ce27baaac..b5908ef99 100644 --- a/Oqtane.Client/Themes/Controls/Theme/Login.razor +++ b/Oqtane.Client/Themes/Controls/Theme/Login.razor @@ -9,12 +9,23 @@ ... - + @if (PageState.Runtime == Runtime.Hybrid) + { + + } + else + { +
+ + + +
+ }
@if (ShowLogin) { - + @SharedLocalizer["Login"] } diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index 4a61cb048..fc41f5659 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -21,30 +21,65 @@ public class LoginBase : ThemeControlBase [Inject] public IJSRuntime jsRuntime { get; set; } [Inject] public IServiceProvider ServiceProvider { get; set; } - protected void LoginUser() + private bool allowexternallogin; + private bool allowsitelogin; + protected string loginurl; + protected string logouturl; + protected string returnurl; + + protected override void OnParametersSet() { - var allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false; - var allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true")); + allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false; + allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true")); + + // set login url + if (allowexternallogin && !allowsitelogin) + { + // external login + loginurl = Utilities.TenantUrl(PageState.Alias, "/pages/external"); + } + else + { + // local login + loginurl = NavigateUrl("login"); + } - var returnurl = ""; if (!PageState.QueryString.ContainsKey("returnurl")) { - returnurl = WebUtility.UrlEncode(PageState.Route.PathAndQuery); // remember current url + // remember current url + loginurl += "?returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery); } else { - returnurl = PageState.QueryString["returnurl"]; // use existing value + // use existing value + loginurl = "?returnurl=" + PageState.QueryString["returnurl"]; } + // set logout url + logouturl = Utilities.TenantUrl(PageState.Alias, "/pages/logout/"); + + // verify anonymous users can access current page + if (UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) && Utilities.IsPageModuleVisible(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate)) + { + returnurl = PageState.Route.PathAndQuery; + } + else + { + returnurl = PageState.Alias.Path; + } + } + + protected void LoginUser() + { if (allowexternallogin && !allowsitelogin) { // external login - NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + returnurl), true); + NavigationManager.NavigateTo(loginurl, true); } else { // local login - NavigationManager.NavigateTo(NavigateUrl("login", "?returnurl=" + returnurl)); + NavigationManager.NavigateTo(loginurl); } } @@ -52,30 +87,20 @@ protected async Task LogoutUser() { await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username); - Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path); - var url = route.PathAndQuery; - - // verify if anonymous users can access page - if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) || !Utilities.IsPageModuleVisible(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate)) - { - url = PageState.Alias.Path; - } - - - if (PageState.Runtime == Shared.Runtime.Hybrid) + if (PageState.Runtime == Runtime.Hybrid) { // hybrid apps utilize an interactive logout await UserService.LogoutUserAsync(PageState.User); var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(url, true); + NavigationManager.NavigateTo(returnurl, true); } - else + else // this condition is only valid for legacy Login button inheriting from LoginBase { // post to the Logout page to complete the logout process - var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = url }; + var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = returnurl }; var interop = new Interop(jsRuntime); - await interop.SubmitForm(Utilities.TenantUrl(PageState.Alias, "/pages/logout/"), fields); + await interop.SubmitForm(logouturl, fields); } } } diff --git a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor index 850e28c32..69abd0e84 100644 --- a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor +++ b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor @@ -11,12 +11,12 @@ ... - + @context.User.Identity.Name @if (ShowRegister && PageState.Site.AllowRegistration) { - + @Localizer["Register"] } @@ -33,16 +33,6 @@ { _returnurl = WebUtility.UrlEncode(PageState.Route.PathAndQuery); } - - private void RegisterUser() - { - NavigationManager.NavigateTo(NavigateUrl("register", "returnurl=" + _returnurl)); - } - - private void UpdateProfile() - { - NavigationManager.NavigateTo(NavigateUrl("profile", "returnurl=" + _returnurl)); - } } diff --git a/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor b/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor index b0c7774fb..e96fdb7a3 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor @@ -83,7 +83,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } @@ -100,7 +100,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } } diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 71143fc3f..450fe7ef8 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,127 +1,19 @@ @namespace Oqtane.UI -@inject IStringLocalizer Localizer -@inject ILogService LoggingService -@inherits ErrorBoundary +@inject SiteState SiteState -@if (CurrentException is null) +@if (ModuleState.RenderMode == RenderModes.Static) { - if (_message != "" && _messagePosition == "top") - { - - } - @if (ModuleType != null) - { - - @if (_progressIndicator) - { -
- } - } - if (_message != "" && _messagePosition == "bottom") - { - - } + } -else +else { - @if (!string.IsNullOrEmpty(_error)) - { - - } + } @code { - private string _message; - private string _error; - private MessageType _messageType; - private string _messagePosition; - private bool _progressIndicator = false; - - private Type ModuleType { get; set; } - private IDictionary ModuleParameters { get; set; } - [CascadingParameter] protected PageState PageState { get; set; } [CascadingParameter] private Module ModuleState { get; set; } - - private ModuleMessage ModuleMessage { get; set; } - - protected override bool ShouldRender() - { - return PageState?.RenderId == ModuleState?.RenderId; - } - - protected override void OnParametersSet() - { - _message = ""; - if (ShouldRender()) - { - if (!string.IsNullOrEmpty(ModuleState.ModuleType)) - { - ModuleType = Type.GetType(ModuleState.ModuleType); - if (ModuleType != null) - { - ModuleParameters = new Dictionary { { "ModuleInstance", this } }; - return; - } - // module does not exist with typename specified - _message = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0)); - _messageType = MessageType.Error; - _messagePosition = "top"; - } - else - { - _message = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName); - _messageType = MessageType.Error; - _messagePosition = "top"; - } - } - } - - public void AddModuleMessage(string message, MessageType type) - { - AddModuleMessage(message, type, "top"); - } - - public void AddModuleMessage(string message, MessageType type, string position) - { - _message = message; - _messageType = type; - _messagePosition = position; - _progressIndicator = false; - StateHasChanged(); - } - - public void ShowProgressIndicator() - { - _progressIndicator = true; - StateHasChanged(); - } - - public void HideProgressIndicator() - { - _progressIndicator = false; - StateHasChanged(); - } - - protected override async Task OnErrorAsync(Exception exception) - { - // retrieve friendly localized error - _error = Localizer["Error.Module.Exception"]; - // log error - string category = GetType().AssemblyQualifiedName; - string feature = Utilities.GetTypeNameLastSegment(category, 1); - await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, PageState.User?.UserId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message); - await base.OnErrorAsync(exception); - return; - } - - public new void Recover() - { - _error = ""; - base.Recover(); - } - } diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor new file mode 100644 index 000000000..d02df5f1d --- /dev/null +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -0,0 +1,149 @@ +@namespace Oqtane.UI +@inject SiteState SiteStateService +@inject IStringLocalizer Localizer +@inject ILogService LoggingService +@inherits ErrorBoundary + +@if (CurrentException is null) +{ + @if (ModuleType != null) + { + + + @if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top") + { + + } + + @if (_progressIndicator) + { +
+ } + @if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom") + { + + } +
+
+ } +} +else +{ + @if (!string.IsNullOrEmpty(_error)) + { + + } +} + +@code { + private Type ModuleType { get; set; } + private IDictionary ModuleParameters { get; set; } + + private string _messageContent; + private MessageType _messageType; + private string _messagePosition; + private bool _progressIndicator = false; + private string _error; + + [Parameter] + public SiteState SiteState { get; set; } + + [Parameter] + public PageState PageState { get; set; } + + [Parameter] + public Module ModuleState { get; set; } + + RenderFragment DynamicComponent { get; set; } + + protected override bool ShouldRender() + { + return PageState?.RenderId == ModuleState?.RenderId; + } + + protected override void OnParametersSet() + { + _messageContent = ""; + + if (ShouldRender()) + { + if (!string.IsNullOrEmpty(ModuleState.ModuleType)) + { + ModuleType = Type.GetType(ModuleState.ModuleType); + if (ModuleType != null) + { + // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary) + SiteStateService.Alias = SiteState.Alias; + SiteStateService.AntiForgeryToken = SiteState.AntiForgeryToken; + SiteStateService.AuthorizationToken = SiteState.AuthorizationToken; + SiteStateService.RemoteIPAddress = SiteState.RemoteIPAddress; + SiteStateService.IsPrerendering = SiteState.IsPrerendering; + + ModuleParameters = new Dictionary { { "RenderModeBoundary", this } }; + } + else + { + // module does not exist with typename specified + _messageContent = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0)); + _messageType = MessageType.Error; + _messagePosition = "top"; + } + } + else + { + _messageContent = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName); + _messageType = MessageType.Error; + _messagePosition = "top"; + } + } + } + + public void AddModuleMessage(string message, MessageType type) + { + AddModuleMessage(message, type, "top"); + } + + public void AddModuleMessage(string message, MessageType type, string position) + { + _messageContent = message; + _messageType = type; + _messagePosition = position; + _progressIndicator = false; + StateHasChanged(); + } + + public void ShowProgressIndicator() + { + _progressIndicator = true; + StateHasChanged(); + } + + public void HideProgressIndicator() + { + _progressIndicator = false; + StateHasChanged(); + } + + private void DismissMessage() + { + _messageContent = ""; + } + + protected override async Task OnErrorAsync(Exception exception) + { + // retrieve friendly localized error + _error = Localizer["Error.Module.Exception"]; + // log error + string category = GetType().AssemblyQualifiedName; + string feature = Utilities.GetTypeNameLastSegment(category, 1); + await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, PageState.User?.UserId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message); + await base.OnErrorAsync(exception); + return; + } + + public new void Recover() + { + _error = ""; + base.Recover(); + } +} \ No newline at end of file diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index f7526324c..8e6ca4c04 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -53,7 +53,7 @@ } else { - + } @((MarkupString)_headResources) @@ -66,7 +66,7 @@ } else { - + } From ff2f218bf0158c56ca9ec94c89bd7d835927e726 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 8 Feb 2024 15:53:24 -0500 Subject: [PATCH 048/280] set Html/Text module to Static rendering --- Oqtane.Client/Modules/HtmlText/Index.razor | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Oqtane.Client/Modules/HtmlText/Index.razor b/Oqtane.Client/Modules/HtmlText/Index.razor index 91efe2bbc..9e8db9616 100644 --- a/Oqtane.Client/Modules/HtmlText/Index.razor +++ b/Oqtane.Client/Modules/HtmlText/Index.razor @@ -17,6 +17,8 @@ @code { private string content = ""; + public override string RenderMode => RenderModes.Static; + protected override async Task OnParametersSetAsync() { try From b5f710678076626f7c4d4dea2f0ae493deb30e22 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 8 Feb 2024 15:58:31 -0500 Subject: [PATCH 049/280] render mode optimization --- Oqtane.Client/UI/ModuleInstance.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 450fe7ef8..9e439f6d7 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,7 +1,7 @@ @namespace Oqtane.UI @inject SiteState SiteState -@if (ModuleState.RenderMode == RenderModes.Static) +@if (PageState.Site.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { } From e6df8dcd2ea6b040f67338caa90d985537107adb Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 08:47:20 -0500 Subject: [PATCH 050/280] preserve backward compatibility but flag methods as obsolete --- Oqtane.Client/UI/ModuleInstance.razor | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 9e439f6d7..89ab01ac3 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -11,9 +11,32 @@ else } @code { + // this component is on the static side of the render mode boundary + // it passes state as serializable parameters across the boundary so that the state can be used by downstream interactive components + [CascadingParameter] protected PageState PageState { get; set; } [CascadingParameter] private Module ModuleState { get; set; } + + [Obsolete("AddModuleMessage is deprecated. Use ModuleBase.AddModuleMessage instead.", false)] + public void AddModuleMessage(string message, MessageType type) + { + } + + [Obsolete("AddModuleMessage is deprecated. Use ModuleBase.AddModuleMessage instead.", false)] + public void AddModuleMessage(string message, MessageType type, string position) + { + } + + [Obsolete("ShowProgressIndicator is deprecated. Use ModuleBase.ShowProgressIndicator instead.", false)] + public void ShowProgressIndicator() + { + } + + [Obsolete("HideProgressIndicator is deprecated. Use ModuleBase.HideProgressIndicator instead.", false)] + public void HideProgressIndicator() + { + } } From a686bec0259a14878285593db7e151308a5292c3 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 08:56:25 -0500 Subject: [PATCH 051/280] add text to display render mode --- Oqtane.Client/UI/ModuleInstance.razor | 1 + Oqtane.Client/UI/RenderModeBoundary.razor | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 89ab01ac3..cc669db86 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,6 +1,7 @@ @namespace Oqtane.UI @inject SiteState SiteState +
@ModuleState.RenderMode
@if (PageState.Site.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index d02df5f1d..824797d0c 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -54,8 +54,6 @@ else [Parameter] public Module ModuleState { get; set; } - RenderFragment DynamicComponent { get; set; } - protected override bool ShouldRender() { return PageState?.RenderId == ModuleState?.RenderId; From d03565ad95bd11eda6140f1d362fedfb9b137a5f Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 09:10:03 -0500 Subject: [PATCH 052/280] improve debug message --- Oqtane.Client/UI/ModuleInstance.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index cc669db86..53ac20f64 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,14 +1,14 @@ @namespace Oqtane.UI @inject SiteState SiteState -
@ModuleState.RenderMode
+
Render Mode: @ModuleState.RenderMode

@if (PageState.Site.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { - + } else { - + } @code { From f6fb3cc7664f7dc25433609075b52a56c18d8c89 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 10:59:51 -0500 Subject: [PATCH 053/280] specify default interactive render mode --- Oqtane.Client/UI/ModuleInstance.razor | 5 +++-- Oqtane.Client/UI/RenderMode.cs | 2 +- Oqtane.Client/UI/RenderModeBoundary.razor | 12 ++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 53ac20f64..b217749b2 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,14 +1,15 @@ @namespace Oqtane.UI @inject SiteState SiteState -
Render Mode: @ModuleState.RenderMode

@if (PageState.Site.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { +
Render Mode: @PageState.Site.RenderMode

} else { - +
Render Mode: @ModuleState.RenderMode

+ } @code { diff --git a/Oqtane.Client/UI/RenderMode.cs b/Oqtane.Client/UI/RenderMode.cs index c9cd35579..a6c1c8652 100644 --- a/Oqtane.Client/UI/RenderMode.cs +++ b/Oqtane.Client/UI/RenderMode.cs @@ -17,7 +17,7 @@ public static IComponentRenderMode GetInteractiveRenderMode(string runtime, bool case Runtimes.Auto: return new InteractiveAutoRenderMode(prerender); } - return null; + return new InteractiveServerRenderMode(prerender); // default to interactiver server } } } diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index 824797d0c..73127f544 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -1,5 +1,5 @@ @namespace Oqtane.UI -@inject SiteState SiteStateService +@inject SiteState ComponentSiteState // can refer to either a static or interactive SiteState - it depends on the render mode @inject IStringLocalizer Localizer @inject ILogService LoggingService @inherits ErrorBoundary @@ -71,11 +71,11 @@ else if (ModuleType != null) { // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary) - SiteStateService.Alias = SiteState.Alias; - SiteStateService.AntiForgeryToken = SiteState.AntiForgeryToken; - SiteStateService.AuthorizationToken = SiteState.AuthorizationToken; - SiteStateService.RemoteIPAddress = SiteState.RemoteIPAddress; - SiteStateService.IsPrerendering = SiteState.IsPrerendering; + ComponentSiteState.Alias = SiteState.Alias; + ComponentSiteState.AntiForgeryToken = SiteState.AntiForgeryToken; + ComponentSiteState.AuthorizationToken = SiteState.AuthorizationToken; + ComponentSiteState.RemoteIPAddress = SiteState.RemoteIPAddress; + ComponentSiteState.IsPrerendering = SiteState.IsPrerendering; ModuleParameters = new Dictionary { { "RenderModeBoundary", this } }; } From ea75ddfa853550bba6591e5231372f2c1b2bdd36 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 14:34:33 -0500 Subject: [PATCH 054/280] rename RenderMode class and adding usings --- Oqtane.Client/Oqtane.Client.csproj | 1 + Oqtane.Client/UI/{RenderMode.cs => InteractiveRenderMode.cs} | 2 +- Oqtane.Client/UI/ModuleInstance.razor | 2 +- Oqtane.Client/UI/PaneLayout.razor | 5 ----- Oqtane.Client/_Imports.razor | 3 +++ Oqtane.Server/Components/App.razor | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) rename Oqtane.Client/UI/{RenderMode.cs => InteractiveRenderMode.cs} (94%) delete mode 100644 Oqtane.Client/UI/PaneLayout.razor diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index b59b39097..306c9a36d 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -18,6 +18,7 @@ Oqtane true true + Default diff --git a/Oqtane.Client/UI/RenderMode.cs b/Oqtane.Client/UI/InteractiveRenderMode.cs similarity index 94% rename from Oqtane.Client/UI/RenderMode.cs rename to Oqtane.Client/UI/InteractiveRenderMode.cs index a6c1c8652..a840fe681 100644 --- a/Oqtane.Client/UI/RenderMode.cs +++ b/Oqtane.Client/UI/InteractiveRenderMode.cs @@ -4,7 +4,7 @@ namespace Oqtane.UI { - public static class RenderMode + public static class InteractiveRenderMode { public static IComponentRenderMode GetInteractiveRenderMode(string runtime, bool prerender) { diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index b217749b2..281188997 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -9,7 +9,7 @@ else {
Render Mode: @ModuleState.RenderMode

- + } @code { diff --git a/Oqtane.Client/UI/PaneLayout.razor b/Oqtane.Client/UI/PaneLayout.razor deleted file mode 100644 index d91733fe1..000000000 --- a/Oqtane.Client/UI/PaneLayout.razor +++ /dev/null @@ -1,5 +0,0 @@ -@namespace Oqtane.UI - -@code { - // panelayouts are deprecated - this component is included for backward compatibility -} \ No newline at end of file diff --git a/Oqtane.Client/_Imports.razor b/Oqtane.Client/_Imports.razor index 45403934d..73af8f3a3 100644 --- a/Oqtane.Client/_Imports.razor +++ b/Oqtane.Client/_Imports.razor @@ -5,10 +5,13 @@ @using System.Net.Http.Json @using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.Extensions.Localization @using Microsoft.JSInterop +@using static Microsoft.AspNetCore.Components.Web.RenderMode @using Oqtane.Client @using Oqtane.Models diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 8e6ca4c04..3d5ab3e5c 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -53,7 +53,7 @@ } else { - + } @((MarkupString)_headResources) @@ -66,7 +66,7 @@ } else { - + } From df4d4d36bc3faeb147985aa44102c7ae925bc9ce Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 15:46:44 -0500 Subject: [PATCH 055/280] create component using RenderTreeBuilder --- Oqtane.Client/UI/InteractiveRenderMode.cs | 8 ++++---- Oqtane.Client/UI/RenderModeBoundary.razor | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Oqtane.Client/UI/InteractiveRenderMode.cs b/Oqtane.Client/UI/InteractiveRenderMode.cs index a840fe681..1094aafbc 100644 --- a/Oqtane.Client/UI/InteractiveRenderMode.cs +++ b/Oqtane.Client/UI/InteractiveRenderMode.cs @@ -11,13 +11,13 @@ public static IComponentRenderMode GetInteractiveRenderMode(string runtime, bool switch (runtime) { case Runtimes.Server: - return new InteractiveServerRenderMode(prerender); + return new InteractiveServerRenderMode(prerender: prerender); case Runtimes.WebAssembly: - return new InteractiveWebAssemblyRenderMode(prerender); + return new InteractiveWebAssemblyRenderMode(prerender: prerender); case Runtimes.Auto: - return new InteractiveAutoRenderMode(prerender); + return new InteractiveAutoRenderMode(prerender: prerender); } - return new InteractiveServerRenderMode(prerender); // default to interactiver server + return new InteractiveServerRenderMode(prerender: prerender); // default to interactiver server } } } diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index 73127f544..b82f9da88 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -14,7 +14,7 @@ { } - + @DynamicComponent @if (_progressIndicator) {
@@ -37,7 +37,7 @@ else @code { private Type ModuleType { get; set; } - private IDictionary ModuleParameters { get; set; } + RenderFragment DynamicComponent { get; set; } private string _messageContent; private MessageType _messageType; @@ -77,7 +77,12 @@ else ComponentSiteState.RemoteIPAddress = SiteState.RemoteIPAddress; ComponentSiteState.IsPrerendering = SiteState.IsPrerendering; - ModuleParameters = new Dictionary { { "RenderModeBoundary", this } }; + DynamicComponent = builder => + { + builder.OpenComponent(0, ModuleType); + builder.AddAttribute(1, "RenderModeBoundary", this); + builder.CloseComponent(); + }; } else { From fce72cad55fa68761921adcfc0cda25cdead0dfc Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 16:24:30 -0500 Subject: [PATCH 056/280] Interactivity needs to be selectable regardless of the default render mode --- Oqtane.Client/Modules/Admin/Site/Index.razor | 20 +++++++++--------- Oqtane.Client/Modules/Admin/Sites/Add.razor | 21 ++++++++----------- .../Resources/Modules/Admin/Site/Index.resx | 2 +- .../Resources/Modules/Admin/Sites/Add.resx | 2 +- Oqtane.Shared/Models/Site.cs | 2 +- 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index f879f0280..801e7d16b 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -320,18 +320,18 @@
+
+ +
+ +
+
@if (_rendermode == RenderModes.Interactive) { -
- -
- -
-
diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index e9ee4a1c7..0ebd97872 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -80,19 +80,16 @@ else
- @if (_rendermode == RenderModes.Interactive) - { -
- -
- -
+
+ +
+
- } +
diff --git a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx index 1e4609a7f..6761e06df 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx @@ -424,7 +424,7 @@ Hybrid Enabled? - The interactive render mode for the site + The interactive render mode for modules Interactivity: diff --git a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx index 64f8fb7cf..27eac08a9 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx @@ -247,7 +247,7 @@ Enter Connection String - The interactive render mode for the site + The interactive render mode for modules Interactivity: diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index aa2f29001..f5d4cb013 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -74,7 +74,7 @@ public class Site : ModelBase, IDeletable public string RenderMode { get; set; } /// - /// The interactive render mode for the site ie. Server,WebAssembly,Auto (only applies to Interactive rendermode) + /// The interactive render mode for modules ie. Server,WebAssembly,Auto /// public string Runtime { get; set; } From da02bea945dace5c0963441fbcc1abb274e5abd7 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 9 Feb 2024 16:35:27 -0500 Subject: [PATCH 057/280] change RESX values for Runtime --- Oqtane.Client/Resources/SharedResources.resx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/Resources/SharedResources.resx b/Oqtane.Client/Resources/SharedResources.resx index cc721f5bf..91660d33e 100644 --- a/Oqtane.Client/Resources/SharedResources.resx +++ b/Oqtane.Client/Resources/SharedResources.resx @@ -313,10 +313,10 @@ Not Specified - Server Rendering + Server - WebAssembly Rendering + WebAssembly Static Server Rendering @@ -442,13 +442,13 @@ Effective Date cannot be after Expiry Date. - Auto Rendering + Auto Mode Headless API (No Rendering) - Global Interactivity + Global Interactive Rendering Static Server Rendering From 62b3ca2fb985f63e40444d4e2d4cb395504ef927 Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 9 Feb 2024 14:19:25 -0800 Subject: [PATCH 058/280] Updates Referenced Maui Packages To Latest --- Oqtane.Maui/Oqtane.Maui.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index 03c6e1f0b..3f1624de0 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -71,8 +71,8 @@ - - + + From 403325d9ddccfcafe6200777be29a0ada5e58414 Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 9 Feb 2024 15:18:09 -0800 Subject: [PATCH 059/280] Updates Maui Project Package References includes which will otherwise be requested as an update from 8.0.3 in package manager. --- Oqtane.Maui/Oqtane.Maui.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index 3f1624de0..681fac363 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -72,6 +72,7 @@ + From caa9cc213dc3978da1bb40eb4bfd90a529e30b3b Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sat, 10 Feb 2024 11:25:54 -0500 Subject: [PATCH 060/280] fix #3760 include form button wrapper CSS class for inline-block --- Oqtane.Client/Themes/Controls/Theme/Login.razor | 2 +- Oqtane.Server/wwwroot/css/app.css | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/Login.razor b/Oqtane.Client/Themes/Controls/Theme/Login.razor index b5908ef99..d8e6a28b5 100644 --- a/Oqtane.Client/Themes/Controls/Theme/Login.razor +++ b/Oqtane.Client/Themes/Controls/Theme/Login.razor @@ -15,7 +15,7 @@ } else { -
+ diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css index c1d0b44b6..2be7b9c74 100644 --- a/Oqtane.Server/wwwroot/css/app.css +++ b/Oqtane.Server/wwwroot/css/app.css @@ -228,3 +228,7 @@ app { .app-fas { margin-left: 5px; } + +.app-form-button { + display: inline-block; +} From 856afcf3bf8d5eb43c58cf0487fae418c23c8ffd Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sat, 10 Feb 2024 11:46:07 -0500 Subject: [PATCH 061/280] updates to make identical to POC - still not working --- Oqtane.Client/UI/ModuleInstance.razor | 2 +- Oqtane.Server/Components/_Imports.razor | 29 +++++++++++++++++++++++++ Oqtane.Server/Startup.cs | 15 ++++++++----- 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 Oqtane.Server/Components/_Imports.razor diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 281188997..dca42083e 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -9,7 +9,7 @@ else {
Render Mode: @ModuleState.RenderMode

- + } @code { diff --git a/Oqtane.Server/Components/_Imports.razor b/Oqtane.Server/Components/_Imports.razor new file mode 100644 index 000000000..73af8f3a3 --- /dev/null +++ b/Oqtane.Server/Components/_Imports.razor @@ -0,0 +1,29 @@ +@using System +@using System.Linq +@using System.Collections.Generic +@using System.Net.Http +@using System.Net.Http.Json + +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.Extensions.Localization +@using Microsoft.JSInterop +@using static Microsoft.AspNetCore.Components.Web.RenderMode + +@using Oqtane.Client +@using Oqtane.Models +@using Oqtane.Modules +@using Oqtane.Modules.Controls +@using Oqtane.Providers +@using Oqtane.Security +@using Oqtane.Services +@using Oqtane.Shared +@using Oqtane.Themes +@using Oqtane.Themes.Controls +@using Oqtane.UI +@using Oqtane.Enums +@using Oqtane.Installer +@using Oqtane.Interfaces diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index d162e62cb..87f87a18a 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -151,7 +151,7 @@ public void ConfigureServices(IServiceCollection services) { if (_env.IsDevelopment()) { - options.DetailedErrors = false; + options.DetailedErrors = true; } }).AddHubOptions(options => { @@ -178,13 +178,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan if (env.IsDevelopment()) { - app.UseDeveloperExceptionPage(); app.UseWebAssemblyDebugging(); app.UseForwardedHeaders(); } else { app.UseForwardedHeaders(); + app.UseExceptionHandler("/Error", createScopeForErrors: true); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } @@ -210,18 +210,23 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncMan app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/" + Constants.Version + "/swagger.json", Constants.PackageId + " " + Constants.Version); }); } + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapRazorPages(); + }); + app.UseEndpoints(endpoints => { endpoints.MapRazorComponents() .AddInteractiveServerRenderMode() - .AddInteractiveWebAssemblyRenderMode(); + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(SiteRouter).Assembly); }); // simulate the fallback routing approach of traditional Blazor - allowing the custom SiteRouter to handle all routing concerns app.UseEndpoints(endpoints => { - endpoints.MapControllers(); - endpoints.MapRazorPages(); endpoints.MapFallback(); }); From 19adfd5116a23c3ccff70c8c12ecc3ffe48736c8 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 10 Feb 2024 09:40:46 -0800 Subject: [PATCH 062/280] sets responsive breakpoint to bootstrap md 767.98px --- .../wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css index eac1145d8..266adcc89 100644 --- a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css @@ -197,7 +197,7 @@ } } -@media (max-width: 767px) { +@media (max-width: 767.98px) { .app-logo { height: 80px; display: flex; From 6c3526d47eb1393f87a32f6704b19ebc35c565b4 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 10 Feb 2024 09:42:40 -0800 Subject: [PATCH 063/280] sets responsive breakpoint to 767.98 bootstrap md --- .../wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css index 9eec314f9..1b9ea4098 100644 --- a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css @@ -96,7 +96,7 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu z-index: 1000; } -@media (max-width: 767px) { +@media (max-width: 767.98px) { .app-menu { width: 100%; From 266e08817ed3dcf5d568fe9646b95258e5aa4598 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 10 Feb 2024 09:43:18 -0800 Subject: [PATCH 064/280] sets responsive breakpoint to bootstrap md 767.98px --- .../Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css index e78e77d17..2a6101ef2 100644 --- a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].Theme.[Theme]/Theme.css @@ -90,7 +90,7 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu mix-blend-mode: difference; } -@media (max-width: 767px) { +@media (max-width: 767.98px) { .app-menu { width: 100%; From 8d9a050ad634b7e4506b6cd8199138a02cbae968 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 08:51:41 -0500 Subject: [PATCH 065/280] Resolve issue where components are not being rendered interactively --- Oqtane.Client/UI/RenderModeBoundary.razor | 2 +- Oqtane.Shared/Models/Route.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index b82f9da88..a0ab867e0 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -1,5 +1,5 @@ @namespace Oqtane.UI -@inject SiteState ComponentSiteState // can refer to either a static or interactive SiteState - it depends on the render mode +@inject SiteState ComponentSiteState @inject IStringLocalizer Localizer @inject ILogService LoggingService @inherits ErrorBoundary diff --git a/Oqtane.Shared/Models/Route.cs b/Oqtane.Shared/Models/Route.cs index 7d5b8833d..56dcc3b1d 100644 --- a/Oqtane.Shared/Models/Route.cs +++ b/Oqtane.Shared/Models/Route.cs @@ -9,6 +9,11 @@ namespace Oqtane.Models /// public class Route { + /// + /// parameterless constructor to prevent deserialization exceptions + /// + public Route() { } + /// /// default constructor /// the route parameter can be obtained from NavigationManager.Uri on client or HttpContext.Request.GetEncodedUrl() on server From 9aa7672b17dc9b9a6a8a90ea062b4a7608812482 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 09:05:47 -0500 Subject: [PATCH 066/280] remove debugging info from UI --- Oqtane.Client/UI/ModuleInstance.razor | 2 -- 1 file changed, 2 deletions(-) diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index dca42083e..37075685b 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -3,12 +3,10 @@ @if (PageState.Site.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { -
Render Mode: @PageState.Site.RenderMode

} else { -
Render Mode: @ModuleState.RenderMode

} From 2b6965f8016cec8f435381a65ff73a0d906e1d76 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 09:14:05 -0500 Subject: [PATCH 067/280] allow prerender selection in all scenarios --- Oqtane.Client/Modules/Admin/Site/Index.razor | 19 ++++++++----------- .../Resources/Modules/Admin/Site/Index.resx | 2 +- .../Resources/Modules/Admin/Sites/Add.resx | 6 ------ 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 801e7d16b..dc0230cba 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -330,18 +330,15 @@
- @if (_rendermode == RenderModes.Interactive) - { -
- -
- -
+
+ +
+
- } +
diff --git a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx index 6761e06df..dca1fe8e1 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx @@ -277,7 +277,7 @@ Hosting Model - Specifies if the site supports prerendering + Specifies if interactive modules should prerender their output Prerender? diff --git a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx index 27eac08a9..0443db36c 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Sites/Add.resx @@ -222,12 +222,6 @@ Error loading Database Configuration Control - - Specifies if the site supports prerendering - - - Prerender? - The default render mode for the site From a4741e28c5dcbecfdbfd8c3df0ac5f7f90ebca95 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 12:40:11 -0500 Subject: [PATCH 068/280] include script resources during static rendering --- Oqtane.Server/Components/App.razor | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 3d5ab3e5c..63958b71d 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -167,7 +167,7 @@ var theme = themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType)); if (theme?.Resources != null) { - resources.AddRange(theme.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); + resources.AddRange(theme.Resources); } var type = Type.GetType(page.ThemeType); if (type != null) @@ -175,10 +175,14 @@ var obj = Activator.CreateInstance(type) as IThemeControl; if (obj?.Resources != null) { - resources.AddRange(obj.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); + resources.AddRange(obj.Resources); } } ManageStyleSheets(resources, alias, theme.ThemeName); + if (_renderMode == RenderModes.Static) + { + ManageScripts(resources, alias); + } // scripts if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server) @@ -534,7 +538,7 @@ if (resources != null) { int count = 0; - foreach (var resource in resources) + foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) { if (resource.Url.StartsWith("~")) { @@ -554,4 +558,17 @@ } } } + + private void ManageScripts(List resources, Alias alias) + { + if (resources != null) + { + foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Script)) + { + AddScript(resource, alias); + } + } + + } + } From f68e9c7681c3e10c268c4903a8bd2bb0a54ab7d8 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 12 Feb 2024 11:41:33 -0800 Subject: [PATCH 069/280] updates bootstrap to latest --- Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs b/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs index 49f21038c..465c06bf1 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs +++ b/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs @@ -16,9 +16,9 @@ public class ThemeInfo : ITheme ContainerSettingsType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client", Resources = new List() { - new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.0/cyborg/bootstrap.min.css", Integrity = "sha512-jwIqEv8o/kTBMJVtbNCBrDqhBojl0YSUam+EFpLjVOC86Ci6t4ZciTnIkelFNOik+dEQVymKGcQLiaJZNAfWRg==", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/cyborg/bootstrap.min.css", Integrity = "sha512-RfNxVfFNFgqk9MXO4TCKXYXn9hgc+keHCg3xFFGbnp2q7Cifda+YYzMTDHwsQtNx4DuqIMgfvZead7XOtB9CDQ==", CrossOrigin = "anonymous" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" }, - new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", Integrity = "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", CrossOrigin = "anonymous" } + new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg==", CrossOrigin = "anonymous" } } }; } From d723bbe3b7d2d0eb80c839acb20d54f45bd44fd5 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 12 Feb 2024 11:44:27 -0800 Subject: [PATCH 070/280] Updates to bootstrap 5.3.2 --- .../wwwroot/Themes/Templates/External/Client/ThemeInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs index cac21823f..5d7a086f1 100644 --- a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs @@ -17,9 +17,9 @@ public class ThemeInfo : ITheme Resources = new List() { // obtained from https://cdnjs.com/libraries - new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css", Integrity = "sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css", Integrity = "sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==", CrossOrigin = "anonymous" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" }, - new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", Integrity = "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", CrossOrigin = "anonymous" } + new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-X/YkDZyjTf4wyc2Vy16YGCPHwAY8rZJY+POgokZjQB2mhIRFJCckEGc6YyX9eNsPfn0PzThEuNs+uaomE5CO6A==", CrossOrigin = "anonymous" } } }; From d48c257b19b19dbee58a4c359571209e1b56a988 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 12 Feb 2024 11:53:42 -0800 Subject: [PATCH 071/280] Update Bootstrap 5.3.2 Integrity --- .../wwwroot/Themes/Templates/External/Client/ThemeInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs index 5d7a086f1..f56ef74c1 100644 --- a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs @@ -17,7 +17,7 @@ public class ThemeInfo : ITheme Resources = new List() { // obtained from https://cdnjs.com/libraries - new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css", Integrity = "sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css", Integrity = "sha512-b2QcS5SsA8tZodcDtGRELiGv5SaKSk1vDHDaQRda0htPYWZ6046lr3kJ5bAAQdpV2mmA/4v0wQF9MyU6/pDIAg==", CrossOrigin = "anonymous" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" }, new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-X/YkDZyjTf4wyc2Vy16YGCPHwAY8rZJY+POgokZjQB2mhIRFJCckEGc6YyX9eNsPfn0PzThEuNs+uaomE5CO6A==", CrossOrigin = "anonymous" } } From 6168621a362c993962d401152a20f5f88e8c2299 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 12 Feb 2024 11:58:08 -0800 Subject: [PATCH 072/280] Update ThemeInfo.cs --- Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs b/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs index 465c06bf1..92bd9afe2 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs +++ b/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs @@ -18,7 +18,7 @@ public class ThemeInfo : ITheme { new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/cyborg/bootstrap.min.css", Integrity = "sha512-RfNxVfFNFgqk9MXO4TCKXYXn9hgc+keHCg3xFFGbnp2q7Cifda+YYzMTDHwsQtNx4DuqIMgfvZead7XOtB9CDQ==", CrossOrigin = "anonymous" }, new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" }, - new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg==", CrossOrigin = "anonymous" } + new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-X/YkDZyjTf4wyc2Vy16YGCPHwAY8rZJY+POgokZjQB2mhIRFJCckEGc6YyX9eNsPfn0PzThEuNs+uaomE5CO6A==", CrossOrigin = "anonymous" } } }; } From ead9f0b3c6ef4e47221d4966defa4fd1ae4cefeb Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 15:43:24 -0500 Subject: [PATCH 073/280] enable Admin Dashboard in static rendering --- .../Themes/Controls/Theme/ControlPanel.razor | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 0daff8a8d..4cf8d4534 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -38,7 +38,7 @@ @if (_canViewAdminDashboard || UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) { - @@ -53,7 +53,10 @@ {
- + + + +

@@ -238,6 +241,8 @@
} + + @code{ [Parameter] public string ButtonClass { get; set; } = "btn-outline-secondary"; @@ -257,6 +262,9 @@ [Parameter] public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right + [SupplyParameterFromForm(FormName = "ControlPanelForm")] + public string action { get; set; } + private bool _canViewAdminDashboard = false; private bool _showEditMode = false; private bool _deleteConfirmation = false; @@ -313,6 +321,11 @@ } } + private void AdminDashboard() + { + Navigate("Admin"); + } + protected override async Task OnParametersSetAsync() { _canViewAdminDashboard = CanViewAdminDashboard(); From 8b803faf7297ab8c5af85ab9abc75072f0d722dd Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 15:45:35 -0500 Subject: [PATCH 074/280] remove unused Action form field --- Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor | 3 --- 1 file changed, 3 deletions(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 4cf8d4534..8aabd05ba 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -262,9 +262,6 @@ [Parameter] public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right - [SupplyParameterFromForm(FormName = "ControlPanelForm")] - public string action { get; set; } - private bool _canViewAdminDashboard = false; private bool _showEditMode = false; private bool _deleteConfirmation = false; From 6bcf47fc4baeb409c415c3847e53244ea8ffd1e9 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 12 Feb 2024 16:00:01 -0500 Subject: [PATCH 075/280] enable Edit Mode in static rendering --- .../Themes/Controls/Theme/ControlPanel.razor | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 8aabd05ba..beec2fb0a 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -22,18 +22,21 @@ @if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered))) { - if (PageState.EditMode) - { - - } - else - { - - } +
+ + @if (PageState.EditMode) + { + + } + else + { + + } +
} @if (_canViewAdminDashboard || UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) @@ -53,7 +56,7 @@ {
-
+
@@ -323,6 +326,11 @@ Navigate("Admin"); } + private async Task EditMode() + { + await ToggleEditMode(PageState.EditMode); + } + protected override async Task OnParametersSetAsync() { _canViewAdminDashboard = CanViewAdminDashboard(); From e0bec82a1c9e7bf90304ab168348a2c2673ee655 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 13 Feb 2024 11:58:00 -0500 Subject: [PATCH 076/280] enable close of modal admin container on static rendering --- Oqtane.Client/Themes/AdminContainer.razor | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/AdminContainer.razor b/Oqtane.Client/Themes/AdminContainer.razor index 7dfbbee1a..8fbbc976d 100644 --- a/Oqtane.Client/Themes/AdminContainer.razor +++ b/Oqtane.Client/Themes/AdminContainer.razor @@ -8,7 +8,10 @@ @@ -303,11 +320,6 @@ private string settingCategory = "CP-category"; private string settingPane = "CP-pane"; - private void AdminDashboard() - { - Navigate("Admin"); - } - private async Task EditMode() { await ToggleEditMode(PageState.EditMode); From 3db744269e1d5fd0bfa29d949a6d90ea695fb45e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 14 Feb 2024 11:05:49 -0500 Subject: [PATCH 079/280] force control panel to interactive render mode --- ...anel.resx => ControlPanelInteractive.resx} | 0 .../Themes/Controls/Theme/ControlPanel.razor | 615 +----------------- .../Theme/ControlPanelInteractive.razor | 596 +++++++++++++++++ Oqtane.Client/UI/RenderModeBoundary.razor | 6 +- Oqtane.Shared/Shared/SiteState.cs | 12 + 5 files changed, 627 insertions(+), 602 deletions(-) rename Oqtane.Client/Resources/Themes/Controls/{ControlPanel.resx => ControlPanelInteractive.resx} (100%) create mode 100644 Oqtane.Client/Themes/Controls/Theme/ControlPanelInteractive.razor diff --git a/Oqtane.Client/Resources/Themes/Controls/ControlPanel.resx b/Oqtane.Client/Resources/Themes/Controls/ControlPanelInteractive.resx similarity index 100% rename from Oqtane.Client/Resources/Themes/Controls/ControlPanel.resx rename to Oqtane.Client/Resources/Themes/Controls/ControlPanelInteractive.resx diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 6789eb73a..e45105524 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -1,19 +1,7 @@ -@using System.Net @namespace Oqtane.Themes.Controls @inherits ThemeControlBase @inject NavigationManager NavigationManager -@inject IUserService UserService -@inject IModuleDefinitionService ModuleDefinitionService -@inject IThemeService ThemeService -@inject IModuleService ModuleService @inject IPageService PageService -@inject IPageModuleService PageModuleService -@inject ILogService logger -@inject ISettingService SettingService -@inject IJSRuntime jsRuntime -@inject IServiceProvider ServiceProvider -@inject IStringLocalizer Localizer -@inject IStringLocalizer SharedLocalizer @if (ShowLanguageSwitcher) { @@ -22,7 +10,7 @@ @if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered))) { -
+ @if (PageState.EditMode) { @@ -41,230 +29,17 @@ @if (_canViewAdminDashboard || UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) { - - -
-
-
@Localizer["ControlPanel"]
- -
-
-
- @if (_canViewAdminDashboard) - { -
-
- - - - -
-
-
- } - @if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) - { -
-
- -
-
-
-
- @if (PageState.Page.UserId == null) - { -
- - -
- } -
- - -
-
- - -
-
-
-
-
- @if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone)) - { -
- - -
- } - else - { -
- - -
- } -
-
-
- - @if (_deleteConfirmation) - { -
- -
- } - -
- -
-
- - - @if (_moduleType == "new") - { - @if (_moduleDefinitions != null) - { - - - } - } - else - { - - - } -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- -
- @((MarkupString)_message) -
- } -
-
-
- - -
-
-
-
-
-
+ @if (PageState.Site.RenderMode == RenderModes.Interactive) + { + + } + else + { + + } } -@code{ +@code { [Parameter] public string ButtonClass { get; set; } = "btn-outline-secondary"; @@ -285,70 +60,15 @@ private bool _canViewAdminDashboard = false; private bool _showEditMode = false; - private bool _deleteConfirmation = false; - private List _categories = new List(); - private List _allModuleDefinitions; - private List _moduleDefinitions; - private List _pages = new List(); - private List _modules = new List(); - private List _containers = new List(); - - [SupplyParameterFromForm] public string ModuleType { get => ""; set => _moduleType = value; } - [SupplyParameterFromForm] public string Category { get => ""; set => _category = value; } - [SupplyParameterFromForm] public string ModuleDefinitionName { get => ""; set => _moduleDefinitionName = value; } - [SupplyParameterFromForm] public string PageId { get => ""; set => _pageId = value; } - [SupplyParameterFromForm] public string ModuleId { get => ""; set => _moduleId = value; } - [SupplyParameterFromForm] public string Title { get => ""; set => _title = value; } - [SupplyParameterFromForm] public string Pane { get => ""; set => _pane = value; } - [SupplyParameterFromForm] public int Location { get => -1; set => _location = value; } - [SupplyParameterFromForm] public string Container { get => ""; set => _container = value; } - [SupplyParameterFromForm] public string Visibility { get => ""; set => _visibility = value; } - - protected string _moduleType = "new"; - private string _category = "Common"; - protected string _moduleDefinitionName = "-"; - protected string _pageId = "-"; - protected string _moduleId = "-"; - protected string _title = ""; - private string _pane = ""; - protected int _location = int.MaxValue; - protected string _container = ""; - protected string _visibility = "view"; - - protected string _message { get; private set; } = ""; - private string settingCategory = "CP-category"; - private string settingPane = "CP-pane"; - - private async Task EditMode() - { - await ToggleEditMode(PageState.EditMode); - } - - protected override async Task OnParametersSetAsync() + protected override void OnParametersSet() { _canViewAdminDashboard = CanViewAdminDashboard(); + _showEditMode = false; if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) { _showEditMode = true; - LoadSettingsAsync(); - - _pages?.Clear(); - foreach (Page p in PageState.Pages) - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) - { - _pages.Add(p); - } - } - - var themes = await ThemeService.GetThemesAsync(); - _containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType); - _container = PageState.Site.DefaultContainerType; - _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); - _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList(); - _categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList(); } else { @@ -359,7 +79,7 @@ _showEditMode = true; break; } - } + } } } @@ -379,131 +99,6 @@ return false; } - private void CategoryChanged(ChangeEventArgs e) - { - _category = (string)e.Value; - _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList(); - _moduleDefinitionName = "-"; - _message = ""; - } - - private void ModuleDefinitionChanged(ChangeEventArgs e) - { - _moduleDefinitionName = (string)e.Value; - if (_moduleDefinitionName != "-") - { - var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == _moduleDefinitionName); - _message = "
" + moduleDefinition.Description + "
"; - } - else - { - _message = ""; - } - StateHasChanged(); - } - - private void PageChanged(ChangeEventArgs e) - { - _pageId = (string)e.Value; - if (_pageId != "-") - { - _modules = PageState.Modules - .Where(module => module.PageId == int.Parse(_pageId) && - UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList)) - .ToList(); - } - _moduleId = "-"; - StateHasChanged(); - } - - private async Task AddModule() - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) - { - if ((_moduleType == "new" && _moduleDefinitionName != "-") || (_moduleType != "new" && _moduleId != "-")) - { - if (_moduleType == "new") - { - Module module = new Module(); - module.SiteId = PageState.Site.SiteId; - module.PageId = PageState.Page.PageId; - module.ModuleDefinitionName = _moduleDefinitionName; - module.AllPages = false; - - var permissions = new List(); - if (_visibility == "view") - { - // set module view permissions to page view permissions - permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View); - } - else - { - // set module view permissions to page edit permissions - permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit); - } - // set module edit permissions to page edit permissions - permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit); - module.PermissionList = permissions; - - module = await ModuleService.AddModuleAsync(module); - ModuleId = module.ModuleId.ToString(); - } - - var pageModule = new PageModule - { - PageId = PageState.Page.PageId, - ModuleId = int.Parse(_moduleId), - Title = _title - }; - if (pageModule.Title == "") - { - if (_moduleType == "new") - { - pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == _moduleDefinitionName)?.Name; - } - else - { - pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(_moduleId))?.Title; - } - } - - pageModule.Pane = _pane; - pageModule.Order = _location; - pageModule.ContainerType = _container; - - if (pageModule.ContainerType == PageState.Site.DefaultContainerType) - { - pageModule.ContainerType = ""; - } - - await PageModuleService.AddPageModuleAsync(pageModule); - await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane); - await UpdateSettingsAsync(); - - _message = $"
{Localizer["Success.Page.ModuleAdd"]}
"; - _title = ""; - NavigationManager.NavigateTo(NavigateUrl()); - } - else - { - _message = $"
{Localizer["Message.Require.ModuleSelect"]}
"; - } - } - else - { - _message = $"
{Localizer["Error.Authorize.No"]}
"; - } - } - - private List SetPermissions(List permissions, int siteId, string modulePermission, string pagePermission) - { - foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission)) - { - permissions.Add(new Permission { SiteId = siteId, EntityName = EntityNames.Module, PermissionName = modulePermission, RoleId = permission.RoleId, UserId = permission.UserId, IsAuthorized = permission.IsAuthorized }); - } - return permissions; - } - private async Task ToggleEditMode(bool EditMode) { Page page = null; @@ -528,188 +123,14 @@ PageState.QueryString.Add("edit", PageState.EditMode.ToString().ToLower()); var url = PageState.Route.AbsolutePath + Utilities.CreateQueryString(PageState.QueryString); NavigationManager.NavigateTo(url); - } - else - { - if (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)) - { - PageState.EditMode = true; - NavigationManager.NavigateTo(NavigateUrl(page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false"))); - } - } - } - - private void Navigate(string location) - { - Module module; - switch (location) - { - case "Admin": - // get admin dashboard moduleid - module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule); - if (module != null) - { - NavigationManager.NavigateTo(EditUrl("admin", module.ModuleId, "Index", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery))); - } - break; - case "Add": - case "Edit": - string url = ""; - // get page management moduleid - module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule); - - if (module != null) - { - switch (location) - { - case "Add": - url = EditUrl("admin/pages", module.ModuleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"); - break; - case "Edit": - url = EditUrl("admin/pages", module.ModuleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"); - break; - } - } - - if (url != "") - { - NavigationManager.NavigateTo(url); - } - - break; - } - } - - private async void Publish(string action) - { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) - { - var permissions = PageState.Page.PermissionList; - switch (action) - { - case "publish": - if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone)) - { - permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true)); - } - if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered)) - { - permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true)); - } - break; - case "unpublish": - if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone)) - { - permissions.RemoveAll(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone); - } - - if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered)) - { - permissions.RemoveAll(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered); - } - break; - } - PageState.Page.PermissionList = permissions; - await PageService.UpdatePageAsync(PageState.Page); - NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true)); - } - } - - private void ConfirmDelete() - { - _deleteConfirmation = !_deleteConfirmation; - StateHasChanged(); - } - - private async Task DeletePage() - { - ConfirmDelete(); - - var page = PageState.Page; - try - { - if (page.UserId == null) - { - page.IsDeleted = true; - await PageService.UpdatePageAsync(page); - await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page); - NavigationManager.NavigateTo(NavigateUrl("")); - } - else // personalized page - { - await PageService.DeletePageAsync(page.PageId); - await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page); - NavigationManager.NavigateTo(NavigateUrl()); - } - } - catch (Exception ex) - { - await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message); - } - } - - // the following code is duplicated from LoginBase - private async Task LogoutUser() - { - await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username); - - Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path); - var url = route.PathAndQuery; - - // verify if anonymous users can access page - if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList)) - { - url = PageState.Alias.Path; - } - - if (PageState.Runtime == Shared.Runtime.Hybrid) - { - // hybrid apps utilize an interactive logout - await UserService.LogoutUserAsync(PageState.User); - var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); - authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(url, true); } else { - // post to the Logout page to complete the logout process - var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = url }; - var interop = new Interop(jsRuntime); - await interop.SubmitForm(Utilities.TenantUrl(PageState.Alias, "/pages/logout/"), fields); + if (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)) + { + PageState.EditMode = true; + NavigationManager.NavigateTo(NavigateUrl(page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false"))); + } } } - - private void LoadSettingsAsync() - { - _category = SettingService.GetSetting(PageState.User.Settings, settingCategory, "Common"); - var pane = SettingService.GetSetting(PageState.User.Settings, settingPane, ""); - if (PageState.Page.Panes.Contains(pane)) - { - _pane = pane; - } - else - { - if (PageState.Page.Panes.FindIndex(item => item.Equals(PaneNames.Default, StringComparison.OrdinalIgnoreCase)) != -1) - { - _pane = PaneNames.Default; - } - else - { - _pane = PaneNames.Admin; - } - } - } - - private async Task UpdateSettingsAsync() - { - Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); - settings = SettingService.SetSetting(settings, settingCategory, _category); - settings = SettingService.SetSetting(settings, settingPane, _pane); - await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); - } - - private void ClearMessage() - { - _message = ""; - } } diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanelInteractive.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanelInteractive.razor new file mode 100644 index 000000000..77812f60a --- /dev/null +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanelInteractive.razor @@ -0,0 +1,596 @@ +@using System.Net +@namespace Oqtane.Themes.Controls +@inject NavigationManager NavigationManager +@inject SiteState ComponentSiteState +@inject IUserService UserService +@inject IModuleDefinitionService ModuleDefinitionService +@inject IThemeService ThemeService +@inject IModuleService ModuleService +@inject IPageService PageService +@inject IPageModuleService PageModuleService +@inject ILogService logger +@inject ISettingService SettingService +@inject IJSRuntime jsRuntime +@inject IServiceProvider ServiceProvider +@inject ILogService LoggingService +@inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer + + + +
+
+
@Localizer["ControlPanel"]
+ +
+
+
+ @if (_canViewAdminDashboard) + { +
+
+ +
+
+
+ } + @if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) + { +
+
+ +
+
+
+
+ @if (PageState.Page.UserId == null) + { + + } + + +
+
+
+
+ @if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone)) + { + + } + else + { + + } +
+
+
+ + @if (_deleteConfirmation) + { +
+ +
+ } + +
+
+ + + @if (_moduleType == "new") + { + @if (_moduleDefinitions != null) + { + + + } + } + else + { + + + } +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + @((MarkupString)_message) +
+ } + +
+
+ +
+
+
+
+
+ +@code { + [Parameter] + public SiteState SiteState { get; set; } + + [Parameter] + public PageState PageState { get; set; } + + [Parameter] + public string ButtonClass { get; set; } + + [Parameter] + public string ContainerClass { get; set; } + + [Parameter] + public string HeaderClass { get; set; } + + [Parameter] + public string BodyClass { get; set; } + + [Parameter] + public bool ShowLanguageSwitcher { get; set; } + + [Parameter] + public string LanguageDropdownAlignment { get; set; } + + private bool _canViewAdminDashboard = false; + private bool _deleteConfirmation = false; + private List _categories = new List(); + private List _allModuleDefinitions; + private List _moduleDefinitions; + private List _pages = new List(); + private List _modules = new List(); + private List _containers = new List(); + + private string _category = "Common"; + private string _pane = ""; + protected string _pageId { get; private set; } = "-"; + protected string _moduleId { get; private set; } = "-"; + protected string _moduleType { get; private set; } = "new"; + protected string _moduleDefinitionName { get; private set; } = "-"; + + protected string _title { get; private set; } = ""; + protected string _containerType { get; private set; } = ""; + protected int _location { get; private set; } = int.MaxValue; + protected string _visibility { get; private set; } = "view"; + protected string _message { get; private set; } = ""; + + private string settingCategory = "CP-category"; + private string settingPane = "CP-pane"; + + protected override async Task OnParametersSetAsync() + { + // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary) + ComponentSiteState.Clone(SiteState); + + _canViewAdminDashboard = CanViewAdminDashboard(); + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) + { + LoadSettingsAsync(); + + _pages?.Clear(); + foreach (Page p in PageState.Pages) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) + { + _pages.Add(p); + } + } + + var themes = await ThemeService.GetThemesAsync(); + _containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType); + _containerType = PageState.Site.DefaultContainerType; + _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); + _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList(); + _categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList(); + } + } + + private bool CanViewAdminDashboard() + { + var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin"); + if (admin != null) + { + foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId)) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList)) + { + return true; + } + } + } + return false; + } + + private void CategoryChanged(ChangeEventArgs e) + { + _category = (string)e.Value; + _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList(); + _moduleDefinitionName = "-"; + _message = ""; + } + + private void ModuleChanged(ChangeEventArgs e) + { + _moduleDefinitionName = (string)e.Value; + if (_moduleDefinitionName != "-") + { + var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == _moduleDefinitionName); + _message = "
" + moduleDefinition.Description + "
"; + } + else + { + _message = ""; + } + StateHasChanged(); + } + + private void PageChanged(ChangeEventArgs e) + { + _pageId = (string)e.Value; + if (_pageId != "-") + { + _modules = PageState.Modules + .Where(module => module.PageId == int.Parse(_pageId) && + UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList)) + .ToList(); + } + _moduleId = "-"; + StateHasChanged(); + } + + private async Task AddModule() + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) + { + if ((_moduleType == "new" && _moduleDefinitionName != "-") || (_moduleType != "new" && _moduleId != "-")) + { + if (_moduleType == "new") + { + Module module = new Module(); + module.SiteId = PageState.Site.SiteId; + module.PageId = PageState.Page.PageId; + module.ModuleDefinitionName = _moduleDefinitionName; + module.AllPages = false; + + var permissions = new List(); + if (_visibility == "view") + { + // set module view permissions to page view permissions + permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View); + } + else + { + // set module view permissions to page edit permissions + permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit); + } + // set module edit permissions to page edit permissions + permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit); + module.PermissionList = permissions; + + module = await ModuleService.AddModuleAsync(module); + _moduleId = module.ModuleId.ToString(); + } + + var pageModule = new PageModule + { + PageId = PageState.Page.PageId, + ModuleId = int.Parse(_moduleId), + Title = _title + }; + if (pageModule.Title == "") + { + if (_moduleType == "new") + { + pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == _moduleDefinitionName)?.Name; + } + else + { + pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(_moduleId))?.Title; + } + } + + pageModule.Pane = _pane; + pageModule.Order = _location; + pageModule.ContainerType = _containerType; + + if (pageModule.ContainerType == PageState.Site.DefaultContainerType) + { + pageModule.ContainerType = ""; + } + + await PageModuleService.AddPageModuleAsync(pageModule); + await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane); + await UpdateSettingsAsync(); + + _message = $"
{Localizer["Success.Page.ModuleAdd"]}
"; + _title = ""; + NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, "")); + } + else + { + _message = $"
{Localizer["Message.Require.ModuleSelect"]}
"; + } + } + else + { + _message = $"
{Localizer["Error.Authorize.No"]}
"; + } + } + + private List SetPermissions(List permissions, int siteId, string modulePermission, string pagePermission) + { + foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission)) + { + permissions.Add(new Permission { SiteId = siteId, EntityName = EntityNames.Module, PermissionName = modulePermission, RoleId = permission.RoleId, UserId = permission.UserId, IsAuthorized = permission.IsAuthorized }); + } + return permissions; + } + + private void Navigate(string location) + { + Module module; + switch (location) + { + case "Admin": + // get admin dashboard moduleid + module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule); + if (module != null) + { + NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin", module.ModuleId, "Index", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery))); + } + break; + case "Add": + case "Edit": + string url = ""; + // get page management moduleid + module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule); + if (module != null) + { + url = Utilities.EditUrl(PageState.Alias.Path, "admin/pages", module.ModuleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"); + NavigationManager.NavigateTo(url); + } + break; + } + } + + private async void Publish(string action) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) + { + var permissions = PageState.Page.PermissionList; + switch (action) + { + case "publish": + if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone)) + { + permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true)); + } + if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered)) + { + permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true)); + } + break; + case "unpublish": + if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone)) + { + permissions.RemoveAll(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone); + } + + if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered)) + { + permissions.RemoveAll(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered); + } + break; + } + PageState.Page.PermissionList = permissions; + await PageService.UpdatePageAsync(PageState.Page); + NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, "refresh")); + } + } + + private void ConfirmDelete() + { + _deleteConfirmation = !_deleteConfirmation; + StateHasChanged(); + } + + private async Task DeletePage() + { + ConfirmDelete(); + + var page = PageState.Page; + try + { + if (page.UserId == null) + { + page.IsDeleted = true; + await PageService.UpdatePageAsync(page); + await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page); + NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, "", "")); + } + else // personalized page + { + await PageService.DeletePageAsync(page.PageId); + await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page); + NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, "")); + } + } + catch (Exception ex) + { + await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message); + } + } + + // the following code is duplicated from LoginBase + private async Task LogoutUser() + { + await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username); + + Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path); + var url = route.PathAndQuery; + + // verify if anonymous users can access page + if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList)) + { + url = PageState.Alias.Path; + } + + if (PageState.Runtime == Shared.Runtime.Hybrid) + { + // hybrid apps utilize an interactive logout + await UserService.LogoutUserAsync(PageState.User); + var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); + authstateprovider.NotifyAuthenticationChanged(); + NavigationManager.NavigateTo(url, true); + } + else + { + // post to the Logout page to complete the logout process + var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = url }; + var interop = new Interop(jsRuntime); + await interop.SubmitForm(Utilities.TenantUrl(PageState.Alias, "/pages/logout/"), fields); + } + } + + private void LoadSettingsAsync() + { + _category = SettingService.GetSetting(PageState.User.Settings, settingCategory, "Common"); + var pane = SettingService.GetSetting(PageState.User.Settings, settingPane, ""); + if (PageState.Page.Panes.Contains(pane)) + { + _pane = pane; + } + else + { + if (PageState.Page.Panes.FindIndex(item => item.Equals(PaneNames.Default, StringComparison.OrdinalIgnoreCase)) != -1) + { + _pane = PaneNames.Default; + } + else + { + _pane = PaneNames.Admin; + } + } + } + + private async Task UpdateSettingsAsync() + { + Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + settings = SettingService.SetSetting(settings, settingCategory, _category); + settings = SettingService.SetSetting(settings, settingPane, _pane); + await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); + } + + private void ClearMessage() + { + _message = ""; + } +} diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index a0ab867e0..71ca8f3f7 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -71,11 +71,7 @@ else if (ModuleType != null) { // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary) - ComponentSiteState.Alias = SiteState.Alias; - ComponentSiteState.AntiForgeryToken = SiteState.AntiForgeryToken; - ComponentSiteState.AuthorizationToken = SiteState.AuthorizationToken; - ComponentSiteState.RemoteIPAddress = SiteState.RemoteIPAddress; - ComponentSiteState.IsPrerendering = SiteState.IsPrerendering; + ComponentSiteState.Clone(SiteState); DynamicComponent = builder => { diff --git a/Oqtane.Shared/Shared/SiteState.cs b/Oqtane.Shared/Shared/SiteState.cs index 5cb9d19a0..3a689e6cc 100644 --- a/Oqtane.Shared/Shared/SiteState.cs +++ b/Oqtane.Shared/Shared/SiteState.cs @@ -1,3 +1,6 @@ +using System.Net; +using System.Xml.Linq; +using System; using Oqtane.Models; namespace Oqtane.Shared @@ -26,5 +29,14 @@ public void AppendHeadContent(string content) Properties.HeadContent += content; } } + + public void Clone(SiteState siteState) + { + Alias = siteState.Alias; + AntiForgeryToken = siteState.AntiForgeryToken; + AuthorizationToken = siteState.AuthorizationToken; + RemoteIPAddress = siteState.RemoteIPAddress; + IsPrerendering = siteState.IsPrerendering; + } } } From a65959de3f6ec9b6f864252a85a2c8bc5128d599 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 14 Feb 2024 11:54:04 -0500 Subject: [PATCH 080/280] fix #3781 - ModuleBase breaking change --- Oqtane.Client/Modules/ModuleBase.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index e6582ffdb..1bb76dca6 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -10,6 +10,7 @@ using Microsoft.JSInterop; using System.Linq; using System.Dynamic; +using System.Net.Http.Headers; namespace Oqtane.Modules { @@ -489,5 +490,8 @@ public string ContentUrl(int fileid, bool asAttachment) { return Utilities.FileUrl(PageState.Alias, fileid, asAttachment); } + + // Referencing ModuleInstance methods from ModuleBase is deprecated. Use the ModuleBase methods instead + public ModuleInstance ModuleInstance { get { return new ModuleInstance(); } } } } From 872ec90654a06cda96305f90556826580e56a56a Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 14 Feb 2024 13:48:56 -0500 Subject: [PATCH 081/280] force ModuleActions to interactive render mode --- .../Controls/Container/ModuleActions.razor | 48 ++++--------------- .../Controls/Container/ModuleActionsBase.cs | 12 +++-- .../Container/ModuleActionsInteractive.razor | 42 ++++++++++++++++ 3 files changed, 59 insertions(+), 43 deletions(-) create mode 100644 Oqtane.Client/Themes/Controls/Container/ModuleActionsInteractive.razor diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor b/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor index a651f0481..d7ac8ed81 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor @@ -1,45 +1,15 @@ @namespace Oqtane.Themes.Controls -@inherits ModuleActionsBase +@inherits ContainerBase @attribute [OqtaneIgnore] @if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction) { -
- - -
+ @if (PageState.Site.RenderMode == RenderModes.Interactive) + { + + } + else + { + + } } diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs b/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs index fb61b7145..75394add0 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs @@ -7,18 +7,22 @@ using Oqtane.Security; using Oqtane.Services; using Oqtane.Shared; +using Oqtane.UI; // ReSharper disable UnassignedGetOnlyAutoProperty // ReSharper disable MemberCanBePrivate.Global namespace Oqtane.Themes.Controls { - public class ModuleActionsBase : ContainerBase + public class ModuleActionsBase : ComponentBase { [Inject] public NavigationManager NavigationManager { get; set; } [Inject] public IPageModuleService PageModuleService { get; set; } [Inject] public IModuleService ModuleService { get; set; } + [Parameter] public PageState PageState { get; set; } + [Parameter] public Module ModuleState { get; set; } + public List Actions; protected override void OnParametersSet() @@ -88,7 +92,7 @@ protected virtual List GetActions() private async Task EditUrlAsync(string url, int moduleId, string import) { await Task.Yield(); - return EditUrl(moduleId, import); + return Utilities.EditUrl(PageState.Alias.Path, PageState.Page.Path, moduleId, import, ""); } protected async Task ModuleAction(ActionViewModel action) @@ -97,7 +101,7 @@ protected async Task ModuleAction(ActionViewModel action) { PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId); - string url = NavigateUrl(true); + string url = Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, "refresh"); if (action.Action != null) { @@ -130,7 +134,7 @@ private async Task DeleteModule(string url, PageModule pagemodule) private async Task Settings(string url, PageModule pagemodule) { await Task.Yield(); - url = EditUrl(pagemodule.ModuleId, "Settings"); + url = Utilities.EditUrl(PageState.Alias.Path, PageState.Page.Path, pagemodule.ModuleId, "Settings", ""); return url; } diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActionsInteractive.razor b/Oqtane.Client/Themes/Controls/Container/ModuleActionsInteractive.razor new file mode 100644 index 000000000..c83c701b5 --- /dev/null +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActionsInteractive.razor @@ -0,0 +1,42 @@ +@namespace Oqtane.Themes.Controls +@inherits ModuleActionsBase +@attribute [OqtaneIgnore] + +
+ + +
\ No newline at end of file From 8567f9b19f8494cbec2bbd22031654ecbc696383 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 11:52:25 -0800 Subject: [PATCH 082/280] Updates package dependences to latest versions. --- Oqtane.Server/Oqtane.Server.csproj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 39a232b40..1d9774b5e 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -32,20 +32,20 @@ - - + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + From f81eaf62ff8fa00dcfe354d1e26154b1112f8694 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 11:54:20 -0800 Subject: [PATCH 083/280] Update to latest package dependecies --- Oqtane.Shared/Oqtane.Shared.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index acdb88187..a4e3c1bca 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -19,11 +19,11 @@ - - + + - + From 90a58a1f375915944637dc48f687687dbfc2db57 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 11:55:51 -0800 Subject: [PATCH 084/280] Update to latest package dependencies --- Oqtane.Client/Oqtane.Client.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 306c9a36d..19de19044 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -22,9 +22,9 @@ - - - + + + From 3665a792d8534b80ad3e5e07a899d68917f0532f Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 11:57:26 -0800 Subject: [PATCH 085/280] Update to latest package dependencies --- Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj index a1107d0b9..13e4e9d93 100644 --- a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj +++ b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj @@ -33,8 +33,8 @@ - - + + From 6a0935960bdad9ebab4f04952e4282f00d82be1e Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 11:58:21 -0800 Subject: [PATCH 086/280] Update to latest package dependencies --- Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj index 17abd6c98..16fd27936 100644 --- a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj +++ b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj @@ -33,7 +33,7 @@ - + From 206a83c9354b78b7ba994a7e702ccd8150ab16fb Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 11:59:02 -0800 Subject: [PATCH 087/280] Update to latest package dependencies --- Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj index 361d671b8..6067334ed 100644 --- a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj +++ b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj @@ -33,7 +33,7 @@ - + From d33172df114d7b2424c6495055906bf5924695dc Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 12:05:35 -0800 Subject: [PATCH 088/280] Update to latest project dependencies --- Oqtane.Maui/Oqtane.Maui.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index 681fac363..fcdfdb4cf 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -65,15 +65,15 @@ - - + + - + - - - + + + From 6db217387fad8bd7b841f458e86f7006f51f1b04 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 12:51:10 -0800 Subject: [PATCH 089/280] Update project dependecies to 8.0.2 --- .../External/Client/[Owner].Theme.[Theme].Client.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].Theme.[Theme].Client.csproj b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].Theme.[Theme].Client.csproj index 3ab970684..8fc597a24 100644 --- a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].Theme.[Theme].Client.csproj +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].Theme.[Theme].Client.csproj @@ -12,10 +12,10 @@ - - - - + + + + From 8fe25293060ef6edda930ccb7ed43a1e3ece040f Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 12:52:26 -0800 Subject: [PATCH 090/280] Update project dependecies to 8.0.2 --- .../External/Client/[Owner].Module.[Module].Client.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj index 48bbf7700..b048bda3c 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj @@ -13,10 +13,10 @@ - - - - + + + + From 8a636736b465e76d710aabdde683737083a21325 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 12:53:14 -0800 Subject: [PATCH 091/280] Update project dependecies to 8.0.2 --- .../External/Server/[Owner].Module.[Module].Server.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].Module.[Module].Server.csproj b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].Module.[Module].Server.csproj index 7411d973e..bf9b6b122 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].Module.[Module].Server.csproj +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/[Owner].Module.[Module].Server.csproj @@ -19,10 +19,10 @@ - - - - + + + + From abdd5cf19b7d011638e4e258004bed4f84c0e914 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 13:30:41 -0800 Subject: [PATCH 092/280] Updates To New Namespace For DynamicComponent Type - Fixes #3753 --- Oqtane.Maui/Head.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Maui/Head.razor b/Oqtane.Maui/Head.razor index 7cd81125c..e94898e53 100644 --- a/Oqtane.Maui/Head.razor +++ b/Oqtane.Maui/Head.razor @@ -1,6 +1,6 @@ @code { - Type ComponentType = Type.GetType("Oqtane.Head, Oqtane.Client"); + Type ComponentType = Type.GetType("Oqtane.UI.Head, Oqtane.Client"); } From 2e3ef87c428310edbf4a696ed7fd874ad08ec047 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 14 Feb 2024 14:55:21 -0800 Subject: [PATCH 093/280] adds app-form-button styles to sync with Oqtane.Server App.css --- Oqtane.Maui/wwwroot/css/app.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Oqtane.Maui/wwwroot/css/app.css b/Oqtane.Maui/wwwroot/css/app.css index c1d0b44b6..2be7b9c74 100644 --- a/Oqtane.Maui/wwwroot/css/app.css +++ b/Oqtane.Maui/wwwroot/css/app.css @@ -228,3 +228,7 @@ app { .app-fas { margin-left: 5px; } + +.app-form-button { + display: inline-block; +} From 7d1b4d916e062a7a572d4f9dfd76e23c64fb6852 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 15 Feb 2024 10:22:14 -0500 Subject: [PATCH 094/280] fix #3793 - render issues on .NET MAUI --- .../Modules/Admin/Dashboard/Index.razor | 1 + .../Controls/Container/ModuleActions.razor | 2 +- .../Themes/Controls/Theme/ControlPanel.razor | 2 +- Oqtane.Client/UI/ModuleInstance.razor | 2 +- Oqtane.Client/UI/ThemeBuilder.razor | 24 +++++++++++++++++++ Oqtane.Server/Components/App.razor | 5 ++-- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor index 69f3d9cb5..431d98cad 100644 --- a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor +++ b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor @@ -27,6 +27,7 @@ private List _pages; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View; + public override string RenderMode => RenderModes.Static; protected override void OnInitialized() { diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor b/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor index d7ac8ed81..749519a6e 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor @@ -4,7 +4,7 @@ @if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction) { - @if (PageState.Site.RenderMode == RenderModes.Interactive) + @if (PageState.RenderMode == RenderModes.Interactive) { } diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index e45105524..e84213954 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -29,7 +29,7 @@ @if (_canViewAdminDashboard || UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) { - @if (PageState.Site.RenderMode == RenderModes.Interactive) + @if (PageState.RenderMode == RenderModes.Interactive) { } diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 37075685b..1aea64b6e 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,7 +1,7 @@ @namespace Oqtane.UI @inject SiteState SiteState -@if (PageState.Site.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) +@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { } diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 262a919a2..ccb80cf28 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -53,6 +53,30 @@ { headcontent = AddHeadContent(headcontent, PageState.Page.HeadContent); } + if (PageState.RenderMode == RenderModes.Static) + { + string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); + int count = 0; + foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Level == ResourceLevel.Module)) + { + // if (resource.Url.StartsWith("~")) + // { + // resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(name) + "/").Replace("//", "/"); + // } + if (!resource.Url.Contains("://") && PageState.Alias.BaseUrl != "" && !resource.Url.StartsWith(PageState.Alias.BaseUrl)) + { + resource.Url = PageState.Alias.BaseUrl + resource.Url; + } + + if (!headcontent.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) + { + count++; + string id = "id=\"app-stylesheet-" + resource.Level.ToString().ToLower() + "-" + batch + "-" + count.ToString("00") + "\" "; + headcontent += "" + Environment.NewLine; + } + } + + } SiteState.Properties.HeadContent = headcontent; DynamicComponent = builder => diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 63958b71d..83cc43f13 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -537,6 +537,7 @@ { if (resources != null) { + string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); int count = 0; foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) { @@ -552,7 +553,7 @@ if (!_styleSheets.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) { count++; - string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + count.ToString("00") + "\" "; + string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + batch + "-" + count.ToString("00") + "\" "; _styleSheets += "" + Environment.NewLine; } } @@ -568,7 +569,5 @@ AddScript(resource, alias); } } - } - } From ed7904b67324326d00a86d645ae46ff01c1cb1c6 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 15 Feb 2024 15:48:18 -0500 Subject: [PATCH 095/280] create server-side SiteService --- .../OqtaneServiceCollectionExtensions.cs | 2 +- .../Modules/Admin/Dashboard/Index.razor | 2 +- Oqtane.Client/Program.cs | 2 +- Oqtane.Client/Services/SiteService.cs | 3 +- Oqtane.Server/Controllers/SiteController.cs | 235 +------------- .../OqtaneServiceCollectionExtensions.cs | 34 +++ .../Middleware/TenantMiddleware.cs | 6 +- Oqtane.Server/Services/SiteService.cs | 288 ++++++++++++++++++ Oqtane.Server/Startup.cs | 1 - 9 files changed, 347 insertions(+), 226 deletions(-) create mode 100644 Oqtane.Server/Services/SiteService.cs diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs index 0062e399a..7dcb25759 100644 --- a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -17,7 +17,7 @@ public static IServiceCollection AddOqtaneAuthentication(this IServiceCollection return services; } - public static IServiceCollection AddOqtaneScopedServices(this IServiceCollection services) + public static IServiceCollection AddOqtaneClientScopedServices(this IServiceCollection services) { services.AddScoped(); services.AddScoped(); diff --git a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor index 431d98cad..7f5df0526 100644 --- a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor +++ b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor @@ -27,7 +27,7 @@ private List _pages; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View; - public override string RenderMode => RenderModes.Static; + //public override string RenderMode => RenderModes.Static; protected override void OnInitialized() { diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 3a40b0552..dad17d44c 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -44,7 +44,7 @@ public static async Task Main(string[] args) builder.Services.AddOqtaneAuthentication(); // register scoped core services - builder.Services.AddOqtaneScopedServices(); + builder.Services.AddOqtaneClientScopedServices(); var serviceProvider = builder.Services.BuildServiceProvider(); diff --git a/Oqtane.Client/Services/SiteService.cs b/Oqtane.Client/Services/SiteService.cs index 1aa8a659d..6432ab9ef 100644 --- a/Oqtane.Client/Services/SiteService.cs +++ b/Oqtane.Client/Services/SiteService.cs @@ -18,8 +18,7 @@ public SiteService(HttpClient http, SiteState siteState) : base(http, siteState) public async Task> GetSitesAsync() { - List sites = await GetJsonAsync>(Apiurl); - return sites.OrderBy(item => item.Name).ToList(); + return await GetJsonAsync>(Apiurl); } public async Task GetSiteAsync(int siteId) diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 81df67bb3..471cc977b 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -3,192 +3,49 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Models; using Oqtane.Shared; -using System.Linq; using Oqtane.Enums; using Oqtane.Infrastructure; -using Oqtane.Repository; using System.Net; -using Oqtane.Security; -using System.Globalization; -using Microsoft.Extensions.Caching.Memory; -using Oqtane.Extensions; -using System; +using Oqtane.Services; +using System.Threading.Tasks; namespace Oqtane.Controllers { [Route(ControllerRoutes.ApiRoute)] public class SiteController : Controller { - private readonly ISiteRepository _sites; - private readonly IPageRepository _pages; - private readonly IThemeRepository _themes; - private readonly IModuleRepository _modules; - private readonly IPageModuleRepository _pageModules; - private readonly IModuleDefinitionRepository _moduleDefinitions; - private readonly ILanguageRepository _languages; - private readonly IUserPermissions _userPermissions; - private readonly ISettingRepository _settings; - private readonly ISyncManager _syncManager; + private readonly ISiteService _siteService; private readonly ILogManager _logger; - private readonly IMemoryCache _cache; - private readonly Alias _alias; - public SiteController(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IModuleRepository modules, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger, IMemoryCache cache) + public SiteController(ISiteService siteService, ILogManager logger) { - _sites = sites; - _pages = pages; - _themes = themes; - _modules = modules; - _pageModules = pageModules; - _moduleDefinitions = moduleDefinitions; - _languages = languages; - _userPermissions = userPermissions; - _settings = settings; - _syncManager = syncManager; + _siteService = siteService; _logger = logger; - _cache = cache; - _alias = tenantManager.GetAlias(); } // GET: api/ [HttpGet] [Authorize(Roles = RoleNames.Host)] - public IEnumerable Get() + public async Task> Get() { - return _sites.GetSites(); + return await _siteService.GetSitesAsync(); } // GET api//5 [HttpGet("{id}")] - public Site Get(int id) + public async Task Get(int id) { - if (!User.Identity.IsAuthenticated) - { - return _cache.GetOrCreate($"site:{HttpContext.GetAlias().SiteKey}", entry => - { - entry.SlidingExpiration = TimeSpan.FromMinutes(30); - return GetSite(id); - }); - } - else - { - return GetSite(id); - } - } - - private Site GetSite(int siteid) - { - var site = _sites.GetSite(siteid); - if (site != null && site.SiteId == _alias.SiteId) - { - // site settings - site.Settings = _settings.GetSettings(EntityNames.Site, site.SiteId) - .Where(item => !item.IsPrivate || User.IsInRole(RoleNames.Admin)) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); - - // populate File Extensions - site.ImageFiles = site.Settings.ContainsKey("ImageFiles") && !string.IsNullOrEmpty(site.Settings["ImageFiles"]) - ? site.Settings["ImageFiles"] : Constants.ImageFiles; - site.UploadableFiles = site.Settings.ContainsKey("UploadableFiles") && !string.IsNullOrEmpty(site.Settings["UploadableFiles"]) - ? site.Settings["UploadableFiles"] : Constants.UploadableFiles; - - // pages - List settings = _settings.GetSettings(EntityNames.Page).ToList(); - site.Pages = new List(); - foreach (Page page in _pages.GetPages(site.SiteId)) - { - if (!page.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.PermissionList))) - { - page.Settings = settings.Where(item => item.EntityId == page.PageId) - .Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.PermissionList)) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); - site.Pages.Add(page); - } - } - - site.Pages = GetPagesHierarchy(site.Pages); - - // modules - List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(site.SiteId).ToList(); - settings = _settings.GetSettings(EntityNames.Module).ToList(); - site.Modules = new List(); - foreach (PageModule pagemodule in _pageModules.GetPageModules(site.SiteId).Where(pm => !pm.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, pm.Module.PermissionList))) - { - if(Utilities.IsPageModuleVisible(pagemodule.EffectiveDate, pagemodule.ExpiryDate) || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList)) - { - Module module = new Module - { - SiteId = pagemodule.Module.SiteId, - ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName, - AllPages = pagemodule.Module.AllPages, - PermissionList = pagemodule.Module.PermissionList, - CreatedBy = pagemodule.Module.CreatedBy, - CreatedOn = pagemodule.Module.CreatedOn, - ModifiedBy = pagemodule.Module.ModifiedBy, - ModifiedOn = pagemodule.Module.ModifiedOn, - DeletedBy = pagemodule.DeletedBy, - DeletedOn = pagemodule.DeletedOn, - IsDeleted = pagemodule.IsDeleted, - - PageModuleId = pagemodule.PageModuleId, - ModuleId = pagemodule.ModuleId, - PageId = pagemodule.PageId, - Title = pagemodule.Title, - Pane = pagemodule.Pane, - Order = pagemodule.Order, - ContainerType = pagemodule.ContainerType, - EffectiveDate = pagemodule.EffectiveDate, - ExpiryDate = pagemodule.ExpiryDate, - - ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == pagemodule.Module.ModuleDefinitionName)), - - Settings = settings - .Where(item => item.EntityId == pagemodule.ModuleId) - .Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList)) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue) - }; - - site.Modules.Add(module); - } - } - - site.Modules = site.Modules.OrderBy(item => item.PageId).ThenBy(item => item.Pane).ThenBy(item => item.Order).ToList(); - - // languages - site.Languages = _languages.GetLanguages(site.SiteId).ToList(); - var defaultCulture = CultureInfo.GetCultureInfo(Constants.DefaultCulture); - site.Languages.Add(new Language { Code = defaultCulture.Name, Name = defaultCulture.DisplayName, Version = Constants.Version, IsDefault = !site.Languages.Any(l => l.IsDefault) }); - - // themes - site.Themes = _themes.FilterThemes(_themes.GetThemes().ToList()); - - return site; - } - else - { - if (site != null) - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Get Attempt {SiteId}", siteid); - HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; - } - else - { - HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; - } - return null; - } + return await _siteService.GetSiteAsync(id); } // POST api/ [HttpPost] [Authorize(Roles = RoleNames.Host)] - public Site Post([FromBody] Site site) + public async Task Post([FromBody] Site site) { if (ModelState.IsValid) { - site = _sites.AddSite(site); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Create); - _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site); + site = await _siteService.AddSiteAsync(site); } else { @@ -202,20 +59,11 @@ public Site Post([FromBody] Site site) // PUT api//5 [HttpPut("{id}")] [Authorize(Roles = RoleNames.Admin)] - public Site Put(int id, [FromBody] Site site) + public async Task Put(int id, [FromBody] Site site) { - var current = _sites.GetSite(site.SiteId, false); - if (ModelState.IsValid && site.SiteId == _alias.SiteId && site.TenantId == _alias.TenantId && site.SiteId == id && current != null) + if (ModelState.IsValid) { - site = _sites.UpdateSite(site); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); - string action = SyncEventActions.Refresh; - if (current.RenderMode != site.RenderMode || current.Runtime != site.Runtime) - { - action = SyncEventActions.Reload; - } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, action); - _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site); + site = await _siteService.UpdateSiteAsync(site); } else { @@ -229,60 +77,9 @@ public Site Put(int id, [FromBody] Site site) // DELETE api//5 [HttpDelete("{id}")] [Authorize(Roles = RoleNames.Host)] - public void Delete(int id) + public async Task Delete(int id) { - var site = _sites.GetSite(id); - if (site != null && site.SiteId == _alias.SiteId) - { - _sites.DeleteSite(id); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Delete); - _logger.Log(id, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Delete Attempt {SiteId}", id); - HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; - } - } - - private static List GetPagesHierarchy(List pages) - { - List hierarchy = new List(); - Action, Page> getPath = null; - getPath = (pageList, page) => - { - IEnumerable children; - int level; - if (page == null) - { - level = -1; - children = pages.Where(item => item.ParentId == null); - } - else - { - level = page.Level; - children = pages.Where(item => item.ParentId == page.PageId); - } - foreach (Page child in children) - { - child.Level = level + 1; - child.HasChildren = pages.Any(item => item.ParentId == child.PageId && !item.IsDeleted && item.IsNavigation); - hierarchy.Add(child); - getPath(pageList, child); - } - }; - pages = pages.OrderBy(item => item.Order).ToList(); - getPath(pages, null); - - // add any non-hierarchical items to the end of the list - foreach (Page page in pages) - { - if (hierarchy.Find(item => item.PageId == page.PageId) == null) - { - hierarchy.Add(page); - } - } - return hierarchy; + await _siteService.DeleteSiteAsync(id); } } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 4145f8a08..dc742cbfc 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -68,7 +68,41 @@ internal static IServiceCollection AddOqtaneSingletonServices(this IServiceColle internal static IServiceCollection AddOqtaneServerScopedServices(this IServiceCollection services) { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + // alternative used within infrastructure classes services.AddScoped(); + return services; } diff --git a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs index dd9e97dd5..4af3d6c23 100644 --- a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs +++ b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs @@ -23,7 +23,11 @@ public async Task Invoke(HttpContext context) var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager; string path = context.Request.Path.ToString(); - if (config.IsInstalled() && !path.StartsWith("/_")) // ignore Blazor framework requests + // note that in order to support Alias subfolders we used to ignore Blazor framework requests... + // but this does not work in static rendering as the web UI request originates from /_blazor + //if (config.IsInstalled() && !path.StartsWith("/_")) + + if (config.IsInstalled()) { // get alias (note that this also sets SiteState.Alias) var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager; diff --git a/Oqtane.Server/Services/SiteService.cs b/Oqtane.Server/Services/SiteService.cs new file mode 100644 index 000000000..eb52dbd27 --- /dev/null +++ b/Oqtane.Server/Services/SiteService.cs @@ -0,0 +1,288 @@ +using Oqtane.Models; +using System.Threading.Tasks; +using System.Linq; +using System.Collections.Generic; +using System; +using Oqtane.Documentation; +using Microsoft.Extensions.Caching.Memory; +using Oqtane.Infrastructure; +using Oqtane.Repository; +using Oqtane.Security; +using Microsoft.AspNetCore.Http; +using Oqtane.Enums; +using Oqtane.Shared; +using System.Globalization; +using System.Net; +using Oqtane.Extensions; + +namespace Oqtane.Services +{ + [PrivateApi("Don't show in the documentation, as everything should use the Interface")] + public class ServerSiteService : ISiteService + { + private readonly ISiteRepository _sites; + private readonly IPageRepository _pages; + private readonly IThemeRepository _themes; + private readonly IPageModuleRepository _pageModules; + private readonly IModuleDefinitionRepository _moduleDefinitions; + private readonly ILanguageRepository _languages; + private readonly IUserPermissions _userPermissions; + private readonly ISettingRepository _settings; + private readonly ISyncManager _syncManager; + private readonly ILogManager _logger; + private readonly IMemoryCache _cache; + private readonly IHttpContextAccessor _accessor; + private readonly Alias _alias; + + public ServerSiteService(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger, IMemoryCache cache, IHttpContextAccessor accessor) + { + _sites = sites; + _pages = pages; + _themes = themes; + _pageModules = pageModules; + _moduleDefinitions = moduleDefinitions; + _languages = languages; + _userPermissions = userPermissions; + _settings = settings; + _syncManager = syncManager; + _logger = logger; + _cache = cache; + _accessor = accessor; + _alias = tenantManager.GetAlias(); + } + + public async Task> GetSitesAsync() + { + List sites = new List(); + if (_accessor.HttpContext.User.IsInRole(RoleNames.Host)) + { + sites = _sites.GetSites().OrderBy(item => item.Name).ToList(); + } + return await Task.Run(() => sites); + } + + public async Task GetSiteAsync(int siteId) + { + Site site = null; + if (!_accessor.HttpContext.User.Identity.IsAuthenticated) + { + site = _cache.GetOrCreate($"site:{_accessor.HttpContext.GetAlias().SiteKey}", entry => + { + entry.SlidingExpiration = TimeSpan.FromMinutes(30); + return GetSite(siteId); + }); + } + else + { + site = GetSite(siteId); + } + return await Task.Run(() => site); + } + + private Site GetSite(int siteid) + { + var site = _sites.GetSite(siteid); + if (site != null && site.SiteId == _alias.SiteId) + { + // site settings + site.Settings = _settings.GetSettings(EntityNames.Site, site.SiteId) + .Where(item => !item.IsPrivate || _accessor.HttpContext.User.IsInRole(RoleNames.Admin)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + + // populate File Extensions + site.ImageFiles = site.Settings.ContainsKey("ImageFiles") && !string.IsNullOrEmpty(site.Settings["ImageFiles"]) + ? site.Settings["ImageFiles"] : Constants.ImageFiles; + site.UploadableFiles = site.Settings.ContainsKey("UploadableFiles") && !string.IsNullOrEmpty(site.Settings["UploadableFiles"]) + ? site.Settings["UploadableFiles"] : Constants.UploadableFiles; + + // pages + List settings = _settings.GetSettings(EntityNames.Page).ToList(); + site.Pages = new List(); + foreach (Page page in _pages.GetPages(site.SiteId)) + { + if (!page.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList))) + { + page.Settings = settings.Where(item => item.EntityId == page.PageId) + .Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + site.Pages.Add(page); + } + } + + site.Pages = GetPagesHierarchy(site.Pages); + + // modules + List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(site.SiteId).ToList(); + settings = _settings.GetSettings(EntityNames.Module).ToList(); + site.Modules = new List(); + foreach (PageModule pagemodule in _pageModules.GetPageModules(site.SiteId).Where(pm => !pm.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, pm.Module.PermissionList))) + { + if (Utilities.IsPageModuleVisible(pagemodule.EffectiveDate, pagemodule.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, pagemodule.Module.PermissionList)) + { + Module module = new Module + { + SiteId = pagemodule.Module.SiteId, + ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName, + AllPages = pagemodule.Module.AllPages, + PermissionList = pagemodule.Module.PermissionList, + CreatedBy = pagemodule.Module.CreatedBy, + CreatedOn = pagemodule.Module.CreatedOn, + ModifiedBy = pagemodule.Module.ModifiedBy, + ModifiedOn = pagemodule.Module.ModifiedOn, + DeletedBy = pagemodule.DeletedBy, + DeletedOn = pagemodule.DeletedOn, + IsDeleted = pagemodule.IsDeleted, + + PageModuleId = pagemodule.PageModuleId, + ModuleId = pagemodule.ModuleId, + PageId = pagemodule.PageId, + Title = pagemodule.Title, + Pane = pagemodule.Pane, + Order = pagemodule.Order, + ContainerType = pagemodule.ContainerType, + EffectiveDate = pagemodule.EffectiveDate, + ExpiryDate = pagemodule.ExpiryDate, + + ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == pagemodule.Module.ModuleDefinitionName)), + + Settings = settings + .Where(item => item.EntityId == pagemodule.ModuleId) + .Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, pagemodule.Module.PermissionList)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue) + }; + + site.Modules.Add(module); + } + } + + site.Modules = site.Modules.OrderBy(item => item.PageId).ThenBy(item => item.Pane).ThenBy(item => item.Order).ToList(); + + // languages + site.Languages = _languages.GetLanguages(site.SiteId).ToList(); + var defaultCulture = CultureInfo.GetCultureInfo(Constants.DefaultCulture); + site.Languages.Add(new Language { Code = defaultCulture.Name, Name = defaultCulture.DisplayName, Version = Constants.Version, IsDefault = !site.Languages.Any(l => l.IsDefault) }); + + // themes + site.Themes = _themes.FilterThemes(_themes.GetThemes().ToList()); + } + else + { + if (site != null) + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Get Attempt {SiteId}", siteid); + site = null; + } + } + return site; + } + + public async Task AddSiteAsync(Site site) + { + if (_accessor.HttpContext.User.IsInRole(RoleNames.Host)) + { + site = _sites.AddSite(site); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Create); + _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site); + } + else + { + site = null; + } + return await Task.Run(() => site); + } + + public async Task UpdateSiteAsync(Site site) + { + if (_accessor.HttpContext.User.IsInRole(RoleNames.Admin)) + { + var current = _sites.GetSite(site.SiteId, false); + if (site.SiteId == _alias.SiteId && site.TenantId == _alias.TenantId && current != null) + { + site = _sites.UpdateSite(site); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); + string action = SyncEventActions.Refresh; + if (current.RenderMode != site.RenderMode || current.Runtime != site.Runtime) + { + action = SyncEventActions.Reload; + } + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, action); + _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Put Attempt {Site}", site); + site = null; + } + } + else + { + site = null; + } + return await Task.Run(() => site); + } + + public async Task DeleteSiteAsync(int siteId) + { + if (_accessor.HttpContext.User.IsInRole(RoleNames.Host)) + { + var site = _sites.GetSite(siteId); + if (site != null && site.SiteId == _alias.SiteId) + { + _sites.DeleteSite(siteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Delete); + _logger.Log(siteId, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", siteId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Delete Attempt {SiteId}", siteId); + } + } + await Task.CompletedTask; + } + + private static List GetPagesHierarchy(List pages) + { + List hierarchy = new List(); + Action, Page> getPath = null; + getPath = (pageList, page) => + { + IEnumerable children; + int level; + if (page == null) + { + level = -1; + children = pages.Where(item => item.ParentId == null); + } + else + { + level = page.Level; + children = pages.Where(item => item.ParentId == page.PageId); + } + foreach (Page child in children) + { + child.Level = level + 1; + child.HasChildren = pages.Any(item => item.ParentId == child.PageId && !item.IsDeleted && item.IsNavigation); + hierarchy.Add(child); + getPath(pageList, child); + } + }; + pages = pages.OrderBy(item => item.Order).ToList(); + getPath(pages, null); + + // add any non-hierarchical items to the end of the list + foreach (Page page in pages) + { + if (hierarchy.Find(item => item.PageId == page.PageId) == null) + { + hierarchy.Add(page); + } + } + return hierarchy; + } + + [Obsolete("This method is deprecated.", false)] + public void SetAlias(Alias alias) + { + } + } +} diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 87f87a18a..991336a30 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -70,7 +70,6 @@ public void ConfigureServices(IServiceCollection services) // register scoped core services services.AddScoped() - .AddOqtaneScopedServices() .AddOqtaneServerScopedServices(); services.AddSingleton(); From ebadccbe251df9435c2174ceadec193be8bec92a Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 15 Feb 2024 16:05:27 -0500 Subject: [PATCH 096/280] remove unnecessary using --- Oqtane.Server/Services/SiteService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Oqtane.Server/Services/SiteService.cs b/Oqtane.Server/Services/SiteService.cs index eb52dbd27..8f7c659a6 100644 --- a/Oqtane.Server/Services/SiteService.cs +++ b/Oqtane.Server/Services/SiteService.cs @@ -12,7 +12,6 @@ using Oqtane.Enums; using Oqtane.Shared; using System.Globalization; -using System.Net; using Oqtane.Extensions; namespace Oqtane.Services From dcc8043cf60751e35e78579e749ca1bd4ce76a60 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 15 Feb 2024 21:17:23 -0500 Subject: [PATCH 097/280] load PageState in App component and pass to SiteRouter to optimize data loading --- Oqtane.Client/UI/PageState.cs | 1 + Oqtane.Client/UI/Routes.razor | 24 +++--- Oqtane.Client/UI/SiteRouter.razor | 14 ++-- Oqtane.Maui/Main.razor | 4 - Oqtane.Maui/MauiProgram.cs | 2 +- Oqtane.Server/Components/App.razor | 127 ++++++++++++++++++----------- 6 files changed, 100 insertions(+), 72 deletions(-) diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index 7d8a59589..71a8ccf12 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -25,6 +25,7 @@ public class PageState public string ReturnUrl { get; set; } public bool IsInternalNavigation { get; set; } public Guid RenderId { get; set; } + public bool Refresh { get; set; } public List Pages { diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index 3b0f51917..5abd97038 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -16,8 +16,8 @@ @if (string.IsNullOrEmpty(_installation.Message)) {
- - + +
} @@ -32,7 +32,7 @@ @code { [Parameter] - public string AntiForgeryToken { get; set; } + public PageState PageState { get; set; } = null; [Parameter] public string RenderMode { get; set; } @@ -41,13 +41,10 @@ public string Runtime { get; set; } [Parameter] - public int VisitorId { get; set; } + public string AntiForgeryToken { get; set; } = ""; [Parameter] - public string RemoteIPAddress { get; set; } - - [Parameter] - public string AuthorizationToken { get; set; } + public string AuthorizationToken { get; set; } = ""; [CascadingParameter] HttpContext HttpContext { get; set; } @@ -56,18 +53,23 @@ private string _display = ""; private Installation _installation = new Installation { Success = false, Message = "" }; - private PageState PageState { get; set; } + private PageState _pageState { get; set; } protected override async Task OnParametersSetAsync() { + if (PageState != null) + { + _pageState = PageState; + } + if (RenderMode == RenderModes.Interactive) { _display = "display: none;"; } - SiteState.RemoteIPAddress = RemoteIPAddress; SiteState.AntiForgeryToken = AntiForgeryToken; SiteState.AuthorizationToken = AuthorizationToken; + SiteState.RemoteIPAddress = (_pageState != null) ? _pageState.RemoteIPAddress : ""; SiteState.IsPrerendering = (HttpContext != null) ? true : false; _installation = await InstallationService.IsInstalled(); @@ -90,7 +92,7 @@ private void ChangeState(PageState pageState) { - PageState = pageState; + _pageState = pageState; StateHasChanged(); } } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 3a0081a39..752ff9961 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -35,9 +35,6 @@ [Parameter] public string Runtime { get; set; } - [Parameter] - public int VisitorId { get; set; } - [CascadingParameter] PageState PageState { get; set; } @@ -68,7 +65,7 @@ protected override async Task OnParametersSetAsync() { - if (PageState == null) + if (PageState == null || PageState.Refresh) { await Refresh(); } @@ -100,6 +97,7 @@ var editmode = false; var refresh = false; var lastsyncdate = DateTime.MinValue; + var visitorId = -1; _error = ""; Route route = new Route(_absoluteUri, SiteState.Alias.Path); @@ -148,6 +146,7 @@ { editmode = PageState.EditMode; lastsyncdate = PageState.LastSyncDate; + visitorId = PageState.VisitorId; } if (PageState?.Page.Path != route.PagePath) { @@ -159,7 +158,7 @@ } // get user - if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId) + if (PageState == null || PageState.Refresh || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId) { var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); // verify user is authenticated for current site @@ -293,11 +292,12 @@ LastSyncDate = lastsyncdate, RenderMode = RenderMode, Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime), - VisitorId = VisitorId, + VisitorId = visitorId, RemoteIPAddress = SiteState.RemoteIPAddress, ReturnUrl = returnurl, IsInternalNavigation = _isInternalNavigation, - RenderId = Guid.NewGuid() + RenderId = Guid.NewGuid(), + Refresh = false }; OnStateChange?.Invoke(_pagestate); diff --git a/Oqtane.Maui/Main.razor b/Oqtane.Maui/Main.razor index a00a2e9b5..bf24f4c20 100644 --- a/Oqtane.Maui/Main.razor +++ b/Oqtane.Maui/Main.razor @@ -19,12 +19,8 @@ else protected override void OnInitialized() { Parameters = new Dictionary(); - Parameters.Add(new KeyValuePair("AntiForgeryToken", "")); Parameters.Add(new KeyValuePair("RenderMode", RenderModes.Interactive)); Parameters.Add(new KeyValuePair("Runtime", Runtimes.Hybrid)); - Parameters.Add(new KeyValuePair("VisitorId", -1)); - Parameters.Add(new KeyValuePair("RemoteIPAddress", "")); - Parameters.Add(new KeyValuePair("AuthorizationToken", "")); if (MauiConstants.UseAppSettings) { diff --git a/Oqtane.Maui/MauiProgram.cs b/Oqtane.Maui/MauiProgram.cs index fe147872b..cd81526bf 100644 --- a/Oqtane.Maui/MauiProgram.cs +++ b/Oqtane.Maui/MauiProgram.cs @@ -47,7 +47,7 @@ public static MauiApp CreateMauiApp() builder.Services.AddOqtaneAuthentication(); // register scoped core services - builder.Services.AddOqtaneScopedServices(); + builder.Services.AddOqtaneClientScopedServices(); var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); foreach (var assembly in assemblies) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 83cc43f13..e8103ca2e 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -20,7 +20,7 @@ @inject IAntiforgery Antiforgery @inject IConfigManager ConfigManager @inject ITenantManager TenantManager -@inject ISiteRepository SiteRepository +@inject ISiteService SiteService @inject IPageRepository PageRepository @inject IThemeRepository ThemeRepository @inject ILanguageRepository LanguageRepository @@ -31,63 +31,66 @@ @inject IVisitorRepository VisitorRepository @inject IJwtManager JwtManager - - - - - - - - - - @if (!string.IsNullOrEmpty(_PWAScript)) - { - - } - @((MarkupString)_styleSheets) - - - @if (_renderMode == RenderModes.Static) - { - - } - else - { - - } - @((MarkupString)_headResources) - - - @if (string.IsNullOrEmpty(_message)) - { +@if (_pageState != null) +{ + + + + + + + + + + @if (!string.IsNullOrEmpty(_PWAScript)) + { + + } + @((MarkupString)_styleSheets) + + @if (_renderMode == RenderModes.Static) { - + } else { - + } + @((MarkupString)_headResources) + + + @if (string.IsNullOrEmpty(_message)) + { + @if (_renderMode == RenderModes.Static) + { + + } + else + { + + } - - + + - @if (!string.IsNullOrEmpty(_reconnectScript)) - { - @((MarkupString)_reconnectScript) + @if (!string.IsNullOrEmpty(_reconnectScript)) + { + @((MarkupString)_reconnectScript) + } + @if (!string.IsNullOrEmpty(_PWAScript)) + { + @((MarkupString)_PWAScript) + } + @((MarkupString)_bodyResources) } - @if (!string.IsNullOrEmpty(_PWAScript)) + else { - @((MarkupString)_PWAScript) +
@_message
} - @((MarkupString)_bodyResources) - } - else - { -
@_message
- } - - + + +} @code { private string _renderMode = RenderModes.Interactive; @@ -104,12 +107,13 @@ private string _PWAScript = ""; private string _reconnectScript = ""; private string _message = ""; + private PageState _pageState; // CascadingParameter is required to access HttpContext [CascadingParameter] HttpContext Context { get; set; } - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { _antiForgeryToken = Antiforgery.GetAndStoreTokens(Context).RequestToken; _remoteIPAddress = Context.Connection.RemoteIpAddress?.ToString() ?? ""; @@ -127,7 +131,7 @@ HandleDefaultAliasRedirect(alias, url); } - var site = SiteRepository.GetSite(alias.SiteId); + var site = await SiteService.GetSiteAsync(alias.SiteId); if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.RenderMode != RenderModes.Headless) { _renderMode = site.RenderMode; @@ -226,6 +230,31 @@ _language = culture.Split('|')[0]; _language = _language.Replace("c=", ""); } + + // create initial PageState + _pageState = new PageState + { + Alias = alias, + Site = site, + Page = page, + User = null, + Uri = new Uri(url, UriKind.Absolute), + Route = route, + QueryString = Utilities.ParseQueryString(route.Query), + UrlParameters = route.UrlParameters, + ModuleId = -1, + Action = "", + EditMode = false, + LastSyncDate = DateTime.MinValue, + RenderMode = _renderMode, + Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), _runtime), + VisitorId = _visitorId, + RemoteIPAddress = _remoteIPAddress, + ReturnUrl = "", + IsInternalNavigation = false, + RenderId = Guid.NewGuid(), + Refresh = true + }; } else { From 829e004ee50972bef81d76795ef60a6a9192d994 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 15 Feb 2024 21:26:44 -0500 Subject: [PATCH 098/280] bump version to 5.1.0 --- Oqtane.Client/Oqtane.Client.csproj | 4 ++-- Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj | 4 ++-- .../Oqtane.Database.PostgreSQL.csproj | 4 ++-- Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj | 4 ++-- Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj | 4 ++-- Oqtane.Maui/Oqtane.Maui.csproj | 6 +++--- Oqtane.Package/Oqtane.Client.nuspec | 4 ++-- Oqtane.Package/Oqtane.Framework.nuspec | 6 +++--- Oqtane.Package/Oqtane.Server.nuspec | 4 ++-- Oqtane.Package/Oqtane.Shared.nuspec | 4 ++-- Oqtane.Package/Oqtane.Updater.nuspec | 4 ++-- Oqtane.Package/install.ps1 | 2 +- Oqtane.Package/upgrade.ps1 | 2 +- Oqtane.Server/Oqtane.Server.csproj | 4 ++-- Oqtane.Shared/Oqtane.Shared.csproj | 4 ++-- Oqtane.Shared/Shared/Constants.cs | 4 ++-- Oqtane.Updater/Oqtane.Updater.csproj | 4 ++-- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 19de19044..e519e2c43 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -4,7 +4,7 @@ net8.0 Exe Debug;Release - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -12,7 +12,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj index b09daf658..c50f94cfa 100644 --- a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj +++ b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj index 13e4e9d93..3444d3729 100644 --- a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj +++ b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj index 6067334ed..04b3651cc 100644 --- a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj +++ b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj index 16fd27936..e58d51e20 100644 --- a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj +++ b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj @@ -2,7 +2,7 @@ net8.0 - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git true diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index fcdfdb4cf..cb3672a8d 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -6,7 +6,7 @@ Exe - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -14,7 +14,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git Oqtane.Maui @@ -31,7 +31,7 @@ 0E29FC31-1B83-48ED-B6E0-9F3C67B775D4 - 5.0.3 + 5.1.0 1 14.2 diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index e4c87763a..e2762ec73 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -2,7 +2,7 @@ Oqtane.Client - 5.0.3 + 5.1.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Framework.nuspec b/Oqtane.Package/Oqtane.Framework.nuspec index a96b5382a..ebd0b4eda 100644 --- a/Oqtane.Package/Oqtane.Framework.nuspec +++ b/Oqtane.Package/Oqtane.Framework.nuspec @@ -2,7 +2,7 @@ Oqtane.Framework - 5.0.3 + 5.1.0 Shaun Walker .NET Foundation Oqtane Framework @@ -11,8 +11,8 @@ .NET Foundation false MIT - https://github.com/oqtane/oqtane.framework/releases/download/v5.0.3/Oqtane.Framework.5.0.3.Upgrade.zip - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/download/v5.1.0/Oqtane.Framework.5.1.0.Upgrade.zip + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 icon.png oqtane framework diff --git a/Oqtane.Package/Oqtane.Server.nuspec b/Oqtane.Package/Oqtane.Server.nuspec index 7577ef974..6e783ae21 100644 --- a/Oqtane.Package/Oqtane.Server.nuspec +++ b/Oqtane.Package/Oqtane.Server.nuspec @@ -2,7 +2,7 @@ Oqtane.Server - 5.0.3 + 5.1.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index 800186c6d..bc41fd154 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -2,7 +2,7 @@ Oqtane.Shared - 5.0.3 + 5.1.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Updater.nuspec b/Oqtane.Package/Oqtane.Updater.nuspec index 2abc25a1c..d2958199a 100644 --- a/Oqtane.Package/Oqtane.Updater.nuspec +++ b/Oqtane.Package/Oqtane.Updater.nuspec @@ -2,7 +2,7 @@ Oqtane.Updater - 5.0.3 + 5.1.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 icon.png oqtane diff --git a/Oqtane.Package/install.ps1 b/Oqtane.Package/install.ps1 index eeafbdc38..21103c062 100644 --- a/Oqtane.Package/install.ps1 +++ b/Oqtane.Package/install.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.0.3.Install.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.0.Install.zip" -Force \ No newline at end of file diff --git a/Oqtane.Package/upgrade.ps1 b/Oqtane.Package/upgrade.ps1 index d86753f0f..762ca550f 100644 --- a/Oqtane.Package/upgrade.ps1 +++ b/Oqtane.Package/upgrade.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.0.3.Upgrade.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.0.Upgrade.zip" -Force \ No newline at end of file diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 1d9774b5e..0ea8b4d3b 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index a4e3c1bca..c17f55290 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 795e2d81b..f8db5bf9f 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -4,8 +4,8 @@ namespace Oqtane.Shared { public class Constants { - public static readonly string Version = "5.0.3"; - public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3"; + public static readonly string Version = "5.1.0"; + public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.1.0"; public const string PackageId = "Oqtane.Framework"; public const string ClientId = "Oqtane.Client"; public const string UpdaterPackageId = "Oqtane.Updater"; diff --git a/Oqtane.Updater/Oqtane.Updater.csproj b/Oqtane.Updater/Oqtane.Updater.csproj index 27e608177..231694c5d 100644 --- a/Oqtane.Updater/Oqtane.Updater.csproj +++ b/Oqtane.Updater/Oqtane.Updater.csproj @@ -3,7 +3,7 @@ net8.0 Exe - 5.0.3 + 5.1.0 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0 https://github.com/oqtane/oqtane.framework Git Oqtane From 90269212142668e07d4b85be22edc709b5db2256 Mon Sep 17 00:00:00 2001 From: mostafametwally Date: Fri, 16 Feb 2024 11:54:15 +0100 Subject: [PATCH 099/280] display verification message instead of redirecting new user before email verification --- .../Modules/Admin/Register/Index.razor | 110 +++++++++--------- 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index b7c808511..98fc932f9 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -9,60 +9,63 @@ @if (PageState.Site.AllowRegistration) { - - - ... - - - - - - -
-
-
- -
- + if (!_userCreated) + { + + + ... + + + + + + + +
+
+ +
+ +
-
-
- -
-
- - -
+
+ +
+
+ + +
+
-
-
- -
-
- - -
+
+ +
+
+ + +
+
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- - - - - +
+ + + + + + } } else { @@ -80,6 +83,7 @@ else private string _confirm = string.Empty; private string _email = string.Empty; private string _displayname = string.Empty; + private bool _userCreated = false; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous; @@ -121,14 +125,8 @@ else if (user != null) { await logger.LogInformation("User Created {Username} {Email}", _username, _email); - if (PageState.QueryString.ContainsKey("returnurl")) - { - NavigationManager.NavigateTo(WebUtility.UrlDecode(PageState.QueryString["returnurl"])); - } - else // legacy behavior - { - AddModuleMessage(Localizer["Info.User.AccountCreate"], MessageType.Info); - } + _userCreated = true; + AddModuleMessage(Localizer["Info.User.AccountCreate"], MessageType.Info); } else { From 740b89258d30c1084b3b295f9f43c1b6682fa4c6 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 16 Feb 2024 19:26:01 +0800 Subject: [PATCH 100/280] Fix #3807: parsing the data attributes. --- Oqtane.Client/UI/ThemeBuilder.razor | 9 ++++++++- Oqtane.Server/wwwroot/js/interop.js | 31 ++++++++++++++++++----------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 9432e2ac4..98cae26c9 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -145,6 +145,7 @@ string integrity = ""; string crossorigin = ""; string type = ""; + var dataAttributes = new Dictionary(); foreach (var attribute in attributes) { if (attribute.Contains("=")) @@ -167,6 +168,12 @@ case "type": type = value[1]; break; + default: + if(!string.IsNullOrWhiteSpace(value[0]) && value[0].StartsWith("data-")) + { + dataAttributes.Add(value[0], value[1]); + } + break; } } } @@ -174,7 +181,7 @@ if (!string.IsNullOrEmpty(src)) { src = (src.Contains("://")) ? src : PageState.Alias.BaseUrl + src; - scripts.Add(new { href = src, bundle = "", integrity = integrity, crossorigin = crossorigin, es6module = (type == "module"), location = location.ToString().ToLower() }); + scripts.Add(new { href = src, bundle = "", integrity = integrity, crossorigin = crossorigin, es6module = (type == "module"), location = location.ToString().ToLower(), dataAttributes = dataAttributes }); } else { diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index 8305f766c..b457ad1d0 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -206,18 +206,25 @@ Oqtane.Interop = { returnPromise: true, before: function (path, element) { for (let s = 0; s < scripts.length; s++) { - if (path === scripts[s].href && scripts[s].integrity !== '') { - element.integrity = scripts[s].integrity; - } - if (path === scripts[s].href && scripts[s].crossorigin !== '') { - element.crossOrigin = scripts[s].crossorigin; - } - if (path === scripts[s].href && scripts[s].es6module === true) { - element.type = "module"; - } - if (path === scripts[s].href && scripts[s].location === 'body') { - document.body.appendChild(element); - return false; // return false to bypass default DOM insertion mechanism + if (path === scripts[s].href) { + if (scripts[s].integrity !== '') { + element.integrity = scripts[s].integrity; + } + if (scripts[s].crossorigin !== '') { + element.crossOrigin = scripts[s].crossorigin; + } + if (scripts[s].es6module === true) { + element.type = "module"; + } + if (typeof scripts[s].dataAttributes !== "undefined" && scripts[s].dataAttributes !== null) { + for (var key in scripts[s].dataAttributes) { + element.setAttribute(key, scripts[s].dataAttributes[key]); + } + } + if (scripts[s].location === 'body') { + document.body.appendChild(element); + return false; // return false to bypass default DOM insertion mechanism + } } } } From b0487798c2ecc9b87cfb7d089f4827fb31f2a8ca Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 16 Feb 2024 11:13:31 -0500 Subject: [PATCH 101/280] fix issues with installer --- Oqtane.Server/Components/App.razor | 4 +++- .../Infrastructure/UpgradeManager.cs | 1 - Oqtane.Server/Services/SiteService.cs | 22 +++++++++++-------- Oqtane.Shared/Shared/Constants.cs | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index e8103ca2e..0e3d5ac3f 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -31,7 +31,7 @@ @inject IVisitorRepository VisitorRepository @inject IJwtManager JwtManager -@if (_pageState != null) +@if (_initialized) { @@ -93,6 +93,7 @@ } @code { + private bool _initialized = false; private string _renderMode = RenderModes.Interactive; private string _runtime = Runtimes.Server; private bool _prerender = true; @@ -266,6 +267,7 @@ _message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name"; } } + _initialized = true; } private void HandleDefaultAliasRedirect(Alias alias, string url) diff --git a/Oqtane.Server/Infrastructure/UpgradeManager.cs b/Oqtane.Server/Infrastructure/UpgradeManager.cs index a81b5ca0e..d23103a45 100644 --- a/Oqtane.Server/Infrastructure/UpgradeManager.cs +++ b/Oqtane.Server/Infrastructure/UpgradeManager.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; -using Oqtane.Extensions; using Oqtane.Models; using Oqtane.Repository; using Oqtane.Shared; diff --git a/Oqtane.Server/Services/SiteService.cs b/Oqtane.Server/Services/SiteService.cs index 8f7c659a6..c1b1a1abe 100644 --- a/Oqtane.Server/Services/SiteService.cs +++ b/Oqtane.Server/Services/SiteService.cs @@ -27,11 +27,11 @@ public class ServerSiteService : ISiteService private readonly ILanguageRepository _languages; private readonly IUserPermissions _userPermissions; private readonly ISettingRepository _settings; + private readonly ITenantManager _tenantManager; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly IMemoryCache _cache; private readonly IHttpContextAccessor _accessor; - private readonly Alias _alias; public ServerSiteService(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger, IMemoryCache cache, IHttpContextAccessor accessor) { @@ -43,11 +43,11 @@ public ServerSiteService(ISiteRepository sites, IPageRepository pages, IThemeRep _languages = languages; _userPermissions = userPermissions; _settings = settings; + _tenantManager = tenantManager; _syncManager = syncManager; _logger = logger; _cache = cache; _accessor = accessor; - _alias = tenantManager.GetAlias(); } public async Task> GetSitesAsync() @@ -80,8 +80,9 @@ public async Task GetSiteAsync(int siteId) private Site GetSite(int siteid) { + var alias = _tenantManager.GetAlias(); var site = _sites.GetSite(siteid); - if (site != null && site.SiteId == _alias.SiteId) + if (site != null && site.SiteId == alias.SiteId) { // site settings site.Settings = _settings.GetSettings(EntityNames.Site, site.SiteId) @@ -179,8 +180,9 @@ public async Task AddSiteAsync(Site site) { if (_accessor.HttpContext.User.IsInRole(RoleNames.Host)) { + var alias = _tenantManager.GetAlias(); site = _sites.AddSite(site); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Create); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Create); _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site); } else @@ -194,17 +196,18 @@ public async Task UpdateSiteAsync(Site site) { if (_accessor.HttpContext.User.IsInRole(RoleNames.Admin)) { + var alias = _tenantManager.GetAlias(); var current = _sites.GetSite(site.SiteId, false); - if (site.SiteId == _alias.SiteId && site.TenantId == _alias.TenantId && current != null) + if (site.SiteId == alias.SiteId && site.TenantId == alias.TenantId && current != null) { site = _sites.UpdateSite(site); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); string action = SyncEventActions.Refresh; if (current.RenderMode != site.RenderMode || current.Runtime != site.Runtime) { action = SyncEventActions.Reload; } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, action); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Site, site.SiteId, action); _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site); } else @@ -224,11 +227,12 @@ public async Task DeleteSiteAsync(int siteId) { if (_accessor.HttpContext.User.IsInRole(RoleNames.Host)) { + var alias = _tenantManager.GetAlias(); var site = _sites.GetSite(siteId); - if (site != null && site.SiteId == _alias.SiteId) + if (site != null && site.SiteId == alias.SiteId) { _sites.DeleteSite(siteId); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Delete); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Delete); _logger.Log(siteId, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", siteId); } else diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index f8db5bf9f..e538ef9d1 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -5,7 +5,7 @@ namespace Oqtane.Shared public class Constants { public static readonly string Version = "5.1.0"; - public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.1.0"; + public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0"; public const string PackageId = "Oqtane.Framework"; public const string ClientId = "Oqtane.Client"; public const string UpdaterPackageId = "Oqtane.Updater"; From 8d0aa65ab2216a4c60f616c06338fcfae6bd793b Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 16 Feb 2024 11:17:14 -0500 Subject: [PATCH 102/280] fix #3811 - add PreserveCompilationContext back to server project --- Oqtane.Server/Oqtane.Server.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 0ea8b4d3b..c06187fe7 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -17,6 +17,7 @@ Oqtane true $(DefineConstants);OQTANE;OQTANE3 + true none From 04da9891081b4eba23c50c652cc7deaa4d8595a8 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 16 Feb 2024 15:08:04 -0500 Subject: [PATCH 103/280] get title and headcontent working again on interactive render mode --- Oqtane.Client/UI/InteractiveRenderMode.cs | 4 ++-- Oqtane.Client/UI/ThemeBuilder.razor | 24 ----------------------- Oqtane.Server/Components/App.razor | 8 ++++++-- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/Oqtane.Client/UI/InteractiveRenderMode.cs b/Oqtane.Client/UI/InteractiveRenderMode.cs index 1094aafbc..0483b7486 100644 --- a/Oqtane.Client/UI/InteractiveRenderMode.cs +++ b/Oqtane.Client/UI/InteractiveRenderMode.cs @@ -6,7 +6,7 @@ namespace Oqtane.UI { public static class InteractiveRenderMode { - public static IComponentRenderMode GetInteractiveRenderMode(string runtime, bool prerender) + public static IComponentRenderMode? GetInteractiveRenderMode(string runtime, bool prerender) { switch (runtime) { @@ -17,7 +17,7 @@ public static IComponentRenderMode GetInteractiveRenderMode(string runtime, bool case Runtimes.Auto: return new InteractiveAutoRenderMode(prerender: prerender); } - return new InteractiveServerRenderMode(prerender: prerender); // default to interactiver server + return null; // default to inherit existing render mode } } } diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index ccb80cf28..262a919a2 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -53,30 +53,6 @@ { headcontent = AddHeadContent(headcontent, PageState.Page.HeadContent); } - if (PageState.RenderMode == RenderModes.Static) - { - string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); - int count = 0; - foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Level == ResourceLevel.Module)) - { - // if (resource.Url.StartsWith("~")) - // { - // resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(name) + "/").Replace("//", "/"); - // } - if (!resource.Url.Contains("://") && PageState.Alias.BaseUrl != "" && !resource.Url.StartsWith(PageState.Alias.BaseUrl)) - { - resource.Url = PageState.Alias.BaseUrl + resource.Url; - } - - if (!headcontent.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) - { - count++; - string id = "id=\"app-stylesheet-" + resource.Level.ToString().ToLower() + "-" + batch + "-" + count.ToString("00") + "\" "; - headcontent += "" + Environment.NewLine; - } - } - - } SiteState.Properties.HeadContent = headcontent; DynamicComponent = builder => diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 0e3d5ac3f..1b7418321 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -184,12 +184,12 @@ } } ManageStyleSheets(resources, alias, theme.ThemeName); + + // scripts if (_renderMode == RenderModes.Static) { ManageScripts(resources, alias); } - - // scripts if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server) { _reconnectScript = CreateReconnectScript(); @@ -233,6 +233,10 @@ } // create initial PageState + // page needs to be populated + // site.modules need to be populated + // user needs to be populated + _pageState = new PageState { Alias = alias, From 100fc20928581b1c1ef7c79771acdeef9af07c49 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 16 Feb 2024 15:15:02 -0500 Subject: [PATCH 104/280] ensure script resources are loaded before rendering ThemeBuilder --- Oqtane.Client/UI/SiteRouter.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 752ff9961..db59fd4f8 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -50,7 +50,7 @@ DynamicComponent = builder => { - if (PageState != null) + if (PageState != null && !PageState.Refresh) { builder.OpenComponent(0, typeof(ThemeBuilder)); builder.CloseComponent(); From 2c17551d50253d796c935555ae2bcf0e2a4fee1f Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 16 Feb 2024 15:36:23 -0500 Subject: [PATCH 105/280] remove PageRepository reference in App --- Oqtane.Server/Components/App.razor | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 1b7418321..c566722d3 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -21,7 +21,6 @@ @inject IConfigManager ConfigManager @inject ITenantManager TenantManager @inject ISiteService SiteService -@inject IPageRepository PageRepository @inject IThemeRepository ThemeRepository @inject ILanguageRepository LanguageRepository @inject IServerStateManager ServerStateManager @@ -140,12 +139,19 @@ _prerender = site.Prerender; Route route = new Route(url, alias.Path); - var page = PageRepository.GetPage(route.PagePath, site.SiteId); - if (page == null && route.PagePath == "" && site.HomePageId != null) + var page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); + if (page == null && route.PagePath == "") // naked path refers to site home page { - page = PageRepository.GetPage(site.HomePageId.Value); + if (site.HomePageId != null) + { + page = site.Pages.FirstOrDefault(item => item.PageId == site.HomePageId); + } + if (page == null) + { + // fallback to use the first page in the collection + page = site.Pages.FirstOrDefault(); + } } - if (page == null || page.IsDeleted) { HandlePageNotFound(site, page, route); @@ -233,10 +239,6 @@ } // create initial PageState - // page needs to be populated - // site.modules need to be populated - // user needs to be populated - _pageState = new PageState { Alias = alias, From b68fc6187f5df74a937bab0ea17a9ec47db7dcf3 Mon Sep 17 00:00:00 2001 From: mostafametwally Date: Fri, 16 Feb 2024 22:04:12 +0100 Subject: [PATCH 106/280] localized usermanager email messages and message formatting to include site name and link #3794 --- Oqtane.Server/Managers/UserManager.cs | 71 ++++++--- .../Resources/Managers.UserManager.resx | 150 ++++++++++++++++++ 2 files changed, 200 insertions(+), 21 deletions(-) create mode 100644 Oqtane.Server/Resources/Managers.UserManager.resx diff --git a/Oqtane.Server/Managers/UserManager.cs b/Oqtane.Server/Managers/UserManager.cs index 4d273be7f..20ebc948b 100644 --- a/Oqtane.Server/Managers/UserManager.cs +++ b/Oqtane.Server/Managers/UserManager.cs @@ -6,6 +6,7 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Models; @@ -29,8 +30,10 @@ public class UserManager : IUserManager private readonly ISettingRepository _settings; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly IStringLocalizer _localizer; + private readonly ISiteRepository _siteRepo; - public UserManager(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager identityUserManager, SignInManager identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, IFileRepository files, IProfileRepository profiles, ISettingRepository settings, ISyncManager syncManager, ILogManager logger) + public UserManager(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager identityUserManager, SignInManager identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, IFileRepository files, IProfileRepository profiles, ISettingRepository settings, ISyncManager syncManager, ILogManager logger, IStringLocalizer localizer, ISiteRepository siteRepo) { _users = users; _roles = roles; @@ -45,6 +48,8 @@ public UserManager(IUserRepository users, IRoleRepository roles, IUserRoleReposi _settings = settings; _syncManager = syncManager; _logger = logger; + _localizer = localizer; + _siteRepo = siteRepo; } public User GetUser(int userid, int siteid) @@ -148,21 +153,33 @@ public async Task AddUser(User user) if (User != null) { + string siteName = _siteRepo.GetSite(user.SiteId).Name; if (!user.EmailConfirmed) { string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); - string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; - var notification = new Notification(user.SiteId, User, "User Account Verification", body); + string subject = _localizer["VerificationEmailSubject"]; + subject = subject.Replace("[SiteName]", siteName); + string body = _localizer["VerificationEmailBody"].Value; + body = body.Replace("[UserDisplayName]", user.DisplayName); + body = body.Replace("[URL]", url); + body = body.Replace("[SiteName]", siteName); + var notification = new Notification(alias.SiteId, User, subject, body); _notifications.AddNotification(notification); } else { if (!user.SuppressNotification) { - string url = alias.Protocol + alias.Name; - string body = "Dear " + user.DisplayName + ",\n\nA User Account Has Been Successfully Created For You With The Username " + user.Username + ". Please Visit " + url + " And Use The Login Option To Sign In. If You Do Not Know Your Password, Use The Forgot Password Option On The Login Page To Reset Your Account.\n\nThank You!"; - var notification = new Notification(user.SiteId, User, "User Account Notification", body); + string url = alias.Protocol + alias.Name + "/login"; + string subject = _localizer["NoVerificationEmailSubject"]; + subject = subject.Replace("[SiteName]", siteName); + string body = _localizer["NoVerificationEmailBody"].Value; + body = body.Replace("[UserDisplayName]", user.DisplayName); + body = body.Replace("[URL]", url); + body = body.Replace("[SiteName]", siteName); + body = body.Replace("[Username]", user.Username); + var notification = new Notification(alias.SiteId, User, subject, body); _notifications.AddNotification(notification); } } @@ -307,11 +324,17 @@ public async Task LoginUser(User user, bool setCookie, bool isPersistent) user.TwoFactorCode = token; user.TwoFactorExpiry = DateTime.UtcNow.AddMinutes(10); _users.UpdateUser(user); - - string body = "Dear " + user.DisplayName + ",\n\nYou requested a secure verification code to log in to your account. Please enter the secure verification code on the site:\n\n" + token + - "\n\nPlease note that the code is only valid for 10 minutes so if you are unable to take action within that time period, you should initiate a new login on the site." + - "\n\nThank You!"; - var notification = new Notification(user.SiteId, user, "User Verification Code", body); + var alias = _tenantManager.GetAlias(); + string url = alias.Protocol + alias.Name; + string siteName = _siteRepo.GetSite(alias.SiteId).Name; + string subject = _localizer["TwoFactorEmailSubject"]; + subject = subject.Replace("[SiteName]", siteName); + string body = _localizer["TwoFactorEmailBody"].Value; + body = body.Replace("[UserDisplayName]", user.DisplayName); + body = body.Replace("[URL]", url); + body = body.Replace("[SiteName]", siteName); + body = body.Replace("[Token]", token); + var notification = new Notification(alias.SiteId, user, subject, body); _notifications.AddNotification(notification); _logger.Log(LogLevel.Information, this, LogFunction.Security, "User Verification Notification Sent For {Username}", user.Username); @@ -355,10 +378,14 @@ public async Task LoginUser(User user, bool setCookie, bool isPersistent) user = _users.GetUser(user.Username); string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser); string url = alias.Protocol + alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); - string body = "Dear " + user.DisplayName + ",\n\nYou attempted multiple times unsuccessfully to log in to your account and it is now locked out. Please wait a few minutes and then try again... or use the link below to reset your password:\n\n" + url + - "\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." + - "\n\nThank You!"; - var notification = new Notification(user.SiteId, user, "User Lockout", body); + string siteName = _siteRepo.GetSite(alias.SiteId).Name; + string subject = _localizer["UserLockoutEmailSubject"]; + subject = subject.Replace("[SiteName]", siteName); + string body = _localizer["UserLockoutEmailBody"].Value; + body = body.Replace("[UserDisplayName]", user.DisplayName); + body = body.Replace("[URL]", url); + body = body.Replace("[SiteName]", siteName); + var notification = new Notification(alias.SiteId, user, subject, body); _notifications.AddNotification(notification); _logger.Log(LogLevel.Information, this, LogFunction.Security, "User Lockout Notification Sent For {Username}", user.Username); } @@ -404,12 +431,14 @@ public async Task ForgotPassword(User user) user = _users.GetUser(user.Username); string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser); string url = alias.Protocol + alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); - string body = "Dear " + user.DisplayName + ",\n\nYou recently requested to reset your password. Please use the link below to complete the process:\n\n" + url + - "\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." + - "\n\nIf you did not request to reset your password you can safely ignore this message." + - "\n\nThank You!"; - - var notification = new Notification(_tenantManager.GetAlias().SiteId, user, "User Password Reset", body); + string siteName = _siteRepo.GetSite(alias.SiteId).Name; + string subject = _localizer["ForgotPasswordEmailSubject"]; + subject = subject.Replace("[SiteName]", siteName); + string body = _localizer["ForgotPasswordEmailBody"].Value; + body = body.Replace("[UserDisplayName]", user.DisplayName); + body = body.Replace("[URL]", url); + body = body.Replace("[SiteName]", siteName); + var notification = new Notification(_tenantManager.GetAlias().SiteId, user, subject, body); _notifications.AddNotification(notification); _logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset Notification Sent For {Username}", user.Username); } diff --git a/Oqtane.Server/Resources/Managers.UserManager.resx b/Oqtane.Server/Resources/Managers.UserManager.resx new file mode 100644 index 000000000..66eec09cd --- /dev/null +++ b/Oqtane.Server/Resources/Managers.UserManager.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Dear [UserDisplayName]<br><br>You recently requested to reset your password. Please use the link below to complete the process: <b><a href="[URL]"><br><br>Click here to Reset Password</a></b><br><br>Please note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site.<br><br>If you did not request to reset your password you can safely ignore this message.<br><br>Thank You!<br>[SiteName] team + + + Password Reset Notification Sent For [SiteName] + + + Dear [UserDisplayName],<br><br>A user account has been successfully created for you with the username <b>[Username]</b>. Please <b><a href="[URL]">click here to login</a></b>. If you do not know your password, use the forgot password option on the login page to reset your account.<br><br>Thank You!<br>[SiteName] Team + + + User Account Notification for [SiteName] + + + Dear [UserDisplayName] + ",<br><br>You requested a secure verification code to log in to your account. Please enter the secure verification code on the site:<br><br><b>[Token] </b><br><br>Please note that the code is only valid for 10 minutes so if you are unable to take action within that time period, you should initiate a new login on the [Alias].<br><br>Thank You!<br>[SiteName] Team" + + + User Verification Code for [SiteName] + + + Dear [UserDisplayName], <br><br>You attempted multiple times unsuccessfully to log in to your account and it is now locked out. Please wait a few minutes and then try again... or use the link below to reset your password:<br><br> <b><a href=[URL]>Reset Password</a></b><br><br>Please note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site <a href="[SiteURL]">[SiteName]</a>.<br><br>Thank You!<br>[SiteName] Team + + + User Lockout Notification for [SiteName] + + + Dear [UserDisplayName],<br><br>In order to verify the email address associated to your user account, please click the link below:<br><br> <b><a href="[URL]">Click Here To Verify</a></b> <br><br>If the link is not displayed please copy and paste the following link to your browser <br><br> [URL] <br><br>Thank You!<br>[SiteName] Team + + + Email Verification for [SiteName] + + \ No newline at end of file From db6c65c7e88cf190bf089532c490e418f20e1626 Mon Sep 17 00:00:00 2001 From: mostafametwally Date: Fri, 16 Feb 2024 23:17:56 +0100 Subject: [PATCH 107/280] fix account lockout to read from correct setting, consider timezone offset and enable lockout --- .../Extensions/OqtaneSiteIdentityBuilderExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneSiteIdentityBuilderExtensions.cs b/Oqtane.Server/Extensions/OqtaneSiteIdentityBuilderExtensions.cs index d732421f1..6234d2fbc 100644 --- a/Oqtane.Server/Extensions/OqtaneSiteIdentityBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneSiteIdentityBuilderExtensions.cs @@ -21,8 +21,9 @@ public static OqtaneSiteOptionsBuilder WithSiteIdentity(this OqtaneSiteOptionsBu options.Password.RequireNonAlphanumeric = bool.Parse(sitesettings.GetValue("IdentityOptions:Password:RequireNonAlphanumeric", options.Password.RequireNonAlphanumeric.ToString())); // lockout options - options.Lockout.MaxFailedAccessAttempts = int.Parse(sitesettings.GetValue("IdentityOptions:Password:MaxFailedAccessAttempts", options.Lockout.MaxFailedAccessAttempts.ToString())); - options.Lockout.DefaultLockoutTimeSpan = TimeSpan.Parse(sitesettings.GetValue("IdentityOptions:Password:DefaultLockoutTimeSpan", options.Lockout.DefaultLockoutTimeSpan.ToString())); + options.Lockout.MaxFailedAccessAttempts = int.Parse(sitesettings.GetValue("IdentityOptions:Lockout:MaxFailedAccessAttempts", options.Lockout.MaxFailedAccessAttempts.ToString())); + options.Lockout.DefaultLockoutTimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow) + TimeSpan.Parse(sitesettings.GetValue("IdentityOptions:Lockout:DefaultLockoutTimeSpan", options.Lockout.DefaultLockoutTimeSpan.ToString())); + options.Lockout.AllowedForNewUsers = options.Lockout.MaxFailedAccessAttempts > 0; }); return builder; From 5d64ea48baff2b292899ea424402cb65365a5e51 Mon Sep 17 00:00:00 2001 From: mostafametwally Date: Sat, 17 Feb 2024 12:28:55 +0100 Subject: [PATCH 108/280] added links from login to register and vice versa --- Oqtane.Client/Modules/Admin/Login/Index.razor | 9 +++++++-- Oqtane.Client/Modules/Admin/Register/Index.razor | 9 ++++++++- Oqtane.Client/Resources/Modules/Admin/Login/Index.resx | 3 +++ .../Resources/Modules/Admin/Register/Index.resx | 3 +++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index 64c1d93f6..61c9fe9a2 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -47,8 +47,13 @@

- - } + + @if (PageState.Site.AllowRegistration) + { +

+ @Localizer["Register"] + } + }
} diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index b7c808511..8526e02ef 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -60,6 +60,11 @@
+ @if (_allowsitelogin) + { +

+ @Localizer["Login"] + } @@ -80,12 +85,14 @@ else private string _confirm = string.Empty; private string _email = string.Empty; private string _displayname = string.Empty; + private bool _allowsitelogin = true; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous; protected override async Task OnInitializedAsync() { - _passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId); + _passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId); + _allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true")); } protected override void OnParametersSet() diff --git a/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx index 3467911a9..0b1a87802 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx @@ -228,4 +228,7 @@ The Review Claims Option Was Enabled In External Login Settings. Please Visit The Event Log To View The Claims Returned By The Provider. + + Register as new user? + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Register/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Register/Index.resx index 1895cbef0..77d441965 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Register/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Register/Index.resx @@ -177,4 +177,7 @@ Username: + + Already have account, Login? + \ No newline at end of file From a741b1b9ace601993f9693958d7d1a732fbc6aa4 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 17 Feb 2024 07:22:32 -0800 Subject: [PATCH 109/280] Fix Login Button Control Url While On Login Page --- Oqtane.Client/Themes/Controls/Theme/LoginBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index fc41f5659..7d7d575c8 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -52,7 +52,7 @@ protected override void OnParametersSet() else { // use existing value - loginurl = "?returnurl=" + PageState.QueryString["returnurl"]; + loginurl += "?returnurl=" + PageState.QueryString["returnurl"]; } // set logout url From 57a86cd8368f7b8a8d162495d05c4cd9a2d5e823 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 17 Feb 2024 09:11:56 -0800 Subject: [PATCH 110/280] Fix handling of returnurl parameter in UserProfile component --- Oqtane.Client/Themes/Controls/Theme/UserProfile.razor | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor index 69abd0e84..f4a2130b9 100644 --- a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor +++ b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor @@ -31,7 +31,16 @@ protected override void OnParametersSet() { - _returnurl = WebUtility.UrlEncode(PageState.Route.PathAndQuery); + if (!PageState.QueryString.ContainsKey("returnurl")) + { + // remember current url + _returnurl += WebUtility.UrlEncode(PageState.Route.PathAndQuery); + } + else + { + // use existing value + _returnurl += PageState.QueryString["returnurl"]; + } } } From 114ebac21b825ac75fbd62e999d2f0eb3e6cebc8 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 17 Feb 2024 12:12:57 -0800 Subject: [PATCH 111/280] adds reload "true" boolean to the Save NavigateTo() method --- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 3084ef84c..2fb8a06f8 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -630,11 +630,11 @@ await logger.LogInformation("Page Saved {Page}", _page); if (!string.IsNullOrEmpty(PageState.ReturnUrl)) { - NavigationManager.NavigateTo(PageState.ReturnUrl); + NavigationManager.NavigateTo(PageState.ReturnUrl, true); } else { - NavigationManager.NavigateTo(NavigateUrl()); + NavigationManager.NavigateTo(NavigateUrl(), true); } } else From 972601caf617b6eeb27cf0fa419db7d7e00b601b Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 17 Feb 2024 17:55:38 -0800 Subject: [PATCH 112/280] correct documentation spelling error --- Oqtane.Client/Services/Interfaces/IPageService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/IPageService.cs b/Oqtane.Client/Services/Interfaces/IPageService.cs index 2f5c4c6d0..d4002c3f8 100644 --- a/Oqtane.Client/Services/Interfaces/IPageService.cs +++ b/Oqtane.Client/Services/Interfaces/IPageService.cs @@ -10,7 +10,7 @@ namespace Oqtane.Services public interface IPageService { /// - /// Retuns a list of pages + /// Returns a list of pages /// /// /// From 2262d44638eceb80ac6510a1cb891668b37515ab Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 17 Feb 2024 18:17:13 -0800 Subject: [PATCH 113/280] Removes unnecessary Oqtane.UI namespace --- Oqtane.Client/Services/Interfaces/IModuleDefinitionService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/IModuleDefinitionService.cs b/Oqtane.Client/Services/Interfaces/IModuleDefinitionService.cs index fbf2fafbe..707728eb5 100644 --- a/Oqtane.Client/Services/Interfaces/IModuleDefinitionService.cs +++ b/Oqtane.Client/Services/Interfaces/IModuleDefinitionService.cs @@ -1,5 +1,4 @@ using Oqtane.Models; -using Oqtane.UI; using System.Collections.Generic; using System.Threading.Tasks; From 79ce990644730375438d4d5096ef0b7f7a3c1247 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 17 Feb 2024 18:22:01 -0800 Subject: [PATCH 114/280] cleanup unused namespaces --- Oqtane.Client/Services/ModuleDefinitionService.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Oqtane.Client/Services/ModuleDefinitionService.cs b/Oqtane.Client/Services/ModuleDefinitionService.cs index 97f705322..932bef8ff 100644 --- a/Oqtane.Client/Services/ModuleDefinitionService.cs +++ b/Oqtane.Client/Services/ModuleDefinitionService.cs @@ -3,11 +3,8 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using System; -using System.Reflection; using Oqtane.Documentation; using Oqtane.Shared; -using Oqtane.UI; namespace Oqtane.Services { From 77ce31128c0e61fcc8487a759f80485ab27281a0 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 18 Feb 2024 21:37:06 +0800 Subject: [PATCH 115/280] Fix #3833: introduce token replace class. --- .../Controllers/ModuleDefinitionController.cs | 90 ++++++---- Oqtane.Server/Controllers/ThemeController.cs | 88 ++++++---- .../OqtaneServiceCollectionExtensions.cs | 3 + .../Interfaces/ITokenReplace.cs | 27 +++ Oqtane.Server/Infrastructure/TokenReplace.cs | 158 ++++++++++++++++++ Oqtane.Shared/Interfaces/ITokenSource.cs | 13 ++ 6 files changed, 319 insertions(+), 60 deletions(-) create mode 100644 Oqtane.Server/Infrastructure/Interfaces/ITokenReplace.cs create mode 100644 Oqtane.Server/Infrastructure/TokenReplace.cs create mode 100644 Oqtane.Shared/Interfaces/ITokenSource.cs diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 4fbea7ebd..39ae9f488 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -16,6 +16,7 @@ using System.Text.Json; using System.Net; using Oqtane.Modules; +using Oqtane.Infrastructure.Interfaces; namespace Oqtane.Controllers { @@ -319,52 +320,33 @@ public List