From e6dfe6fe89d24e628e691fb327a7c4f9e5c84837 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 27 Mar 2024 08:57:52 -0400 Subject: [PATCH 01/45] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 18226e27..a38c1f57 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Latest Release -[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. +[5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) was released on Mar 27, 2024 and is a major release providing Static Server-Side Rendering support for Blazor in .NET 8. This release includes 263 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 5100. 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) @@ -63,8 +63,9 @@ Backlog (TBD) - [ ] Folder Providers - [ ] Generative AI Integration -5.1.0 (Q1 2024) -- [ ] Full Stack Blazor (Static Server-Side Rendering) +[5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) (Mar 27, 2024) +- [x] Static Server-Side (SSR) Blazor support +- [x] Auto render mode support [5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024) - [x] Stabilization improvements From 5f42918cc9feda9bbe0841d688e7af3bb27dd256 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 27 Mar 2024 10:09:39 -0400 Subject: [PATCH 02/45] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a38c1f57..ddcfaaef 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,9 @@ Backlog (TBD) - [ ] Generative AI Integration [5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) (Mar 27, 2024) -- [x] Static Server-Side (SSR) Blazor support -- [x] Auto render mode support +- [x] Migration to new unified Blazor approach in .NET 8 (ie. blazor.web.js) +- [x] Static Server-Side (SSR) rendering support +- [x] Interactive Auto render mode support [5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024) - [x] Stabilization improvements From ddc97b99fa0608ce86828cf10d699e399540724f Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 27 Mar 2024 10:37:03 -0400 Subject: [PATCH 03/45] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ddcfaaef..5e9deea5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Latest Release -[5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) was released on Mar 27, 2024 and is a major release providing Static Server-Side Rendering support for Blazor in .NET 8. This release includes 263 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 5100. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. +[5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) was released on Mar 27, 2024 and is a major release providing Static Server Rendering support for Blazor in .NET 8. This release includes 263 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 5100. 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) @@ -65,7 +65,7 @@ Backlog (TBD) [5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) (Mar 27, 2024) - [x] Migration to new unified Blazor approach in .NET 8 (ie. blazor.web.js) -- [x] Static Server-Side (SSR) rendering support +- [x] Static Server Rendering (SSR) support - [x] Interactive Auto render mode support [5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024) From 4f70f228f1a1e0690190a683192faa5ebd2f1e52 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 27 Mar 2024 10:43:55 -0400 Subject: [PATCH 04/45] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e9deea5..85b85e8f 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,8 @@ Backlog (TBD) - [ ] Generative AI Integration [5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) (Mar 27, 2024) -- [x] Migration to new unified Blazor approach in .NET 8 (ie. blazor.web.js) +- [x] Migration to the new unified Blazor approach in .NET 8 (ie. blazor.web.js) - [x] Static Server Rendering (SSR) support -- [x] Interactive Auto render mode support [5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024) - [x] Stabilization improvements From e410f82fdb967cdff7a9601da6e1bb934881c6d1 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 27 Mar 2024 15:01:47 -0400 Subject: [PATCH 05/45] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 85b85e8f..0a56d241 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,9 @@ Backlog (TBD) - [ ] Folder Providers - [ ] Generative AI Integration +5.1.1 (Apr 2024) +- [ ] Stabilization improvements + [5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) (Mar 27, 2024) - [x] Migration to the new unified Blazor approach in .NET 8 (ie. blazor.web.js) - [x] Static Server Rendering (SSR) support From a8af9da249a0bde658cac995c53778b883b06849 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 28 Mar 2024 22:18:30 +0800 Subject: [PATCH 06/45] Fix #4074: use the correct property value. --- Oqtane.Client/Modules/Controls/ActionLink.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index 45b1e784..9517e275 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -99,7 +99,7 @@ if (!string.IsNullOrEmpty(Text)) { - _text = Localize(nameof(Text), _text); + _text = Localize(nameof(Text), Text); } else { From 6b8dd9bf0302511265fe83e1f76df5656079a2f3 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 28 Mar 2024 14:23:13 -0400 Subject: [PATCH 07/45] fix #4075 - auth cookie being rejected under some scenarios - change from Strict to Lax to match latest .NET Identity configuration --- Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 635b6723..19eb4cbe 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -157,7 +157,7 @@ namespace Microsoft.Extensions.DependencyInjection services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = true; - options.Cookie.SameSite = SameSiteMode.Strict; + options.Cookie.SameSite = SameSiteMode.Lax; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.Events.OnRedirectToLogin = context => { From 9f654918aecea703e8fcf061e16e2dc44ad0f9aa Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 28 Mar 2024 16:12:02 -0400 Subject: [PATCH 08/45] fix #4073 - OIDC/OAuth2 flow with static rendering --- Oqtane.Client/UI/SiteRouter.razor | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index cb82abd6..4c6ce291 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -124,12 +124,20 @@ { if (querystring.ContainsKey("reload") && querystring["reload"] == "post") { - // post back so that the cookies are set correctly - required on any change to the principal - var interop = new Interop(JSRuntime); - var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) }; - string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/"); - await interop.SubmitForm(url, fields); - return; + if (PageState.RenderMode == RenderModes.Interactive) + { + // post back so that the cookies are set correctly - required on any change to the principal + var interop = new Interop(JSRuntime); + var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) }; + string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/"); + await interop.SubmitForm(url, fields); + return; + } + else + { + NavigationManager.NavigateTo(_absoluteUri.Replace("?reload=post", "").Replace("&reload=post", ""), true); + return; + } } else { From 93057d9449d2904b2577be57e82782a8db73ffec Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 29 Mar 2024 07:50:03 -0400 Subject: [PATCH 09/45] set active tab correctly in RichTextEditor for scenarios where rich text editor is disabled --- Oqtane.Client/Modules/Controls/RichTextEditor.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index b99032a4..e59cc893 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -159,7 +159,7 @@ _originalrichhtml = ""; // Quill wraps content in

