From 367a23171d187a5b69a1789dcb8363fc5805e5a5 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 30 Mar 2021 17:26:03 +0300 Subject: [PATCH 1/6] thene -> theme --- Oqtane.Client/Modules/Admin/Themes/View.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/Admin/Themes/View.razor b/Oqtane.Client/Modules/Admin/Themes/View.razor index 2510759d..d6d4b4de 100644 --- a/Oqtane.Client/Modules/Admin/Themes/View.razor +++ b/Oqtane.Client/Modules/Admin/Themes/View.razor @@ -24,7 +24,7 @@ - + From 09c040128a28a2ff07ab2ccbf39922604397d8b6 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 30 Mar 2021 17:48:49 -0400 Subject: [PATCH 2/6] Ensure Install Wizard will only be displayed if the Master database connection string in appsettings.json is not specified. This addresses a potential security issue where the Install Wizard could be displayed in an existing installation if the Master database connection failed during startup. --- Oqtane.Client/App.razor | 28 ++++++++++------- Oqtane.Client/Modules/Admin/Sites/Index.razor | 2 +- .../Controllers/InstallationController.cs | 3 +- .../Infrastructure/DatabaseManager.cs | 30 +++++++++++++------ .../Interfaces/IDatabaseManager.cs | 4 +-- .../Infrastructure/UpgradeManager.cs | 15 ++++++---- Oqtane.Server/Pages/_Host.cshtml | 4 ++- Oqtane.Server/wwwroot/css/app.css | 9 +++++- 8 files changed, 63 insertions(+), 32 deletions(-) diff --git a/Oqtane.Client/App.razor b/Oqtane.Client/App.razor index 3d13adff..ca4b25bd 100644 --- a/Oqtane.Client/App.razor +++ b/Oqtane.Client/App.razor @@ -1,31 +1,39 @@ -@inject IInstallationService InstallationService +@inject IInstallationService InstallationService @if (_initialized) { - @if (!_installed) + @if (!_installation.Success) { } else { - - - - - + @if (string.IsNullOrEmpty(_installation.Message)) + { + + + + + + } + else + { +
+ @_installation.Message +
+ } } } @code { + private Installation _installation; private bool _initialized; - private bool _installed; private PageState PageState { get; set; } protected override async Task OnParametersSetAsync() { - var installation = await InstallationService.IsInstalled(); - _installed = installation.Success; + _installation = await InstallationService.IsInstalled(); _initialized = true; } diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 3a571cd3..9d028e1d 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -22,7 +22,7 @@ else - @context.Name + @context.Name } diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 01de103b..2d8491d6 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -55,8 +55,7 @@ namespace Oqtane.Controllers [HttpGet("installed")] public Installation IsInstalled() { - bool isInstalled = _databaseManager.IsInstalled(); - return new Installation {Success = isInstalled, Message = string.Empty}; + return _databaseManager.IsInstalled(); } [HttpGet("upgrade")] diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 308b5cf0..9ee98e25 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -33,27 +33,30 @@ namespace Oqtane.Infrastructure _cache = cache; } - public bool IsInstalled() + public Installation IsInstalled() { - var defaultConnectionString = NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey)); - var result = !string.IsNullOrEmpty(defaultConnectionString); - if (result) + var result = new Installation { Success = false, Message = string.Empty }; + if (!string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey))) { + result.Success = true; using (var scope = _serviceScopeFactory.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); - result = db.Database.CanConnect(); - if (result) + if (db.Database.CanConnect()) { try { - result = db.Tenant.Any(); + var provisioned = db.Tenant.Any(); } catch { - result = false; + result.Message = "Master Database Not Installed Correctly"; } } + else + { + result.Message = "Cannot Connect To Master Database"; + } } } return result; @@ -74,7 +77,8 @@ namespace Oqtane.Infrastructure // startup or silent installation install = new InstallConfig { ConnectionString = _config.GetConnectionString(SettingKeys.ConnectionStringKey), TenantName = TenantNames.Master, IsNewTenant = false }; - if (!IsInstalled()) + var installation = IsInstalled(); + if (!installation.Success) { install.Aliases = GetInstallationConfig(SettingKeys.DefaultAliasKey, string.Empty); install.HostPassword = GetInstallationConfig(SettingKeys.HostPasswordKey, string.Empty); @@ -97,6 +101,14 @@ namespace Oqtane.Infrastructure install.ConnectionString = ""; } } + else + { + if (!string.IsNullOrEmpty(installation.Message)) + { + // problem with prior installation + install.ConnectionString = ""; + } + } } else { diff --git a/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs b/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs index ffb0ff9c..6257db16 100644 --- a/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs @@ -1,11 +1,11 @@ -using Oqtane.Models; +using Oqtane.Models; using Oqtane.Shared; namespace Oqtane.Infrastructure { public interface IDatabaseManager { - bool IsInstalled(); + Installation IsInstalled(); Installation Install(); Installation Install(InstallConfig install); } diff --git a/Oqtane.Server/Infrastructure/UpgradeManager.cs b/Oqtane.Server/Infrastructure/UpgradeManager.cs index cbfcc63b..b2385b2b 100644 --- a/Oqtane.Server/Infrastructure/UpgradeManager.cs +++ b/Oqtane.Server/Infrastructure/UpgradeManager.cs @@ -25,14 +25,12 @@ namespace Oqtane.Infrastructure public void Upgrade(Tenant tenant, string version) { - // core framework upgrade logic - note that you can check if current tenant is Master if you only want to execute logic once - var pageTemplates = new List(); - + // core framework upgrade logic - note that you can check if current tenant is Master if you only want to execute the logic once switch (version) { case "0.9.0": - // add a page to all existing sites on upgrade - + // this code is commented out on purpose - it provides an example of how to programmatically add a page to all existing sites on upgrade + var pageTemplates = new List(); //pageTemplates.Add(new PageTemplate //{ // Name = "Test", @@ -68,7 +66,12 @@ namespace Oqtane.Infrastructure case "2.0.2": if (tenant.Name == TenantNames.Master) { - Directory.Delete(Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", "Internal", Path.DirectorySeparatorChar.ToString()), true); + // remove Internal module template files as they are no longer supported + var internalTemplatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", "Internal", Path.DirectorySeparatorChar.ToString()); + if (Directory.Exists(internalTemplatePath)) + { + Directory.Delete(internalTemplatePath, true); + } } break; } diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index e1cc6c21..1678969c 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -37,7 +37,9 @@ @if (Model.Message != "") { - @Model.Message +
+ @Model.Message +
} diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css index ce87887d..eebf63a6 100644 --- a/Oqtane.Server/wwwroot/css/app.css +++ b/Oqtane.Server/wwwroot/css/app.css @@ -1,4 +1,4 @@ -@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); +@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; @@ -125,6 +125,13 @@ app { vertical-align: inherit; } +.app-alert { + padding: 20px; + background-color: #f44336; /* red */ + color: white; + margin-bottom: 15px; +} + /* Tooltips */ .app-tooltip { cursor: help; From ec0b317f80589b2afbf2157c12cd015145aed390 Mon Sep 17 00:00:00 2001 From: hishamco Date: Wed, 31 Mar 2021 00:50:19 +0300 Subject: [PATCH 3/6] Fix localizer in Admin pages --- Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor | 2 +- Oqtane.Client/Modules/Admin/Pages/Index.razor | 2 +- Oqtane.Client/Modules/Admin/Profiles/Index.razor | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor index 538bf700..3ebfed0b 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor @@ -26,7 +26,7 @@ else @if (context.AssemblyName != "Oqtane.Client") { - + } @context.Name diff --git a/Oqtane.Client/Modules/Admin/Pages/Index.razor b/Oqtane.Client/Modules/Admin/Pages/Index.razor index 4ff925fc..fef67427 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Index.razor @@ -16,7 +16,7 @@ - + @(new string('-', context.Level * 2))@(context.Name) diff --git a/Oqtane.Client/Modules/Admin/Profiles/Index.razor b/Oqtane.Client/Modules/Admin/Profiles/Index.razor index 141730f9..4705b290 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Index.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Index.razor @@ -19,7 +19,7 @@ else - + @context.Name From c92a81fcb6f1f644b0110bdb9558fc64092a3468 Mon Sep 17 00:00:00 2001 From: hishamco Date: Wed, 31 Mar 2021 14:15:36 +0300 Subject: [PATCH 4/6] Remove unnecessary localizer from RecycleBin page --- Oqtane.Client/Modules/Admin/RecycleBin/Index.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor index 7c30c7a1..47e2a47a 100644 --- a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor +++ b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor @@ -34,7 +34,7 @@ @if (_pages.Any()) {
- +
} } @@ -68,7 +68,7 @@ @if (_modules.Any()) {
- +
} From bd48e1d8f1d37c7285ea4f4e228a89f3b1efe2ef Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 31 Mar 2021 15:39:01 -0400 Subject: [PATCH 5/6] if running on WebAssembly reload the client application if the server application is restarted --- Oqtane.Client/UI/SiteRouter.razor | 9 +++++++-- Oqtane.Server/Infrastructure/SyncManager.cs | 4 ++-- Oqtane.Server/Startup.cs | 5 ++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 6b42f15b..ea3148dc 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -80,7 +80,7 @@ var urlparameters = string.Empty; var editmode = false; var reload = Reload.None; - var lastsyncdate = DateTime.UtcNow; + var lastsyncdate = DateTime.UtcNow.AddHours(-1); var runtime = GetRuntime(); Uri uri = new Uri(_absoluteUri); @@ -107,9 +107,14 @@ SiteState.Alias = alias; // set state for services lastsyncdate = alias.SyncDate; - // process any sync events for site + // process any sync events if (reload != Reload.Site && alias.SyncEvents.Any()) { + // if running on WebAssembly reload the client application if the server application was restarted + if (runtime == Shared.Runtime.WebAssembly && PageState != null && alias.SyncEvents.Exists(item => item.TenantId == -1)) + { + NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority + "?reload", true); + } if (alias.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == alias.SiteId)) { reload = Reload.Site; diff --git a/Oqtane.Server/Infrastructure/SyncManager.cs b/Oqtane.Server/Infrastructure/SyncManager.cs index f41c01b0..d70cc456 100644 --- a/Oqtane.Server/Infrastructure/SyncManager.cs +++ b/Oqtane.Server/Infrastructure/SyncManager.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System; using System.Collections.Generic; using System.Linq; @@ -17,7 +17,7 @@ namespace Oqtane.Infrastructure public List GetSyncEvents(int tenantId, DateTime lastSyncDate) { - return SyncEvents.Where(item => item.TenantId == tenantId && item.ModifiedOn >= lastSyncDate).ToList(); + return SyncEvents.Where(item => (item.TenantId == tenantId || item.TenantId == -1) && item.ModifiedOn >= lastSyncDate).ToList(); } public void AddSyncEvent(int tenantId, string entityName, int entityId) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index ba2a7d89..1e744c01 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -226,7 +226,7 @@ namespace Oqtane } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync) { ServiceActivator.Configure(app.ApplicationServices); @@ -264,6 +264,9 @@ namespace Oqtane endpoints.MapControllers(); endpoints.MapFallbackToPage("/_Host"); }); + + // create a sync event to identify server application startup + sync.AddSyncEvent(-1, "Application", -1); } } } From 58c84da9c990f62bce927109a7476a1fdb66147a Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 1 Apr 2021 09:44:07 -0400 Subject: [PATCH 6/6] add ability to test SMTP connection in Site Settings --- Oqtane.Client/Modules/Admin/Site/Index.razor | 287 ++++++++++-------- .../Modules/Admin/UserProfile/Add.razor | 2 +- .../Modules/Admin/UserProfile/View.razor | 2 +- Oqtane.Client/UI/SiteRouter.razor | 2 +- .../Controllers/NotificationController.cs | 6 +- 5 files changed, 168 insertions(+), 131 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index bbfd28f7..62de4921 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -7,146 +7,150 @@ @inject IThemeService ThemeService @inject ISettingService SettingService @inject IStringLocalizer Localizer +@inject INotificationService NotificationService @if (_initialized) { - - - - - - - - - - - - - - - - - - - - - - - - - - @if (_layouts.Count > 0) - { +
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
+ + + + + + + + + + + + + + + + + +
- + - +
+ + + +
+ + + +
+ + + +
+ + + +
+
+ + + + + + + + + + + + - } - - - - - - - - - - - - - - - - -
+ + + +
+ + + +
+ + +
- - - -
- - - -
- - - -
- - - -
- + @if (_layouts.Count > 0) + { + + + + + + + + + } + + + + + + + + + + + + + + + + + +
@@ -201,6 +205,8 @@
- @Localizer["Please Note That SMTP Requires The Notification Job To Be Enabled In the Scheduled Jobs"] + @Localizer["Please Note That SMTP Requires The Notification Job To Be Enabled In Scheduled Jobs"]
+ +

