From dd2a69814703fc10cd6baad9bca50edffd8d96f6 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 20 Dec 2023 14:17:23 -0800 Subject: [PATCH 01/99] Refreshes settings page if logo changes. --- Oqtane.Client/Modules/Admin/Site/Index.razor | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index c55eb2ba..cd7ba367 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -673,6 +673,10 @@ } else { + if (logofileid != -1 && logofileid != _logofileid) + { + NavigationManager.Refresh(); + } AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success); await ScrollToPageTop(); } From 140535d87546c2e1babac15627b5a00ee4f5d63d Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 21 Dec 2023 12:50:13 -0500 Subject: [PATCH 02/99] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d6922eb..fadaf2dd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Latest Release -[5.0.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.0) was released on Nov 16, 2023 and is a major release targeted at .NET 8. This release includes 45 pull requests by 4 different contributors, pushing the total number of project commits all-time to over 4300. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. +[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. [![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) @@ -53,6 +53,9 @@ Backlog (TBD) 5.1.0 (Q1 2024) - [ ] Full Stack Blazor (Static Server-Side Rendering) +[5.0.1](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.1) (Dec 21, 2023) +- [x] Stabilization improvements + [5.0.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.0) (Nov 16, 2023) - [x] Migration to .NET 8 From 52069f35c5deddeafa4661194099b8163c11a000 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 21 Dec 2023 15:54:46 -0500 Subject: [PATCH 03/99] refactor logic related to domain filtering for emails during external login --- ...taneSiteAuthenticationBuilderExtensions.cs | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs b/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs index 68a002c7..604270c1 100644 --- a/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs @@ -205,6 +205,10 @@ namespace Oqtane.Extensions { email = item[emailClaimType].ToString().ToLower(); } + else + { + id = ""; // if email is not valid we will assume id is not valid + } } } if (!string.IsNullOrEmpty(id)) @@ -290,6 +294,10 @@ namespace Oqtane.Extensions { email = context.Principal.FindFirstValue(emailClaimType); } + else + { + id = ""; // if email is not valid we will assume id is not valid + } } // validate user @@ -610,23 +618,27 @@ namespace Oqtane.Extensions private static bool EmailValid(string email, string domainfilter) { - if (!string.IsNullOrEmpty(email) && email.Contains("@") && email.Contains(".")) + if (!string.IsNullOrEmpty(email)) { - var domains = domainfilter.ToLower().Split(',', StringSplitOptions.RemoveEmptyEntries); - foreach (var domain in domains) + if (email.Contains("@") && email.Contains(".")) { - if (domain.StartsWith("!")) + var domains = domainfilter.ToLower().Split(',', StringSplitOptions.RemoveEmptyEntries); + foreach (var domain in domains) { - if (email.ToLower().Contains(domain.Substring(1))) return false; - } - else - { - if (!email.ToLower().Contains(domain)) return false; + if (domain.StartsWith("!")) + { + if (email.ToLower().Contains(domain.Substring(1))) return false; + } + else + { + if (!email.ToLower().Contains(domain)) return false; + } } + return true; } - return true; - } - return false; + return false; + } + return (string.IsNullOrEmpty(domainfilter)); // email is optional unless domain filter is specified } } } From 4b938db0c196a900e1db2c7048026795b97617fb Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 22 Dec 2023 10:28:14 -0800 Subject: [PATCH 04/99] refresh = true when logo is updated --- Oqtane.Client/Modules/Admin/Site/Index.razor | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index cd7ba367..06190904 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -579,6 +579,10 @@ if (logofileid != -1) { site.LogoFileId = logofileid; + if (logofileid != _logofileid) + { + refresh = true; + } } int? faviconFieldId = _faviconfilemanager.GetFileId(); if (faviconFieldId == -1) faviconFieldId = null; From 9612e4d4e92955caf6b36bdcf83ced740bc57c8f Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 22 Dec 2023 10:30:28 -0800 Subject: [PATCH 05/99] Removes unnecessary logo refresh logic. --- Oqtane.Client/Modules/Admin/Site/Index.razor | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 06190904..874c3c98 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -677,10 +677,6 @@ } else { - if (logofileid != -1 && logofileid != _logofileid) - { - NavigationManager.Refresh(); - } AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success); await ScrollToPageTop(); } From 49f7ee604265e8e7a6d5527e0d8e124c163e5371 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 23 Dec 2023 09:25:02 -0800 Subject: [PATCH 06/99] change to reload from refresh to update site logo --- 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 874c3c98..b9d94457 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -581,7 +581,7 @@ site.LogoFileId = logofileid; if (logofileid != _logofileid) { - refresh = true; + reload = true; } } int? faviconFieldId = _faviconfilemanager.GetFileId(); From 006cd1ee896629a93de7b6a0210b4f1c9dc97704 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 23 Dec 2023 11:26:57 -0800 Subject: [PATCH 07/99] Refresh Page On Client After Saving Changed Logo --- Oqtane.Client/Modules/Admin/Site/Index.razor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index b9d94457..f6cc5ee5 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -581,7 +581,8 @@ site.LogoFileId = logofileid; if (logofileid != _logofileid) { - reload = true; + _logofileid = logofileid; + refresh = true; } } int? faviconFieldId = _faviconfilemanager.GetFileId(); From 8ed11cdc0780f1753978caba9c4b9edaee64b8c9 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 23 Dec 2023 12:02:58 -0800 Subject: [PATCH 08/99] Adds the comment for client logo refresh boolean --- 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 f6cc5ee5..3ad4d605 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -582,7 +582,7 @@ if (logofileid != _logofileid) { _logofileid = logofileid; - refresh = true; + refresh = true; // needs to be refreshed on client } } int? faviconFieldId = _faviconfilemanager.GetFileId(); From 42422845b0dea75416a8e8d1bcfb2e9c789a114c Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 29 Dec 2023 11:00:29 -0800 Subject: [PATCH 09/99] Updates Owner/Module Name Tooltip/Notification --- .../Resources/Modules/Admin/ModuleDefinitions/Create.resx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx b/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx index cac13d97..d2978659 100644 --- a/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx +++ b/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx @@ -130,16 +130,16 @@ Please Note That The Module Creator Is Only Intended To Be Used In A Development Environment - You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template + You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same Or Contain The Word "Oqtane" ) And Choose A Template You Must Provide A Valid Description (ie. No Punctuation) - Enter the name of the organization who is developing this module. It should not contain spaces or punctuation. + Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or contain the word "Oqtane". - Enter a name for this module. It should not contain spaces or punctuation. + Enter a name for this module. It should not contain spaces or punctuation or contain the word "Oqtane". Enter a short description for the module @@ -171,4 +171,4 @@ The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href={0}>Restart</a> Your Application To Activate The Module. - \ No newline at end of file + From 6820b748f78b73489d04787482470ee789e06f5a Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 29 Dec 2023 11:37:31 -0800 Subject: [PATCH 10/99] Updates Module Name/Owner and Notification Text --- .../Resources/Modules/Admin/ModuleDefinitions/Create.resx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx b/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx index d2978659..94942a50 100644 --- a/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx +++ b/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Create.resx @@ -136,10 +136,10 @@ You Must Provide A Valid Description (ie. No Punctuation) - Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or contain the word "Oqtane". + Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or contain the word "oqtane". - Enter a name for this module. It should not contain spaces or punctuation or contain the word "Oqtane". + Enter a name for this module. It should not contain spaces or punctuation or contain the word "oqtane". Enter a short description for the module From 47cee5f6a108f588dc476bc82bf706d2465faf14 Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 29 Dec 2023 11:39:35 -0800 Subject: [PATCH 11/99] Updates Module Owner/Name HelpText --- Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor index 94770893..f673ca10 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor @@ -13,13 +13,13 @@
- +
- +
From 9b24e61033aa83d040911cc6a97e7946f82e6a01 Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 29 Dec 2023 12:49:49 -0800 Subject: [PATCH 12/99] Clear Module Message Proir To Adding A Message To UI --- Oqtane.Client/Modules/ModuleBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index f5c0bef7..9825a334 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -266,6 +266,7 @@ namespace Oqtane.Modules public void AddModuleMessage(string message, MessageType type, string position) { + ClearModuleMessage(); ModuleInstance.AddModuleMessage(message, type, position); } From 233f40f3e9b02d65ae181ec1a8c84f086bde8c59 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Sun, 31 Dec 2023 12:21:38 +0100 Subject: [PATCH 13/99] Start Date and Expiry Date for Module instances and Pages #3538 This is complete excluding Reporting and Notifications which can be added at a later date. I just really wanted to get the schema and the functionality into place. --- .../Modules/Admin/Modules/Settings.razor | 55 +++- Oqtane.Client/Modules/Admin/Pages/Add.razor | 272 +++++++++++------- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 52 ++++ Oqtane.Client/Modules/Admin/Users/Roles.razor | 55 +++- .../Modules/Admin/Modules/Settings.resx | 12 + .../Resources/Modules/Admin/Pages/Add.resx | 12 + .../Resources/Modules/Admin/Pages/Edit.resx | 12 + Oqtane.Client/Resources/SharedResources.resx | 3 + Oqtane.Client/UI/SiteRouter.razor | 94 ++++-- Oqtane.Server/Controllers/ModuleController.cs | 4 +- Oqtane.Server/Controllers/SiteController.cs | 93 ++++-- .../05010001_AddPageEffectiveExpiryDate.cs | 32 +++ ...010002_AddPageModuleEffectiveExpiryDate.cs | 32 +++ Oqtane.Shared/Models/Module.cs | 8 +- Oqtane.Shared/Models/Page.cs | 8 + Oqtane.Shared/Models/PageModule.cs | 9 +- 16 files changed, 571 insertions(+), 182 deletions(-) create mode 100644 Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs create mode 100644 Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index 7f4f35f1..225a6e72 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -48,6 +48,18 @@
+
+ +
+ +
+
+
+ +
+ +
+
@@ -114,7 +126,7 @@ -@code { + @code { public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; public override string Title => "Module Settings"; @@ -141,7 +153,8 @@ private DateTime createdon; private string modifiedby; private DateTime modifiedon; - + private DateTime? _effectivedate = null; + private DateTime? _expirydate = null; protected override void OnInitialized() { _module = ModuleState.ModuleDefinition.Name; @@ -156,6 +169,8 @@ createdon = ModuleState.CreatedOn; modifiedby = ModuleState.ModifiedBy; modifiedon = ModuleState.ModifiedOn; + _effectivedate = ModuleState.EffectiveDate; + _expirydate = ModuleState.ExpiryDate; if (ModuleState.ModuleDefinition != null) { @@ -214,12 +229,20 @@ var interop = new Interop(JSRuntime); if (await interop.FormValid(form)) { + if (!string.IsNullOrEmpty(_title)) { + if (!ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) + { + AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); + return; + } var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId); pagemodule.PageId = int.Parse(_pageId); pagemodule.Title = _title; pagemodule.Pane = _pane; + pagemodule.EffectiveDate = _effectivedate; + pagemodule.ExpiryDate = _expirydate; pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty; if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType) { @@ -269,5 +292,33 @@ AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning); } } + private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) + { + // Check if both dates are null, in which case the validation passes + if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + // Check if EffectiveDate is not null and ExpiryDate is null + if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is null and ExpiryDate is not null + if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) + { + return true; + } + + // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate + if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) + { + return false; + } + + // If none of the above conditions are met, validation passes + return true; + } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index 6e95fdf3..c03a7e0a 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -119,6 +119,18 @@
+
+ +
+ +
+
+
+ +
+ +
+
@@ -233,6 +245,8 @@ protected Page _parent = null; protected Dictionary _icons; private string _iconresources = ""; + private DateTime? _effectivedate = null; + private DateTime? _expirydate = null; protected override async Task OnInitializedAsync() { @@ -265,6 +279,8 @@ _children.Add(p); } } + _effectivedate = PageState.Page.EffectiveDate; + _expirydate = PageState.Page.ExpiryDate; ThemeSettings(); _initialized = true; } @@ -274,18 +290,18 @@ AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error); } } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Page {Error}", ex.Message); - AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error); - } - } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Page {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error); + } + } - private async void ParentChanged(ChangeEventArgs e) - { - try - { - _parentid = (string)e.Value; + private async void ParentChanged(ChangeEventArgs e) + { + try + { + _parentid = (string)e.Value; _children = new List(); foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid)))) { @@ -295,13 +311,13 @@ } } StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message); - AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error); - } - } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message); + AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error); + } + } private void ThemeChanged(ChangeEventArgs e) { @@ -318,109 +334,116 @@ } } - private void ThemeSettings() - { - _themeSettingsType = null; + private void ThemeSettings() + { + _themeSettingsType = null; var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype))); - if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType)) - { - _themeSettingsType = Type.GetType(theme.ThemeSettingsType); - if (_themeSettingsType != null) - { - ThemeSettingsComponent = builder => - { - builder.OpenComponent(0, _themeSettingsType); - builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); }); - builder.CloseComponent(); - }; - } - _refresh = true; - } - } + if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType)) + { + _themeSettingsType = Type.GetType(theme.ThemeSettingsType); + if (_themeSettingsType != null) + { + ThemeSettingsComponent = builder => + { + builder.OpenComponent(0, _themeSettingsType); + builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); }); + builder.CloseComponent(); + }; + } + _refresh = true; + } + } - private async Task SavePage() - { - validated = true; - var interop = new Interop(JSRuntime); - if (await interop.FormValid(form)) - { - Page page = null; - try - { + private async Task SavePage() + { + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(form)) + { + Page page = null; + try + { + if (!ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) + { + AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); + return; + } if (!string.IsNullOrEmpty(_themetype) && !string.IsNullOrEmpty(_containertype)) - { - page = new Page(); - page.SiteId = PageState.Page.SiteId; - page.Name = _name; + { + page = new Page(); + page.SiteId = PageState.Page.SiteId; + page.Name = _name; - if (string.IsNullOrEmpty(_path)) - { - _path = _name; - } - if (_path.Contains("/")) - { - if (_path.EndsWith("/") && _path != "/") - { - _path = _path.Substring(0, _path.Length - 1); - } - _path = _path.Substring(_path.LastIndexOf("/") + 1); - } + if (string.IsNullOrEmpty(_path)) + { + _path = _name; + } + if (_path.Contains("/")) + { + if (_path.EndsWith("/") && _path != "/") + { + _path = _path.Substring(0, _path.Length - 1); + } + _path = _path.Substring(_path.LastIndexOf("/") + 1); + } - if (_parentid == "-1") - { - page.ParentId = null; - page.Path = Utilities.GetFriendlyUrl(_path); - } - else - { - page.ParentId = Int32.Parse(_parentid); - var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault(); - if (parent.Path == string.Empty) - { - page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); - } - else - { - page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path); - } - } + if (_parentid == "-1") + { + page.ParentId = null; + page.Path = Utilities.GetFriendlyUrl(_path); + } + else + { + page.ParentId = Int32.Parse(_parentid); + var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault(); + 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); - if (_pages.Any(item => item.Path == page.Path)) - { - AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning); - return; - } + var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); + if (_pages.Any(item => item.Path == page.Path)) + { + AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning); + return; + } - if (page.ParentId == null && Constants.ReservedRoutes.Contains(page.Name.ToLower())) - { - AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], page.Name), MessageType.Warning); - return; - } + if (page.ParentId == null && Constants.ReservedRoutes.Contains(page.Name.ToLower())) + { + AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], page.Name), MessageType.Warning); + return; + } - Page child; - switch (_insert) - { - case "<<": - page.Order = 0; - break; - case "<": - child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); - page.Order = child.Order - 1; - break; - case ">": - child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); - page.Order = child.Order + 1; - break; - case ">>": - page.Order = int.MaxValue; - break; - } + Page child; + switch (_insert) + { + case "<<": + page.Order = 0; + break; + case "<": + child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); + page.Order = child.Order - 1; + break; + case ">": + child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); + page.Order = child.Order + 1; + break; + case ">>": + page.Order = int.MaxValue; + break; + } - page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation)); - page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); + page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation)); + page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); page.Url = _url; page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable)); + page.EffectiveDate = _effectivedate; + page.ExpiryDate = _expirydate; page.UserId = null; // appearance @@ -490,4 +513,33 @@ { _icon = NewIcon; } + private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) + { + // Check if both dates are null, in which case the validation passes + if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is not null and ExpiryDate is null + if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is null and ExpiryDate is not null + if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) + { + return true; + } + + // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate + if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) + { + return false; + } + + // If none of the above conditions are met, validation passes + return true; + } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 222d0119..3b64188b 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -134,6 +134,18 @@
+
+ +
+ +
+
+
+ +
+ +
+
@@ -322,6 +334,8 @@ protected Page _parent = null; protected Dictionary _icons; private string _iconresources = ""; + private DateTime? _effectivedate = null; + private DateTime? _expirydate = null; protected override async Task OnInitializedAsync() { @@ -370,6 +384,8 @@ } _url = _page.Url; _icon = _page.Icon; + _effectivedate = _page.EffectiveDate; + _expirydate = _page.ExpiryDate; _ispersonalizable = _page.IsPersonalizable.ToString(); // appearance @@ -487,6 +503,11 @@ { try { + if (!ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) + { + AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); + return; + } if (!string.IsNullOrEmpty(_themetype) && _containertype != "-") { string currentPath = _page.Path; @@ -563,6 +584,8 @@ _page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); _page.Url = _url; _page.Icon = _icon ?? string.Empty; + _page.EffectiveDate = _effectivedate; + _page.ExpiryDate = _expirydate; _page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable)); // appearance @@ -666,4 +689,33 @@ { _icon = NewIcon; } + private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) + { + // Check if both dates are null, in which case the validation passes + if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is not null and ExpiryDate is null + if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is null and ExpiryDate is not null + if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) + { + return true; + } + + // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate + if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) + { + return false; + } + + // If none of the above conditions are met, validation passes + return true; + } } diff --git a/Oqtane.Client/Modules/Admin/Users/Roles.razor b/Oqtane.Client/Modules/Admin/Users/Roles.razor index 8766c46a..990aea43 100644 --- a/Oqtane.Client/Modules/Admin/Users/Roles.razor +++ b/Oqtane.Client/Modules/Admin/Users/Roles.razor @@ -34,13 +34,13 @@ else
- +
- +
@@ -75,8 +75,8 @@ else private string name = string.Empty; private List roles; private int roleid = -1; - private DateTime? effectivedate = null; - private DateTime? expirydate = null; + private DateTime? _effectivedate = null; + private DateTime? _expirydate = null; private List userroles; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; @@ -92,7 +92,7 @@ else if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { roles = await RoleService.GetRolesAsync(PageState.Site.SiteId, true); - roles.RemoveAll(item => item.Name == RoleNames.Everyone || item.Name == RoleNames.Unauthenticated); + roles.RemoveAll(item => item.Name == RoleNames.Everyone || item.Name == RoleNames.Unauthenticated); } else { @@ -127,11 +127,16 @@ else { if (roleid != -1) { + if (!ValidateEffectiveExpiryDates(_effectivedate,_expirydate)) + { + AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); + return; + } var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault(); if (userrole != null) { - userrole.EffectiveDate = effectivedate; - userrole.ExpiryDate = expirydate; + userrole.EffectiveDate = _effectivedate; + userrole.ExpiryDate = _expirydate; await UserRoleService.UpdateUserRoleAsync(userrole); } else @@ -139,15 +144,15 @@ else userrole = new UserRole(); userrole.UserId = userid; userrole.RoleId = roleid; - userrole.EffectiveDate = effectivedate; - userrole.ExpiryDate = expirydate; + userrole.EffectiveDate = _effectivedate; + userrole.ExpiryDate = _expirydate; await UserRoleService.AddUserRoleAsync(userrole); } await logger.LogInformation("User Assigned To Role {UserRole}", userrole); AddModuleMessage(Localizer["Success.User.AssignRole"], MessageType.Success); await GetUserRoles(); - StateHasChanged(); + StateHasChanged(); } else { @@ -177,4 +182,34 @@ else AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error); } } + + private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) + { + // Check if both dates are null, in which case the validation passes + if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is not null and ExpiryDate is null + if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is null and ExpiryDate is not null + if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) + { + return true; + } + + // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate + if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) + { + return false; + } + + // If none of the above conditions are met, validation passes + return true; + } } diff --git a/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx b/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx index 5b7849ec..722fa2f1 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx @@ -165,4 +165,16 @@ Pane: + + The date that this module is active + + + Effective Date: + + + The date that this module expires + + + Expiry Date: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx index 62972b72..9ebed89a 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Pages/Add.resx @@ -255,4 +255,16 @@ Theme Settings + + The date that this page is active + + + Effective Date: + + + The date that this page expires + + + Expiry Date: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx index 984e6461..478e7616 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Pages/Edit.resx @@ -285,4 +285,16 @@ Please Note That Overriding The Default Site Theme With An Unrelated Page Theme May Result In Compatibility Issues For Your Site + + The date that this page is active + + + Effective Date: + + + The date that this page expires + + + Expiry Date: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/SharedResources.resx b/Oqtane.Client/Resources/SharedResources.resx index b00c7ce9..6152a066 100644 --- a/Oqtane.Client/Resources/SharedResources.resx +++ b/Oqtane.Client/Resources/SharedResources.resx @@ -438,4 +438,7 @@ Test + + Effective Date cannot be after Expiry Date. + \ No newline at end of file diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 51877aa0..51805407 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -258,42 +258,51 @@ } } } + + bool isAdminOrHost = false; + if(user != null) + { + isAdminOrHost = user.Roles.Contains(RoleNames.Host) || user.Roles.Contains(RoleNames.Admin); + } - if (page != null) + if (page != null && (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate))) { // check if user is authorized to view page if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) { - // 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); - - // populate page state (which acts as a client-side cache for subsequent requests) - _pagestate = new PageState + if (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) { - 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, - Runtime = runtime, - VisitorId = VisitorId, - RemoteIPAddress = SiteState.RemoteIPAddress, - ReturnUrl = returnurl, - IsInternalNavigation = _isInternalNavigation - }; + // load additional metadata for current page + page = ProcessPage(page, site, user, SiteState.Alias); - OnStateChange?.Invoke(_pagestate); - await ScrollToFragment(_pagestate.Uri); + // 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, + Runtime = runtime, + VisitorId = VisitorId, + RemoteIPAddress = SiteState.RemoteIPAddress, + ReturnUrl = returnurl, + IsInternalNavigation = _isInternalNavigation + }; + + OnStateChange?.Invoke(_pagestate); + await ScrollToFragment(_pagestate.Uri); + } } } else // page not found @@ -307,7 +316,7 @@ } else // not mapped { - if (user == null) + if (user == null && IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) { // 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))); @@ -578,4 +587,29 @@ } } } + private bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate) + { + DateTime currentUtcTime = DateTime.UtcNow; + + // Check if either effectiveDate or expiryDate is provided + if (effectiveDate.HasValue && expiryDate.HasValue) + { + return currentUtcTime >= effectiveDate.Value && currentUtcTime <= expiryDate.Value; + } + // Check if only effectiveDate is provided + else if (effectiveDate.HasValue) + { + return currentUtcTime >= effectiveDate.Value; + } + // Check if only expiryDate is provided + else if (expiryDate.HasValue) + { + return currentUtcTime <= expiryDate.Value; + } + // If neither effectiveDate nor expiryDate is provided, consider the page/module visible + else + { + return true; + } + } } diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index f8172db1..8acde463 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -75,6 +75,8 @@ namespace Oqtane.Controllers module.Pane = pagemodule.Pane; module.Order = pagemodule.Order; module.ContainerType = pagemodule.ContainerType; + module.EffectiveDate = pagemodule.EffectiveDate; + module.ExpiryDate = pagemodule.ExpiryDate; module.ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName)); @@ -169,7 +171,7 @@ namespace Oqtane.Controllers { if (!pageModules.Exists(item => item.ModuleId == module.ModuleId && item.PageId == page.PageId) && !page.Path.StartsWith("admin/")) { - _pageModules.AddPageModule(new PageModule { PageId = page.PageId, ModuleId = pageModule.ModuleId, Title = pageModule.Title, Pane = pageModule.Pane, Order = pageModule.Order, ContainerType = pageModule.ContainerType }); + _pageModules.AddPageModule(new PageModule { PageId = page.PageId, ModuleId = pageModule.ModuleId, Title = pageModule.Title, Pane = pageModule.Pane, Order = pageModule.Order, ContainerType = pageModule.ContainerType, EffectiveDate = pageModule.EffectiveDate, ExpiryDate = pageModule.ExpiryDate }); } } } diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 4d1b7184..3092297d 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -13,6 +13,8 @@ using System.Globalization; using Microsoft.Extensions.Caching.Memory; using Oqtane.Extensions; using System; +using Oqtane.UI; +using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Oqtane.Controllers { @@ -92,59 +94,71 @@ namespace Oqtane.Controllers site.UploadableFiles = site.Settings.ContainsKey("UploadableFiles") && !string.IsNullOrEmpty(site.Settings["UploadableFiles"]) ? site.Settings["UploadableFiles"] : Constants.UploadableFiles; + var modelsUser = _userPermissions.GetUser(User); + var isAdminOrHost = modelsUser.Roles.Contains(RoleNames.Host) || modelsUser.Roles.Contains(RoleNames.Admin); + // pages List settings = _settings.GetSettings(EntityNames.Page).ToList(); site.Pages = new List(); - foreach (Page page in _pages.GetPages(site.SiteId)) + foreach (Page page in _pages.GetPages(site.SiteId).Where(p => !p.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, p.PermissionList))) { - if (!page.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, page.PermissionList)) + if (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) { - page.Settings = settings.Where(item => item.EntityId == page.PageId) + 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)) + foreach (PageModule pagemodule in _pageModules.GetPageModules(site.SiteId).Where(pm => !pm.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, pm.Module.PermissionList))) { - if (!pagemodule.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.PermissionList)) + if (isAdminOrHost || IsPageModuleVisible(pagemodule.EffectiveDate, pagemodule.ExpiryDate)) { - Module module = new Module(); - module.SiteId = pagemodule.Module.SiteId; - module.ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName; - module.AllPages = pagemodule.Module.AllPages; - module.PermissionList = pagemodule.Module.PermissionList; - module.CreatedBy = pagemodule.Module.CreatedBy; - module.CreatedOn = pagemodule.Module.CreatedOn; - module.ModifiedBy = pagemodule.Module.ModifiedBy; - module.ModifiedOn = pagemodule.Module.ModifiedOn; - module.DeletedBy = pagemodule.DeletedBy; - module.DeletedOn = pagemodule.DeletedOn; - module.IsDeleted = pagemodule.IsDeleted; + 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, - module.PageModuleId = pagemodule.PageModuleId; - module.ModuleId = pagemodule.ModuleId; - module.PageId = pagemodule.PageId; - module.Title = pagemodule.Title; - module.Pane = pagemodule.Pane; - module.Order = pagemodule.Order; - module.ContainerType = pagemodule.ContainerType; + 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, - module.ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName)); + ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == pagemodule.Module.ModuleDefinitionName)), - module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId) + 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); + .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 @@ -277,5 +291,30 @@ namespace Oqtane.Controllers } return hierarchy; } + private bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate) + { + DateTime currentUtcTime = DateTime.UtcNow; + + // Check if either effectiveDate or expiryDate is provided + if (effectiveDate.HasValue && expiryDate.HasValue) + { + return currentUtcTime >= effectiveDate.Value && currentUtcTime <= expiryDate.Value; + } + // Check if only effectiveDate is provided + else if (effectiveDate.HasValue) + { + return currentUtcTime >= effectiveDate.Value; + } + // Check if only expiryDate is provided + else if (expiryDate.HasValue) + { + return currentUtcTime <= expiryDate.Value; + } + // If neither effectiveDate nor expiryDate is provided, consider the page/module visible + else + { + return true; + } + } } } diff --git a/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs b/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs new file mode 100644 index 00000000..bed22cd2 --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/05010001_AddPageEffectiveExpiryDate.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.05.01.00.01")] + public class AddPageEffectiveExpiryDate : MultiDatabaseMigration + { + public AddPageEffectiveExpiryDate(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);; + pageEntityBuilder.AddDateTimeColumn("EffectiveDate", true); + pageEntityBuilder.AddDateTimeColumn("ExpiryDate", true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); + pageEntityBuilder.DropColumn("EffectiveDate"); + pageEntityBuilder.DropColumn("ExpiryDate"); + } + } +} diff --git a/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs b/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs new file mode 100644 index 00000000..f0b9147d --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/05010002_AddPageModuleEffectiveExpiryDate.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.05.01.00.02")] + public class AddPageModuleEffectiveExpiryDate : MultiDatabaseMigration + { + public AddPageModuleEffectiveExpiryDate(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);; + pageModuleEntityBuilder.AddDateTimeColumn("EffectiveDate", true); + pageModuleEntityBuilder.AddDateTimeColumn("ExpiryDate", true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase); + pageModuleEntityBuilder.DropColumn("EffectiveDate"); + pageModuleEntityBuilder.DropColumn("ExpiryDate"); + } + } +} diff --git a/Oqtane.Shared/Models/Module.cs b/Oqtane.Shared/Models/Module.cs index 07c2a507..5d03c405 100644 --- a/Oqtane.Shared/Models/Module.cs +++ b/Oqtane.Shared/Models/Module.cs @@ -75,10 +75,16 @@ namespace Oqtane.Models [NotMapped] public string ContainerType { get; set; } + [NotMapped] + public DateTime? EffectiveDate { get; set; } + + [NotMapped] + public DateTime? ExpiryDate { get; set; } + #endregion #region SiteRouter properties - + [NotMapped] public string ModuleType { get; set; } [NotMapped] diff --git a/Oqtane.Shared/Models/Page.cs b/Oqtane.Shared/Models/Page.cs index c4c74a9a..a1b6d370 100644 --- a/Oqtane.Shared/Models/Page.cs +++ b/Oqtane.Shared/Models/Page.cs @@ -82,6 +82,14 @@ namespace Oqtane.Models public bool IsNavigation { get; set; } public bool IsClickable { get; set; } public int? UserId { get; set; } + /// + /// Start of when this assignment is valid. See also + /// + public DateTime? EffectiveDate { get; set; } + /// + /// End of when this assignment is valid. See also + /// + public DateTime? ExpiryDate { get; set; } public bool IsPersonalizable { get; set; } #region IDeletable Properties diff --git a/Oqtane.Shared/Models/PageModule.cs b/Oqtane.Shared/Models/PageModule.cs index e8ff50e5..e3f0adb9 100644 --- a/Oqtane.Shared/Models/PageModule.cs +++ b/Oqtane.Shared/Models/PageModule.cs @@ -41,7 +41,14 @@ namespace Oqtane.Models /// Reference to a Razor Container which wraps this module instance. /// public string ContainerType { get; set; } - + /// + /// Start of when this assignment is valid. See also + /// + public DateTime? EffectiveDate { get; set; } + /// + /// End of when this assignment is valid. See also + /// + public DateTime? ExpiryDate { get; set; } #region IDeletable Properties public string DeletedBy { get; set; } From 5ce51934304ee77e3f4a73f176104cebf9e6e159 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Tue, 2 Jan 2024 16:09:54 +0100 Subject: [PATCH 14/99] Modifications --- .../Modules/Admin/Modules/Settings.razor | 39 +++--------------- Oqtane.Client/Modules/Admin/Pages/Add.razor | 39 +++--------------- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 39 +++--------------- Oqtane.Client/Modules/Admin/Users/Roles.razor | 41 +++---------------- Oqtane.Client/UI/SiteRouter.razor | 4 +- Oqtane.Server/Controllers/SiteController.cs | 38 ++--------------- Oqtane.Shared/Shared/Utilities.cs | 28 +++++++++++++ 7 files changed, 55 insertions(+), 173 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index 225a6e72..b1ed379a 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -169,8 +169,8 @@ createdon = ModuleState.CreatedOn; modifiedby = ModuleState.ModifiedBy; modifiedon = ModuleState.ModifiedOn; - _effectivedate = ModuleState.EffectiveDate; - _expirydate = ModuleState.ExpiryDate; + _effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate); + _expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate); if (ModuleState.ModuleDefinition != null) { @@ -232,7 +232,7 @@ if (!string.IsNullOrEmpty(_title)) { - if (!ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) + if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) { AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); return; @@ -241,8 +241,8 @@ pagemodule.PageId = int.Parse(_pageId); pagemodule.Title = _title; pagemodule.Pane = _pane; - pagemodule.EffectiveDate = _effectivedate; - pagemodule.ExpiryDate = _expirydate; + pagemodule.EffectiveDate = Utilities.LocalDateAndTimeAsUtc(_effectivedate); + pagemodule.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate); pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty; if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType) { @@ -292,33 +292,4 @@ AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning); } } - private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) - { - // Check if both dates are null, in which case the validation passes - if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is not null and ExpiryDate is null - if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is null and ExpiryDate is not null - if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) - { - return true; - } - - // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate - if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) - { - return false; - } - - // If none of the above conditions are met, validation passes - return true; - } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index c03a7e0a..05a97d7a 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -279,8 +279,8 @@ _children.Add(p); } } - _effectivedate = PageState.Page.EffectiveDate; - _expirydate = PageState.Page.ExpiryDate; + _effectivedate = Utilities.UtcAsLocalDate(PageState.Page.EffectiveDate); + _expirydate = Utilities.UtcAsLocalDate(PageState.Page.ExpiryDate); ThemeSettings(); _initialized = true; } @@ -363,7 +363,7 @@ Page page = null; try { - if (!ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) + if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) { AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); return; @@ -442,8 +442,8 @@ page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); page.Url = _url; page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable)); - page.EffectiveDate = _effectivedate; - page.ExpiryDate = _expirydate; + page.EffectiveDate = Utilities.LocalDateAndTimeAsUtc(_effectivedate); + page.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate); page.UserId = null; // appearance @@ -513,33 +513,4 @@ { _icon = NewIcon; } - private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) - { - // Check if both dates are null, in which case the validation passes - if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is not null and ExpiryDate is null - if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is null and ExpiryDate is not null - if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) - { - return true; - } - - // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate - if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) - { - return false; - } - - // If none of the above conditions are met, validation passes - return true; - } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 3b64188b..3084ef84 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -384,8 +384,8 @@ } _url = _page.Url; _icon = _page.Icon; - _effectivedate = _page.EffectiveDate; - _expirydate = _page.ExpiryDate; + _effectivedate = Utilities.UtcAsLocalDate(_page.EffectiveDate); + _expirydate = Utilities.UtcAsLocalDate(_page.ExpiryDate); _ispersonalizable = _page.IsPersonalizable.ToString(); // appearance @@ -503,7 +503,7 @@ { try { - if (!ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) + if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) { AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); return; @@ -584,8 +584,8 @@ _page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable)); _page.Url = _url; _page.Icon = _icon ?? string.Empty; - _page.EffectiveDate = _effectivedate; - _page.ExpiryDate = _expirydate; + _page.EffectiveDate = Utilities.LocalDateAndTimeAsUtc(_effectivedate); + _page.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate); _page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable)); // appearance @@ -689,33 +689,4 @@ { _icon = NewIcon; } - private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) - { - // Check if both dates are null, in which case the validation passes - if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is not null and ExpiryDate is null - if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is null and ExpiryDate is not null - if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) - { - return true; - } - - // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate - if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) - { - return false; - } - - // If none of the above conditions are met, validation passes - return true; - } } diff --git a/Oqtane.Client/Modules/Admin/Users/Roles.razor b/Oqtane.Client/Modules/Admin/Users/Roles.razor index 990aea43..8d65480a 100644 --- a/Oqtane.Client/Modules/Admin/Users/Roles.razor +++ b/Oqtane.Client/Modules/Admin/Users/Roles.razor @@ -60,8 +60,8 @@ else @context.Role.Name - @context.EffectiveDate - @context.ExpiryDate + @Utilities.UtcAsLocalDate(context.EffectiveDate) + @Utilities.UtcAsLocalDate(context.ExpiryDate) @@ -113,6 +113,7 @@ else try { userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, userid); + } catch (Exception ex) { @@ -127,7 +128,7 @@ else { if (roleid != -1) { - if (!ValidateEffectiveExpiryDates(_effectivedate,_expirydate)) + if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate)) { AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning); return; @@ -144,8 +145,8 @@ else userrole = new UserRole(); userrole.UserId = userid; userrole.RoleId = roleid; - userrole.EffectiveDate = _effectivedate; - userrole.ExpiryDate = _expirydate; + userrole.EffectiveDate = Utilities.UtcAsLocalDate(_effectivedate); + userrole.ExpiryDate = Utilities.UtcAsLocalDate(_expirydate); await UserRoleService.AddUserRoleAsync(userrole); } @@ -182,34 +183,4 @@ else AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error); } } - - private bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) - { - // Check if both dates are null, in which case the validation passes - if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is not null and ExpiryDate is null - if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) - { - return true; - } - - // Check if EffectiveDate is null and ExpiryDate is not null - if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) - { - return true; - } - - // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate - if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) - { - return false; - } - - // If none of the above conditions are met, validation passes - return true; - } } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 51805407..be5b6ac7 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -262,7 +262,7 @@ bool isAdminOrHost = false; if(user != null) { - isAdminOrHost = user.Roles.Contains(RoleNames.Host) || user.Roles.Contains(RoleNames.Admin); + isAdminOrHost = UserSecurity.IsAuthorized(user, RoleNames.Admin) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList); } if (page != null && (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate))) @@ -270,7 +270,7 @@ // check if user is authorized to view page if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) { - if (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) + if (isAdminOrHost || Utilities.ValidateEffectiveExpiryDates(page.EffectiveDate, page.ExpiryDate)) { // load additional metadata for current page page = ProcessPage(page, site, user, SiteState.Alias); diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 3092297d..67d2a84e 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -94,21 +94,16 @@ namespace Oqtane.Controllers site.UploadableFiles = site.Settings.ContainsKey("UploadableFiles") && !string.IsNullOrEmpty(site.Settings["UploadableFiles"]) ? site.Settings["UploadableFiles"] : Constants.UploadableFiles; - var modelsUser = _userPermissions.GetUser(User); - var isAdminOrHost = modelsUser.Roles.Contains(RoleNames.Host) || modelsUser.Roles.Contains(RoleNames.Admin); - // pages List settings = _settings.GetSettings(EntityNames.Page).ToList(); site.Pages = new List(); - foreach (Page page in _pages.GetPages(site.SiteId).Where(p => !p.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, p.PermissionList))) + foreach (Page page in _pages.GetPages(site.SiteId)) { - if (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) + if (!page.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, page.PermissionList)) { - page.Settings = settings - .Where(item => item.EntityId == page.PageId) + 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); } } @@ -121,7 +116,7 @@ namespace Oqtane.Controllers 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 (isAdminOrHost || IsPageModuleVisible(pagemodule.EffectiveDate, pagemodule.ExpiryDate)) + if (!pagemodule.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.PermissionList)) { Module module = new Module { @@ -291,30 +286,5 @@ namespace Oqtane.Controllers } return hierarchy; } - private bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate) - { - DateTime currentUtcTime = DateTime.UtcNow; - - // Check if either effectiveDate or expiryDate is provided - if (effectiveDate.HasValue && expiryDate.HasValue) - { - return currentUtcTime >= effectiveDate.Value && currentUtcTime <= expiryDate.Value; - } - // Check if only effectiveDate is provided - else if (effectiveDate.HasValue) - { - return currentUtcTime >= effectiveDate.Value; - } - // Check if only expiryDate is provided - else if (expiryDate.HasValue) - { - return currentUtcTime <= expiryDate.Value; - } - // If neither effectiveDate nor expiryDate is provided, consider the page/module visible - else - { - return true; - } - } } } diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 82b32796..044abc2e 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -572,7 +572,35 @@ namespace Oqtane.Shared return (localDateTime?.Date, localTime); } + public static bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) + { + // Check if both dates are null, in which case the validation passes + if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + // Check if EffectiveDate is not null and ExpiryDate is null + if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) + { + return true; + } + + // Check if EffectiveDate is null and ExpiryDate is not null + if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) + { + return true; + } + + // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate + if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) + { + return false; + } + + // If none of the above conditions are met, validation passes + return true; + } [Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)] public static string ContentUrl(Alias alias, int fileId) { From d35ef2d3606765e696a1926e8e39dc3724e55379 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 2 Jan 2024 15:25:07 -0500 Subject: [PATCH 15/99] synchronize static assets with .NET MAUI project --- Oqtane.Maui/wwwroot/css/app.css | 15 ++++ Oqtane.Maui/wwwroot/js/interop.js | 131 ++++++++++++++++-------------- 2 files changed, 83 insertions(+), 63 deletions(-) diff --git a/Oqtane.Maui/wwwroot/css/app.css b/Oqtane.Maui/wwwroot/css/app.css index 5da25ceb..c1d0b44b 100644 --- a/Oqtane.Maui/wwwroot/css/app.css +++ b/Oqtane.Maui/wwwroot/css/app.css @@ -213,3 +213,18 @@ app { right: 0.75rem; top: 0.5rem; } + +/* Oqtane Control Styles */ + +/* Pager */ +.app-pager-pointer { + cursor: pointer; +} + +.app-sort-th { + cursor: pointer; +} + +.app-fas { + margin-left: 5px; +} diff --git a/Oqtane.Maui/wwwroot/js/interop.js b/Oqtane.Maui/wwwroot/js/interop.js index 8a677952..7daf41c1 100644 --- a/Oqtane.Maui/wwwroot/js/interop.js +++ b/Oqtane.Maui/wwwroot/js/interop.js @@ -27,14 +27,8 @@ Oqtane.Interop = { document.title = title; } }, - includeMeta: function (id, attribute, name, content, key) { - var meta; - if (id !== "" && key === "id") { - meta = document.getElementById(id); - } - else { - meta = document.querySelector("meta[" + attribute + "=\"" + CSS.escape(name) + "\"]"); - } + includeMeta: function (id, attribute, name, content) { + var meta = document.querySelector("meta[" + attribute + "=\"" + CSS.escape(name) + "\"]"); if (meta === null) { meta = document.createElement("meta"); meta.setAttribute(attribute, name); @@ -119,13 +113,26 @@ Oqtane.Interop = { this.includeLink(links[i].id, links[i].rel, links[i].href, links[i].type, links[i].integrity, links[i].crossorigin, links[i].insertbefore); } }, - includeScript: function (id, src, integrity, crossorigin, content, location) { - var script = document.querySelector("script[src=\"" + CSS.escape(src) + "\"]"); + includeScript: function (id, src, integrity, crossorigin, type, content, location) { + var script; + if (src !== "") { + script = document.querySelector("script[src=\"" + CSS.escape(src) + "\"]"); + } + else { + script = document.getElementById(id); + } + if (script !== null) { + script.remove(); + script = null; + } if (script === null) { script = document.createElement("script"); if (id !== "") { script.id = id; } + if (type !== "") { + script.type = type; + } if (src !== "") { script.src = src; if (integrity !== "") { @@ -141,43 +148,22 @@ Oqtane.Interop = { script.async = false; this.addScript(script, location) .then(() => { - console.log(src + ' loaded'); + if (src !== "") { + console.log(src + ' loaded'); + } + else { + console.log(id + ' loaded'); + } }) .catch(() => { - console.error(src + ' failed'); + if (src !== "") { + console.error(src + ' failed'); + } + else { + console.error(id + ' failed'); + } }); } - else { - if (script.id !== id) { - script.setAttribute('id', id); - } - if (src !== "") { - if (script.src !== this.getAbsoluteUrl(src)) { - script.removeAttribute('integrity'); - script.removeAttribute('crossorigin'); - script.src = src; - } - if (integrity !== "") { - if (script.integrity !== integrity) { - script.setAttribute('integrity', integrity); - } - } else { - script.removeAttribute('integrity'); - } - if (crossorigin !== "") { - if (script.crossOrigin !== crossorigin) { - script.setAttribute('crossorigin', crossorigin); - } - } else { - script.removeAttribute('crossorigin'); - } - } - else { - if (script.innerHTML !== content) { - script.innerHTML = content; - } - } - } }, addScript: function (script, location) { if (location === 'head') { @@ -229,6 +215,10 @@ Oqtane.Interop = { 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 + } } } }) @@ -289,19 +279,21 @@ Oqtane.Interop = { var fileinput = document.getElementById(id); if (fileinput !== null) { for (var i = 0; i < fileinput.files.length; i++) { - files.push(fileinput.files[i].name); + files.push(fileinput.files[i].name + ":" + fileinput.files[i].size); } } return files; }, uploadFiles: function (posturl, folder, id, antiforgerytoken) { - var fileinput = document.getElementById(id + 'FileInput'); + var fileinput = document.getElementById('FileInput_' + id); var files = fileinput.files; - var progressinfo = document.getElementById(id + 'ProgressInfo'); - var progressbar = document.getElementById(id + 'ProgressBar'); + var progressinfo = document.getElementById('ProgressInfo_' + id); + var progressbar = document.getElementById('ProgressBar_' + id); - progressinfo.setAttribute("style", "display: inline;"); - progressbar.setAttribute("style", "width: 200px; display: inline;"); + if (progressinfo !== null && progressbar !== null) { + progressinfo.setAttribute("style", "display: inline;"); + progressbar.setAttribute("style", "width: 100%; display: inline;"); + } for (var i = 0; i < files.length; i++) { var FileChunk = []; @@ -332,21 +324,29 @@ Oqtane.Interop = { var request = new XMLHttpRequest(); request.open('POST', posturl, true); request.upload.onloadstart = function (e) { - progressinfo.innerHTML = file.name + ' 0%'; - progressbar.value = 0; + if (progressinfo !== null && progressbar !== null) { + progressinfo.innerHTML = file.name + ' 0%'; + progressbar.value = 0; + } }; request.upload.onprogress = function (e) { - var percent = Math.ceil((e.loaded / e.total) * 100); - progressinfo.innerHTML = file.name + '[' + PartCount + '] ' + percent + '%'; - progressbar.value = (percent / 100); + if (progressinfo !== null && progressbar !== null) { + var percent = Math.ceil((e.loaded / e.total) * 100); + progressinfo.innerHTML = file.name + '[' + PartCount + '] ' + percent + '%'; + progressbar.value = (percent / 100); + } }; request.upload.onloadend = function (e) { - progressinfo.innerHTML = file.name + ' 100%'; - progressbar.value = 1; + if (progressinfo !== null && progressbar !== null) { + progressinfo.innerHTML = file.name + ' 100%'; + progressbar.value = 1; + } }; - request.upload.onerror = function () { - progressinfo.innerHTML = file.name + ' Error: ' + xhr.status; - progressbar.value = 0; + request.upload.onerror = function() { + if (progressinfo !== null && progressbar !== null) { + progressinfo.innerHTML = file.name + ' Error: ' + xhr.status; + progressbar.value = 0; + } }; request.send(data); } @@ -356,10 +356,15 @@ Oqtane.Interop = { } } }, - refreshBrowser: function (reload, wait) { - setInterval(function () { - window.location.reload(reload); - }, wait * 1000); + refreshBrowser: function (verify, wait) { + async function attemptReload (verify) { + if (verify) { + await fetch(''); + } + window.location.reload(); + } + attemptReload(verify); + setInterval(attemptReload, wait * 1000); }, redirectBrowser: function (url, wait) { setInterval(function () { From 22e4e4efc1d92c38650204c237a85d1d2fe2860c Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Wed, 3 Jan 2024 12:12:27 +0100 Subject: [PATCH 16/99] Updates Loops tighter Updated Logout base SiteController corrected. --- .../Themes/Controls/Theme/LoginBase.cs | 3 +- Oqtane.Client/UI/SiteRouter.razor | 43 +++------------ Oqtane.Server/Controllers/SiteController.cs | 4 +- Oqtane.Shared/Shared/Utilities.cs | 54 +++++++++++++------ 4 files changed, 47 insertions(+), 57 deletions(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index f8f71ee9..4a61cb04 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -56,11 +56,12 @@ namespace Oqtane.Themes.Controls var url = route.PathAndQuery; // verify if anonymous users can access page - if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList)) + 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) { // hybrid apps utilize an interactive logout diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index be5b6ac7..db9e1563 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -258,20 +258,14 @@ } } } - - bool isAdminOrHost = false; - if(user != null) - { - isAdminOrHost = UserSecurity.IsAuthorized(user, RoleNames.Admin) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList); - } - if (page != null && (isAdminOrHost || IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate))) + if (page != null) { // check if user is authorized to view page - if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) + if ((Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)) || UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) { - if (isAdminOrHost || Utilities.ValidateEffectiveExpiryDates(page.EffectiveDate, page.ExpiryDate)) - { + // if (UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList) || Utilities.ValidateEffectiveExpiryDates(page.EffectiveDate, page.ExpiryDate)) + // { // load additional metadata for current page page = ProcessPage(page, site, user, SiteState.Alias); @@ -302,7 +296,7 @@ OnStateChange?.Invoke(_pagestate); await ScrollToFragment(_pagestate.Uri); - } + // } } } else // page not found @@ -316,7 +310,7 @@ } else // not mapped { - if (user == null && IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) + if (user == null && Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate)) { // 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))); @@ -587,29 +581,4 @@ } } } - private bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate) - { - DateTime currentUtcTime = DateTime.UtcNow; - - // Check if either effectiveDate or expiryDate is provided - if (effectiveDate.HasValue && expiryDate.HasValue) - { - return currentUtcTime >= effectiveDate.Value && currentUtcTime <= expiryDate.Value; - } - // Check if only effectiveDate is provided - else if (effectiveDate.HasValue) - { - return currentUtcTime >= effectiveDate.Value; - } - // Check if only expiryDate is provided - else if (expiryDate.HasValue) - { - return currentUtcTime <= expiryDate.Value; - } - // If neither effectiveDate nor expiryDate is provided, consider the page/module visible - else - { - return true; - } - } } diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 67d2a84e..df0384c1 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -99,7 +99,7 @@ namespace Oqtane.Controllers site.Pages = new List(); foreach (Page page in _pages.GetPages(site.SiteId)) { - if (!page.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, page.PermissionList)) + 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)) @@ -116,7 +116,7 @@ namespace Oqtane.Controllers 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 (!pagemodule.IsDeleted && _userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.PermissionList)) + if(Utilities.IsPageModuleVisible(pagemodule.EffectiveDate, pagemodule.ExpiryDate) || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList)) { Module module = new Module { diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 044abc2e..c00d8cc8 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -572,34 +572,54 @@ namespace Oqtane.Shared return (localDateTime?.Date, localTime); } + public static bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate) + { + DateTime currentUtcTime = DateTime.UtcNow; + + if (effectiveDate.HasValue && expiryDate.HasValue) + { + return currentUtcTime >= effectiveDate.Value && currentUtcTime <= expiryDate.Value; + } + else if (effectiveDate.HasValue) + { + return currentUtcTime >= effectiveDate.Value; + } + else if (expiryDate.HasValue) + { + // Include equality check here + return currentUtcTime <= expiryDate.Value; + } + else + { + return true; + } + } public static bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate) { - // Check if both dates are null, in which case the validation passes - if (effectiveDate == DateTime.MinValue && expiryDate == DateTime.MinValue) + // Treat DateTime.MinValue as null + effectiveDate ??= DateTime.MinValue; + expiryDate ??= DateTime.MinValue; + + // Check if both effectiveDate and expiryDate have values + if (effectiveDate != DateTime.MinValue && expiryDate != DateTime.MinValue) + { + return effectiveDate <= expiryDate; + } + // Check if only effectiveDate has a value + else if (effectiveDate != DateTime.MinValue) { return true; } - - // Check if EffectiveDate is not null and ExpiryDate is null - if (effectiveDate != DateTime.MinValue && expiryDate == DateTime.MinValue) + // Check if only expiryDate has a value + else if (expiryDate != DateTime.MinValue) { return true; } - - // Check if EffectiveDate is null and ExpiryDate is not null - if (effectiveDate == DateTime.MinValue && expiryDate != DateTime.MinValue) + // If neither effectiveDate nor expiryDate has a value, consider the page/module visible + else { return true; } - - // Check if ExpiryDate is not null and EffectiveDate is after ExpiryDate - if (expiryDate != DateTime.MinValue && effectiveDate != DateTime.MinValue && effectiveDate > expiryDate) - { - return false; - } - - // If none of the above conditions are met, validation passes - return true; } [Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)] public static string ContentUrl(Alias alias, int fileId) From 12a14fbe29d180d9cc151e42a3d6fd136621b742 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:25:13 -0800 Subject: [PATCH 17/99] Adds Marketplace Button --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fadaf2dd..9662e6bf 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ [![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) +[![Visit Marketplace](https://github.com/oqtane/oqtane.framework/blob/master/Oqtane.Server/wwwroot/icon.png)](https://www.oqtane.net/) + # Oqtane Framework ![Oqtane](https://github.com/oqtane/framework/blob/master/oqtane.png?raw=true "Oqtane") From 9237d68b79f73c4b6ecb630dfda4ba0da532a9f7 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:35:24 -0800 Subject: [PATCH 18/99] Update Marketplace Icon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9662e6bf..caa61eef 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![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) -[![Visit Marketplace](https://github.com/oqtane/oqtane.framework/blob/master/Oqtane.Server/wwwroot/icon.png)](https://www.oqtane.net/) +[![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) # Oqtane Framework From d8e414a4a20e410b19421ed276d5b7666e54ef00 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:45:43 -0800 Subject: [PATCH 19/99] Icon and Link for Oqtane Marketplace --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index caa61eef..33a9d2cc 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![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) [![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) +[Visit Marketplace](https://www.oqtane.net/) # Oqtane Framework From 683c3e96d672bd36f5e60596d03a57b489a2cbc8 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:47:13 -0800 Subject: [PATCH 20/99] Update Marketplace Message --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33a9d2cc..ce63955a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) -[Visit Marketplace](https://www.oqtane.net/) +[Visit the Oqtane Marketplace](https://www.oqtane.net/) # Oqtane Framework From 055d6bf601f4f7e5ed71bbbcdbf3f3f148d5498e Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:48:24 -0800 Subject: [PATCH 21/99] Adjust Marketplace Placement --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ce63955a..2e728218 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ [![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) -[![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) -[Visit the Oqtane Marketplace](https://www.oqtane.net/) +[Visit the Oqtane Marketplace](https://www.oqtane.net/)[![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) + # Oqtane Framework From ab1e56a14eed06e928e2fc67e9c069341e332b55 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:49:14 -0800 Subject: [PATCH 22/99] Updates Marketplace Message --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e728218..61f2d76a 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ [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. [![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) - -[Visit the Oqtane Marketplace](https://www.oqtane.net/)[![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) +[![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) +[Visit the Oqtane Marketplace](https://www.oqtane.net/) # Oqtane Framework From efe20a1fe81a979ad638e2f471bbef50da18ac64 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 3 Jan 2024 10:59:14 -0800 Subject: [PATCH 23/99] Adds Marketplace Section --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 61f2d76a..f74ef946 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ [![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) [![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) -[Visit the Oqtane Marketplace](https://www.oqtane.net/) - # Oqtane Framework @@ -42,6 +40,11 @@ Please note that this project is owned by the .NET Foundation and is governed by - If you are getting started with Oqtane, a [series of videos](https://www.youtube.com/watch?v=JPfUZPlRRCE&list=PLYhXmd7yV0elLNLfQwZBUlM7ZSMYPTZ_f) are available which explain how to install the product, interact with the user interface, and develop custom modules. +# Oqtane Marketplace + +Explore and enhance your Oqtane experience by visiting the Oqtane Marketplace. Discover a variety of modules, themes, and extensions contributed by the community. [Visit Oqtane Marketplace](https://www.oqtane.net) + + # Documentation There is a separate [Documentation repository](https://github.com/oqtane/oqtane.docs) which contains a variety of types of documentation for Oqtane, including API documentation that is auto generated using Docfx. The contents of the repository is published to Githib Pages and is available at [https://docs.oqtane.org](https://docs.oqtane.org/) From 3ead35c984c727496dc3b95e22f1bb9b022f0251 Mon Sep 17 00:00:00 2001 From: Jon Welfringer <7365166+W6HBR@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:12:17 -0800 Subject: [PATCH 24/99] Update (Profiles) Edit.razor to fix breaking changes Prior functionality allowed 4 characters for "order" which now causes validation errors for any order value > 99. This change allows a value of up to 9999 which is consistent with the prior 4 character length value. Prior functionality allowed 2 characters for "rows" which now causes validattion error for any row count > 10. This change allows a value up to 99 which is consistent with the prior 2 character length value. --- Oqtane.Client/Modules/Admin/Profiles/Edit.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor index 91fe98ec..84555328 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor @@ -34,7 +34,7 @@
- +
@@ -46,7 +46,7 @@
- +
From f75179b2f60224c88a78efa5daf57ec77a2032b7 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 4 Jan 2024 13:47:51 -0500 Subject: [PATCH 25/99] component rendering optimizations --- Oqtane.Client/Modules/HtmlText/Index.razor | 19 ++++++----- Oqtane.Client/UI/ContainerBuilder.razor | 26 +++++++-------- Oqtane.Client/UI/ModuleInstance.razor | 37 ++++++++++++---------- Oqtane.Client/UI/PageState.cs | 9 ++++-- Oqtane.Client/UI/Pane.razor | 11 ++++--- Oqtane.Client/UI/SiteRouter.razor | 1 + Oqtane.Shared/Models/Module.cs | 2 ++ 7 files changed, 61 insertions(+), 44 deletions(-) diff --git a/Oqtane.Client/Modules/HtmlText/Index.razor b/Oqtane.Client/Modules/HtmlText/Index.razor index 77f7b95d..b02ee9ff 100644 --- a/Oqtane.Client/Modules/HtmlText/Index.razor +++ b/Oqtane.Client/Modules/HtmlText/Index.razor @@ -15,17 +15,20 @@ } @code { - private string content = ""; + private string content = ""; - protected override async Task OnParametersSetAsync() - { - try + protected override async Task OnParametersSetAsync() + { + try { - var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); - if (htmltext != null) + if (PageState.RenderModuleInstance(ModuleState)) { - content = htmltext.Content; - content = Utilities.FormatContent(content, PageState.Alias, "render"); + var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); + if (htmltext != null) + { + content = htmltext.Content; + content = Utilities.FormatContent(content, PageState.Alias, "render"); + } } } catch (Exception ex) diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 15cc7fbc..4d895570 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -2,7 +2,7 @@ @namespace Oqtane.UI @inject SiteState SiteState -@if (_visible) +@if (ComponentType != null && _visible) { @@ -17,12 +17,11 @@ } - } @code { - private bool _visible = true; - private bool _useadminborder = false; + private bool _visible = true; + private bool _useadminborder = false; public Type ComponentType { get; set; } [CascadingParameter] @@ -31,12 +30,12 @@ [Parameter] public Module ModuleState { get; set; } - protected override void OnInitialized() - { - ((INotifyPropertyChanged)SiteState.Properties).PropertyChanged += PropertyChanged; - } - - protected override void OnParametersSet() + protected override void OnInitialized() + { + ((INotifyPropertyChanged)SiteState.Properties).PropertyChanged += PropertyChanged; + } + + protected override void OnParametersSet() { string container = ModuleState.ContainerType; if (PageState.ModuleId != -1 && PageState.Route.Action != "" && ModuleState.UseAdminContainer) @@ -53,7 +52,10 @@ _useadminborder = false; } - ComponentType = Type.GetType(container) ?? Type.GetType(Constants.DefaultContainer); + if (PageState.RenderModuleInstance(ModuleState)) + { + ComponentType = Type.GetType(container) ?? Type.GetType(Constants.DefaultContainer); + } } private void PropertyChanged(object sender, PropertyChangedEventArgs e) @@ -72,6 +74,4 @@ { ((INotifyPropertyChanged)SiteState.Properties).PropertyChanged -= PropertyChanged; } - - } diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 78ae6d5c..7c45a106 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -5,7 +5,7 @@ @if (CurrentException is null) { - if (_messagePosition == "top") + if (_message != "" && _messagePosition == "top") { } @@ -17,7 +17,7 @@
} } - if (_messagePosition == "bottom") + if (_message != "" && _messagePosition == "bottom") { } @@ -51,24 +51,27 @@ else protected override void OnParametersSet() { _message = ""; - if (!string.IsNullOrEmpty(ModuleState.ModuleType)) + if (PageState.RenderModuleInstance(ModuleState)) { - ModuleType = Type.GetType(ModuleState.ModuleType); - if (ModuleType != null) + if (!string.IsNullOrEmpty(ModuleState.ModuleType)) { - ModuleParameters = new Dictionary { { "ModuleInstance", this } }; - return; + 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"; } - // 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"; } } diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index ccde8fc2..86c3d5a1 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; using Oqtane.Models; namespace Oqtane.UI @@ -38,5 +36,12 @@ namespace Oqtane.UI { get { return Site.Languages; } } + + + // determines if the PageState matches the ModuleState for component rendering purposes + public bool RenderModuleInstance(Module ModuleState) + { + return Page.PageId == ModuleState.PageId && (ModuleId == -1 || ModuleId == ModuleState.ModuleId) && Action == ModuleState.Action; + } } } diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 1ad17b6f..ed487f24 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -95,7 +95,7 @@ else if (authorized) { - CreateComponent(builder, module); + CreateComponent(builder, module, module.PageModuleId); } } } @@ -106,7 +106,7 @@ else // check if user is authorized to view module if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList)) { - CreateComponent(builder, module); + CreateComponent(builder, module, -1); } } } @@ -115,11 +115,14 @@ else }; } - private void CreateComponent(RenderTreeBuilder builder, Module module) + private void CreateComponent(RenderTreeBuilder builder, Module module, int key) { builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent)); builder.AddAttribute(1, "ModuleState", module); - builder.SetKey(module.PageModuleId); + if (key != -1) + { + builder.SetKey(module.PageModuleId); + } builder.CloseComponent(); } } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 51877aa0..b538afb1 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -508,6 +508,7 @@ } module.PaneModuleIndex = paneindex[module.Pane.ToLower()]; + module.Action = action; // container fallback if (string.IsNullOrEmpty(module.ContainerType)) diff --git a/Oqtane.Shared/Models/Module.cs b/Oqtane.Shared/Models/Module.cs index 07c2a507..49c35ded 100644 --- a/Oqtane.Shared/Models/Module.cs +++ b/Oqtane.Shared/Models/Module.cs @@ -85,6 +85,8 @@ namespace Oqtane.Models public int PaneModuleIndex { get; set; } [NotMapped] public int PaneModuleCount { get; set; } + [NotMapped] + public string Action { get; set; } #endregion From 3dc28c7291bcb4af8b2aca7e270baf7746b8c7eb Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 4 Jan 2024 16:40:15 -0500 Subject: [PATCH 26/99] Fix #3604 - display message if user is attempting to run the application prior to performing a full compilation --- .../Infrastructure/DatabaseManager.cs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 01138129..5d24dd9f 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -216,19 +216,27 @@ namespace Oqtane.Infrastructure // get database type var type = Type.GetType(databaseType); - // create database object from type - var database = Activator.CreateInstance(type) as IDatabase; - - // create data directory if does not exist - var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString(); - if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty); - - var dbOptions = new DbContextOptionsBuilder().UseOqtaneDatabase(database, NormalizeConnectionString(install.ConnectionString)).Options; - using (var dbc = new DbContext(dbOptions)) + if (type != null) { - // create empty database if it does not exist - dbc.Database.EnsureCreated(); - result.Success = true; + // create database object from type + var database = Activator.CreateInstance(type) as IDatabase; + + // create data directory if does not exist + var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString(); + if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty); + + var dbOptions = new DbContextOptionsBuilder().UseOqtaneDatabase(database, NormalizeConnectionString(install.ConnectionString)).Options; + using (var dbc = new DbContext(dbOptions)) + { + // create empty database if it does not exist + dbc.Database.EnsureCreated(); + result.Success = true; + } + } + else + { + result.Message = $"The Database Provider {databaseType} Does Not Exist. If This Is A Development Environment Please Ensure You Have Performed A Full Compilation Of All Projects In The Oqtane Solution Prior To Running The Application."; + _filelogger.LogError(Utilities.LogMessage(this, result.Message)); } } catch (Exception ex) From 8b41a03080f13c0aac9a517069196e87af743b27 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Fri, 5 Jan 2024 10:15:51 +0100 Subject: [PATCH 27/99] Modified Logic from || to && UserSecurity.IsAuthorized && Utilities.IsPageModuleVisible fixed --- Oqtane.Client/UI/SiteRouter.razor | 69 +++++++++++++++++-------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index db9e1563..92f7040c 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -262,41 +262,48 @@ if (page != null) { // check if user is authorized to view page - if ((Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)) || UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) + if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList))) + //if ((Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)) || UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) { - // if (UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList) || Utilities.ValidateEffectiveExpiryDates(page.EffectiveDate, page.ExpiryDate)) - // { - // load additional metadata for current page - page = ProcessPage(page, site, user, SiteState.Alias); + // 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 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, - Runtime = runtime, - VisitorId = VisitorId, - RemoteIPAddress = SiteState.RemoteIPAddress, - ReturnUrl = returnurl, - IsInternalNavigation = _isInternalNavigation - }; + // 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, + Runtime = runtime, + VisitorId = VisitorId, + RemoteIPAddress = SiteState.RemoteIPAddress, + ReturnUrl = returnurl, + IsInternalNavigation = _isInternalNavigation + }; - OnStateChange?.Invoke(_pagestate); - await ScrollToFragment(_pagestate.Uri); - // } + OnStateChange?.Invoke(_pagestate); + await ScrollToFragment(_pagestate.Uri); + } + 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 From 02c22c18942e481f770f6f3c080eecd9cd60a3f1 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 5 Jan 2024 11:49:57 -0500 Subject: [PATCH 28/99] improved rendering optimization --- Oqtane.Client/Modules/HtmlText/Index.razor | 2 +- Oqtane.Client/Modules/ModuleBase.cs | 5 +++++ Oqtane.Client/Themes/ContainerBase.cs | 6 +++++- Oqtane.Client/UI/ContainerBuilder.razor | 7 ++++++- Oqtane.Client/UI/ModuleInstance.razor | 7 ++++++- Oqtane.Client/UI/PageState.cs | 8 +------- Oqtane.Client/UI/Pane.razor | 3 +++ Oqtane.Client/UI/SiteRouter.razor | 4 ++-- Oqtane.Shared/Models/Module.cs | 2 +- 9 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Oqtane.Client/Modules/HtmlText/Index.razor b/Oqtane.Client/Modules/HtmlText/Index.razor index b02ee9ff..91efe2bb 100644 --- a/Oqtane.Client/Modules/HtmlText/Index.razor +++ b/Oqtane.Client/Modules/HtmlText/Index.razor @@ -21,7 +21,7 @@ { try { - if (PageState.RenderModuleInstance(ModuleState)) + if (ShouldRender()) { var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); if (htmltext != null) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 9825a334..79c00367 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -113,6 +113,11 @@ namespace Oqtane.Modules } } + protected override bool ShouldRender() + { + return PageState.RenderId == ModuleState.RenderId; + } + // path method public string ModulePath() diff --git a/Oqtane.Client/Themes/ContainerBase.cs b/Oqtane.Client/Themes/ContainerBase.cs index a35c1478..d05f3610 100644 --- a/Oqtane.Client/Themes/ContainerBase.cs +++ b/Oqtane.Client/Themes/ContainerBase.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components; using Oqtane.Models; namespace Oqtane.Themes @@ -8,5 +8,9 @@ namespace Oqtane.Themes [CascadingParameter] protected Module ModuleState { get; set; } + protected override bool ShouldRender() + { + return PageState.RenderId == ModuleState.RenderId; + } } } diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 4d895570..1607ea18 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -30,6 +30,11 @@ [Parameter] public Module ModuleState { get; set; } + protected override bool ShouldRender() + { + return PageState.RenderId == ModuleState.RenderId; + } + protected override void OnInitialized() { ((INotifyPropertyChanged)SiteState.Properties).PropertyChanged += PropertyChanged; @@ -52,7 +57,7 @@ _useadminborder = false; } - if (PageState.RenderModuleInstance(ModuleState)) + if (ShouldRender()) { ComponentType = Type.GetType(container) ?? Type.GetType(Constants.DefaultContainer); } diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 7c45a106..6bffb143 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -48,10 +48,15 @@ else private ModuleMessage ModuleMessage { get; set; } + protected override bool ShouldRender() + { + return PageState.RenderId == ModuleState.RenderId; + } + protected override void OnParametersSet() { _message = ""; - if (PageState.RenderModuleInstance(ModuleState)) + if (ShouldRender()) { if (!string.IsNullOrEmpty(ModuleState.ModuleType)) { diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index 86c3d5a1..7de88d96 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -23,6 +23,7 @@ namespace Oqtane.UI public string RemoteIPAddress { get; set; } public string ReturnUrl { get; set; } public bool IsInternalNavigation { get; set; } + public Guid RenderId { get; set; } public List Pages { @@ -36,12 +37,5 @@ namespace Oqtane.UI { get { return Site.Languages; } } - - - // determines if the PageState matches the ModuleState for component rendering purposes - public bool RenderModuleInstance(Module ModuleState) - { - return Page.PageId == ModuleState.PageId && (ModuleId == -1 || ModuleId == ModuleState.ModuleId) && Action == ModuleState.Action; - } } } diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index ed487f24..3c35ffac 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -45,6 +45,9 @@ else { foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId)) { + // set renderid - this allows the framework to determine which components should be rendered when PageState changes + module.RenderId = PageState.RenderId; + var pane = module.Pane; if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction) { diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index b538afb1..692e7e6d 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -289,7 +289,8 @@ VisitorId = VisitorId, RemoteIPAddress = SiteState.RemoteIPAddress, ReturnUrl = returnurl, - IsInternalNavigation = _isInternalNavigation + IsInternalNavigation = _isInternalNavigation, + RenderId = Guid.NewGuid() }; OnStateChange?.Invoke(_pagestate); @@ -508,7 +509,6 @@ } module.PaneModuleIndex = paneindex[module.Pane.ToLower()]; - module.Action = action; // container fallback if (string.IsNullOrEmpty(module.ContainerType)) diff --git a/Oqtane.Shared/Models/Module.cs b/Oqtane.Shared/Models/Module.cs index 49c35ded..832afe69 100644 --- a/Oqtane.Shared/Models/Module.cs +++ b/Oqtane.Shared/Models/Module.cs @@ -86,7 +86,7 @@ namespace Oqtane.Models [NotMapped] public int PaneModuleCount { get; set; } [NotMapped] - public string Action { get; set; } + public Guid RenderId { get; set; } #endregion From 5117c1a5280f7db6d4f883421b60cf5c20799e0f Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 5 Jan 2024 12:06:36 -0500 Subject: [PATCH 29/99] changed max profiel field rows to 10 --- Oqtane.Client/Modules/Admin/Profiles/Edit.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor index 84555328..48b71098 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor @@ -46,7 +46,7 @@
- +
From 352e20f01b1a62def8b6746376959a4319c6eeea Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 5 Jan 2024 12:14:43 -0500 Subject: [PATCH 30/99] remove commented code --- Oqtane.Client/UI/SiteRouter.razor | 1 - 1 file changed, 1 deletion(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 1c1df139..1da8a8cd 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -263,7 +263,6 @@ { // 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))) - //if ((Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)) || UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)) { // load additional metadata for current page page = ProcessPage(page, site, user, SiteState.Alias); From 88a07ecf63cb9c04f6544cf24881e587a03a9fdb Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sat, 6 Jan 2024 08:42:07 -0500 Subject: [PATCH 31/99] more rendering optimizations --- Oqtane.Client/UI/Pane.razor | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 3c35ffac..0b5a2b9b 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -46,7 +46,10 @@ else foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId)) { // set renderid - this allows the framework to determine which components should be rendered when PageState changes - module.RenderId = PageState.RenderId; + if (module.RenderId != PageState.RenderId) + { + module.RenderId = PageState.RenderId; + } var pane = module.Pane; if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction) From c271d4bfe4dda91d370fb138ae4334f34499d407 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sat, 6 Jan 2024 08:52:05 -0500 Subject: [PATCH 32/99] improve ShouldRender logic --- Oqtane.Client/Modules/ModuleBase.cs | 2 +- Oqtane.Client/Themes/ContainerBase.cs | 2 +- Oqtane.Client/UI/ContainerBuilder.razor | 2 +- Oqtane.Client/UI/ModuleInstance.razor | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 79c00367..05281844 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -115,7 +115,7 @@ namespace Oqtane.Modules protected override bool ShouldRender() { - return PageState.RenderId == ModuleState.RenderId; + return PageState?.RenderId == ModuleState?.RenderId; } // path method diff --git a/Oqtane.Client/Themes/ContainerBase.cs b/Oqtane.Client/Themes/ContainerBase.cs index d05f3610..8e0250c4 100644 --- a/Oqtane.Client/Themes/ContainerBase.cs +++ b/Oqtane.Client/Themes/ContainerBase.cs @@ -10,7 +10,7 @@ namespace Oqtane.Themes protected override bool ShouldRender() { - return PageState.RenderId == ModuleState.RenderId; + return PageState?.RenderId == ModuleState?.RenderId; } } } diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 1607ea18..893dafd1 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -32,7 +32,7 @@ protected override bool ShouldRender() { - return PageState.RenderId == ModuleState.RenderId; + return PageState?.RenderId == ModuleState?.RenderId; } protected override void OnInitialized() diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 6bffb143..71143fc3 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -50,7 +50,7 @@ else protected override bool ShouldRender() { - return PageState.RenderId == ModuleState.RenderId; + return PageState?.RenderId == ModuleState?.RenderId; } protected override void OnParametersSet() From 5f778e706f7cbc121715df0ef403904ca2a404c8 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sat, 6 Jan 2024 15:29:28 -0500 Subject: [PATCH 33/99] fix #3584 - browse/edit using relative path for current site --- Oqtane.Client/Modules/Admin/Sites/Index.razor | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 20a652ee..58f281a5 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -48,11 +48,25 @@ else private void Edit(string name) { - NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name + "/admin/site", true); + if (PageState.Alias.Name == name) + { + NavigationManager.NavigateTo("/admin/site"); + } + else + { + NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name + "/admin/site", true); + } } private void Browse(string name) { - NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name, true); + if (PageState.Alias.Name == name) + { + NavigationManager.NavigateTo("/"); + } + else + { + NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name, true); + } } } From 9f0753214035e5f4468565363e603ce595498346 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 10:59:11 -0800 Subject: [PATCH 34/99] documentation spelling correction --- Oqtane.Client/Services/Interfaces/IModuleService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/IModuleService.cs b/Oqtane.Client/Services/Interfaces/IModuleService.cs index a25aa3f7..46777fdf 100644 --- a/Oqtane.Client/Services/Interfaces/IModuleService.cs +++ b/Oqtane.Client/Services/Interfaces/IModuleService.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace Oqtane.Services { /// - /// Service to retreive and store modules () + /// Service to retrieve and store modules () /// public interface IModuleService { From cf3b8378bde930fceb422d40280eafd1290a5edf Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:05:46 -0800 Subject: [PATCH 35/99] Documentation Spelling Correction --- Oqtane.Client/Services/Interfaces/INotificationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/INotificationService.cs b/Oqtane.Client/Services/Interfaces/INotificationService.cs index a831dd5d..760f4a36 100644 --- a/Oqtane.Client/Services/Interfaces/INotificationService.cs +++ b/Oqtane.Client/Services/Interfaces/INotificationService.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace Oqtane.Services { /// - /// Service to store and retreive notifications () + /// Service to store and retrieve notifications () /// public interface INotificationService { From e27fce12274e731c7a3aea91f29751c53b58701c Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:06:32 -0800 Subject: [PATCH 36/99] Documentation Spelling Correction --- Oqtane.Client/Services/Interfaces/IPageModuleService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/IPageModuleService.cs b/Oqtane.Client/Services/Interfaces/IPageModuleService.cs index dd42060a..77bc5d3b 100644 --- a/Oqtane.Client/Services/Interfaces/IPageModuleService.cs +++ b/Oqtane.Client/Services/Interfaces/IPageModuleService.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace Oqtane.Services { /// - /// Service to store and retreive a + /// Service to store and retrieve a /// public interface IPageModuleService { From 1ea28411daa1c9dae788a103567706659a9aa980 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:07:08 -0800 Subject: [PATCH 37/99] Documentation Spelling Correction --- Oqtane.Client/Services/Interfaces/IProfileService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/IProfileService.cs b/Oqtane.Client/Services/Interfaces/IProfileService.cs index 2059e8d1..72c2506c 100644 --- a/Oqtane.Client/Services/Interfaces/IProfileService.cs +++ b/Oqtane.Client/Services/Interfaces/IProfileService.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace Oqtane.Services { /// - /// Service to store and retreive entries + /// Service to store and retrieve entries /// public interface IProfileService { From 4b45103a4ee6f70ff914d7a11dfdb3efad16d942 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:07:35 -0800 Subject: [PATCH 38/99] Documentation Spelling Correction --- Oqtane.Client/Services/Interfaces/ISiteService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/ISiteService.cs b/Oqtane.Client/Services/Interfaces/ISiteService.cs index 9534b51f..5541d1ba 100644 --- a/Oqtane.Client/Services/Interfaces/ISiteService.cs +++ b/Oqtane.Client/Services/Interfaces/ISiteService.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Oqtane.Services { /// - /// Service to store and retreive entries + /// Service to store and retrieve entries /// public interface ISiteService { From e5013c918e3cc804316f7f2c3542ae2d124d2ff2 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:08:08 -0800 Subject: [PATCH 39/99] Documentation Spelling Correction --- Oqtane.Client/Services/Interfaces/ISiteTemplateService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Services/Interfaces/ISiteTemplateService.cs b/Oqtane.Client/Services/Interfaces/ISiteTemplateService.cs index 8068ee4e..48444277 100644 --- a/Oqtane.Client/Services/Interfaces/ISiteTemplateService.cs +++ b/Oqtane.Client/Services/Interfaces/ISiteTemplateService.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace Oqtane.Services { /// - /// Service to retreive entries + /// Service to retrieve entries /// public interface ISiteTemplateService { From ea9d88009f0209f07ac0d486034aa786caed44e2 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:09:06 -0800 Subject: [PATCH 40/99] Documentation Spelling Correction --- Oqtane.Client/Services/Interfaces/IThemeService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Services/Interfaces/IThemeService.cs b/Oqtane.Client/Services/Interfaces/IThemeService.cs index 4dc636c2..62617c55 100644 --- a/Oqtane.Client/Services/Interfaces/IThemeService.cs +++ b/Oqtane.Client/Services/Interfaces/IThemeService.cs @@ -17,7 +17,7 @@ namespace Oqtane.Services Task> GetThemesAsync(); /// - /// Returns a specific thenme + /// Returns a specific theme /// /// /// @@ -56,7 +56,7 @@ namespace Oqtane.Services List GetContainerControls(List themes, string themeControlType); /// - /// Updates a existing theem + /// Updates a existing theme /// /// /// From 09b0e09932106f87b6ef5aa97c61419838c643c3 Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 7 Jan 2024 11:10:53 -0800 Subject: [PATCH 41/99] Documentation Spelling Correction --- Oqtane.Shared/Documentation/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Shared/Documentation/readme.md b/Oqtane.Shared/Documentation/readme.md index cd55726a..ba715490 100644 --- a/Oqtane.Shared/Documentation/readme.md +++ b/Oqtane.Shared/Documentation/readme.md @@ -2,6 +2,6 @@ This folder contains special attributes for the API Code Generator. -The idea is that only items marked with special attributes are valide public APIs, and only these will be documented in the public docs +The idea is that only items marked with special attributes are valid public APIs, and only these will be documented in the public docs -As of 2020, all APIs are documented, and only these marked as `[PrivateApi]` will be excluded. In future, we may reverse this to only document things marked as `[PublicApi]`. \ No newline at end of file +As of 2020, all APIs are documented, and only these marked as `[PrivateApi]` will be excluded. In future, we may reverse this to only document things marked as `[PublicApi]`. From 45f26bb22edda2754d680fe136f0aadf1e87a2da Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 8 Jan 2024 14:10:03 -0800 Subject: [PATCH 42/99] Clarify Getting Started Instructions. --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f74ef946..8b45aba5 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,18 @@ Please note that this project is owned by the .NET Foundation and is governed by **Using Version 5:** - Install **[.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)**. - + - Install the latest edition (v17.8 or higher) of [Visual Studio 2022](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**. -- clone the Oqtane dev branch source code to your local system. Open the **Oqtane.sln** solution file and Build the solution. Make sure you specify Oqtane.Server as the Startup Project and then Run the application. +- clone the Oqtane dev branch source code to your local system. + +- Open the **Oqtane.sln** solution file. + +- **Important:** Build the solution. + +- Make sure you specify Oqtane.Server as the Startup Project + +- Run the application. **Installing an official release:** From 95b74c5f2feacbabc9f14360b29a80f2f14e63ce Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 8 Jan 2024 14:46:37 -0800 Subject: [PATCH 43/99] Fix capitalization in list items. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b45aba5..f8a8e677 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Please note that this project is owned by the .NET Foundation and is governed by - Install the latest edition (v17.8 or higher) of [Visual Studio 2022](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**. -- clone the Oqtane dev branch source code to your local system. +- Clone the Oqtane dev branch source code to your local system. - Open the **Oqtane.sln** solution file. From a9b85caeb738cb70f8861c97dbabbeaa9e3a3359 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 13:44:47 -0800 Subject: [PATCH 44/99] Upgrade multiple NuGet packages Upgraded the following NuGet packages: - Microsoft.AspNetCore.Components.Authorization from v8.0.0 to v8.0.1 - Microsoft.AspNetCore.Components.WebAssembly from v8.0.0 to v8.0.1 - Microsoft.Extensions.Localization from v8.0.0 to v8.0.1 --- Oqtane.Maui/Oqtane.Maui.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index 0b8d3657..021499e5 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -65,11 +65,11 @@ - - + + - + From 297ec64bde23e513ee05daef18cb02f53d36e0b0 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 13:53:39 -0800 Subject: [PATCH 45/99] Upgrade multiple NuGet packages --- Oqtane.Client/Oqtane.Client.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 880f5e1b..3b9926f7 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -21,10 +21,10 @@ - - - - + + + + From 5b0deb9fc2ab7b7e58ebfc57606a70440a96325d Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 13:55:56 -0800 Subject: [PATCH 46/99] Upgrade multiple NuGet packages Upgraded the following NuGet packages: - EFCore.NamingConventions from v8.0.0-rc.2 to v8.0.2 - Microsoft.EntityFrameworkCore.Relational from v8.0.0 to v8.0.1 --- 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 185f3e5f..54d3f5c3 100644 --- a/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj +++ b/Oqtane.Database.PostgreSQL/Oqtane.Database.PostgreSQL.csproj @@ -33,8 +33,8 @@ - - + + From 191c07b6a1c77ea2dc45eaa9a836403bc30fdb72 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 13:58:28 -0800 Subject: [PATCH 47/99] Upgrade multiple NuGet packages Upgraded the following NuGet packages: - Microsoft.EntityFrameworkCore.SqlServer from v8.0.0 to v8.0.1 --- 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 5b8d94b3..031f8e8f 100644 --- a/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj +++ b/Oqtane.Database.SqlServer/Oqtane.Database.SqlServer.csproj @@ -33,7 +33,7 @@ - + From b454932ff5caedfe9169d1e1321e808e74aee264 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 14:03:24 -0800 Subject: [PATCH 48/99] Upgrade multiple NuGet packages Upgraded the following NuGet packages: - Microsoft.EntityFrameworkCore.Sqlite from v8.0.0 to v8.0.1 --- 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 6af2de3f..1b9a0257 100644 --- a/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj +++ b/Oqtane.Database.Sqlite/Oqtane.Database.Sqlite.csproj @@ -33,7 +33,7 @@ - + From 564b0ee0c4cee5cf67234ce9d0c5a9b6476b07a7 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 14:08:09 -0800 Subject: [PATCH 49/99] Upgrade NuGet Packages to Latest Versions This commit updates the versions of several NuGet packages used in the project. The following packages have been upgraded: - Microsoft.AspNetCore.Components.WebAssembly.Server from 8.0.0 to 8.0.1 - Microsoft.AspNetCore.Identity.EntityFrameworkCore from 8.0.0 to 8.0.1 - Microsoft.Data.SqlClient from 5.2.0-preview3.23201.1 to 5.2.0-preview4.23342.2 - Microsoft.EntityFrameworkCore from 8.0.0 to 8.0.1 - Microsoft.EntityFrameworkCore.Design from 8.0.0 to 8.0.1 - Microsoft.Extensions.Localization from 8.0.0 to 8.0.1 - Microsoft.AspNetCore.Authentication.OpenIdConnect from 8.0.0 to 8.0.1 - Microsoft.Data.Sqlite.Core from 8.0.0 to 8.0.1 The versions of SixLabors.ImageSharp, Swashbuckle.AspNetCore, SQLitePCLRaw.bundle_e_sqlite3, and Oqtane.Licensing remain unchanged. --- Oqtane.Server/Oqtane.Server.csproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 3b7d540a..c91148db 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -33,19 +33,19 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + From 15cf2069b6b1fa541a3a3e8cced52222fbfce2f9 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 9 Jan 2024 14:09:56 -0800 Subject: [PATCH 50/99] Update NuGet Packages to New Versions This commit updates the versions of several NuGet packages used in the project. The following packages have been upgraded: - Microsoft.EntityFrameworkCore from 8.0.0 to 8.0.1 - Microsoft.EntityFrameworkCore.Relational from 8.0.0 to 8.0.1 - System.Text.Json from 8.0.0 to 8.0.1 The versions of Microsoft.Extensions.DependencyInjection.Abstractions and System.ComponentModel.Annotations remain unchanged. --- 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 265cc578..857ab359 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -19,11 +19,11 @@ - - + + - + From e047d4e8a6a702a41a023ad6e15e57b42ab3df06 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Wed, 10 Jan 2024 14:49:47 +0100 Subject: [PATCH 51/99] Start end End date Range check Checks that the Start date starts before the End date. Message added to Resx --- Oqtane.Client/Modules/Admin/Jobs/Edit.razor | 7 ++++++- Oqtane.Client/Resources/Modules/Admin/Jobs/Edit.resx | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Jobs/Edit.razor b/Oqtane.Client/Modules/Admin/Jobs/Edit.razor index 41926187..848ab8e5 100644 --- a/Oqtane.Client/Modules/Admin/Jobs/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Jobs/Edit.razor @@ -31,7 +31,7 @@
- +
+
+ +
+ +
+
@@ -89,7 +95,7 @@
@SharedLocalizer["Cancel"] - @if (PageState.QueryString.ContainsKey("id")) + @if (PageState.QueryString.ContainsKey("id")) {

@@ -111,6 +117,7 @@ private string _defaultvalue = string.Empty; private string _options = string.Empty; private string _validation = string.Empty; + private string _autocomplete = string.Empty; private string _isrequired = "False"; private string _isprivate = "False"; private string createdby; @@ -142,6 +149,7 @@ _defaultvalue = profile.DefaultValue; _options = profile.Options; _validation = profile.Validation; + _autocomplete = profile.Autocomplete; _isrequired = profile.IsRequired.ToString(); _isprivate = profile.IsPrivate.ToString(); createdby = profile.CreatedBy; @@ -187,8 +195,10 @@ profile.DefaultValue = _defaultvalue; profile.Options = _options; profile.Validation = _validation; + profile.Autocomplete = _autocomplete; profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired)); profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate)); + if (_profileid != -1) { profile = await ProfileService.UpdateProfileAsync(profile); From 9315358fa65ce3e2bd2c82b6a784b55f7fda2c89 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 13 Jan 2024 20:59:42 -0800 Subject: [PATCH 60/99] adds autocomplete --- Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx index 973f8719..e392e48f 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx @@ -195,4 +195,10 @@ Rows: + + Autocomplete setting for the property + + + Autocomplete: + From 23d27aee6b00d66d1fa511c5f807981cf91a1118 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 13 Jan 2024 21:04:15 -0800 Subject: [PATCH 61/99] ENH: Adds Profile Properties Autocomplete --- .../Modules/Admin/UserProfile/Index.razor | 83 ++++++++++++------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index be4c362f..11e37543 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -36,7 +36,7 @@
- +
@@ -65,13 +65,13 @@
- +
- +
@@ -123,24 +123,52 @@ { @if (p.Rows == 1) { - @if (p.IsRequired) + if (!string.IsNullOrEmpty(p.Autocomplete)) { - + @if (p.IsRequired) + { + + } + else + { + + } } else { - + @if (p.IsRequired) + { + + } + else + { + + } } } else { - @if (p.IsRequired) + if (!string.IsNullOrEmpty(p.Autocomplete)) { - + @if (p.IsRequired) + { + + } + else + { + + } } else { - + @if (p.IsRequired) + { + + } + else + { + + } } } } @@ -360,10 +388,10 @@ photofileid = -1; photo = null; } - var sitesettings = await SettingService.GetSiteSettingsAsync(SiteState.Alias.SiteId); - _ImageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles); settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + var sitesettings = await SettingService.GetSiteSettingsAsync(SiteState.Alias.SiteId); + _ImageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles); await LoadNotificationsAsync(); @@ -549,7 +577,7 @@ try { ModuleInstance.ShowProgressIndicator(); - foreach(var Notification in notifications) + foreach (var Notification in notifications) { if (!Notification.IsDeleted) { @@ -561,12 +589,12 @@ await NotificationService.DeleteNotificationAsync(Notification.NotificationId); } await logger.LogInformation("Notification Deleted {Notification}", Notification); - } + } await logger.LogInformation("Notifications Permanently Deleted"); await LoadNotificationsAsync(); ModuleInstance.HideProgressIndicator(); - StateHasChanged(); + StateHasChanged(); } catch (Exception ex) { @@ -574,21 +602,20 @@ AddModuleMessage(ex.Message, MessageType.Error); ModuleInstance.HideProgressIndicator(); } - + } private void TogglePassword() - { - if (_passwordtype == "password") - { - _passwordtype = "text"; - _togglepassword = SharedLocalizer["HidePassword"]; - } - else - { - _passwordtype = "password"; - _togglepassword = SharedLocalizer["ShowPassword"]; - } - } - + { + if (_passwordtype == "password") + { + _passwordtype = "text"; + _togglepassword = SharedLocalizer["HidePassword"]; + } + else + { + _passwordtype = "password"; + _togglepassword = SharedLocalizer["ShowPassword"]; + } + } } From 7c52b6ab23004a30d5f51d45fd1db33a427b0075 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 13 Jan 2024 21:07:08 -0800 Subject: [PATCH 62/99] remove name from password input --- Oqtane.Client/Modules/Admin/UserProfile/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 11e37543..083e88da 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -36,7 +36,7 @@
- +
From d01a3c327e78b08e2fcfe3d164e65b32942b7681 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 13 Jan 2024 21:09:00 -0800 Subject: [PATCH 63/99] remove space --- Oqtane.Client/Modules/Admin/UserProfile/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 083e88da..939899ba 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -577,7 +577,7 @@ try { ModuleInstance.ShowProgressIndicator(); - foreach (var Notification in notifications) + foreach(var Notification in notifications) { if (!Notification.IsDeleted) { From 22acc2307c138b970744b5981831b90a16bdd5d9 Mon Sep 17 00:00:00 2001 From: Cody Date: Sat, 13 Jan 2024 21:09:41 -0800 Subject: [PATCH 64/99] remove extra line --- Oqtane.Client/Modules/Admin/UserProfile/Index.razor | 1 - 1 file changed, 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 939899ba..44519a4f 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -602,7 +602,6 @@ AddModuleMessage(ex.Message, MessageType.Error); ModuleInstance.HideProgressIndicator(); } - } private void TogglePassword() From a1b07316650973e8b6ba82a064b79b497dcb247b Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 15 Jan 2024 08:24:06 -0800 Subject: [PATCH 65/99] profile autocomplete migration --- .../Tenant/05010003_AddProfileAutocomplete.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs diff --git a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs new file mode 100644 index 00000000..c82fbc9b --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.05.00.01.03")] + public class AddProfileAutocomplete : MultiDatabaseMigration + { + public AddProfileAutocomplete(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); + profileEntityBuilder.AddStringColumn("Autocomplete", 200, true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + // not implemented + } + } +} From 439866216cfac2dc826dea3210ce746bfcac15dc Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 15 Jan 2024 09:10:12 -0800 Subject: [PATCH 66/99] adds autocomplete attribute to select element --- .../Modules/Admin/UserProfile/Index.razor | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 44519a4f..466e853f 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -103,21 +103,40 @@
- @if (!string.IsNullOrEmpty(p.Options)) + @if (!string.IsNullOrEmpty(p.Options)) { - + @foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - + @if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option)) + { + + } + else + { + + } } - else + + } + else + { + + + } } else { From e0cdfcf403145e8af0aa39625e118a531608fdfa Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 15 Jan 2024 09:30:37 -0800 Subject: [PATCH 67/99] adds Autocomplete property --- Oqtane.Shared/Models/Profile.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Oqtane.Shared/Models/Profile.cs b/Oqtane.Shared/Models/Profile.cs index 336cd262..f4db036d 100644 --- a/Oqtane.Shared/Models/Profile.cs +++ b/Oqtane.Shared/Models/Profile.cs @@ -78,5 +78,11 @@ namespace Oqtane.Models /// Optional number of rows (textarea) /// public int Rows { get; set; } + + /// + /// Autocomplete setting for the property. + /// If set, enable autocomplete for the corresponding input field. + /// + public string Autocomplete { get; set; } } } From 3a5dc629083fea1acee4a8bee01d1dfb498078ff Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 15 Jan 2024 09:56:11 -0800 Subject: [PATCH 68/99] Sanitize _aliasname by removing protocols --- Oqtane.Client/Modules/Admin/Site/Index.razor | 75 ++++++++++---------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 57f9b66b..8adbd48b 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -812,46 +812,43 @@ } } - private async Task SaveAlias() - { - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - if (!string.IsNullOrEmpty(_aliasname)) - { - // Remove 'http://' and 'https://' from the alias name - string cleanedAliasName = _aliasname.Replace("http://", "").Replace("https://", ""); - - var aliases = await AliasService.GetAliasesAsync(); - // Check if the cleaned alias name exists in the database - var alias = aliases.Where(item => item.Name == cleanedAliasName).FirstOrDefault(); - bool unique = (alias == null || alias.AliasId == _aliasid); - if (unique) - { - if (_aliasid == 0) - { - alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = cleanedAliasName, IsDefault = bool.Parse(_defaultalias) }; - await AliasService.AddAliasAsync(alias); - } - else - { - alias = _aliases.Single(item => item.AliasId == _aliasid); - alias.Name = cleanedAliasName; - alias.IsDefault = bool.Parse(_defaultalias); - await AliasService.UpdateAliasAsync(alias); - } - } - else // duplicate alias - { - AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); - await ScrollToPageTop(); - } +private async Task SaveAlias() +{ + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + if (!string.IsNullOrEmpty(_aliasname)) + { + _aliasname = _aliasname.Replace("http://", "").Replace("https://", ""); + var aliases = await AliasService.GetAliasesAsync(); + var alias = aliases.Where(item => item.Name == _aliasname).FirstOrDefault(); + bool unique = (alias == null || alias.AliasId == _aliasid); + if (unique) + { + if (_aliasid == 0) + { + alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = _aliasname, IsDefault = bool.Parse(_defaultalias) }; + await AliasService.AddAliasAsync(alias); + } + else + { + alias = _aliases.Single(item => item.AliasId == _aliasid); + alias.Name = _aliasname; + alias.IsDefault = bool.Parse(_defaultalias); + await AliasService.UpdateAliasAsync(alias); + } + } + else // duplicate alias + { + AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); + await ScrollToPageTop(); } - await GetAliases(); - _aliasid = -1; - _aliasname = ""; - StateHasChanged(); - } - } + } + await GetAliases(); + _aliasid = -1; + _aliasname = ""; + StateHasChanged(); + } +} private async Task CancelAlias() { From 3cec9f7ee029f234cb6b6eb44cc12836d2130e57 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 15 Jan 2024 09:59:22 -0800 Subject: [PATCH 69/99] fix formatting --- Oqtane.Client/Modules/Admin/Site/Index.razor | 74 ++++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 8adbd48b..40b3e40f 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -812,43 +812,43 @@ } } -private async Task SaveAlias() -{ - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - if (!string.IsNullOrEmpty(_aliasname)) - { - _aliasname = _aliasname.Replace("http://", "").Replace("https://", ""); - var aliases = await AliasService.GetAliasesAsync(); - var alias = aliases.Where(item => item.Name == _aliasname).FirstOrDefault(); - bool unique = (alias == null || alias.AliasId == _aliasid); - if (unique) - { - if (_aliasid == 0) - { - alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = _aliasname, IsDefault = bool.Parse(_defaultalias) }; - await AliasService.AddAliasAsync(alias); - } - else - { - alias = _aliases.Single(item => item.AliasId == _aliasid); - alias.Name = _aliasname; - alias.IsDefault = bool.Parse(_defaultalias); - await AliasService.UpdateAliasAsync(alias); - } - } - else // duplicate alias - { - AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); - await ScrollToPageTop(); - } - } - await GetAliases(); - _aliasid = -1; - _aliasname = ""; - StateHasChanged(); - } -} + private async Task SaveAlias() + { + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + if (!string.IsNullOrEmpty(_aliasname)) + { + _aliasname = _aliasname.Replace("http://", "").Replace("https://", ""); + var aliases = await AliasService.GetAliasesAsync(); + var alias = aliases.Where(item => item.Name == _aliasname).FirstOrDefault(); + bool unique = (alias == null || alias.AliasId == _aliasid); + if (unique) + { + if (_aliasid == 0) + { + alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = _aliasname, IsDefault = bool.Parse(_defaultalias) }; + await AliasService.AddAliasAsync(alias); + } + else + { + alias = _aliases.Single(item => item.AliasId == _aliasid); + alias.Name = _aliasname; + alias.IsDefault = bool.Parse(_defaultalias); + await AliasService.UpdateAliasAsync(alias); + } + } + else // duplicate alias + { + AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); + await ScrollToPageTop(); + } + } + await GetAliases(); + _aliasid = -1; + _aliasname = ""; + StateHasChanged(); + } + } private async Task CancelAlias() { From bfed0ed79179befc96a20bc7a5365bad8ea786db Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 16 Jan 2024 10:43:24 -0800 Subject: [PATCH 70/99] Refactor SaveAlias method and add URL protocol check Restructured the SaveAlias method for improved readability and added a check to handle cases where the _aliasname contains a URL protocol (e.g., "://"). This ensures proper handling of different URL formats. --- Oqtane.Client/Modules/Admin/Site/Index.razor | 74 ++++++++++++-------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 40b3e40f..01a6bba3 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -814,40 +814,52 @@ private async Task SaveAlias() { - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - if (!string.IsNullOrEmpty(_aliasname)) - { - _aliasname = _aliasname.Replace("http://", "").Replace("https://", ""); + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + if (!string.IsNullOrEmpty(_aliasname)) + { var aliases = await AliasService.GetAliasesAsync(); - var alias = aliases.Where(item => item.Name == _aliasname).FirstOrDefault(); - bool unique = (alias == null || alias.AliasId == _aliasid); - if (unique) - { - if (_aliasid == 0) - { - alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = _aliasname, IsDefault = bool.Parse(_defaultalias) }; - await AliasService.AddAliasAsync(alias); - } - else - { - alias = _aliases.Single(item => item.AliasId == _aliasid); - alias.Name = _aliasname; - alias.IsDefault = bool.Parse(_defaultalias); - await AliasService.UpdateAliasAsync(alias); - } - } - else // duplicate alias - { - AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); + + int protocolIndex = _aliasname.IndexOf("://", StringComparison.OrdinalIgnoreCase); + if (protocolIndex != -1) + { + _aliasname = _aliasname.Substring(protocolIndex + 3); + } + + var alias = aliases.FirstOrDefault(item => item.Name == _aliasname); + + bool unique = (alias == null || alias.AliasId == _aliasid); + + if (unique) + { + if (_aliasid == 0) + { + alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = _aliasname, IsDefault = bool.Parse(_defaultalias) }; + await AliasService.AddAliasAsync(alias); + } + else + { + alias = _aliases.SingleOrDefault(item => item.AliasId == _aliasid); + if (alias != null) + { + alias.Name = _aliasname; + alias.IsDefault = bool.Parse(_defaultalias); + await AliasService.UpdateAliasAsync(alias); + } + } + + await GetAliases(); + _aliasid = -1; + _aliasname = ""; + StateHasChanged(); + } + else // Duplicate alias + { + AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); await ScrollToPageTop(); } - } - await GetAliases(); - _aliasid = -1; - _aliasname = ""; - StateHasChanged(); - } + } + } } private async Task CancelAlias() From cfd9e4b25641c395ed45df70697b69cf10e3c008 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 16 Jan 2024 17:29:54 -0800 Subject: [PATCH 71/99] Updates request.status to request.statusText --- Oqtane.Maui/wwwroot/js/interop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Maui/wwwroot/js/interop.js b/Oqtane.Maui/wwwroot/js/interop.js index 81898c16..a901c7be 100644 --- a/Oqtane.Maui/wwwroot/js/interop.js +++ b/Oqtane.Maui/wwwroot/js/interop.js @@ -344,7 +344,7 @@ Oqtane.Interop = { }; request.upload.onerror = function() { if (progressinfo !== null && progressbar !== null) { - progressinfo.innerHTML = file.name + ' Error: ' + request.status; + progressinfo.innerHTML = file.name + ' Error: ' + request.statusText; progressbar.value = 0; } }; From ab0e95177e0acd00e00b004e3ef1c6b8102c9926 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 16 Jan 2024 17:30:41 -0800 Subject: [PATCH 72/99] Updates request.status to request.statusText --- Oqtane.Server/wwwroot/js/interop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index 81898c16..a901c7be 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -344,7 +344,7 @@ Oqtane.Interop = { }; request.upload.onerror = function() { if (progressinfo !== null && progressbar !== null) { - progressinfo.innerHTML = file.name + ' Error: ' + request.status; + progressinfo.innerHTML = file.name + ' Error: ' + request.statusText; progressbar.value = 0; } }; From 0770e00d8d5df127e7640c37c1324882f19f76af Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 16 Jan 2024 17:46:30 -0800 Subject: [PATCH 73/99] Updates Autocomplete.HelpText --- Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx index e392e48f..be944e51 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx @@ -196,7 +196,7 @@ Rows: - Autocomplete setting for the property + The HTML autocomplete attribute allows you to specify browser behavior for automated assistance in filling out form field values, with a character limit of 30 to ensure concise and effective usage. Autocomplete: From eb6b160377ff1cfbc141a0b2b6da76052e415443 Mon Sep 17 00:00:00 2001 From: Cody Date: Tue, 16 Jan 2024 17:56:32 -0800 Subject: [PATCH 74/99] updates autocomplete default tooltip and limits characters to 30. --- Oqtane.Client/Modules/Admin/Profiles/Edit.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor index 76734ea2..0a35d6be 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor @@ -77,9 +77,9 @@
- +
- +
From 4f23ad37f54c49de4f1152a6757f38d97946dbc0 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 17 Jan 2024 09:07:03 -0800 Subject: [PATCH 75/99] Sets Profile Autocomplete Property 50 Character Limit --- .../Migrations/Tenant/05010003_AddProfileAutocomplete.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs index c82fbc9b..e7a804e4 100644 --- a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs +++ b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs @@ -17,7 +17,7 @@ namespace Oqtane.Migrations.Tenant protected override void Up(MigrationBuilder migrationBuilder) { var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); - profileEntityBuilder.AddStringColumn("Autocomplete", 200, true); + profileEntityBuilder.AddStringColumn("Autocomplete", 50, true); } protected override void Down(MigrationBuilder migrationBuilder) From 474adf2d531fbd6a1a2a840e814ee2ab23e8253f Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 17 Jan 2024 13:35:52 -0500 Subject: [PATCH 76/99] fix issue when inserting images into RichTextEditor --- Oqtane.Client/Modules/Controls/RichTextEditor.razor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 24a14170..61672446 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -260,7 +260,8 @@ { var interop = new RichTextEditorInterop(JSRuntime); await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name)); - _richfilemanager = false; + _richhtml = await interop.GetHtml(_editorElement); + _richfilemanager = false; } else { From 26872c829bf01d7118894aa1812dd55c92aba62f Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 18 Jan 2024 14:06:10 -0800 Subject: [PATCH 77/99] adds autocomplete attribute to username, email and display name input elements. --- Oqtane.Client/Modules/Admin/Register/Index.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index b7c80851..dc559700 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -23,7 +23,7 @@
- +
@@ -47,13 +47,13 @@
- +
- +
From 6e90da90f120327854d0e03045e3564ddb891926 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 18 Jan 2024 14:08:05 -0800 Subject: [PATCH 78/99] adds autocomplete to email and username + fixes a typo --- Oqtane.Client/Installer/Installer.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index eb4ab1a8..433c37b0 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -69,9 +69,9 @@

@Localizer["ApplicationAdmin"]


- +
- +
@@ -95,7 +95,7 @@
- +
From 67afc050b859c1de4b5029a8599b7d2ca53178c9 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 18 Jan 2024 14:23:10 -0800 Subject: [PATCH 79/99] Adds to form autocomplete="on" attribute and setting. --- Oqtane.Client/Modules/Admin/Register/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index dc559700..106e31ad 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -18,7 +18,7 @@ -
+
From ea4c1bf5e5a728425c8b81362181854c2e65c453 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 18 Jan 2024 14:38:31 -0800 Subject: [PATCH 80/99] removes hardcoded autocomplete attributes last added --- Oqtane.Client/Modules/Admin/Register/Index.razor | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index 106e31ad..b7c80851 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -18,12 +18,12 @@ - +
- +
@@ -47,13 +47,13 @@
- +
- +
From c6dbb417243581755fde9c4617441dacbe42b09f Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 18 Jan 2024 14:41:02 -0800 Subject: [PATCH 81/99] removes recently added autocomplete attributes --- Oqtane.Client/Modules/Admin/UserProfile/Index.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 466e853f..0988ff4b 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -65,13 +65,13 @@
- +
- +
From d9b575b051d4a743220e5dd1cf8017ef5f217df6 Mon Sep 17 00:00:00 2001 From: Cody Date: Fri, 19 Jan 2024 08:15:48 -0800 Subject: [PATCH 82/99] undo changes to autocomplete. --- Oqtane.Client/Installer/Installer.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index 433c37b0..7e223ca0 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -71,7 +71,7 @@
- +
@@ -95,7 +95,7 @@
- +
From 2b12b675825f44110a1539755eac38b376b69eec Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 19 Jan 2024 13:22:38 -0500 Subject: [PATCH 83/99] do not include Licensing assembly with framework but prevent uninstall --- Oqtane.Package/Oqtane.Client.nuspec | 1 - Oqtane.Package/Oqtane.Shared.nuspec | 1 - .../Infrastructure/InstallationManager.cs | 48 +++++++++++-------- Oqtane.Server/Oqtane.Server.csproj | 1 - 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index 4c346c87..2424b8f7 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -19,7 +19,6 @@ - \ No newline at end of file diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index 8c6be30a..71e9dcd8 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -19,7 +19,6 @@ - \ No newline at end of file diff --git a/Oqtane.Server/Infrastructure/InstallationManager.cs b/Oqtane.Server/Infrastructure/InstallationManager.cs index 0d26600b..1307b57f 100644 --- a/Oqtane.Server/Infrastructure/InstallationManager.cs +++ b/Oqtane.Server/Infrastructure/InstallationManager.cs @@ -137,16 +137,20 @@ namespace Oqtane.Infrastructure // register assembly if (Path.GetExtension(filename) == ".dll") { - // if package version was not installed previously - if (!File.Exists(Path.Combine(sourceFolder, name + ".log"))) + // do not register licensing assemblies + if (!Path.GetFileName(filename).StartsWith("Oqtane.Licensing.")) { - if (assemblies.ContainsKey(Path.GetFileName(filename))) + // if package version was not installed previously + if (!File.Exists(Path.Combine(sourceFolder, name + ".log"))) { - assemblies[Path.GetFileName(filename)] += 1; - } - else - { - assemblies.Add(Path.GetFileName(filename), 1); + if (assemblies.ContainsKey(Path.GetFileName(filename))) + { + assemblies[Path.GetFileName(filename)] += 1; + } + else + { + assemblies.Add(Path.GetFileName(filename), 1); + } } } } @@ -255,22 +259,26 @@ namespace Oqtane.Infrastructure // delete assets if (Path.GetExtension(filepath) == ".dll") { - // use assembly log to determine if assembly is used in other packages - if (assemblies.ContainsKey(Path.GetFileName(filepath))) + // do not remove licensing assemblies + if (!Path.GetFileName(filepath).StartsWith("Oqtane.Licensing.")) { - if (assemblies[Path.GetFileName(filepath)] == 1) + // use assembly log to determine if assembly is used in other packages + if (assemblies.ContainsKey(Path.GetFileName(filepath))) + { + if (assemblies[Path.GetFileName(filepath)] == 1) + { + DeleteFile(filepath); + assemblies.Remove(Path.GetFileName(filepath)); + } + else + { + assemblies[Path.GetFileName(filepath)] -= 1; + } + } + else // does not exist in assembly log { DeleteFile(filepath); - assemblies.Remove(Path.GetFileName(filepath)); } - else - { - assemblies[Path.GetFileName(filepath)] -= 1; - } - } - else // does not exist in assembly log - { - DeleteFile(filepath); } } else // not an assembly diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index c91148db..65492794 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -47,7 +47,6 @@ - From eeec04b21a29cb1633224c9cd7b381168709f5fe Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 19 Jan 2024 14:53:54 -0500 Subject: [PATCH 84/99] update copyright year --- .../Infrastructure/SiteTemplates/DefaultSiteTemplate.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs b/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs index 6819277a..e572c5f0 100644 --- a/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs +++ b/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs @@ -68,7 +68,7 @@ namespace Oqtane.SiteTemplates new Permission(PermissionNames.View, RoleNames.Admin, true), new Permission(PermissionNames.Edit, RoleNames.Admin, true) }, - Content = "

Copyright (c) 2018-2023 .NET Foundation

" + + Content = "

Copyright (c) 2018-2024 .NET Foundation

" + "

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

" + "

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

" + "

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

" From c09e5e65521cd5ca9e3b9a571cad2da3f5037354 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 19 Jan 2024 15:35:48 -0500 Subject: [PATCH 85/99] improve help text for autocomplete --- Oqtane.Client/Modules/Admin/Profiles/Edit.razor | 2 +- Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor index 0a35d6be..6c820ac2 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor @@ -77,7 +77,7 @@
- +
diff --git a/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx b/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx index be944e51..79a2f0f4 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Profiles/Edit.resx @@ -1,4 +1,4 @@ - + Exe - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 https://github.com/oqtane/oqtane.framework Git Oqtane.Maui @@ -31,7 +31,7 @@ 0E29FC31-1B83-48ED-B6E0-9F3C67B775D4 - 5.0.1 + 5.0.2 1 14.2 diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index 2424b8f7..06250592 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -2,7 +2,7 @@ Oqtane.Client - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Framework.nuspec b/Oqtane.Package/Oqtane.Framework.nuspec index 3b0d65b4..671ba15a 100644 --- a/Oqtane.Package/Oqtane.Framework.nuspec +++ b/Oqtane.Package/Oqtane.Framework.nuspec @@ -2,7 +2,7 @@ Oqtane.Framework - 5.0.1 + 5.0.2 Shaun Walker .NET Foundation Oqtane Framework @@ -11,8 +11,8 @@ .NET Foundation false MIT - https://github.com/oqtane/oqtane.framework/releases/download/v5.0.1/Oqtane.Framework.5.0.1.Upgrade.zip - https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.1 + 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 icon.png oqtane framework diff --git a/Oqtane.Package/Oqtane.Server.nuspec b/Oqtane.Package/Oqtane.Server.nuspec index 65c3d5c4..1b87c609 100644 --- a/Oqtane.Package/Oqtane.Server.nuspec +++ b/Oqtane.Package/Oqtane.Server.nuspec @@ -2,7 +2,7 @@ Oqtane.Server - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index 71e9dcd8..294d5c5c 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -2,7 +2,7 @@ Oqtane.Shared - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Updater.nuspec b/Oqtane.Package/Oqtane.Updater.nuspec index aee8ee24..e16b7bd9 100644 --- a/Oqtane.Package/Oqtane.Updater.nuspec +++ b/Oqtane.Package/Oqtane.Updater.nuspec @@ -2,7 +2,7 @@ Oqtane.Updater - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 icon.png oqtane diff --git a/Oqtane.Package/install.ps1 b/Oqtane.Package/install.ps1 index 634cf373..3f986170 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.1.Install.zip" -Force \ No newline at end of file +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 diff --git a/Oqtane.Package/upgrade.ps1 b/Oqtane.Package/upgrade.ps1 index b9538e69..f1fe650e 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.1.Upgrade.zip" -Force \ No newline at end of file +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 diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 65492794..70f59532 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index 857ab359..d2b161f9 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -3,7 +3,7 @@ net8.0 Debug;Release - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 0e3d8e76..f9573a65 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -1,14 +1,11 @@ using System; -using Oqtane.Models; -using System.Collections.Generic; -using System.Runtime.InteropServices; namespace Oqtane.Shared { public class Constants { - public static readonly string Version = "5.0.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"; + 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 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 bc4faa12..616bc2b9 100644 --- a/Oqtane.Updater/Oqtane.Updater.csproj +++ b/Oqtane.Updater/Oqtane.Updater.csproj @@ -3,7 +3,7 @@ net8.0 Exe - 5.0.1 + 5.0.2 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.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2 https://github.com/oqtane/oqtane.framework Git Oqtane From 63507a556730f671da489c23f677286d7690e415 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 23 Jan 2024 11:07:37 -0500 Subject: [PATCH 91/99] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f8a8e677..0ba4b8f4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [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. [![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) -[![Visit Marketplace](https://github.githubassets.com/images/icons/emoji/unicode/1f3ea.png)](https://www.oqtane.net/) # Oqtane Framework From d9beb4b660ae58e78e2075b24bd683f0e3908dbe Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 23 Jan 2024 13:14:28 -0500 Subject: [PATCH 92/99] remove unnecessary service and usings --- Oqtane.Server/Infrastructure/DatabaseManager.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 5d24dd9f..d05524ca 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.Loader; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; @@ -29,16 +26,14 @@ namespace Oqtane.Infrastructure { private readonly IConfigManager _config; private readonly IServiceScopeFactory _serviceScopeFactory; - private readonly IWebHostEnvironment _environment; private readonly IMemoryCache _cache; private readonly IConfigManager _configManager; private readonly ILogger _filelogger; - public DatabaseManager(IConfigManager config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager, ILogger filelogger) + public DatabaseManager(IConfigManager config, IServiceScopeFactory serviceScopeFactory, IMemoryCache cache, IConfigManager configManager, ILogger filelogger) { _config = config; _serviceScopeFactory = serviceScopeFactory; - _environment = environment; _cache = cache; _configManager = configManager; _filelogger = filelogger; From d57d7ec4d87ad3f119b6d571612f3c0dd53cc32c Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 24 Jan 2024 09:37:27 -0500 Subject: [PATCH 93/99] improvements to .NET MAUI file upload based on #3674 (credit @thabaum) --- Oqtane.Server/Controllers/FileController.cs | 2 ++ Oqtane.Server/Startup.cs | 4 ++-- Oqtane.Shared/Shared/Constants.cs | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 65ead05f..7dc5cfb6 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -20,6 +20,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Formats.Png; using System.Net.Http; +using Microsoft.AspNetCore.Cors; // ReSharper disable StringIndexOfIsCultureSpecific.1 @@ -358,6 +359,7 @@ namespace Oqtane.Controllers } // POST api//upload + [EnableCors(Constants.MauiCorsPolicy)] [HttpPost("upload")] public async Task UploadFile(string folder, IFormFile formfile) { diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 93126c03..e777f4ed 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -133,7 +133,7 @@ namespace Oqtane services.AddCors(options => { - options.AddPolicy(Constants.MauiUserAgent, + options.AddPolicy(Constants.MauiCorsPolicy, policy => { policy.WithOrigins("https://0.0.0.0", "http://0.0.0.0", "app://0.0.0.0") @@ -186,11 +186,11 @@ namespace Oqtane app.UseHttpsRedirection(); app.UseStaticFiles(); - app.UseCors(Constants.MauiUserAgent); app.UseTenantResolution(); app.UseJwtAuthorization(); app.UseBlazorFrameworkFiles(); app.UseRouting(); + app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index f9573a65..efef37e3 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -77,6 +77,7 @@ namespace Oqtane.Shared public static readonly string MauiUserAgent = "MAUI"; public static readonly string MauiAliasPath = "Alias-Path"; + public const string MauiCorsPolicy = "MauiCorsPolicy"; // must be a constant to be used with an attribute public static readonly string VisitorCookiePrefix = "APP_VISITOR_"; From 38a5cc33e81bfeb645f3ffe24c71314f8711cb3e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Wed, 24 Jan 2024 16:49:02 -0500 Subject: [PATCH 94/99] upgrade to MySQL dependencies --- Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj index 8a18443a..4edcb747 100644 --- a/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj +++ b/Oqtane.Database.MySQL/Oqtane.Database.MySQL.csproj @@ -33,8 +33,8 @@ - - + + From 3c328a00b5057aa1f8eb02264d5f3f6afa59dadf Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 25 Jan 2024 23:00:45 +0800 Subject: [PATCH 95/99] fix #3648: update the template to correct the entity table name. --- .../External/Server/Repository/[Module]Context.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Context.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Context.cs index a921ca0f..2cce3945 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Context.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Context.cs @@ -15,5 +15,12 @@ namespace [Owner].Module.[Module].Repository { // ContextBase handles multi-tenant database connections } + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + builder.Entity().ToTable(ActiveDatabase.RewriteName("[Owner][Module]")); + } } } From 7c6424e05cb06a69939632cc276693f39014b1a3 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 25 Jan 2024 10:59:18 -0500 Subject: [PATCH 96/99] fix #3653 - mySQL installation failing on Rows reserved word --- Oqtane.Database.MySQL/MySQLDatabase.cs | 8 ++++++++ Oqtane.Server/Databases/DatabaseBase.cs | 5 +++++ Oqtane.Server/Databases/Interfaces/IDatabase.cs | 2 ++ .../Migrations/EntityBuilders/BaseEntityBuilder.cs | 9 +++++++-- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Oqtane.Database.MySQL/MySQLDatabase.cs b/Oqtane.Database.MySQL/MySQLDatabase.cs index 1b3344a2..648e903e 100644 --- a/Oqtane.Database.MySQL/MySQLDatabase.cs +++ b/Oqtane.Database.MySQL/MySQLDatabase.cs @@ -75,6 +75,14 @@ namespace Oqtane.Database.MySQL return dr; } + public override string RewriteName(string name, bool isQuery) + { + if (name.ToLower() == "rows" && isQuery) + { + name = $"`{name}`"; // escape reserved word in SQL query + } + return name; + } public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) { diff --git a/Oqtane.Server/Databases/DatabaseBase.cs b/Oqtane.Server/Databases/DatabaseBase.cs index a9b91eaf..2342874f 100644 --- a/Oqtane.Server/Databases/DatabaseBase.cs +++ b/Oqtane.Server/Databases/DatabaseBase.cs @@ -66,6 +66,11 @@ namespace Oqtane.Databases return name; } + public virtual string RewriteName(string name, bool isQuery) + { + return name; + } + public virtual string RewriteValue(string value, string type) { return value; diff --git a/Oqtane.Server/Databases/Interfaces/IDatabase.cs b/Oqtane.Server/Databases/Interfaces/IDatabase.cs index 303fbc0f..3c68cf03 100644 --- a/Oqtane.Server/Databases/Interfaces/IDatabase.cs +++ b/Oqtane.Server/Databases/Interfaces/IDatabase.cs @@ -28,6 +28,8 @@ namespace Oqtane.Databases.Interfaces public string RewriteName(string name); + public string RewriteName(string name, bool isQuery); + public string RewriteValue(string value, string type); public void UpdateIdentityStoreTableNames(ModelBuilder builder); diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs index 5bf10e0a..34d54a62 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs @@ -47,7 +47,12 @@ namespace Oqtane.Migrations.EntityBuilders private string RewriteName(string name) { - return ActiveDatabase.RewriteName(name); + return RewriteName(name, false); + } + + private string RewriteName(string name, bool isQuery) + { + return ActiveDatabase.RewriteName(name, isQuery); } private string RewriteValue(string value, string type) @@ -394,7 +399,7 @@ namespace Oqtane.Migrations.EntityBuilders public void UpdateColumn(string columnName, string value, string type, string condition) { - var updateSql = $"UPDATE {RewriteSqlEntityTableName(EntityTableName)} SET {RewriteName(columnName)} = {RewriteValue(value, type)} "; + var updateSql = $"UPDATE {RewriteSqlEntityTableName(EntityTableName)} SET {RewriteName(columnName, true)} = {RewriteValue(value, type)} "; if (!string.IsNullOrEmpty(condition)) { updateSql += $"WHERE {condition}"; From de2c56560ef4a433cfb8593f2db45adb35c035ca Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 25 Jan 2024 13:39:23 -0500 Subject: [PATCH 97/99] resolve regression installation issue with PostgreSQL --- Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs | 5 +++++ .../Migrations/EntityBuilders/BaseEntityBuilder.cs | 2 +- .../Migrations/Framework/MultiDatabaseMigration.cs | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs b/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs index f8806564..a9e6e0d8 100644 --- a/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs +++ b/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs @@ -87,6 +87,11 @@ namespace Oqtane.Database.PostgreSQL return _rewriter.RewriteName(name); } + public override string RewriteName(string name, bool isQuery) + { + return _rewriter.RewriteName(name); + } + public override string RewriteValue(string value, string type) { if (type == "bool") diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs index 34d54a62..b97a3d60 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs @@ -47,7 +47,7 @@ namespace Oqtane.Migrations.EntityBuilders private string RewriteName(string name) { - return RewriteName(name, false); + return ActiveDatabase.RewriteName(name); } private string RewriteName(string name, bool isQuery) diff --git a/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs index 8379c3e3..87fb34cc 100644 --- a/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs +++ b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs @@ -14,7 +14,12 @@ namespace Oqtane.Migrations protected string RewriteName(string name) { - return ActiveDatabase.RewriteName(name); + return ActiveDatabase.RewriteName(name, false); + } + + protected string RewriteName(string name, bool isQuery) + { + return ActiveDatabase.RewriteName(name, isQuery); } } } From e62c529c1ff71a72e67291d4d1478567c56fdf9e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 25 Jan 2024 13:50:13 -0500 Subject: [PATCH 98/99] update default Module and Theme template to .NET 8.0.1 to match framework --- .../External/Client/[Owner].Module.[Module].Client.csproj | 8 ++++---- .../External/Server/[Owner].Module.[Module].Server.csproj | 8 ++++---- .../External/Client/[Owner].Theme.[Theme].Client.csproj | 8 ++++---- 3 files changed, 12 insertions(+), 12 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 32e6c1a1..48bbf770 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 @@ - - - - + + + + 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 7062f5ac..7411d973 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 @@ - - - - + + + + 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 727b74dd..3ab97068 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 bf13f06e6834d3ce2c7f201a1afae1650bc54cfa Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 25 Jan 2024 14:40:32 -0500 Subject: [PATCH 99/99] fix incorrect migration id --- .../Migrations/Tenant/05010003_AddProfileAutocomplete.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs index e7a804e4..6ec00156 100644 --- a/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs +++ b/Oqtane.Server/Migrations/Tenant/05010003_AddProfileAutocomplete.cs @@ -7,7 +7,7 @@ using Oqtane.Repository; namespace Oqtane.Migrations.Tenant { [DbContext(typeof(TenantDBContext))] - [Migration("Tenant.05.00.01.03")] + [Migration("Tenant.05.01.00.03")] public class AddProfileAutocomplete : MultiDatabaseMigration { public AddProfileAutocomplete(IDatabase database) : base(database)