From 85ae7b01b865be24429fe5484c83b775a1f2ff48 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 31 Jul 2025 09:11:09 -0700 Subject: [PATCH 01/12] Update Oqtane.Server.csproj Package Dependencies --- Oqtane.Server/Oqtane.Server.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 44bab0f5..69f4d601 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -36,7 +36,7 @@ - + all @@ -45,8 +45,8 @@ - - + + From 30fcde7157532d19ede87182a82a4e3c02b59012 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 31 Jul 2025 16:06:42 -0400 Subject: [PATCH 02/12] improve notification message when email is verified by administrator --- Oqtane.Server/Managers/UserManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Managers/UserManager.cs b/Oqtane.Server/Managers/UserManager.cs index 5f9cd8dc..76411019 100644 --- a/Oqtane.Server/Managers/UserManager.cs +++ b/Oqtane.Server/Managers/UserManager.cs @@ -261,7 +261,8 @@ namespace Oqtane.Managers var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken); - string body = "Dear " + user.DisplayName + ",\n\nThe Email Address For Your User Account Has Been Verified. You Can Now Login With Your Username And Password."; + string url = alias.Protocol + alias.Name + "/login?name=" + user.Username; + string body = "Dear " + user.DisplayName + ",\n\nThe Email Address For Your User Account Has Been Verified. You Can Now Login With Your Username And Password Using The Link Displayed Below:\n\n" + url + "\n\nThank You!"; var notification = new Notification(user.SiteId, user, "User Account Verification", body); _notifications.AddNotification(notification); } From 4c2960eeae8dff049cc1a038d50cfeded834d4de Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 31 Jul 2025 16:23:40 -0400 Subject: [PATCH 03/12] log the logout event --- Oqtane.Server/Pages/Logout.cshtml.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Pages/Logout.cshtml.cs b/Oqtane.Server/Pages/Logout.cshtml.cs index 5d16ea84..72329c11 100644 --- a/Oqtane.Server/Pages/Logout.cshtml.cs +++ b/Oqtane.Server/Pages/Logout.cshtml.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; +using Oqtane.Enums; using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Managers; @@ -16,11 +17,13 @@ namespace Oqtane.Pages { private readonly IUserManager _userManager; private readonly ISyncManager _syncManager; + private readonly ILogManager _logger; - public LogoutModel(IUserManager userManager, ISyncManager syncManager) + public LogoutModel(IUserManager userManager, ISyncManager syncManager, ILogManager logger) { _userManager = userManager; _syncManager = syncManager; + _logger = logger; } public async Task OnPostAsync(string returnurl, string everywhere) @@ -37,6 +40,7 @@ namespace Oqtane.Pages } _syncManager.AddSyncEvent(alias, EntityNames.User, user.UserId, "Logout"); _syncManager.AddSyncEvent(alias, EntityNames.User, user.UserId, SyncEventActions.Reload); + _logger.Log(LogLevel.Information, this, LogFunction.Security, "User Logout For Username {Username}", user.Username); } await HttpContext.SignOutAsync(Constants.AuthenticationScheme); From 9ae12ff6788cd5a658a06309201b3cf43cad8f9a Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 1 Aug 2025 07:51:58 -0400 Subject: [PATCH 04/12] Resolve issue where visitor cookie was not being added to HttpClient. This was because cookie values cannot contain spaces and therefore need to be Url encoded. --- Oqtane.Server/Controllers/SettingController.cs | 13 +++++++++---- Oqtane.Server/Controllers/VisitorController.cs | 11 ++++++++--- .../Extensions/OqtaneServiceCollectionExtensions.cs | 4 ++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index 2c33c958..b2db2def 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -298,7 +298,7 @@ namespace Oqtane.Controllers if (!authorized) { var visitorCookieName = Constants.VisitorCookiePrefix + _alias.SiteId.ToString(); - authorized = (entityId == GetVisitorCookieId(Request.Cookies[visitorCookieName])); + authorized = (entityId == GetVisitorCookieId(HttpContext.Request.Cookies[visitorCookieName])); } break; default: // custom entity @@ -352,9 +352,14 @@ namespace Oqtane.Controllers private int GetVisitorCookieId(string visitorCookie) { - // visitor cookies contain the visitor id and an expiry date separated by a pipe symbol - visitorCookie = (visitorCookie.Contains("|")) ? visitorCookie.Split('|')[0] : visitorCookie; - return (int.TryParse(visitorCookie, out int visitorId)) ? visitorId : -1; + var visitorId = -1; + if (visitorCookie != null) + { + // visitor cookies now contain the visitor id and an expiry date separated by a pipe symbol + visitorCookie = (visitorCookie.Contains("|")) ? visitorCookie.Split('|')[0] : visitorCookie; + visitorId = int.TryParse(visitorCookie, out int _visitorId) ? _visitorId : -1; + } + return visitorId; } private void AddSyncEvent(string EntityName, int EntityId, int SettingId, string Action) diff --git a/Oqtane.Server/Controllers/VisitorController.cs b/Oqtane.Server/Controllers/VisitorController.cs index e0074452..707d2290 100644 --- a/Oqtane.Server/Controllers/VisitorController.cs +++ b/Oqtane.Server/Controllers/VisitorController.cs @@ -77,9 +77,14 @@ namespace Oqtane.Controllers private int GetVisitorCookieId(string visitorCookie) { - // visitor cookies contain the visitor id and an expiry date separated by a pipe symbol - visitorCookie = (visitorCookie.Contains("|")) ? visitorCookie.Split('|')[0] : visitorCookie; - return (int.TryParse(visitorCookie, out int visitorId)) ? visitorId : -1; + var visitorId = -1; + if (visitorCookie != null) + { + // visitor cookies now contain the visitor id and an expiry date separated by a pipe symbol + visitorCookie = (visitorCookie.Contains("|")) ? visitorCookie.Split('|')[0] : visitorCookie; + visitorId = int.TryParse(visitorCookie, out int _visitorId) ? _visitorId : -1; + } + return visitorId; } } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 3ab2d87f..32fd81ba 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -257,7 +257,7 @@ namespace Microsoft.Extensions.DependencyInjection // set the cookies to allow HttpClient API calls to be authenticated foreach (var cookie in httpContextAccessor.HttpContext.Request.Cookies) { - client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + cookie.Value); + client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + WebUtility.UrlEncode(cookie.Value)); } } @@ -275,7 +275,7 @@ namespace Microsoft.Extensions.DependencyInjection // set the cookies to allow HttpClient API calls to be authenticated foreach (var cookie in httpContextAccessor.HttpContext.Request.Cookies) { - client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + cookie.Value); + client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + WebUtility.UrlEncode(cookie.Value)); } } }); From 02861b8e016c9084c2b694b1a335f55163818a6e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 1 Aug 2025 09:14:58 -0400 Subject: [PATCH 05/12] fix AddModuleMessage not displaying messages in Interactive render mode --- Oqtane.Client/UI/RenderModeBoundary.razor | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index dbaac7f5..4e2f38f1 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -64,8 +64,6 @@ protected override void OnParametersSet() { - _messageContent = ""; - if (ShouldRender()) { if (!string.IsNullOrEmpty(ModuleState.ModuleType)) @@ -107,7 +105,7 @@ public void AddModuleMessage(string message, MessageType type, string position) { - if(message != _messageContent + if (message != _messageContent || type != _messageType || position != _messagePosition) { From aa9664e187bc7dc60ceb8f687d17bf99e9d99ad5 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 1 Aug 2025 10:54:40 -0400 Subject: [PATCH 06/12] improve broken link handling --- Oqtane.Server/Repository/UrlMappingRepository.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Repository/UrlMappingRepository.cs b/Oqtane.Server/Repository/UrlMappingRepository.cs index 774c3189..82f747da 100644 --- a/Oqtane.Server/Repository/UrlMappingRepository.cs +++ b/Oqtane.Server/Repository/UrlMappingRepository.cs @@ -68,6 +68,7 @@ namespace Oqtane.Repository public UrlMapping GetUrlMapping(int siteId, string url) { using var db = _dbContextFactory.CreateDbContext(); + url = (url.StartsWith("/")) ? url.Substring(1) : url; url = (url.Length > 750) ? url.Substring(0, 750) : url; var urlMapping = db.UrlMapping.Where(item => item.SiteId == siteId && item.Url == url).FirstOrDefault(); if (urlMapping == null) @@ -82,7 +83,14 @@ namespace Oqtane.Repository urlMapping.Requests = 1; urlMapping.CreatedOn = DateTime.UtcNow; urlMapping.RequestedOn = DateTime.UtcNow; - urlMapping = AddUrlMapping(urlMapping); + try + { + urlMapping = AddUrlMapping(urlMapping); + } + catch + { + // ignore duplicate key exception which can be caused by a race condition + } } } else From 23c3c47db4df6d814f5618c6a649f93e8ccf7f63 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 1 Aug 2025 14:45:40 -0400 Subject: [PATCH 07/12] add active/deleted filter in User Management --- Oqtane.Client/Modules/Admin/Users/Edit.razor | 2 +- Oqtane.Client/Modules/Admin/Users/Index.razor | 52 ++++++++++++++----- .../Resources/Modules/Admin/Users/Index.resx | 6 +++ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor index 2d75d27a..35e43bb9 100644 --- a/Oqtane.Client/Modules/Admin/Users/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor @@ -153,7 +153,7 @@
@SharedLocalizer["Cancel"] - @if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) && PageState.Runtime != Shared.Runtime.Hybrid && !_ishost) + @if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) && PageState.Runtime != Shared.Runtime.Hybrid && !_ishost && _isdeleted != "True") { } diff --git a/Oqtane.Client/Modules/Admin/Users/Index.razor b/Oqtane.Client/Modules/Admin/Users/Index.razor index 7e53d87e..53218b3c 100644 --- a/Oqtane.Client/Modules/Admin/Users/Index.razor +++ b/Oqtane.Client/Modules/Admin/Users/Index.razor @@ -17,8 +17,21 @@ else { -   - +
+
+
+   + +
+
+ +
+
+
+
@@ -495,6 +508,7 @@ else @code { private List users; + private string _deleted = "false"; private string _allowregistration; private string _registerurl; @@ -564,7 +578,7 @@ else protected override async Task OnInitializedAsync() { - await LoadUsersAsync(true); + await LoadUsersAsync(); var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); _allowregistration = PageState.Site.AllowRegistration.ToString().ToLower(); @@ -636,20 +650,32 @@ else _allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true"); } - private async Task LoadUsersAsync(bool load) + private async Task LoadUsersAsync() { - if (load) + users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered); + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { - users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered); - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host); - users.AddRange(hosts); - users = users.OrderBy(u => u.User.DisplayName).ToList(); - } + var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host); + users.AddRange(hosts); + users = users.OrderBy(u => u.User.DisplayName).ToList(); } + users = users.Where(item => item.User.IsDeleted == bool.Parse(_deleted)).ToList(); } + private async void DeletedChanged(ChangeEventArgs e) + { + try + { + _deleted = e.Value.ToString(); + await LoadUsersAsync(); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error On DeletedChanged"); + } + } + private async Task DeleteUser(UserRole UserRole) { try @@ -672,7 +698,7 @@ else await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name); } AddModuleMessage(Localizer["Success.DeleteUser"], MessageType.Success); - await LoadUsersAsync(true); + await LoadUsersAsync(); StateHasChanged(); } catch (Exception ex) diff --git a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx index 1a008727..16e0d40e 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx @@ -537,4 +537,10 @@ Indicate if host roles are supported from the identity provider. Please use caution with this option as it allows the host user to administrate every site within your installation. + + Active Users + + + Deleted Users + \ No newline at end of file From 61194173313af67cb828c050a7b8366eed501a3e Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 1 Aug 2025 15:43:21 -0400 Subject: [PATCH 08/12] improve interactive rendering logic --- Oqtane.Client/UI/Routes.razor | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index baf8596a..e029fd6d 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -83,10 +83,13 @@ protected override void OnAfterRender(bool firstRender) { - if (firstRender && _display == "display: none;") + if (firstRender) { _display = ""; - StateHasChanged(); // required or else the UI will not refresh + if (PageState != null && PageState.Site.Prerender) + { + StateHasChanged(); // required or else the UI will not refresh + } } } From 334137454e09a6ac04f4fe3d44442257e7880c00 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Sat, 2 Aug 2025 09:46:02 -0400 Subject: [PATCH 09/12] improve FileManager performance when ShowFiles is disabled --- .../Modules/Controls/FileManager.razor | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 9581c58a..af092f0d 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -447,20 +447,31 @@ } else { - // set FileId to first file in upload collection - var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]); - if (file != null) + if (AnonymizeUploadFilenames) { - FileId = file.FileId; - await SetImage(); -#pragma warning disable CS0618 - await OnSelect.InvokeAsync(FileId); -#pragma warning restore CS0618 - await OnSelectFile.InvokeAsync(FileId); - await OnUpload.InvokeAsync(FileId); + // it is not possible to determine the FileId of the uploaded file when filenames are anonymized + await OnUpload.InvokeAsync(-1); + } + else + { + // set FileId to first file in upload collection + var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]); + if (file != null) + { + FileId = file.FileId; + await SetImage(); +#pragma warning disable CS0618 + await OnSelect.InvokeAsync(FileId); +#pragma warning restore CS0618 + await OnSelectFile.InvokeAsync(FileId); + await OnUpload.InvokeAsync(FileId); + } + } + if (ShowFiles) + { + await GetFiles(); + StateHasChanged(); } - await GetFiles(); - StateHasChanged(); } } catch (Exception ex) @@ -492,6 +503,7 @@ private async Task DeleteFile() { _message = string.Empty; + try { await FileService.DeleteFileAsync(FileId); @@ -504,14 +516,17 @@ _messagetype = MessageType.Success; } - await GetFiles(); - FileId = -1; - await SetImage(); + if (ShowFiles) + { + await GetFiles(); + FileId = -1; + await SetImage(); #pragma warning disable CS0618 - await OnSelect.InvokeAsync(FileId); + await OnSelect.InvokeAsync(FileId); #pragma warning restore CS0618 - await OnSelectFile.InvokeAsync(FileId); - StateHasChanged(); + await OnSelectFile.InvokeAsync(FileId); + StateHasChanged(); + } } catch (Exception ex) { From 77949331e2bc64196be7add23cb7574910d1ff17 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 4 Aug 2025 13:06:16 -0400 Subject: [PATCH 10/12] improve FileManager performance --- .../Modules/Controls/FileManager.razor | 266 +++++++++--------- 1 file changed, 133 insertions(+), 133 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index af092f0d..c3ac1846 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -107,7 +107,7 @@ @code { private bool _initialized = false; - private List _folders; + private List _folders = new List(); private List _files = new List(); private string _fileinputid = string.Empty; private string _progressinfoid = string.Empty; @@ -198,19 +198,22 @@ Filter = "nupkg"; ShowSuccess = true; } - - if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder) + else { - Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder); - if (folder != null) + // folder path specified rather than folderid + if (!string.IsNullOrEmpty(Folder)) { - FolderId = folder.FolderId; - } - else - { - FolderId = -1; - _message = "Folder Path " + Folder + " Does Not Exist"; - _messagetype = MessageType.Error; + Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder); + if (folder != null) + { + FolderId = folder.FolderId; + } + else + { + FolderId = -1; + _message = "Folder Path " + Folder + " Does Not Exist"; + _messagetype = MessageType.Error; + } } } @@ -245,25 +248,24 @@ } } - await SetImage(); - if (!string.IsNullOrEmpty(Filter)) { _filter = "." + Filter.Replace(",", ",."); } + GetFolderPermission(); + await SetImage(); await GetFiles(); _initialized = true; } - private async Task GetFiles() + private void GetFolderPermission() { _haseditpermission = false; if (Folder == Constants.PackagesFolder) { _haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); - _files = new List(); } else { @@ -271,69 +273,14 @@ if (folder != null) { _haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.PermissionList); - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Browse, folder.PermissionList)) - { - _files = await FileService.GetFilesAsync(FolderId); - } - else - { - _files = new List(); - } } else { _haseditpermission = false; - _files = new List(); - } - if (_filter != "*") - { - List filtered = new List(); - foreach (File file in _files) - { - if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1) - { - filtered.Add(file); - } - } - _files = filtered; } } } - private async Task FolderChanged(ChangeEventArgs e) - { - _message = string.Empty; - try - { - FolderId = int.Parse((string)e.Value); - await GetFiles(); - FileId = -1; - _file = null; - _image = string.Empty; - - await OnSelectFolder.InvokeAsync(FolderId); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); - _message = Localizer["Error.File.Load"]; - _messagetype = MessageType.Error; - } - } - - private async Task FileChanged(ChangeEventArgs e) - { - _message = string.Empty; - FileId = int.Parse((string)e.Value); - await SetImage(); - #pragma warning disable CS0618 - await OnSelect.InvokeAsync(FileId); - #pragma warning restore CS0618 - await OnSelectFile.InvokeAsync(FileId); - StateHasChanged(); - } - private async Task SetImage() { _image = string.Empty; @@ -357,6 +304,74 @@ } } + private async Task GetFiles() + { + if (ShowFiles) + { + Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId); + if (folder != null) + { + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Browse, folder.PermissionList)) + { + _files = await FileService.GetFilesAsync(FolderId); + } + else + { + _files = new List(); + } + } + else + { + _files = new List(); + } + if (_filter != "*") + { + List filtered = new List(); + foreach (File file in _files) + { + if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1) + { + filtered.Add(file); + } + } + _files = filtered; + } + } + } + + private async Task FolderChanged(ChangeEventArgs e) + { + _message = string.Empty; + try + { + FolderId = int.Parse((string)e.Value); + await OnSelectFolder.InvokeAsync(FolderId); + FileId = -1; + GetFolderPermission(); + await SetImage(); + await GetFiles(); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); + _message = Localizer["Error.File.Load"]; + _messagetype = MessageType.Error; + } + } + + private async Task FileChanged(ChangeEventArgs e) + { + _message = string.Empty; + FileId = int.Parse((string)e.Value); + #pragma warning disable CS0618 + await OnSelect.InvokeAsync(FileId); + #pragma warning restore CS0618 + await OnSelectFile.InvokeAsync(FileId); + await SetImage(); + StateHasChanged(); + } + private async Task UploadFiles() { _message = string.Empty; @@ -433,45 +448,33 @@ _message = Localizer["Success.File.Upload"]; _messagetype = MessageType.Success; } - } - else - { - await logger.LogError("File Upload Failed {Files}", uploads); - _message = Localizer["Error.File.Upload"]; - _messagetype = MessageType.Error; - } - if (Folder == Constants.PackagesFolder) - { - await OnUpload.InvokeAsync(-1); - } - else - { - if (AnonymizeUploadFilenames) - { - // it is not possible to determine the FileId of the uploaded file when filenames are anonymized - await OnUpload.InvokeAsync(-1); - } - else + FileId = -1; + if (Folder != Constants.PackagesFolder && !AnonymizeUploadFilenames) { // set FileId to first file in upload collection var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]); if (file != null) { FileId = file.FileId; - await SetImage(); -#pragma warning disable CS0618 - await OnSelect.InvokeAsync(FileId); -#pragma warning restore CS0618 - await OnSelectFile.InvokeAsync(FileId); - await OnUpload.InvokeAsync(FileId); } } - if (ShowFiles) - { - await GetFiles(); - StateHasChanged(); - } + + await OnUpload.InvokeAsync(FileId); +#pragma warning disable CS0618 + await OnSelect.InvokeAsync(FileId); +#pragma warning restore CS0618 + await OnSelectFile.InvokeAsync(FileId); + + await SetImage(); + await GetFiles(); + StateHasChanged(); + } + else + { + await logger.LogError("File Upload Failed {Files}", uploads); + _message = Localizer["Error.File.Upload"]; + _messagetype = MessageType.Error; } } catch (Exception ex) @@ -485,7 +488,6 @@ finally { tokenSource.Dispose(); } - } else { @@ -503,7 +505,6 @@ private async Task DeleteFile() { _message = string.Empty; - try { await FileService.DeleteFileAsync(FileId); @@ -516,50 +517,49 @@ _messagetype = MessageType.Success; } - if (ShowFiles) - { - await GetFiles(); - FileId = -1; - await SetImage(); + FileId = -1; #pragma warning disable CS0618 - await OnSelect.InvokeAsync(FileId); + await OnSelect.InvokeAsync(FileId); #pragma warning restore CS0618 - await OnSelectFile.InvokeAsync(FileId); - StateHasChanged(); - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); + await OnSelectFile.InvokeAsync(FileId); - _message = Localizer["Error.File.Delete"]; - _messagetype = MessageType.Error; - } - } + await SetImage(); + await GetFiles(); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); - public int GetFileId() => FileId; + _message = Localizer["Error.File.Delete"]; + _messagetype = MessageType.Error; + } + } - public int GetFolderId() => FolderId; + public int GetFileId() => FileId; - public File GetFile() => _file; + public int GetFolderId() => FolderId; - public async Task Refresh() - { - await Refresh(-1); - } + public File GetFile() => _file; - public async Task Refresh(int fileId) - { - await GetFiles(); - if (fileId != -1) + public async Task Refresh() + { + await Refresh(-1); + } + + public async Task Refresh(int fileId) + { + await GetFiles(); + FileId = -1; + if (fileId != -1) { var file = _files.Where(item => item.FileId == fileId).FirstOrDefault(); if (file != null) { FileId = file.FileId; - await SetImage(); } } - StateHasChanged(); + await SetImage(); + StateHasChanged(); } } From 2cefab1c644ae3638ee433c224866bda29437451 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 4 Aug 2025 13:09:37 -0400 Subject: [PATCH 11/12] resolve interactive page load --- Oqtane.Client/UI/Routes.razor | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index e029fd6d..9cc3b5cc 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -48,7 +48,7 @@ private bool _initialized = false; private bool _installed = false; - private string _display = "display: none;"; // prevents flash on initial interactive page load when using prerendering + private string _display = "display: none;"; // prevents flash on initial interactive page load private PageState _pageState { get; set; } @@ -86,10 +86,7 @@ if (firstRender) { _display = ""; - if (PageState != null && PageState.Site.Prerender) - { - StateHasChanged(); // required or else the UI will not refresh - } + StateHasChanged(); } } From 7b36f8d122fe25780794cb88e2c16342b79257fd Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 4 Aug 2025 17:18:25 -0400 Subject: [PATCH 12/12] rolling back to SQLitePCLRaw.bundle_e_sqlite3 version 2.1.11 --- Oqtane.Server/Oqtane.Server.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 69f4d601..a05b1a9d 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -45,7 +45,7 @@ - +