tags which can be used as a signal to set the active tab - if (!string.IsNullOrEmpty(Content) && !Content.StartsWith("

") && AllowRawHtml) + if (!AllowRichText || (AllowRawHtml && !string.IsNullOrEmpty(Content) && !Content.StartsWith("

"))) { _activetab = "Raw"; } From 26220b2f5468ec03fe364db5453c495f1d4d0ef3 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 29 Mar 2024 10:15:24 -0400 Subject: [PATCH 10/45] remove changes to allow path to support urls - urls should be specified as redirects --- Oqtane.Client/Modules/Admin/Pages/Add.razor | 62 +++++++------------ Oqtane.Client/Modules/Admin/Pages/Edit.razor | 64 +++++++------------- 2 files changed, 45 insertions(+), 81 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index 9009ba29..edaebf1a 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -385,45 +385,34 @@ page.ParentId = Int32.Parse(_parentid); } - // path can be a link to an external url - if (!_path.Contains("://")) + if (string.IsNullOrEmpty(_path)) { - if (string.IsNullOrEmpty(_path)) - { - _path = _name; - } + _path = _name; + } - (_path, string parameters) = Utilities.ParsePath(_path); - - if (_path.Contains("/")) + if (_path.Contains("/")) + { + if (_path.EndsWith("/") && _path != "/") { - if (_path.EndsWith("/") && _path != "/") - { - _path = _path.Substring(0, _path.Length - 1); - } - _path = _path.Substring(_path.LastIndexOf("/") + 1); + _path = _path.Substring(0, _path.Length - 1); } - if (_parentid == "-1") - { - page.Path = Utilities.GetFriendlyUrl(_path); - } - else - { - Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId); - if (parent.Path == string.Empty) - { - page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); - } - else - { - page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); - } - } - page.Path += parameters; + _path = _path.Substring(_path.LastIndexOf("/") + 1); + } + if (_parentid == "-1") + { + page.Path = Utilities.GetFriendlyUrl(_path); } else { - page.Path = _path; + Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId); + if (parent.Path == string.Empty) + { + page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); + } + else + { + page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); + } } var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); @@ -497,14 +486,7 @@ } else { - if (!page.Path.Contains("://")) - { - NavigationManager.NavigateTo(page.Path); // redirect to new page created - } - else - { - NavigationManager.NavigateTo(NavigateUrl("admin/pages")); - } + NavigationManager.NavigateTo(page.Path); // redirect to new page created } } else diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 46ba727b..453f1f69 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -380,7 +380,7 @@ } else { - if (_path.Contains("/") & !_path.Contains("://")) + if (_path.Contains("/")) { _path = _path.Substring(_path.LastIndexOf("/") + 1); } @@ -529,45 +529,34 @@ _page.ParentId = Int32.Parse(_parentid); } - // path can be a link to an external url - if (!_path.Contains("://")) + if (string.IsNullOrEmpty(_path)) { - if (string.IsNullOrEmpty(_path)) - { - _path = _name; - } + _path = _name; + } - (_path, string parameters) = Utilities.ParsePath(_path); - - if (_path.Contains("/")) + if (_path.Contains("/")) + { + if (_path.EndsWith("/") && _path != "/") { - if (_path.EndsWith("/") && _path != "/") - { - _path = _path.Substring(0, _path.Length - 1); - } - _path = _path.Substring(_path.LastIndexOf("/") + 1); + _path = _path.Substring(0, _path.Length - 1); } - if (_parentid == "-1") - { - _page.Path = Utilities.GetFriendlyUrl(_path); - } - else - { - Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId); - if (parent.Path == string.Empty) - { - _page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); - } - else - { - _page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); - } - } - _page.Path += parameters; + _path = _path.Substring(_path.LastIndexOf("/") + 1); + } + if (_parentid == "-1") + { + _page.Path = Utilities.GetFriendlyUrl(_path); } else { - _page.Path = _path; + Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId); + if (parent.Path == string.Empty) + { + _page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); + } + else + { + _page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); + } } var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); @@ -658,14 +647,7 @@ } else { - if (!_page.Path.Contains("://")) - { - NavigationManager.NavigateTo(NavigateUrl(), true); // redirect to page being edited - } - else - { - NavigationManager.NavigateTo(NavigateUrl("admin/pages")); - } + NavigationManager.NavigateTo(NavigateUrl(), true); // redirect to page being edited } } else From 5b3849082fbb5bbf41cd04dec06749d25a7f2f69 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 29 Mar 2024 11:19:21 -0400 Subject: [PATCH 11/45] use Constants.RequestVerificationToken rather than magic string --- Oqtane.Client/Modules/Controls/ActionDialog.razor | 8 ++++---- Oqtane.Client/Modules/Controls/ModuleMessage.razor | 2 +- Oqtane.Client/Modules/Controls/Pager.razor | 2 +- Oqtane.Client/Themes/AdminContainer.razor | 2 +- Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor | 2 +- Oqtane.Client/Themes/Controls/Theme/Login.razor | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index f21d5a64..1125d7b0 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -54,7 +54,7 @@ else

@@ -65,12 +65,12 @@ else @if (!string.IsNullOrEmpty(Action)) {
- +
}
- +
@@ -88,7 +88,7 @@ else else {
- +
} diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index 7771a7a9..d8155b3d 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -13,7 +13,7 @@ View Details }
- +
} diff --git a/Oqtane.Client/Modules/Controls/Pager.razor b/Oqtane.Client/Modules/Controls/Pager.razor index fd593c73..a37166ec 100644 --- a/Oqtane.Client/Modules/Controls/Pager.razor +++ b/Oqtane.Client/Modules/Controls/Pager.razor @@ -73,7 +73,7 @@ @if (!string.IsNullOrEmpty(SearchProperties)) {
- +
diff --git a/Oqtane.Client/Themes/AdminContainer.razor b/Oqtane.Client/Themes/AdminContainer.razor index 6231023c..60deaa59 100644 --- a/Oqtane.Client/Themes/AdminContainer.razor +++ b/Oqtane.Client/Themes/AdminContainer.razor @@ -9,7 +9,7 @@ diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index fad09a2b..607743bf 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -12,7 +12,7 @@ @if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered))) {
- + @if (PageState.EditMode) {
From 650c6670f2065fd1c531f34760b813d6d94d9ca1 Mon Sep 17 00:00:00 2001 From: Jon Welfringer <7365166+W6HBR@users.noreply.github.com> Date: Sun, 31 Mar 2024 10:08:19 -0700 Subject: [PATCH 12/45] Fix incorrect parameter passed from ProfileService.cs to ProfileController.cs ProfileService was passing SiteId instead of ProfileId which was causing updates to profile entries to fail with "Unauthorized Profile Put Attempt". --- Oqtane.Client/Services/ProfileService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/ProfileService.cs b/Oqtane.Client/Services/ProfileService.cs index 5f0f1080..700fb764 100644 --- a/Oqtane.Client/Services/ProfileService.cs +++ b/Oqtane.Client/Services/ProfileService.cs @@ -33,7 +33,7 @@ namespace Oqtane.Services public async Task UpdateProfileAsync(Profile profile) { - return await PutJsonAsync($"{Apiurl}/{profile.SiteId}", profile); + return await PutJsonAsync($"{Apiurl}/{profile.ProfileId}", profile); } public async Task DeleteProfileAsync(int profileId) { From 9843dccdf0a506e55dac1b756cbe17735c53d5c3 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 1 Apr 2024 12:00:53 -0400 Subject: [PATCH 13/45] fix #4088 - redirect to login if not authenticated --- Oqtane.Client/UI/SiteRouter.razor | 154 ++++++++++++++---------------- 1 file changed, 73 insertions(+), 81 deletions(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 4c6ce291..967492d3 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -251,105 +251,97 @@ } } - if (page != null) + // check if user is authorized to view page + if (page != null && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList))) { - // check if user is authorized to view page - if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList))) + // edit mode + if (user != null) { - // edit mode - if (user != null) + if (querystring.ContainsKey("editmode") && querystring["edit"] == "true") { - if (querystring.ContainsKey("editmode") && querystring["edit"] == "true") + editmode = true; + } + else + { + editmode = (page.PageId == ((user.Settings.ContainsKey("CP-editmode")) ? int.Parse(user.Settings["CP-editmode"]) : -1)); + if (!editmode) { - editmode = true; - } - else - { - editmode = (page.PageId == ((user.Settings.ContainsKey("CP-editmode")) ? int.Parse(user.Settings["CP-editmode"]) : -1)); - if (!editmode) - { - var userSettings = new Dictionary { { "CP-editmode", "-1" } }; - await SettingService.UpdateUserSettingsAsync(userSettings, user.UserId); - } + var userSettings = new Dictionary { { "CP-editmode", "-1" } }; + await SettingService.UpdateUserSettingsAsync(userSettings, user.UserId); } } - - // load additional metadata for current page - page = ProcessPage(page, site, user, SiteState.Alias); + } - // load additional metadata for modules - (page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias); + // load additional metadata for current page + page = ProcessPage(page, site, user, SiteState.Alias); - // populate page state (which acts as a client-side cache for subsequent requests) - _pagestate = new PageState + // load additional metadata for modules + (page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias); + + // populate page state (which acts as a client-side cache for subsequent requests) + _pagestate = new PageState + { + Alias = SiteState.Alias, + Site = site, + Page = page, + User = user, + Uri = new Uri(_absoluteUri, UriKind.Absolute), + Route = route, + QueryString = querystring, + UrlParameters = route.UrlParameters, + ModuleId = moduleid, + Action = action, + EditMode = editmode, + LastSyncDate = lastsyncdate, + RenderMode = RenderMode, + Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime), + VisitorId = visitorId, + RemoteIPAddress = SiteState.RemoteIPAddress, + ReturnUrl = returnurl, + IsInternalNavigation = _isInternalNavigation, + RenderId = Guid.NewGuid(), + Refresh = false + }; + OnStateChange?.Invoke(_pagestate); + + if (PageState.RenderMode == RenderModes.Interactive) + { + await ScrollToFragment(_pagestate.Uri); + } + } + else + { + if (page == null) + { + // check for url mapping + var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath); + if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) { - Alias = SiteState.Alias, - Site = site, - Page = page, - User = user, - Uri = new Uri(_absoluteUri, UriKind.Absolute), - Route = route, - QueryString = querystring, - UrlParameters = route.UrlParameters, - ModuleId = moduleid, - Action = action, - EditMode = editmode, - LastSyncDate = lastsyncdate, - RenderMode = RenderMode, - Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime), - VisitorId = visitorId, - RemoteIPAddress = SiteState.RemoteIPAddress, - ReturnUrl = returnurl, - IsInternalNavigation = _isInternalNavigation, - RenderId = Guid.NewGuid(), - Refresh = false - }; - OnStateChange?.Invoke(_pagestate); - - if (PageState.RenderMode == RenderModes.Interactive) - { - await ScrollToFragment(_pagestate.Uri); + var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl + route.Query; + NavigationManager.NavigateTo(url, false); + return; } } else - { - // Need to redirect 404 as page doesnot exist in a Permission or Timeframe - if (route.PagePath != "404") - { - // redirect to 404 page - NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", "")); - } - } - } - else // page not found - { - // look for url mapping - var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath); - if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) - { - var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl + route.Query; - NavigationManager.NavigateTo(url, false); - } - else // not mapped { 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))); + return; } - else - { - if (route.PagePath != "404") - { - // redirect to 404 page - NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", "")); - } - else - { - // redirect to home page as a fallback - NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", "")); - } - } + } + + // page not found or user does not have sufficient access + if (route.PagePath != "404") + { + // redirect to 404 page + NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", "")); + } + else + { + // redirect to home page as a fallback + NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", "")); } } } From e600da229ca654cd02e8e2a852ae1a69ecd31453 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 1 Apr 2024 15:11:20 -0400 Subject: [PATCH 14/45] fix #4091 - double slash generated for home page path ("/") and urlparameters --- Oqtane.Shared/Shared/Utilities.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 49905c1e..46616c74 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -80,8 +80,8 @@ namespace Oqtane.Shared // add urlparameters to path if (!string.IsNullOrEmpty(urlparameters)) { - if (urlparameters.StartsWith("/")) urlparameters = urlparameters.Remove(0, 1); - path += $"/{Constants.UrlParametersDelimiter}/{urlparameters}"; + if (urlparameters.StartsWith("/")) urlparameters = urlparameters.Substring(1); + path += (path.EndsWith("/") ? "" : "/") + $"{Constants.UrlParametersDelimiter}/{urlparameters}"; } // build url From 4944a9e51ee552212195330e71e7206b6029a240 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 2 Apr 2024 08:44:51 -0400 Subject: [PATCH 15/45] fix SiteMap so that it supports page Urls --- Oqtane.Server/Pages/Sitemap.cshtml.cs | 13 ++++- Oqtane.Shared/Shared/Utilities.cs | 76 +++++++-------------------- 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/Oqtane.Server/Pages/Sitemap.cshtml.cs b/Oqtane.Server/Pages/Sitemap.cshtml.cs index 461bc3d6..7ba00eb4 100644 --- a/Oqtane.Server/Pages/Sitemap.cshtml.cs +++ b/Oqtane.Server/Pages/Sitemap.cshtml.cs @@ -47,14 +47,23 @@ namespace Oqtane.Pages var sitemap = new List(); // build site map + var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/"))); var moduleDefinitions = _moduleDefinitions.GetModuleDefinitions(_alias.SiteId).ToList(); var pageModules = _pageModules.GetPageModules(_alias.SiteId); foreach (var page in _pages.GetPages(_alias.SiteId)) { if (_userPermissions.IsAuthorized(null, PermissionNames.View, page.PermissionList) && page.IsNavigation) { - var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/"))); - sitemap.Add(new Sitemap { Url = rooturl + Utilities.NavigateUrl(_alias.Path, page.Path, ""), ModifiedOn = DateTime.UtcNow }); + var pageurl = rooturl; + if (string.IsNullOrEmpty(page.Url)) + { + pageurl += Utilities.NavigateUrl(_alias.Path, page.Path, ""); + } + else + { + pageurl += (page.Url.StartsWith("/") ? "" : "/") + page.Url; + } + sitemap.Add(new Sitemap { Url = rooturl + pageurl, ModifiedOn = DateTime.UtcNow }); foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId)) { diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 46616c74..00cfb3f6 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -21,86 +21,50 @@ namespace Oqtane.Shared return $"{type.Namespace}, {assemblyName}"; } - public static (string UrlParameters, string Querystring, string Fragment) ParseParameters(string url) + public static (string UrlParameters, string Querystring, string Fragment) ParseParameters(string parameters) { - // /path/urlparameters // /urlparameters /urlparameters?Id=1 /urlparameters#5 /urlparameters?Id=1#5 /urlparameters?reload#5 // Id=1 Id=1#5 reload#5 reload // #5 - if (!url.Contains("://")) - { - if (!url.StartsWith("/")) // urlparameters always start with "/" - { - url = ((!url.StartsWith("#")) ? "?" : "/") + url; - } - url = Constants.PackageRegistryUrl + url; // create absolute url - } - - var uri = new Uri(url); + // create absolute url to convert to Uri + parameters = (!parameters.StartsWith("/") && !parameters.StartsWith("#") ? "?" : "") + parameters; + parameters = Constants.PackageRegistryUrl + parameters; + var uri = new Uri(parameters); var querystring = uri.Query.Replace("?", ""); var fragment = uri.Fragment.Replace("#", ""); var urlparameters = uri.LocalPath; urlparameters = (urlparameters == "/") ? "" : urlparameters; - if (urlparameters.Contains(Constants.UrlParametersDelimiter)) - { - urlparameters = urlparameters.Substring(urlparameters.IndexOf(Constants.UrlParametersDelimiter) + 1); - } - return (urlparameters, querystring, fragment); } - public static (string Path, string Parameters) ParsePath(string url) - { - url = ((!url.StartsWith("/") && !url.Contains("://")) ? "/" : "") + url; - - (string path, string querystring, string fragment) = ParseParameters(url); - - var uriBuilder = new UriBuilder - { - Path = path, - Query = querystring, - Fragment = fragment - }; - - return (uriBuilder.Path, uriBuilder.Uri.Query + uriBuilder.Uri.Fragment); - } - public static string NavigateUrl(string alias, string path, string parameters) { + string querystring = ""; + string fragment = ""; + if (!string.IsNullOrEmpty(parameters)) { - // parse path - (path, _) = ParsePath(path); - // parse parameters - (string urlparameters, string querystring, string fragment) = ParseParameters(parameters); - - // add urlparameters to path + (string urlparameters, querystring, fragment) = ParseParameters(parameters); if (!string.IsNullOrEmpty(urlparameters)) { - if (urlparameters.StartsWith("/")) urlparameters = urlparameters.Substring(1); - path += (path.EndsWith("/") ? "" : "/") + $"{Constants.UrlParametersDelimiter}/{urlparameters}"; + path += (path.EndsWith("/") ? "" : "/") + $"{Constants.UrlParametersDelimiter}/{urlparameters.Substring(1)}"; } - - // build url - var uriBuilder = new UriBuilder - { - Path = !string.IsNullOrEmpty(alias) - ? (!string.IsNullOrEmpty(path)) ? $"{alias}{path}": $"{alias}" - : $"{path}", - Query = querystring, - Fragment = fragment - }; - path = uriBuilder.Uri.PathAndQuery; } - else + + // build url + var uriBuilder = new UriBuilder { - path = ((!string.IsNullOrEmpty(alias)) ? alias + (!path.StartsWith("/") ? "/" : "") : "") + path; - } + Path = !string.IsNullOrEmpty(alias) + ? (!string.IsNullOrEmpty(path)) ? $"{alias}{path}": $"{alias}" + : $"{path}", + Query = querystring, + Fragment = fragment + }; - return path; + return uriBuilder.Uri.PathAndQuery; } public static string EditUrl(string alias, string path, int moduleid, string action, string parameters) From 010e4610f7c111e3a80fb19f146b14b3fa02051f Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 2 Apr 2024 10:53:07 -0400 Subject: [PATCH 16/45] fix ThemeSettings SetSetting() references to not specify IsPrivate property --- Oqtane.Client/Themes/OqtaneTheme/Themes/ThemeSettings.razor | 6 +++--- .../Templates/External/Client/Themes/ThemeSettings.razor | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/Themes/OqtaneTheme/Themes/ThemeSettings.razor b/Oqtane.Client/Themes/OqtaneTheme/Themes/ThemeSettings.razor index ca6c5d9c..d488e108 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Themes/ThemeSettings.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Themes/ThemeSettings.razor @@ -121,15 +121,15 @@ var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); if (_login != "-") { - settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true); + settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login); } if (_register != "-") { - settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register, true); + settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register); } if (_footer != "-") { - settings = SettingService.SetSetting(settings, GetType().Namespace + ":Footer", _footer, true); + settings = SettingService.SetSetting(settings, GetType().Namespace + ":Footer", _footer); } await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); } diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/ThemeSettings.razor b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/ThemeSettings.razor index 8db32e1f..3c9d2723 100644 --- a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/ThemeSettings.razor +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/ThemeSettings.razor @@ -108,12 +108,12 @@ var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); if (_login != "-") { - settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true); + settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login); } if (_register != "-") { - settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register, true); + settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register); } await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); } From 1ac1933ec113c0bc364c6d6d190693d40f093569 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 2 Apr 2024 16:37:54 -0400 Subject: [PATCH 17/45] Update issue templates --- .github/ISSUE_TEMPLATE/bug-report.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 00000000..a092044e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,25 @@ +--- +name: Bug Report +about: Create a bug report to help us improve the product +title: "[BUG] " +labels: '' +assignees: '' + +--- + +### Oqtane Info +Version - 5.1.0 +Render Mode - Static +Interactivity - Server +Database - SQL Server + +### Describe the bug + + +### Expected Behavior + + +### Steps To Reproduce + + +### Anything else? From 45e02590993d291379fd5fda2649a4d9e7a8c31c Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 2 Apr 2024 16:41:52 -0400 Subject: [PATCH 18/45] Update issue templates --- .github/ISSUE_TEMPLATE/enhancement-request.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/enhancement-request.md diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md new file mode 100644 index 00000000..3e0a91b8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement-request.md @@ -0,0 +1,19 @@ +--- +name: Enhancement Request +about: 'Suggest a product enhancement ' +title: "[ENH] " +labels: '' +assignees: '' + +--- + +### Oqtane Info +Version - 5.1.0 +Render Mode - Static +Interactivity - Server +Database - SQL Server + +### Describe the enhancement + + +### Anything else? From 578b7b0512922166d1dce1640b9424403d8a5e51 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 2 Apr 2024 16:43:43 -0400 Subject: [PATCH 19/45] Update issue templates --- .github/ISSUE_TEMPLATE/bug-report.md | 3 ++- .github/ISSUE_TEMPLATE/enhancement-request.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index a092044e..e16dcee6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -8,7 +8,8 @@ assignees: '' --- ### Oqtane Info -Version - 5.1.0 + +Version - #.#.# Render Mode - Static Interactivity - Server Database - SQL Server diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md index 3e0a91b8..c9890f6d 100644 --- a/.github/ISSUE_TEMPLATE/enhancement-request.md +++ b/.github/ISSUE_TEMPLATE/enhancement-request.md @@ -8,7 +8,8 @@ assignees: '' --- ### Oqtane Info -Version - 5.1.0 + +Version - #.#.# Render Mode - Static Interactivity - Server Database - SQL Server From 4c08a527be6f5659439d136eba16bfc034aac610 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Apr 2024 09:21:13 +0800 Subject: [PATCH 20/45] Fix #3625: add the clear logs function. --- Oqtane.Client/Modules/Admin/Logs/Index.razor | 106 ++++++++++-------- .../Resources/Modules/Admin/Logs/Index.resx | 9 ++ .../Services/Interfaces/ILogService.cs | 7 ++ Oqtane.Client/Services/LogService.cs | 5 + Oqtane.Server/Controllers/LogController.cs | 15 +++ .../Repository/Interfaces/ILogRepository.cs | 2 +- Oqtane.Server/Repository/LogRepository.cs | 6 +- Oqtane.Server/wwwroot/css/app.css | 3 + 8 files changed, 104 insertions(+), 49 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Logs/Index.razor b/Oqtane.Client/Modules/Admin/Logs/Index.razor index cf2f7cbc..8d180f13 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Index.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Index.razor @@ -86,47 +86,48 @@ else

- + + } @code { - private string _level = "-"; - private string _function = "-"; - private string _rows = "10"; - private int _page = 1; - private List _logs; - private int _retention = 30; + private string _level = "-"; + private string _function = "-"; + private string _rows = "10"; + private int _page = 1; + private List _logs; + private int _retention = 30; - public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}"; - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; + public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}"; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; - protected override async Task OnParametersSetAsync() - { - try - { - if (UrlParameters.ContainsKey("level")) - { - _level = UrlParameters["level"]; - } - if (UrlParameters.ContainsKey("function")) - { - _function = UrlParameters["function"]; - } - if (UrlParameters.ContainsKey("rows")) - { - _rows = UrlParameters["rows"]; - } - if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page)) - { - _page = page; - } + protected override async Task OnParametersSetAsync() + { + try + { + if (UrlParameters.ContainsKey("level")) + { + _level = UrlParameters["level"]; + } + if (UrlParameters.ContainsKey("function")) + { + _function = UrlParameters["function"]; + } + if (UrlParameters.ContainsKey("rows")) + { + _rows = UrlParameters["rows"]; + } + if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page)) + { + _page = page; + } await GetLogs(); - var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); - _retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30")); + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + _retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30")); } catch (Exception ex) { @@ -213,22 +214,37 @@ else return classname; } - private async Task SaveSiteSettings() - { - try - { - var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); - settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true); + private async Task SaveSiteSettings() + { + try + { + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true); await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); - AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message); - AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error); - } - } + AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message); + AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error); + } + } + + private async Task ClearLogs() + { + try + { + await LogService.ClearLogsAsync(PageState.Site.SiteId); + await GetLogs(); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Clearing Logs {Error}", ex.Message); + AddModuleMessage(Localizer["Error.ClearLogs"], MessageType.Error); + } + } private void OnPageChange(int page) { diff --git a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx index dfd55880..f464d6fe 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx @@ -210,4 +210,13 @@ Settings Saved Successfully + + Clear Logs + + + Are you sure you wish to clear all the logs? + + + Error Clearing Logs + \ No newline at end of file diff --git a/Oqtane.Client/Services/Interfaces/ILogService.cs b/Oqtane.Client/Services/Interfaces/ILogService.cs index 2a821359..dea788bc 100644 --- a/Oqtane.Client/Services/Interfaces/ILogService.cs +++ b/Oqtane.Client/Services/Interfaces/ILogService.cs @@ -29,6 +29,13 @@ namespace Oqtane.Services /// Task GetLogAsync(int logId); + /// + /// Clear the entire logs of the given site. + /// + /// + /// + Task ClearLogsAsync(int siteId); + /// /// Creates a new log entry /// diff --git a/Oqtane.Client/Services/LogService.cs b/Oqtane.Client/Services/LogService.cs index e575694e..9369f90d 100644 --- a/Oqtane.Client/Services/LogService.cs +++ b/Oqtane.Client/Services/LogService.cs @@ -35,6 +35,11 @@ namespace Oqtane.Services return await GetJsonAsync($"{Apiurl}/{logId}"); } + public async Task ClearLogsAsync(int siteId) + { + await DeleteAsync($"{Apiurl}?siteid={siteId}&includeErrors=true"); + } + public async Task Log(int? pageId, int? moduleId, int? userId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args) { await Log(null, pageId, moduleId, userId, category, feature, function, level, exception, message, args); diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs index 34fc5b7c..490c7563 100644 --- a/Oqtane.Server/Controllers/LogController.cs +++ b/Oqtane.Server/Controllers/LogController.cs @@ -76,5 +76,20 @@ namespace Oqtane.Controllers HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } + + [HttpDelete] + [Authorize(Roles = RoleNames.Admin)] + public void Delete(string siteId, bool includeErrors) + { + if (int.TryParse(siteId, out int parsedSiteId) && parsedSiteId == _alias.SiteId) + { + _logs.DeleteLogs(parsedSiteId, 0, includeErrors); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Delete Attempt {SiteId}", siteId); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } + } } } diff --git a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs index 918785f2..d30da106 100644 --- a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs @@ -8,6 +8,6 @@ namespace Oqtane.Repository IEnumerable GetLogs(int siteId, string level, string function, int rows); Log GetLog(int logId); void AddLog(Log log); - int DeleteLogs(int siteId, int age); + int DeleteLogs(int siteId, int age, bool includeErrors = false); } } diff --git a/Oqtane.Server/Repository/LogRepository.cs b/Oqtane.Server/Repository/LogRepository.cs index 6c388f15..6c767e43 100644 --- a/Oqtane.Server/Repository/LogRepository.cs +++ b/Oqtane.Server/Repository/LogRepository.cs @@ -53,20 +53,20 @@ namespace Oqtane.Repository db.SaveChanges(); } - public int DeleteLogs(int siteId, int age) + public int DeleteLogs(int siteId, int age, bool includeErrors = false) { using var db = _dbContextFactory.CreateDbContext(); // delete logs in batches of 100 records var count = 0; var purgedate = DateTime.UtcNow.AddDays(-age); - var logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate) + var logs = db.Log.Where(item => item.SiteId == siteId && (includeErrors || item.Level != "Error") && item.LogDate < purgedate) .OrderBy(item => item.LogDate).Take(100).ToList(); while (logs.Count > 0) { count += logs.Count; db.Log.RemoveRange(logs); db.SaveChanges(); - logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate) + logs = db.Log.Where(item => item.SiteId == siteId && (includeErrors || item.Level != "Error") && item.LogDate < purgedate) .OrderBy(item => item.LogDate).Take(100).ToList(); } return count; diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css index 863d10d2..f5a65a80 100644 --- a/Oqtane.Server/wwwroot/css/app.css +++ b/Oqtane.Server/wwwroot/css/app.css @@ -35,6 +35,9 @@ app { } /* Action Dialog */ +.app-actiondialog{ + position: absolute; +} .app-actiondialog .modal { position: fixed; /* Stay in place */ z-index: 9999; /* Sit on top */ From 757a39a75efc10c876f91ca4570513f7aae796a9 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Apr 2024 22:27:39 +0800 Subject: [PATCH 21/45] update code by review result. --- .../Resources/Modules/Admin/Logs/Index.resx | 2 +- Oqtane.Client/Services/LogService.cs | 2 +- Oqtane.Server/Controllers/LogController.cs | 4 ++-- .../Repository/Interfaces/ILogRepository.cs | 3 ++- Oqtane.Server/Repository/LogRepository.cs | 20 ++++++++++++++++--- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx index f464d6fe..27b3c4c7 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx @@ -210,7 +210,7 @@ Settings Saved Successfully - + Clear Logs diff --git a/Oqtane.Client/Services/LogService.cs b/Oqtane.Client/Services/LogService.cs index 9369f90d..26c37038 100644 --- a/Oqtane.Client/Services/LogService.cs +++ b/Oqtane.Client/Services/LogService.cs @@ -37,7 +37,7 @@ namespace Oqtane.Services public async Task ClearLogsAsync(int siteId) { - await DeleteAsync($"{Apiurl}?siteid={siteId}&includeErrors=true"); + await DeleteAsync($"{Apiurl}?siteid={siteId}"); } public async Task Log(int? pageId, int? moduleId, int? userId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args) diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs index 490c7563..c35bf6bf 100644 --- a/Oqtane.Server/Controllers/LogController.cs +++ b/Oqtane.Server/Controllers/LogController.cs @@ -79,11 +79,11 @@ namespace Oqtane.Controllers [HttpDelete] [Authorize(Roles = RoleNames.Admin)] - public void Delete(string siteId, bool includeErrors) + public void Delete(string siteId) { if (int.TryParse(siteId, out int parsedSiteId) && parsedSiteId == _alias.SiteId) { - _logs.DeleteLogs(parsedSiteId, 0, includeErrors); + _logs.ClearLogs(parsedSiteId); } else { diff --git a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs index d30da106..623e3a2d 100644 --- a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs @@ -8,6 +8,7 @@ namespace Oqtane.Repository IEnumerable GetLogs(int siteId, string level, string function, int rows); Log GetLog(int logId); void AddLog(Log log); - int DeleteLogs(int siteId, int age, bool includeErrors = false); + int DeleteLogs(int siteId, int age); + void ClearLogs(int siteId); } } diff --git a/Oqtane.Server/Repository/LogRepository.cs b/Oqtane.Server/Repository/LogRepository.cs index 6c767e43..81d5813f 100644 --- a/Oqtane.Server/Repository/LogRepository.cs +++ b/Oqtane.Server/Repository/LogRepository.cs @@ -53,23 +53,37 @@ namespace Oqtane.Repository db.SaveChanges(); } - public int DeleteLogs(int siteId, int age, bool includeErrors = false) + public int DeleteLogs(int siteId, int age) { using var db = _dbContextFactory.CreateDbContext(); // delete logs in batches of 100 records var count = 0; var purgedate = DateTime.UtcNow.AddDays(-age); - var logs = db.Log.Where(item => item.SiteId == siteId && (includeErrors || item.Level != "Error") && item.LogDate < purgedate) + var logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate) .OrderBy(item => item.LogDate).Take(100).ToList(); while (logs.Count > 0) { count += logs.Count; db.Log.RemoveRange(logs); db.SaveChanges(); - logs = db.Log.Where(item => item.SiteId == siteId && (includeErrors || item.Level != "Error") && item.LogDate < purgedate) + logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate) .OrderBy(item => item.LogDate).Take(100).ToList(); } return count; } + + public void ClearLogs(int siteId) + { + using var db = _dbContextFactory.CreateDbContext(); + var getLogsForDelete = () => db.Log.Where(item => item.SiteId == siteId).Take(100).ToList(); + // delete logs in batches of 100 records + var logs = getLogsForDelete(); + while (logs.Count > 0) + { + db.Log.RemoveRange(logs); + db.SaveChanges(); + logs = getLogsForDelete(); + } + } } } From 7b95db4d13e6b2225815e97133412ddad638caf1 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 4 Apr 2024 11:58:05 -0400 Subject: [PATCH 22/45] modify #4099 - fix localization and use Delete rather than Clear in API methods for consistency with rest of framework --- Oqtane.Client/Modules/Admin/Logs/Index.razor | 10 +++++----- .../Resources/Modules/Admin/Logs/Index.resx | 17 ++++++++++------- .../Services/Interfaces/ILogService.cs | 2 +- Oqtane.Client/Services/LogService.cs | 2 +- Oqtane.Server/Controllers/LogController.cs | 2 +- .../Repository/Interfaces/ILogRepository.cs | 1 - Oqtane.Server/Repository/LogRepository.cs | 18 ++---------------- 7 files changed, 20 insertions(+), 32 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Logs/Index.razor b/Oqtane.Client/Modules/Admin/Logs/Index.razor index 8d180f13..a8cfeb70 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Index.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Index.razor @@ -87,7 +87,7 @@ else
- + } @@ -231,18 +231,18 @@ else } } - private async Task ClearLogs() + private async Task DeleteLogs() { try { - await LogService.ClearLogsAsync(PageState.Site.SiteId); + await LogService.DeleteLogsAsync(PageState.Site.SiteId); await GetLogs(); StateHasChanged(); } catch (Exception ex) { - await logger.LogError(ex, "Error Clearing Logs {Error}", ex.Message); - AddModuleMessage(Localizer["Error.ClearLogs"], MessageType.Error); + await logger.LogError(ex, "Error Deleting Logs {Error}", ex.Message); + AddModuleMessage(Localizer["Error.DeleteLogs"], MessageType.Error); } } diff --git a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx index 27b3c4c7..230dd9a4 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Logs/Index.resx @@ -1,4 +1,4 @@ - + Exe - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 https://github.com/oqtane/oqtane.framework Git Oqtane.Maui @@ -31,7 +31,7 @@ 0E29FC31-1B83-48ED-B6E0-9F3C67B775D4 - 5.1.0 + 5.1.1 1 14.2 @@ -65,15 +65,15 @@ - - + + - + - - - + + + diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index e2762ec7..49cf9bd5 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -2,7 +2,7 @@ Oqtane.Client - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Framework.nuspec b/Oqtane.Package/Oqtane.Framework.nuspec index ebd0b4ed..cfaef73d 100644 --- a/Oqtane.Package/Oqtane.Framework.nuspec +++ b/Oqtane.Package/Oqtane.Framework.nuspec @@ -2,7 +2,7 @@ Oqtane.Framework - 5.1.0 + 5.1.1 Shaun Walker .NET Foundation Oqtane Framework @@ -11,8 +11,8 @@ .NET Foundation false MIT - 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 + https://github.com/oqtane/oqtane.framework/releases/download/v5.1.1/Oqtane.Framework.5.1.1.Upgrade.zip + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 icon.png oqtane framework diff --git a/Oqtane.Package/Oqtane.Server.nuspec b/Oqtane.Package/Oqtane.Server.nuspec index 6e783ae2..93c2942e 100644 --- a/Oqtane.Package/Oqtane.Server.nuspec +++ b/Oqtane.Package/Oqtane.Server.nuspec @@ -2,7 +2,7 @@ Oqtane.Server - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index bc41fd15..ac34a811 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -2,7 +2,7 @@ Oqtane.Shared - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Updater.nuspec b/Oqtane.Package/Oqtane.Updater.nuspec index d2958199..fe7d85bd 100644 --- a/Oqtane.Package/Oqtane.Updater.nuspec +++ b/Oqtane.Package/Oqtane.Updater.nuspec @@ -2,7 +2,7 @@ Oqtane.Updater - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 icon.png oqtane diff --git a/Oqtane.Package/install.ps1 b/Oqtane.Package/install.ps1 index 21103c06..ed93995d 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.1.0.Install.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.1.Install.zip" -Force \ No newline at end of file diff --git a/Oqtane.Package/upgrade.ps1 b/Oqtane.Package/upgrade.ps1 index 762ca550..c5c23da0 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.1.0.Upgrade.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.1.Upgrade.zip" -Force \ No newline at end of file diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 6685f7b6..7fe28c3d 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index 5fa002a2..3d8d4a78 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index e538ef9d..a7d1173e 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.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 static readonly string Version = "5.1.1"; + 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,5.1.1"; 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 231694c5..4554897c 100644 --- a/Oqtane.Updater/Oqtane.Updater.csproj +++ b/Oqtane.Updater/Oqtane.Updater.csproj @@ -3,7 +3,7 @@ net8.0 Exe - 5.1.0 + 5.1.1 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.1.0 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1 https://github.com/oqtane/oqtane.framework Git Oqtane From cfce2bdbd981f844ac30305c89f3fb4d5b06d57e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 11 Apr 2024 15:26:55 -0400 Subject: [PATCH 36/45] move RichTextEditor script registration to Body --- Oqtane.Client/Modules/Controls/RichTextEditor.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 77967c9f..d17d71c2 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -146,9 +146,9 @@ public override List Resources => new List() { - new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" }, - new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" }, - new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" } + new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js", Location = ResourceLocation.Body }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body } }; protected override void OnParametersSet() From 4a20fad4e594422d215dcd52c6793048a904fe05 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Fri, 12 Apr 2024 12:21:44 +0200 Subject: [PATCH 37/45] InitializeTokenReplace not setting the correct PackageReference For completeness. --- Oqtane.Server/Controllers/ModuleDefinitionController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 291f183c..2176c9f3 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -365,8 +365,8 @@ namespace Oqtane.Controllers { { "FrameworkVersion", moduleDefinition.Version }, { "ClientReference", $"" }, - { "ServerReference", $"" }, - { "SharedReference", $"" }, + { "ServerReference", $"" }, + { "SharedReference", $"" }, }; }); } From 5954fb91befa7e35a396ddf3bf2479d4f2f5dd0e Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 12 Apr 2024 21:56:49 +0800 Subject: [PATCH 38/45] Fix #4121: avoid nested square bracket issue. --- Oqtane.Server/Infrastructure/TokenReplace.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Infrastructure/TokenReplace.cs b/Oqtane.Server/Infrastructure/TokenReplace.cs index 3c7e8a8c..d2b40db4 100644 --- a/Oqtane.Server/Infrastructure/TokenReplace.cs +++ b/Oqtane.Server/Infrastructure/TokenReplace.cs @@ -93,6 +93,7 @@ namespace Oqtane.Infrastructure } var result = new StringBuilder(); + source = source.Replace("[[", "[$_["); //avoid nested square bracket issue. foreach (Match match in this.TokenizerRegex.Matches(source)) { var key = match.Result("${key}"); @@ -126,7 +127,7 @@ namespace Oqtane.Infrastructure result.Append(match.Result("${text}")); } } - + result.Replace("[$_", "["); //restore the changes. return result.ToString(); } From 8f00730189640eb344fdd1c9b110f2514e30e358 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 12 Apr 2024 13:25:44 -0400 Subject: [PATCH 39/45] fix #4134 - RichTextEditor scenarios --- .../Modules/Controls/RichTextEditor.razor | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index d17d71c2..6da97020 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -109,12 +109,12 @@ private bool _richfilemanager = false; private FileManager _fileManager; private string _richhtml = string.Empty; - private string _originalrichhtml = string.Empty; private bool _rawfilemanager = false; private string _rawhtml = string.Empty; private string _originalrawhtml = string.Empty; private string _message = string.Empty; private string _activetab = "Rich"; + private bool _contentchanged = false; [Parameter] public string Content { get; set; } @@ -156,7 +156,7 @@ _richhtml = Content; _rawhtml = Content; _originalrawhtml = _rawhtml; // preserve for comparison later - _originalrichhtml = ""; + _contentchanged = true; if (!AllowRichText) { @@ -181,24 +181,32 @@ Placeholder, Theme, DebugLevel); + + await interop.LoadEditorContent(_editorElement, _richhtml); + + _initialized = true; } - - if (_initialized) + else { - if (!_richfilemanager) // do not override the content when the file manager is displayed + if (_initialized) { - await interop.LoadEditorContent(_editorElement, _richhtml); - } - - if (string.IsNullOrEmpty(_originalrichhtml)) - { - // preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor as it may have changed) - _originalrichhtml = await interop.GetHtml(_editorElement); + if (_contentchanged) + { + // reload if content passed to component has changed + await interop.LoadEditorContent(_editorElement, _richhtml); + } + else + { + var richhtml = await interop.GetHtml(_editorElement); + if (richhtml != _richhtml) + { + await interop.LoadEditorContent(_editorElement, richhtml); + } + } + _contentchanged = false; } } } - - _initialized = true; // ensures that the rich text editor is created before trying to access its methods } public void CloseRichFileManager() @@ -224,23 +232,17 @@ } else { - var richhtml = ""; if (AllowRichText) { - // return rich text content if it has changed + // return rich text content var interop = new RichTextEditorInterop(JSRuntime); - richhtml = await interop.GetHtml(_editorElement); + return await interop.GetHtml(_editorElement); } - // rich text value will only be blank if AllowRichText is disabled or the JS Interop method failed - if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml) && !string.IsNullOrEmpty(_originalrichhtml)) - { - return richhtml; - } - else - { + else + { // return original raw html content - return _originalrawhtml; - } + return _originalrawhtml; + } } } From 39dff1ea7cc7ee119ddc36f510ad0e8d385b6d73 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 12 Apr 2024 14:58:14 -0400 Subject: [PATCH 40/45] more changes for #4134 - ensure HTML content is preserved --- .../Modules/Controls/RichTextEditor.razor | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 6da97020..0850325d 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -109,6 +109,7 @@ private bool _richfilemanager = false; private FileManager _fileManager; private string _richhtml = string.Empty; + private string _originalrichhtml = string.Empty; private bool _rawfilemanager = false; private string _rawhtml = string.Empty; private string _originalrawhtml = string.Empty; @@ -156,6 +157,7 @@ _richhtml = Content; _rawhtml = Content; _originalrawhtml = _rawhtml; // preserve for comparison later + _originalrichhtml = ""; _contentchanged = true; if (!AllowRichText) @@ -184,6 +186,9 @@ await interop.LoadEditorContent(_editorElement, _richhtml); + // preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor as it may have changed) + _originalrichhtml = await interop.GetHtml(_editorElement); + _initialized = true; } else @@ -194,6 +199,7 @@ { // reload if content passed to component has changed await interop.LoadEditorContent(_editorElement, _richhtml); + _originalrichhtml = await interop.GetHtml(_editorElement); } else { @@ -232,18 +238,24 @@ } else { + var richhtml = ""; + if (AllowRichText) { - // return rich text content var interop = new RichTextEditorInterop(JSRuntime); - return await interop.GetHtml(_editorElement); + richhtml = await interop.GetHtml(_editorElement); + } + + if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml)) + { + return richhtml; } else { - // return original raw html content - return _originalrawhtml; + // return original raw html content + return _originalrawhtml; } - } + } } public async Task InsertRichImage() From bc978a91e37effcb9a964810c9c4cc60f6856b8f Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 12 Apr 2024 15:10:47 -0400 Subject: [PATCH 41/45] convert Quill's empty content to empty string --- Oqtane.Client/Modules/Controls/RichTextEditor.razor | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 0850325d..ce7e4736 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -188,7 +188,7 @@ // preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor as it may have changed) _originalrichhtml = await interop.GetHtml(_editorElement); - + _initialized = true; } else @@ -239,7 +239,7 @@ else { var richhtml = ""; - + if (AllowRichText) { var interop = new RichTextEditorInterop(JSRuntime); @@ -248,6 +248,11 @@ if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml)) { + // convert Quill's empty content to empty string + if (richhtml == "


