From 884793f729babd7ade0eef1cfe508d93fe8569ac Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Sun, 5 Feb 2023 16:47:09 +0100 Subject: [PATCH] Added fix to maintenance page so it is shown before the content cache is created. (#13767) --- .../Persistence/Dtos/KeyValueDto.cs | 3 ++ .../MaintenanceModeActionFilterAttribute.cs | 5 +-- .../PublishedRequestFilterAttribute.cs | 6 +++ .../UmbracoBuilderExtensions.cs | 4 +- .../Routing/UmbracoRouteValueTransformer.cs | 38 +++++++++++++++++-- .../UmbracoRouteValueTransformerTests.cs | 3 +- 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs index c5829873fe..5576b5ca43 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs @@ -5,6 +5,7 @@ using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions; namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; + [TableName(Constants.DatabaseSchema.Tables.KeyValue)] [PrimaryKey("key", AutoIncrement = false)] [ExplicitColumns] @@ -22,4 +23,6 @@ internal class KeyValueDto [Column("updated")] [Constraint(Default = SystemMethods.CurrentDateTime)] public DateTime UpdateDate { get; set; } + + //NOTE that changes to this file needs to be backward compatible. Otherwise our upgrader cannot work, as it uses this to read from the db } diff --git a/src/Umbraco.Web.Common/Controllers/MaintenanceModeActionFilterAttribute.cs b/src/Umbraco.Web.Common/Controllers/MaintenanceModeActionFilterAttribute.cs index 3c4f82f25d..4f5877a765 100644 --- a/src/Umbraco.Web.Common/Controllers/MaintenanceModeActionFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Controllers/MaintenanceModeActionFilterAttribute.cs @@ -10,9 +10,8 @@ namespace Umbraco.Cms.Web.Common.Controllers; internal sealed class MaintenanceModeActionFilterAttribute : TypeFilterAttribute { - public MaintenanceModeActionFilterAttribute() : base(typeof(MaintenanceModeActionFilter)) - { - } + + public MaintenanceModeActionFilterAttribute() : base(typeof(MaintenanceModeActionFilter)) => Order = int.MinValue; // Ensures this run as the first filter. private sealed class MaintenanceModeActionFilter : IActionFilter { diff --git a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs index 95b8bc7320..10986d3882 100644 --- a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs @@ -15,6 +15,12 @@ internal class PublishedRequestFilterAttribute : ResultFilterAttribute /// public override void OnResultExecuting(ResultExecutingContext context) { + if (context.Result is not null) + { + // If the result is already set, we just skip the execution + return; + } + UmbracoRouteValues routeVals = GetUmbracoRouteValues(context); IPublishedRequest pcr = routeVals.PublishedRequest; diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 1bd05a424d..12c47c5fa4 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -55,7 +56,8 @@ public static partial class UmbracoBuilderExtensions x.GetRequiredService(), x.GetRequiredService(), x.GetRequiredService(), - x.GetRequiredService() + x.GetRequiredService(), + x.GetRequiredService>() )); builder.Services.AddSingleton(); builder.Services.TryAddEnumerable(Singleton()); diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index 5617797ec7..4e4749860c 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -14,6 +14,7 @@ using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Web.Common.Controllers; using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Cms.Web.Common.Security; @@ -49,6 +50,7 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer private readonly IRuntimeState _runtime; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IUmbracoVirtualPageRoute _umbracoVirtualPageRoute; + private GlobalSettings _globalSettings; [Obsolete("Please use constructor that is not obsolete, instead of this. This will be removed in Umbraco 13.")] public UmbracoRouteValueTransformer( @@ -64,7 +66,7 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer IControllerActionSearcher controllerActionSearcher, IEventAggregator eventAggregator, IPublicAccessRequestHandler publicAccessRequestHandler) - : this(logger, umbracoContextAccessor, publishedRouter, runtime, routeValuesFactory, routableDocumentFilter, dataProtectionProvider, controllerActionSearcher, publicAccessRequestHandler, StaticServiceProvider.Instance.GetRequiredService()) + : this(logger, umbracoContextAccessor, publishedRouter, runtime, routeValuesFactory, routableDocumentFilter, dataProtectionProvider, controllerActionSearcher, publicAccessRequestHandler, StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService>()) { } @@ -79,10 +81,26 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer IDataProtectionProvider dataProtectionProvider, IControllerActionSearcher controllerActionSearcher, IPublicAccessRequestHandler publicAccessRequestHandler) - : this(logger, umbracoContextAccessor, publishedRouter, runtime, routeValuesFactory, routableDocumentFilter, dataProtectionProvider, controllerActionSearcher, publicAccessRequestHandler, StaticServiceProvider.Instance.GetRequiredService()) + : this(logger, umbracoContextAccessor, publishedRouter, runtime, routeValuesFactory, routableDocumentFilter, dataProtectionProvider, controllerActionSearcher, publicAccessRequestHandler, StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService>()) { } + [Obsolete("Please use constructor that is not obsolete, instead of this. This will be removed in Umbraco 13.")] + public UmbracoRouteValueTransformer( + ILogger logger, + IUmbracoContextAccessor umbracoContextAccessor, + IPublishedRouter publishedRouter, + IRuntimeState runtime, + IUmbracoRouteValuesFactory routeValuesFactory, + IRoutableDocumentFilter routableDocumentFilter, + IDataProtectionProvider dataProtectionProvider, + IControllerActionSearcher controllerActionSearcher, + IPublicAccessRequestHandler publicAccessRequestHandler, + IUmbracoVirtualPageRoute umbracoVirtualPageRoute) + : this(logger, umbracoContextAccessor, publishedRouter, runtime, routeValuesFactory, routableDocumentFilter, dataProtectionProvider, controllerActionSearcher, publicAccessRequestHandler, StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService>()) + + { + } /// /// Initializes a new instance of the class. @@ -97,7 +115,8 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer IDataProtectionProvider dataProtectionProvider, IControllerActionSearcher controllerActionSearcher, IPublicAccessRequestHandler publicAccessRequestHandler, - IUmbracoVirtualPageRoute umbracoVirtualPageRoute) + IUmbracoVirtualPageRoute umbracoVirtualPageRoute, + IOptionsMonitor globalSettings) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _umbracoContextAccessor = @@ -111,6 +130,8 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer _controllerActionSearcher = controllerActionSearcher; _publicAccessRequestHandler = publicAccessRequestHandler; _umbracoVirtualPageRoute = umbracoVirtualPageRoute; + _globalSettings = globalSettings.CurrentValue; + globalSettings.OnChange(x => _globalSettings = x); } /// @@ -154,6 +175,17 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer return null!; } + // Check if the maintenance page should be shown + if (_runtime.Level == RuntimeLevel.Upgrade && _globalSettings.ShowMaintenancePageWhenInUpgradeState) + { + return new RouteValueDictionary + { + // Redirects to the RenderController who handles maintenance page in a filter, instead of having a dedicated controller + [ControllerToken] = ControllerExtensions.GetControllerName(), + [ActionToken] = nameof(RenderController.Index), + }; + } + // Check if there is no existing content and return the no content controller if (!umbracoContext.Content?.HasContent() ?? false) { diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs index cd48e870fc..ec42030e7c 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs @@ -67,7 +67,8 @@ public class UmbracoRouteValueTransformerTests Mock.Of(), Mock.Of(), publicAccessRequestHandler.Object, - Mock.Of() + Mock.Of(), + Mock.Of>() ); return transformer; }