@@ -482,7 +488,6 @@ await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); await logger.LogInformation("Site Settings Saved {Site}", site); - AddModuleMessage(Localizer["Site Settings Saved"], MessageType.Success); } } @@ -502,4 +507,36 @@ AddModuleMessage(Localizer["Error Saving Site"], MessageType.Error); } } + + private async Task SendEmail() + { + if (_smtphost != "" && _smtpport != "" && _smtpsender != "") + { + try + { + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + SettingService.SetSetting(settings, "SMTPHost", _smtphost); + SettingService.SetSetting(settings, "SMTPPort", _smtpport); + SettingService.SetSetting(settings, "SMTPSSL", _smtpssl); + SettingService.SetSetting(settings, "SMTPUsername", _smtpusername); + SettingService.SetSetting(settings, "SMTPPassword", _smtppassword); + SettingService.SetSetting(settings, "SMTPSender", _smtpsender); + await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); + await logger.LogInformation("Site SMTP Settings Saved"); + + await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly.")); + AddModuleMessage(Localizer["SMTP Settings Saved And A Message Has Been Sent To The Email Address Associated To Your User Account... Please Wait A Few Minutes For Delivery. If You Do Not Receive The Email Please Review The Notification Job In Scheduled Jobs For Any Log Details."], MessageType.Info); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Testing SMTP Configuration"); + AddModuleMessage(Localizer["Error Testing SMTP Configuration"], MessageType.Error); + } + } + else + { + AddModuleMessage(Localizer["You Must Specify The SMTP Host, Port, And Sender"], MessageType.Warning); + } + + } } diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor index dcc96ff4..48959e80 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor @@ -55,7 +55,7 @@ { var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null); notification = await NotificationService.AddNotificationAsync(notification); - await logger.LogInformation("Notification Created {Notification}", notification); + await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId); NavigationManager.NavigateTo(NavigateUrl()); } else diff --git a/Oqtane.Client/Modules/Admin/UserProfile/View.razor b/Oqtane.Client/Modules/Admin/UserProfile/View.razor index ff9f3937..263a0345 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/View.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/View.razor @@ -183,7 +183,7 @@ { var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, notificationid); notification = await NotificationService.AddNotificationAsync(notification); - await logger.LogInformation("Notification Created {Notification}", notification); + await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId); NavigationManager.NavigateTo(NavigateUrl()); } else diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index ea3148dc..70bda7df 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -113,7 +113,7 @@ // if running on WebAssembly reload the client application if the server application was restarted if (runtime == Shared.Runtime.WebAssembly && PageState != null && alias.SyncEvents.Exists(item => item.TenantId == -1)) { - NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority + "?reload", true); + NavigationManager.NavigateTo(_absoluteUri + (!_absoluteUri.Contains("?") ? "?" : "&") + "reload", true); } if (alias.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == alias.SiteId)) { diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index 5c73eb78..8fbb4872 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Enums; @@ -65,7 +65,7 @@ namespace Oqtane.Controllers if (IsAuthorized(notification.FromUserId)) { notification = _notifications.AddNotification(notification); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {Notification}", notification); + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {NotificationId}", notification.NotificationId); } return notification; } @@ -78,7 +78,7 @@ namespace Oqtane.Controllers if (IsAuthorized(notification.FromUserId)) { notification = _notifications.UpdateNotification(notification); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {Folder}", notification); + _logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {NotificationId}", notification.NotificationId); } return notification; }