") + { + richhtml = string.Empty; + } return richhtml; } else From 9d8b1fd99b2ba2fcfc49aee4287ae1112228823e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 15 Apr 2024 08:54:23 -0400 Subject: [PATCH 42/45] fixes for #4134 - Rich Text Editor --- .../Modules/Controls/RichTextEditor.razor | 44 ++++++++++++------- .../Modules/Controls/RichTextEditor.resx | 3 ++ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index ce7e4736..ad237acb 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -90,11 +90,11 @@ @if (ReadOnly) { - + } else { - + } } @@ -104,17 +104,23 @@ @code { private bool _initialized = false; + + private RichTextEditorInterop interop; + private FileManager _fileManager; + private string _activetab = "Rich"; + private ElementReference _editorElement; private ElementReference _toolBar; private bool _richfilemanager = false; - private FileManager _fileManager; private string _richhtml = string.Empty; private string _originalrichhtml = string.Empty; + private bool _rawfilemanager = false; + private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N"); private string _rawhtml = string.Empty; private string _originalrawhtml = string.Empty; + private string _message = string.Empty; - private string _activetab = "Rich"; private bool _contentchanged = false; [Parameter] @@ -124,7 +130,7 @@ public bool ReadOnly { get; set; } = false; [Parameter] - public string Placeholder { get; set; } = "Enter Your Content..."; + public string Placeholder { get; set; } [Parameter] public bool AllowFileManagement { get; set; } = true; @@ -152,13 +158,22 @@ new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body } }; + protected override void OnInitialized() + { + interop = new RichTextEditorInterop(JSRuntime); + if (string.IsNullOrEmpty(Placeholder)) + { + Placeholder = Localizer["Placeholder"]; + } + } + protected override void OnParametersSet() { _richhtml = Content; _rawhtml = Content; _originalrawhtml = _rawhtml; // preserve for comparison later _originalrichhtml = ""; - _contentchanged = true; + _contentchanged = true; // identifies when Content parameter has changed if (!AllowRichText) { @@ -172,8 +187,6 @@ if (AllowRichText) { - var interop = new RichTextEditorInterop(JSRuntime); - if (firstRender) { await interop.CreateEditor( @@ -186,7 +199,7 @@ await interop.LoadEditorContent(_editorElement, _richhtml); - // preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor as it may have changed) + // preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified) _originalrichhtml = await interop.GetHtml(_editorElement); _initialized = true; @@ -197,21 +210,24 @@ { if (_contentchanged) { - // reload if content passed to component has changed + // reload editor if Content passed to component has changed await interop.LoadEditorContent(_editorElement, _richhtml); _originalrichhtml = await interop.GetHtml(_editorElement); } else { + // preserve changed content on re-render event var richhtml = await interop.GetHtml(_editorElement); if (richhtml != _richhtml) { - await interop.LoadEditorContent(_editorElement, richhtml); + _richhtml = richhtml; + await interop.LoadEditorContent(_editorElement, _richhtml); } } - _contentchanged = false; } } + + _contentchanged = false; } } @@ -242,7 +258,6 @@ if (AllowRichText) { - var interop = new RichTextEditorInterop(JSRuntime); richhtml = await interop.GetHtml(_editorElement); } @@ -271,7 +286,6 @@ var file = _fileManager.GetFile(); if (file != null) { - var interop = new RichTextEditorInterop(JSRuntime); await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name)); _richhtml = await interop.GetHtml(_editorElement); _richfilemanager = false; @@ -297,7 +311,7 @@ if (file != null) { var interop = new Interop(JSRuntime); - int pos = await interop.GetCaretPosition("rawhtmleditor"); + int pos = await interop.GetCaretPosition(_rawhtmlid); var image = "\"""; _rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos); _rawfilemanager = false; diff --git a/Oqtane.Client/Resources/Modules/Controls/RichTextEditor.resx b/Oqtane.Client/Resources/Modules/Controls/RichTextEditor.resx index 5ac2f720..4e2b64c5 100644 --- a/Oqtane.Client/Resources/Modules/Controls/RichTextEditor.resx +++ b/Oqtane.Client/Resources/Modules/Controls/RichTextEditor.resx @@ -126,4 +126,7 @@ You Must Select An Image To Insert + + Enter Your Content... +
\ No newline at end of file From 4f25b7bbbe6b353eccd95b5412a0f89c558dde36 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 16 Apr 2024 08:02:59 -0400 Subject: [PATCH 43/45] fix SiteRouter issue when running on .NET MAUI --- Oqtane.Client/UI/SiteRouter.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 967492d3..43acc3a6 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -171,9 +171,9 @@ visitorId = PageState.VisitorId; } - if (PageState.RenderMode == RenderModes.Interactive) + if (PageState != null && PageState.RenderMode == RenderModes.Interactive) { - // process any sync events (for synchrozing the client application with the server) + // process any sync events (for synchronizing the client application with the server) var sync = await SyncService.GetSyncEventsAsync(lastsyncdate); lastsyncdate = sync.SyncDate; if (sync.SyncEvents.Any()) From 2a0399b98da1a8c4618fd42f6792d82746002db2 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 16 Apr 2024 12:36:31 -0400 Subject: [PATCH 44/45] include .NET MAUI CORS policy for static files, add support for [wwwroot] in content --- Oqtane.Server/Startup.cs | 16 +++++++++++++--- Oqtane.Shared/Shared/Utilities.cs | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 8180ea9b..0a83d275 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -22,6 +22,7 @@ using Oqtane.UI; using OqtaneSSR.Extensions; using Microsoft.AspNetCore.Components.Authorization; using Oqtane.Providers; +using Microsoft.AspNetCore.Cors.Infrastructure; namespace Oqtane { @@ -135,7 +136,7 @@ namespace Oqtane { // 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(); + .AllowAnyHeader().AllowAnyMethod().AllowCredentials(); }); }); @@ -169,7 +170,7 @@ namespace Oqtane } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync, ILogger logger) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, ILogger logger) { if (!string.IsNullOrEmpty(_configureServicesErrors)) { @@ -198,7 +199,16 @@ namespace Oqtane app.UseOqtaneLocalization(); app.UseHttpsRedirection(); - app.UseStaticFiles(); + app.UseStaticFiles(new StaticFileOptions + { + ServeUnknownFileTypes = true, + OnPrepareResponse = (ctx) => + { + var policy = corsPolicyProvider.GetPolicyAsync(ctx.Context, Constants.MauiCorsPolicy) + .ConfigureAwait(false).GetAwaiter().GetResult(); + corsService.ApplyResult(corsService.EvaluatePolicy(ctx.Context, policy), ctx.Context.Response); + } + }); app.UseExceptionMiddleWare(); app.UseTenantResolution(); app.UseJwtAuthorization(); diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 00cfb3f6..b9e364c3 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -149,6 +149,7 @@ namespace Oqtane.Shared break; case "render": content = content.Replace(Constants.FileUrl, alias?.BaseUrl + aliasUrl + Constants.FileUrl); + content = content.Replace("[wwwroot]", alias?.BaseUrl + aliasUrl + "/"); // legacy content = content.Replace("[siteroot]", UrlCombine("Content", "Tenants", alias.TenantId.ToString(), "Sites", alias.SiteId.ToString())); content = content.Replace(Constants.ContentUrl, alias.Path + Constants.ContentUrl); From b815d945d95cc7efeb9762094d29cd7a19bd0418 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 16 Apr 2024 13:04:25 -0400 Subject: [PATCH 45/45] fix SiteMap path issue --- Oqtane.Server/Pages/Sitemap.cshtml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Pages/Sitemap.cshtml.cs b/Oqtane.Server/Pages/Sitemap.cshtml.cs index 7ba00eb4..c79957c3 100644 --- a/Oqtane.Server/Pages/Sitemap.cshtml.cs +++ b/Oqtane.Server/Pages/Sitemap.cshtml.cs @@ -63,7 +63,7 @@ namespace Oqtane.Pages { pageurl += (page.Url.StartsWith("/") ? "" : "/") + page.Url; } - sitemap.Add(new Sitemap { Url = rooturl + pageurl, ModifiedOn = DateTime.UtcNow }); + sitemap.Add(new Sitemap { Url = pageurl, ModifiedOn = DateTime.UtcNow }); foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId)) {