From a4400f04a5e7932a032a1a74d298936e91f1aecd Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 26 Apr 2021 21:09:06 +0200 Subject: [PATCH 01/36] Get rid of ICoreComposer --- src/Umbraco.Core/Collections/TopoGraph.cs | 2 +- src/Umbraco.Core/Composing/ICoreComposer.cs | 13 -- src/Umbraco.Core/Composing/IUserComposer.cs | 2 +- .../ExamineLuceneComposer.cs | 29 --- ...nt.cs => ExamineLuceneConfigureIndexes.cs} | 12 +- .../ExamineLuceneFinalComposer.cs | 14 -- ...eComponent.cs => ExamineLuceneStarting.cs} | 11 +- .../Extensions/UmbracoBuilderExtensions.cs | 45 ++++ .../Compose/NotificationsComposer.cs | 112 ---------- .../UmbracoBuilder.CoreServices.cs | 138 ++++++++++++ .../Logging/Viewer/LogViewerComposer.cs | 29 --- .../DataTypes/PreValueMigratorComposer.cs | 27 --- .../Compose/NotificationsComposer.cs | 23 -- .../UmbracoBuilderExtensions.cs | 23 ++ .../Testing/UmbracoIntegrationTest.cs | 3 + .../ContentTypeServiceVariantsTests.cs | 4 +- .../Umbraco.Core/Components/ComponentTests.cs | 6 +- .../UmbracoBuilderExtensions.cs | 7 +- src/Umbraco.Web.UI.Client/package-lock.json | 198 +++++------------- src/Umbraco.Web.UI.NetCore/Startup.cs | 5 +- src/Umbraco.Web.UI.NetCore/appsettings.json | 4 +- src/Umbraco.Web/Runtime/WebFinalComposer.cs | 1 - 22 files changed, 282 insertions(+), 426 deletions(-) delete mode 100644 src/Umbraco.Core/Composing/ICoreComposer.cs delete mode 100644 src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs rename src/Umbraco.Examine.Lucene/{ExamineLuceneFinalComponent.cs => ExamineLuceneConfigureIndexes.cs} (70%) delete mode 100644 src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs rename src/Umbraco.Examine.Lucene/{ExamineLuceneComponent.cs => ExamineLuceneStarting.cs} (83%) create mode 100644 src/Umbraco.Examine.Lucene/Extensions/UmbracoBuilderExtensions.cs delete mode 100644 src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs delete mode 100644 src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs delete mode 100644 src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs delete mode 100644 src/Umbraco.PublishedCache.NuCache/Compose/NotificationsComposer.cs diff --git a/src/Umbraco.Core/Collections/TopoGraph.cs b/src/Umbraco.Core/Collections/TopoGraph.cs index 12b0d431ea..2e199dd5a4 100644 --- a/src/Umbraco.Core/Collections/TopoGraph.cs +++ b/src/Umbraco.Core/Collections/TopoGraph.cs @@ -101,7 +101,7 @@ namespace Umbraco.Cms.Core.Collections var start = incr > 0 ? 0 : index; var count = incr > 0 ? index : sorted.Length - index; if (throwOnCycle && Contains(sorted, item, start, count) == false) - throw new Exception(CycleDependencyError); + throw new Exception(CycleDependencyError +": " + item); return; } diff --git a/src/Umbraco.Core/Composing/ICoreComposer.cs b/src/Umbraco.Core/Composing/ICoreComposer.cs deleted file mode 100644 index c6d0b3510c..0000000000 --- a/src/Umbraco.Core/Composing/ICoreComposer.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Umbraco.Cms.Core.Composing -{ - /// - /// Represents a core . - /// - /// - /// Core composers compose after the initial composer, and before user composers. - /// - public interface ICoreComposer : IComposer - { - // TODO: This should die, there should be exactly zero core composers. - } -} diff --git a/src/Umbraco.Core/Composing/IUserComposer.cs b/src/Umbraco.Core/Composing/IUserComposer.cs index 52ed4fdf5c..94c6aa9cad 100644 --- a/src/Umbraco.Core/Composing/IUserComposer.cs +++ b/src/Umbraco.Core/Composing/IUserComposer.cs @@ -6,7 +6,7 @@ /// /// User composers compose after core composers, and before the final composer. /// - [ComposeAfter(typeof(ICoreComposer))] + [ComposeAfter(typeof(IComposer))] public interface IUserComposer : IComposer { } } diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs deleted file mode 100644 index 327ac4b4ba..0000000000 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Runtime.InteropServices; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Infrastructure.Examine -{ - // We want to run after core composers since we are replacing some items - [ComposeAfter(typeof(ICoreComposer))] - public sealed class ExamineLuceneComposer : ComponentComposer - { - public override void Compose(IUmbracoBuilder builder) - { - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - if(!isWindows) return; - - - base.Compose(builder); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneConfigureIndexes.cs similarity index 70% rename from src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs rename to src/Umbraco.Examine.Lucene/ExamineLuceneConfigureIndexes.cs index b95165b121..d64daab514 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneConfigureIndexes.cs @@ -3,26 +3,26 @@ using Examine; using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Runtime; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Examine { - public class ExamineLuceneFinalComponent : IComponent + public class ExamineLuceneConfigureIndexes : INotificationHandler { private readonly ILoggerFactory _loggerFactory; private readonly IExamineManager _examineManager; private readonly IMainDom _mainDom; - public ExamineLuceneFinalComponent(ILoggerFactory loggerFactory, IExamineManager examineManager, IMainDom mainDom) + public ExamineLuceneConfigureIndexes(ILoggerFactory loggerFactory, IExamineManager examineManager, IMainDom mainDom) { _loggerFactory = loggerFactory; _examineManager = examineManager; _mainDom = mainDom; } - public void Initialize() + public void Handle(UmbracoApplicationStarting notification) { if (!_mainDom.IsMainDom) return; @@ -30,8 +30,6 @@ namespace Umbraco.Cms.Infrastructure.Examine _examineManager.ConfigureIndexes(_mainDom, _loggerFactory.CreateLogger()); } - public void Terminate() - { - } + } } diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs deleted file mode 100644 index 518ffc2db8..0000000000 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Umbraco.Cms.Core.Composing; - -namespace Umbraco.Cms.Infrastructure.Examine -{ - // examine's Lucene final composer composes after all user composers - // and *also* after ICoreComposer (in case IUserComposer is disabled) - [ComposeAfter(typeof(IUserComposer))] - [ComposeAfter(typeof(ICoreComposer))] - public class ExamineLuceneFinalComposer : ComponentComposer - { } -} diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneStarting.cs similarity index 83% rename from src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs rename to src/Umbraco.Examine.Lucene/ExamineLuceneStarting.cs index fe1826c989..f640ca4968 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneStarting.cs @@ -4,20 +4,20 @@ using Examine; using Examine.LuceneEngine.Directories; using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Runtime; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Examine { - public sealed class ExamineLuceneComponent : IComponent + public sealed class ExamineLuceneStarting : INotificationHandler { private readonly IndexRebuilder _indexRebuilder; private readonly IExamineManager _examineManager; private readonly IMainDom _mainDom; private readonly ILoggerFactory _loggerFactory; - public ExamineLuceneComponent(IndexRebuilder indexRebuilder, IExamineManager examineManager, IMainDom mainDom, ILoggerFactory loggerFactory) + public ExamineLuceneStarting(IndexRebuilder indexRebuilder, IExamineManager examineManager, IMainDom mainDom, ILoggerFactory loggerFactory) { _indexRebuilder = indexRebuilder; _examineManager = examineManager; @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Examine _loggerFactory = loggerFactory; } - public void Initialize() + public void Handle(UmbracoApplicationStarting notification) { //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the AppDomain //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock @@ -46,8 +46,5 @@ namespace Umbraco.Cms.Infrastructure.Examine /// private void IndexRebuilder_RebuildingIndexes(object sender, IndexRebuildingEventArgs e) => _examineManager.ConfigureIndexes(_mainDom, _loggerFactory.CreateLogger()); - public void Terminate() - { - } } } diff --git a/src/Umbraco.Examine.Lucene/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Examine.Lucene/Extensions/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..1e5c2a6edd --- /dev/null +++ b/src/Umbraco.Examine.Lucene/Extensions/UmbracoBuilderExtensions.cs @@ -0,0 +1,45 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Runtime.InteropServices; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Infrastructure.Examine; + +namespace Umbraco.Extensions +{ + /// + /// Extension methods for for the Examine.Lucene + /// + public static class UmbracoBuilderExtensions + { + /// + /// Adds Umbraco preview support + /// + public static IUmbracoBuilder AddExamineLucene(this IUmbracoBuilder builder) + { + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + if (!isWindows) + { + return builder; + } + + builder.AddNotificationHandler(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + return builder; + } + + public static IUmbracoBuilder AddExamineIndexConfiguration(this IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + + + return builder; + } + + } +} diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs deleted file mode 100644 index a95ac9b07c..0000000000 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Handlers; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services.Notifications; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Core.Compose -{ - public sealed class NotificationsComposer : ICoreComposer - { - public void Compose(IUmbracoBuilder builder) - { - // add handlers for sending user notifications (i.e. emails) - builder.Services.AddUnique(); - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); - - // add handlers for building content relations - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); - - // add notification handlers for property editors - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); - - // add notification handlers for redirect tracking - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); - - // Add notification handlers for DistributedCache - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - ; - // add notification handlers for auditing - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); - } - } -} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index 6eb08bd4d5..4d8a6948a9 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -3,14 +3,20 @@ using Examine; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Serilog; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Handlers; using Umbraco.Cms.Core.HealthChecks.NotificationMethods; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Install; +using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Logging.Serilog.Enrichers; +using Umbraco.Cms.Core.Logging.Viewer; using Umbraco.Cms.Core.Mail; using Umbraco.Cms.Core.Manifest; using Umbraco.Cms.Core.Media; @@ -24,6 +30,7 @@ using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.Notifications; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Core.Templates; using Umbraco.Cms.Core.Trees; @@ -36,6 +43,7 @@ using Umbraco.Cms.Infrastructure.Media; using Umbraco.Cms.Infrastructure.Migrations; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Migrations.PostMigrations; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Runtime; using Umbraco.Cms.Infrastructure.Search; @@ -105,6 +113,8 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection builder.Services.AddUnique(factory => new MigrationBuilder(factory)); + builder.AddPreValueMigrators(); + builder.Services.AddUnique(); // register the published snapshot accessor - the "current" published snapshot is in the umbraco context @@ -207,5 +217,133 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection return builder; } + + + private static IUmbracoBuilder AddPreValueMigrators(this IUmbracoBuilder builder) + { + builder.WithCollectionBuilder() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + + return builder; + } + + public static IUmbracoBuilder AddLogViewer(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + builder.SetLogViewer(); + builder.Services.AddUnique(factory => new SerilogJsonLogViewer(factory.GetRequiredService>(), + factory.GetRequiredService(), + factory.GetRequiredService(), + Log.Logger)); + + return builder; + } + + + public static IUmbracoBuilder AddCoreNotifications(this IUmbracoBuilder builder) + { +// add handlers for sending user notifications (i.e. emails) + builder.Services.AddUnique(); + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + // add handlers for building content relations + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + // add notification handlers for property editors + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + // add notification handlers for redirect tracking + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + // Add notification handlers for DistributedCache + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + ; + // add notification handlers for auditing + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + return builder; + } } } diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs deleted file mode 100644 index dcfcb66d5d..0000000000 --- a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Serilog; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Infrastructure.DependencyInjection; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Core.Logging.Viewer -{ - // ReSharper disable once UnusedMember.Global - public class LogViewerComposer : ICoreComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - builder.SetLogViewer(); - builder.Services.AddUnique(factory => - { - - return new SerilogJsonLogViewer(factory.GetRequiredService>(), - factory.GetRequiredService(), - factory.GetRequiredService(), - Log.Logger); - } ); - } - } -} diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs deleted file mode 100644 index eafec39da3..0000000000 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes -{ - public class PreValueMigratorComposer : ICoreComposer -{ - public void Compose(IUmbracoBuilder builder) - { - // do NOT add DefaultPreValueMigrator to this list! - // it will be automatically used if nothing matches - - builder.WithCollectionBuilder() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - } -} -} diff --git a/src/Umbraco.PublishedCache.NuCache/Compose/NotificationsComposer.cs b/src/Umbraco.PublishedCache.NuCache/Compose/NotificationsComposer.cs deleted file mode 100644 index 9942761040..0000000000 --- a/src/Umbraco.PublishedCache.NuCache/Compose/NotificationsComposer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Services.Notifications; - -namespace Umbraco.Cms.Infrastructure.PublishedCache.Compose -{ - public sealed class NotificationsComposer : ICoreComposer - { - public void Compose(IUmbracoBuilder builder) => - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - ; - } -} diff --git a/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs index 82e62b2328..06ec368706 100644 --- a/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,10 +1,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.Notifications; using Umbraco.Cms.Infrastructure.PublishedCache; using Umbraco.Cms.Infrastructure.PublishedCache.Persistence; @@ -49,10 +51,31 @@ namespace Umbraco.Extensions return idkSvc; }); + builder.AddNuCacheNotifications(); + // add the NuCache health check (hidden from type finder) // TODO: no NuCache health check yet // composition.HealthChecks().Add(); return builder; } + + + private static IUmbracoBuilder AddNuCacheNotifications(this IUmbracoBuilder builder) + { + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + return builder; + } + + } } diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index dbf047cf48..4c9e6671d2 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -217,6 +217,7 @@ namespace Umbraco.Cms.Tests.Integration.Testing .AddBackOfficeIdentity() .AddMembersIdentity() .AddExamine() + .AddExamineLucene() .AddTestServices(TestHelper, GetAppCaches()); if (TestOptions.Mapper) @@ -232,6 +233,8 @@ namespace Umbraco.Cms.Tests.Integration.Testing CustomTestSetup(builder); + + builder.AddExamineIndexConfiguration(); builder.Build(); } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs index a062eff0c3..b76a01c98e 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs @@ -17,7 +17,6 @@ using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.PublishedCache; -using Umbraco.Cms.Infrastructure.PublishedCache.Compose; using Umbraco.Cms.Tests.Common.Builders; using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; @@ -53,8 +52,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services protected override void CustomTestSetup(IUmbracoBuilder builder) { builder.Services.AddUnique(); - var composer = new NotificationsComposer(); - composer.Compose(builder); + // builder.AddCoreNotifications(); } private void AssertJsonStartsWith(int id, string expected) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index e1a65d1541..b792ab6041 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Configuration; @@ -26,7 +27,6 @@ using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.Mappers; using Umbraco.Cms.Tests.UnitTests.TestHelpers; -using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components { @@ -456,7 +456,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components } [ComposeAfter(typeof(Composer4))] - public class Composer2 : TestComposerBase, ICoreComposer + public class Composer2 : TestComposerBase { } @@ -539,7 +539,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components } [ComposeAfter(typeof(Composer4), true)] - public class Composer12 : TestComposerBase, ICoreComposer + public class Composer12 : TestComposerBase { } diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index 54956184ac..d9b9146513 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,8 +1,6 @@ using System.Linq; -using Ganss.XSS; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Hosting; @@ -48,7 +46,10 @@ namespace Umbraco.Extensions .AddDistributedCache() .AddModelsBuilderDashboard() .AddUnattedInstallCreateUser() - .AddExamine(); + .AddCoreNotifications() + .AddLogViewer() + .AddExamine() + .AddExamineLucene(); /// /// Adds Umbraco preview support diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 6f2edfa2ae..9bcf82dee7 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1842,8 +1842,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "optional": true + "dev": true }, "base64id": { "version": "1.0.0", @@ -2052,8 +2051,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true + "dev": true }, "got": { "version": "8.3.2", @@ -2131,7 +2129,6 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", "integrity": "sha1-2N0ZeVldLcATnh/ka4tkbLPN8Dg=", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -2173,7 +2170,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -2183,15 +2179,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2207,7 +2201,6 @@ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -2348,7 +2341,6 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -2374,8 +2366,7 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "optional": true + "dev": true }, "buffer-equal": { "version": "1.0.0", @@ -2572,7 +2563,6 @@ "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", "integrity": "sha1-bDygcfwZRyCIPC3F2psHS/x+npU=", "dev": true, - "optional": true, "requires": { "get-proxy": "^2.0.0", "isurl": "^1.0.0-alpha5", @@ -3096,7 +3086,6 @@ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", "integrity": "sha1-D96NCRIA616AjK8l/mGMAvSOTvo=", "dev": true, - "optional": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -3152,7 +3141,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", "dev": true, - "optional": true, "requires": { "safe-buffer": "5.1.2" } @@ -3594,7 +3582,6 @@ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.0.0", "decompress-tarbz2": "^4.0.0", @@ -3611,7 +3598,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", "dev": true, - "optional": true, "requires": { "pify": "^3.0.0" }, @@ -3620,8 +3606,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } } @@ -3632,7 +3617,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, - "optional": true, "requires": { "mimic-response": "^1.0.0" } @@ -3642,7 +3626,6 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", "integrity": "sha1-cYy9P8sWIJcW5womuE57pFkuWvE=", "dev": true, - "optional": true, "requires": { "file-type": "^5.2.0", "is-stream": "^1.1.0", @@ -3653,8 +3636,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3663,7 +3645,6 @@ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", "integrity": "sha1-MIKluIDqQEOBY0nzeLVsUWvho5s=", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.1.0", "file-type": "^6.1.0", @@ -3676,8 +3657,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", "integrity": "sha1-5QzXXTVv/tTjBtxPW89Sp5kDqRk=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3686,7 +3666,6 @@ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", "integrity": "sha1-wJvDXE0R894J8tLaU+neI+fOHu4=", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.1.1", "file-type": "^5.2.0", @@ -3697,8 +3676,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3707,7 +3685,6 @@ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, - "optional": true, "requires": { "file-type": "^3.8.0", "get-stream": "^2.2.0", @@ -3719,15 +3696,13 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, - "optional": true, "requires": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" @@ -3737,8 +3712,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true } } }, @@ -4026,8 +4000,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -4044,8 +4017,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true, - "optional": true + "dev": true }, "duplexify": { "version": "3.7.1", @@ -4690,7 +4662,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, - "optional": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -4832,7 +4803,6 @@ "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", "integrity": "sha1-C5jmTtgvWs8PKTG6v2khLvUt3Tc=", "dev": true, - "optional": true, "requires": { "mime-db": "^1.28.0" } @@ -4842,7 +4812,6 @@ "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", "integrity": "sha1-cHgZgdGD7hXROZPIgiBFxQbI8KY=", "dev": true, - "optional": true, "requires": { "ext-list": "^2.0.0", "sort-keys-length": "^1.0.0" @@ -5080,7 +5049,6 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, - "optional": true, "requires": { "pend": "~1.2.0" } @@ -5119,15 +5087,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", - "dev": true, - "optional": true + "dev": true }, "filenamify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", "integrity": "sha1-iPr0lfsbR6v9YSMAACoWIoxnfuk=", "dev": true, - "optional": true, "requires": { "filename-reserved-regex": "^2.0.0", "strip-outer": "^1.0.0", @@ -5476,8 +5442,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", - "dev": true, - "optional": true + "dev": true }, "fs-mkdirp-stream": { "version": "1.0.0", @@ -5524,8 +5489,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5546,14 +5510,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5568,20 +5530,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5698,8 +5657,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5711,7 +5669,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5726,7 +5683,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5734,14 +5690,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5760,7 +5714,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5841,8 +5794,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5854,7 +5806,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5940,8 +5891,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5977,7 +5927,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5997,7 +5946,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6041,14 +5989,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -6075,7 +6021,6 @@ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", "integrity": "sha1-NJ8rTZHUTE1NTpy6KtkBQ/rF75M=", "dev": true, - "optional": true, "requires": { "npm-conf": "^1.1.0" } @@ -6084,15 +6029,13 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, - "optional": true, "requires": { "pump": "^3.0.0" }, @@ -6102,7 +6045,6 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, - "optional": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -6215,8 +6157,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "optional": true + "dev": true }, "pump": { "version": "3.0.0", @@ -7419,8 +7360,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha1-FAn5i8ACR9pF2mfO4KNvKC/yZFU=", - "dev": true, - "optional": true + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -7433,7 +7373,6 @@ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", "integrity": "sha1-oEWrOD17SyASoAFIqwql8pAETU0=", "dev": true, - "optional": true, "requires": { "has-symbol-support-x": "^1.4.1" } @@ -7639,8 +7578,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "optional": true + "dev": true }, "ignore": { "version": "4.0.6", @@ -7780,8 +7718,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + "dev": true }, "svgo": { "version": "1.3.2", @@ -7853,7 +7790,6 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, - "optional": true, "requires": { "repeating": "^2.0.0" } @@ -8180,8 +8116,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true, - "optional": true + "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -8231,8 +8166,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", - "dev": true, - "optional": true + "dev": true }, "is-negated-glob": { "version": "1.0.0", @@ -8270,15 +8204,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "optional": true + "dev": true }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "optional": true + "dev": true }, "is-plain-object": { "version": "2.0.4", @@ -8348,15 +8280,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha1-13hIi9CkZmo76KFIK58rqv7eqLQ=", - "dev": true, - "optional": true + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "optional": true + "dev": true }, "is-svg": { "version": "3.0.0", @@ -8451,7 +8381,6 @@ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", "integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=", "dev": true, - "optional": true, "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" @@ -9347,8 +9276,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", - "dev": true, - "optional": true + "dev": true }, "lpad-align": { "version": "1.1.2", @@ -9418,8 +9346,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "optional": true + "dev": true }, "map-visit": { "version": "1.0.0", @@ -9587,8 +9514,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha1-SSNTiHju9CBjy4o+OweYeBSHqxs=", - "dev": true, - "optional": true + "dev": true }, "minimatch": { "version": "3.0.4", @@ -12935,7 +12861,6 @@ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", "integrity": "sha1-JWzEe9DiGMJZxOlVC/QTvCGSr/k=", "dev": true, - "optional": true, "requires": { "config-chain": "^1.1.11", "pify": "^3.0.0" @@ -12945,8 +12870,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -12955,7 +12879,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, - "optional": true, "requires": { "path-key": "^2.0.0" } @@ -13324,8 +13247,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true + "dev": true }, "p-is-promise": { "version": "1.1.0", @@ -13362,7 +13284,6 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -13553,8 +13474,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true, - "optional": true + "dev": true }, "performance-now": { "version": "2.1.0", @@ -14061,8 +13981,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true, - "optional": true + "dev": true }, "prr": { "version": "1.0.1", @@ -14420,7 +14339,6 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, - "optional": true, "requires": { "is-finite": "^1.0.0" } @@ -14775,7 +14693,6 @@ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", "dev": true, - "optional": true, "requires": { "commander": "^2.8.1" } @@ -15170,7 +15087,6 @@ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", "dev": true, - "optional": true, "requires": { "is-plain-obj": "^1.0.0" } @@ -15180,7 +15096,6 @@ "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", "dev": true, - "optional": true, "requires": { "sort-keys": "^1.0.0" } @@ -15528,7 +15443,6 @@ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", "integrity": "sha1-SYdzYmT8NEzyD2w0rKnRPR1O1sU=", "dev": true, - "optional": true, "requires": { "is-natural-number": "^4.0.1" } @@ -15537,8 +15451,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "optional": true + "dev": true }, "strip-final-newline": { "version": "2.0.0", @@ -15568,7 +15481,6 @@ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15694,7 +15606,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha1-jqVdqzeXIlPZqa+Q/c1VmuQ1xVU=", "dev": true, - "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -15709,15 +15620,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15733,7 +15642,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15744,15 +15652,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", - "dev": true, - "optional": true + "dev": true }, "tempfile": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", "dev": true, - "optional": true, "requires": { "temp-dir": "^1.0.0", "uuid": "^3.0.1" @@ -15866,8 +15772,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true, - "optional": true + "dev": true }, "timers-ext": { "version": "0.1.7", @@ -15924,8 +15829,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", - "dev": true, - "optional": true + "dev": true }, "to-fast-properties": { "version": "2.0.0", @@ -16027,7 +15931,6 @@ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -16163,7 +16066,6 @@ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, - "optional": true, "requires": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -16372,8 +16274,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true, - "optional": true + "dev": true }, "use": { "version": "3.1.1", @@ -16867,7 +16768,6 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, - "optional": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 2f97a15d8f..90a632599c 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -3,9 +3,9 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Extensions; -using Microsoft.Extensions.Hosting; namespace Umbraco.Cms.Web.UI.NetCore { @@ -41,9 +41,10 @@ namespace Umbraco.Cms.Web.UI.NetCore { #pragma warning disable IDE0022 // Use expression body for methods services.AddUmbraco(_env, _config) - .AddBackOffice() + .AddBackOffice() .AddWebsite() .AddComposers() + .AddExamineIndexConfiguration() .Build(); #pragma warning restore IDE0022 // Use expression body for methods diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.json b/src/Umbraco.Web.UI.NetCore/appsettings.json index 0d0330b07b..7966ea895a 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.json @@ -39,7 +39,7 @@ }, "RuntimeMinification": { "dataFolder": "umbraco/Data/TEMP/Smidge", - "version": "637510451273675926" + "version": "637550581849220194" }, "Security": { "KeepUserLoggedIn": false, @@ -71,4 +71,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Web/Runtime/WebFinalComposer.cs b/src/Umbraco.Web/Runtime/WebFinalComposer.cs index 818bff521a..9f2fbb1018 100644 --- a/src/Umbraco.Web/Runtime/WebFinalComposer.cs +++ b/src/Umbraco.Web/Runtime/WebFinalComposer.cs @@ -5,7 +5,6 @@ namespace Umbraco.Web.Runtime // web's final composer composes after all user composers // and *also* after ICoreComposer (in case IUserComposer is disabled) [ComposeAfter(typeof(IUserComposer))] - [ComposeAfter(typeof(ICoreComposer))] public class WebFinalComposer : ComponentComposer { } From 80bd5257bccb0e7f0d76eaeb5b4028542d9fd2bf Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 27 Apr 2021 07:35:47 +0200 Subject: [PATCH 02/36] Revert examine to use composers, until we have migrated that to .net standard --- src/Umbraco.Core/Composing/IUserComposer.cs | 1 - .../ExamineLuceneComposer.cs | 18 ++++++++++++++++++ .../ExamineLuceneFinalComposer.cs | 17 +++++++++++++++++ .../Testing/UmbracoIntegrationTest.cs | 10 +++++++--- .../ContentTypeServiceVariantsTests.cs | 1 - .../Umbraco.Core/Components/ComponentTests.cs | 3 +++ .../src/navigation.controller.js | 3 ++- src/Umbraco.Web.UI.NetCore/Startup.cs | 1 - 8 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs create mode 100644 src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs diff --git a/src/Umbraco.Core/Composing/IUserComposer.cs b/src/Umbraco.Core/Composing/IUserComposer.cs index 94c6aa9cad..8e07dae672 100644 --- a/src/Umbraco.Core/Composing/IUserComposer.cs +++ b/src/Umbraco.Core/Composing/IUserComposer.cs @@ -6,7 +6,6 @@ /// /// User composers compose after core composers, and before the final composer. /// - [ComposeAfter(typeof(IComposer))] public interface IUserComposer : IComposer { } } diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs new file mode 100644 index 0000000000..1243e01578 --- /dev/null +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs @@ -0,0 +1,18 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Infrastructure.Examine +{ + // We want to run after core composers since we are replacing some items + public sealed class ExamineLuceneComposer :IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.AddExamineLucene(); + } + } +} diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs new file mode 100644 index 0000000000..ab3476cb70 --- /dev/null +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs @@ -0,0 +1,17 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Infrastructure.Examine +{ + // examine's Lucene final composer composes after all user composers + // and *also* after ICoreComposer (in case IUserComposer is disabled) + [ComposeAfter(typeof(IUserComposer))] + public class ExamineLuceneFinalComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) => builder.AddExamineIndexConfiguration(); + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 4c9e6671d2..cdff3a9168 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -90,9 +90,13 @@ namespace Umbraco.Cms.Tests.Integration.Testing s_firstTestInSession = false; // Ensure CoreRuntime stopped (now it's a HostedService) - IHost host = Services.GetRequiredService(); - await host.StopAsync(); - host.Dispose(); + IHost host = Services?.GetService(); + if (host is not null) + { + await host.StopAsync(); + host.Dispose(); + } + } [TearDown] diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs index b76a01c98e..38ea80e709 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs @@ -52,7 +52,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services protected override void CustomTestSetup(IUmbracoBuilder builder) { builder.Services.AddUnique(); - // builder.AddCoreNotifications(); } private void AssertJsonStartsWith(int id, string expected) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index b792ab6041..e0ab2d630a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -464,6 +464,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components { } + public class Composer4 : TestComposerBase { } @@ -524,6 +525,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components { } + [ComposeAfter(typeof(Composer2))] + [ComposeAfter(typeof(Composer4))] public class Composer9 : TestComposerBase, ITestComposer { } diff --git a/src/Umbraco.Web.UI.Client/src/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/navigation.controller.js index 11bea9b275..06a7a62b88 100644 --- a/src/Umbraco.Web.UI.Client/src/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/navigation.controller.js @@ -298,7 +298,8 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar } /** - * Based on the current state of the application, this configures the scope variables that control the main tree and language drop down + * Based on the current state of the application, this configures the scope variables that + * l the main tree and language drop down */ function configureTreeAndLanguages() { diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 90a632599c..0419a8c0e4 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -44,7 +44,6 @@ namespace Umbraco.Cms.Web.UI.NetCore .AddBackOffice() .AddWebsite() .AddComposers() - .AddExamineIndexConfiguration() .Build(); #pragma warning restore IDE0022 // Use expression body for methods From e52d4dda7e2c551d7983dfb87dea069500f6438b Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 27 Apr 2021 07:43:18 +0200 Subject: [PATCH 03/36] Clean up after reintroduction of examine composers --- .../Testing/UmbracoIntegrationTest.cs | 1 - .../DependencyInjection/UmbracoBuilderExtensions.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index cdff3a9168..106f0f15d3 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -221,7 +221,6 @@ namespace Umbraco.Cms.Tests.Integration.Testing .AddBackOfficeIdentity() .AddMembersIdentity() .AddExamine() - .AddExamineLucene() .AddTestServices(TestHelper, GetAppCaches()); if (TestOptions.Mapper) diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index d9b9146513..23257cdad4 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -48,8 +48,7 @@ namespace Umbraco.Extensions .AddUnattedInstallCreateUser() .AddCoreNotifications() .AddLogViewer() - .AddExamine() - .AddExamineLucene(); + .AddExamine(); /// /// Adds Umbraco preview support From 941b23469713c4060db9caf6e2b892846b29d68d Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 27 Apr 2021 07:50:05 +0200 Subject: [PATCH 04/36] Clean up after reintroduction of examine composers --- src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 106f0f15d3..37ed0e36de 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -236,8 +236,6 @@ namespace Umbraco.Cms.Tests.Integration.Testing CustomTestSetup(builder); - - builder.AddExamineIndexConfiguration(); builder.Build(); } From 2afa7201cee0e75a3778d5b0ffa09cf96224502d Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 27 Apr 2021 10:20:43 +0200 Subject: [PATCH 05/36] Fix comment --- src/Umbraco.Web.UI.Client/src/navigation.controller.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/navigation.controller.js index 06a7a62b88..11bea9b275 100644 --- a/src/Umbraco.Web.UI.Client/src/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/navigation.controller.js @@ -298,8 +298,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar } /** - * Based on the current state of the application, this configures the scope variables that - * l the main tree and language drop down + * Based on the current state of the application, this configures the scope variables that control the main tree and language drop down */ function configureTreeAndLanguages() { From 6a79053a9f887963942e1b1f51029d0739d5ee44 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 09:50:49 +0200 Subject: [PATCH 06/36] Move email models into a folder --- src/Umbraco.Core/Events/SendEmailEventArgs.cs | 2 +- .../HealthChecks/NotificationMethods/EmailNotificationMethod.cs | 2 +- src/Umbraco.Core/Mail/IEmailSender.cs | 2 +- src/Umbraco.Core/Mail/NotImplementedEmailSender.cs | 2 +- src/Umbraco.Core/Models/{ => Email}/EmailMessage.cs | 2 +- src/Umbraco.Core/Models/{ => Email}/EmailMessageAttachment.cs | 2 +- src/Umbraco.Core/Notifications/SendEmailNotification.cs | 2 +- src/Umbraco.Infrastructure/EmailSender.cs | 2 +- src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs | 2 +- .../Services/Implement/NotificationService.cs | 1 + .../Extensions/EmailMessageExtensionsTests.cs | 1 + .../Controllers/AuthenticationController.cs | 1 + src/Umbraco.Web.BackOffice/Controllers/UsersController.cs | 1 + 13 files changed, 13 insertions(+), 9 deletions(-) rename src/Umbraco.Core/Models/{ => Email}/EmailMessage.cs (98%) rename src/Umbraco.Core/Models/{ => Email}/EmailMessageAttachment.cs (88%) diff --git a/src/Umbraco.Core/Events/SendEmailEventArgs.cs b/src/Umbraco.Core/Events/SendEmailEventArgs.cs index 720f125d9c..c1e626c6c1 100644 --- a/src/Umbraco.Core/Events/SendEmailEventArgs.cs +++ b/src/Umbraco.Core/Events/SendEmailEventArgs.cs @@ -1,5 +1,5 @@ using System; -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; namespace Umbraco.Cms.Core.Events { diff --git a/src/Umbraco.Core/HealthChecks/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Core/HealthChecks/NotificationMethods/EmailNotificationMethod.cs index 51e31b1811..6e679ddbb1 100644 --- a/src/Umbraco.Core/HealthChecks/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Core/HealthChecks/NotificationMethods/EmailNotificationMethod.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Mail; -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; using Umbraco.Cms.Core.Services; using Umbraco.Extensions; diff --git a/src/Umbraco.Core/Mail/IEmailSender.cs b/src/Umbraco.Core/Mail/IEmailSender.cs index 5b5adf71eb..45959a5a9a 100644 --- a/src/Umbraco.Core/Mail/IEmailSender.cs +++ b/src/Umbraco.Core/Mail/IEmailSender.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; namespace Umbraco.Cms.Core.Mail { diff --git a/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs index 3632e79c23..29265b4038 100644 --- a/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs +++ b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; namespace Umbraco.Cms.Core.Mail { diff --git a/src/Umbraco.Core/Models/EmailMessage.cs b/src/Umbraco.Core/Models/Email/EmailMessage.cs similarity index 98% rename from src/Umbraco.Core/Models/EmailMessage.cs rename to src/Umbraco.Core/Models/Email/EmailMessage.cs index 153e8f33f7..74aaf0184c 100644 --- a/src/Umbraco.Core/Models/EmailMessage.cs +++ b/src/Umbraco.Core/Models/Email/EmailMessage.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Umbraco.Cms.Core.Models +namespace Umbraco.Cms.Core.Models.Email { public class EmailMessage { diff --git a/src/Umbraco.Core/Models/EmailMessageAttachment.cs b/src/Umbraco.Core/Models/Email/EmailMessageAttachment.cs similarity index 88% rename from src/Umbraco.Core/Models/EmailMessageAttachment.cs rename to src/Umbraco.Core/Models/Email/EmailMessageAttachment.cs index ee4f3ef8cb..bbb24b69f7 100644 --- a/src/Umbraco.Core/Models/EmailMessageAttachment.cs +++ b/src/Umbraco.Core/Models/Email/EmailMessageAttachment.cs @@ -1,6 +1,6 @@ using System.IO; -namespace Umbraco.Cms.Core.Models +namespace Umbraco.Cms.Core.Models.Email { public class EmailMessageAttachment { diff --git a/src/Umbraco.Core/Notifications/SendEmailNotification.cs b/src/Umbraco.Core/Notifications/SendEmailNotification.cs index 194ee68edc..85197c34b8 100644 --- a/src/Umbraco.Core/Notifications/SendEmailNotification.cs +++ b/src/Umbraco.Core/Notifications/SendEmailNotification.cs @@ -1,4 +1,4 @@ -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; namespace Umbraco.Cms.Core.Notifications { diff --git a/src/Umbraco.Infrastructure/EmailSender.cs b/src/Umbraco.Infrastructure/EmailSender.cs index 02e83405d6..ee5fa01195 100644 --- a/src/Umbraco.Infrastructure/EmailSender.cs +++ b/src/Umbraco.Infrastructure/EmailSender.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Mail; -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Infrastructure.Extensions; using SmtpClient = MailKit.Net.Smtp.SmtpClient; diff --git a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs index cc1efa271e..5159d7bed2 100644 --- a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs +++ b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs @@ -1,7 +1,7 @@ using System; using MimeKit; using MimeKit.Text; -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; namespace Umbraco.Cms.Infrastructure.Extensions { diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index aedad0e56b..c6f440942e 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -11,6 +11,7 @@ using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Mail; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Persistence.Repositories; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs index 7915b6b92c..5dc66e284f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using NUnit.Framework; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Email; using Umbraco.Cms.Infrastructure.Extensions; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 707c486f3e..c552c0d976 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -17,6 +17,7 @@ using Umbraco.Cms.Core.Mail; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; +using Umbraco.Cms.Core.Models.Email; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Net; using Umbraco.Cms.Core.Security; diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index cdd00913e7..79f02e3b4f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -26,6 +26,7 @@ using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; +using Umbraco.Cms.Core.Models.Email; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; From 8a02118300bdd556677dbbe8edd277778c6e2ad6 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 10:41:17 +0200 Subject: [PATCH 07/36] Create notification email models --- .../Models/Email/NotificationEmailAddress.cs | 18 +++++++ .../Models/Email/NotificationEmailModel.cs | 50 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs create mode 100644 src/Umbraco.Core/Models/Email/NotificationEmailModel.cs diff --git a/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs b/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs new file mode 100644 index 0000000000..04da915fab --- /dev/null +++ b/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs @@ -0,0 +1,18 @@ +namespace Umbraco.Cms.Core.Models.Email +{ + /// + /// Represents an email address used for notifications. Contains both the address and its display name. + /// + public class NotificationEmailAddress + { + public string DisplayName { get; } + + public string Adress { get; } + + public NotificationEmailAddress(string address, string displayName) + { + Adress = address; + DisplayName = displayName; + } + } +} diff --git a/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs b/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs new file mode 100644 index 0000000000..a7fe0bd846 --- /dev/null +++ b/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Umbraco.Cms.Core.Models.Email +{ + /// + /// Represents an email when sent with notifications. + /// + public class NotificationEmailModel + { + public NotificationEmailAddress From { get; } + + public IEnumerable To { get; } + + public IEnumerable Cc { get; } + + public IEnumerable Bcc { get; } + + public IEnumerable ReplyTo { get; } + + public string Subject { get; } + + public string Body { get; } + + public IList Attachments { get; } + + public bool HasAttachments => Attachments != null && Attachments.Count > 0; + + public NotificationEmailModel( + NotificationEmailAddress from, + IEnumerable to, + IEnumerable cc, + IEnumerable bcc, + IEnumerable replyTo, + string subject, + string body, + IEnumerable attachments) + { + From = from; + To = to; + Cc = cc; + Bcc = bcc; + ReplyTo = replyTo; + Subject = subject; + Body = body; + Attachments = attachments?.ToList(); + } + + } +} From 91b59c6c675c0425ae17a95d8722a9ac1e99f1f0 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 10:42:33 +0200 Subject: [PATCH 08/36] Send NotificationEmailModel with notification --- .../Notifications/SendEmailNotification.cs | 4 +-- src/Umbraco.Infrastructure/EmailSender.cs | 2 +- .../Extensions/EmailMessageExtensions.cs | 27 ++++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Notifications/SendEmailNotification.cs b/src/Umbraco.Core/Notifications/SendEmailNotification.cs index 85197c34b8..3c9caabb0e 100644 --- a/src/Umbraco.Core/Notifications/SendEmailNotification.cs +++ b/src/Umbraco.Core/Notifications/SendEmailNotification.cs @@ -4,8 +4,8 @@ namespace Umbraco.Cms.Core.Notifications { public class SendEmailNotification : INotification { - public SendEmailNotification(EmailMessage message) => Message = message; + public SendEmailNotification(NotificationEmailModel message) => Message = message; - public EmailMessage Message { get; set; } + public NotificationEmailModel Message { get; } } } diff --git a/src/Umbraco.Infrastructure/EmailSender.cs b/src/Umbraco.Infrastructure/EmailSender.cs index ee5fa01195..6b51a9e56d 100644 --- a/src/Umbraco.Infrastructure/EmailSender.cs +++ b/src/Umbraco.Infrastructure/EmailSender.cs @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Infrastructure { if (enableNotification) { - await _eventAggregator.PublishAsync(new SendEmailNotification(message)); + await _eventAggregator.PublishAsync(new SendEmailNotification(message.ToNotificationEmail(_globalSettings.Smtp.From))); } return; } diff --git a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs index 5159d7bed2..62e94917a8 100644 --- a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs +++ b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using MimeKit; using MimeKit.Text; using Umbraco.Cms.Core.Models.Email; @@ -15,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Extensions fromEmail = configuredFromAddress; } - if (!InternetAddress.TryParse(mailMessage.From, out InternetAddress fromAddress)) + if (!InternetAddress.TryParse(fromEmail, out InternetAddress fromAddress)) { throw new ArgumentException($"Email could not be sent. Could not parse from address {fromEmail} as a valid email address."); } @@ -58,6 +59,30 @@ namespace Umbraco.Cms.Infrastructure.Extensions return messageToSend; } + public static NotificationEmailModel ToNotificationEmail(this EmailMessage emailMessage, + string configuredFromAddress) + { + var mimeMessage = emailMessage.ToMimeMessage(configuredFromAddress); + if (mimeMessage.From.Any() is false || mimeMessage.To.Any() is false) + { + throw new InvalidOperationException("There must be a valid from address and recipient address."); + } + // EmailMessage only supports a single from mail, so take the first. + NotificationEmailAddress from = ToNotificationAddress(mimeMessage.From.Mailboxes.First()); + + return new NotificationEmailModel(from, + mimeMessage.To.Mailboxes.Select(ToNotificationAddress), + mimeMessage.Cc.Mailboxes.Select(ToNotificationAddress), + mimeMessage.Bcc.Mailboxes.Select(ToNotificationAddress), + mimeMessage.ReplyTo.Mailboxes.Select(ToNotificationAddress), + mimeMessage.Subject, + emailMessage.Body, + emailMessage.Attachments); + } + + private static NotificationEmailAddress ToNotificationAddress(MailboxAddress mailboxAddress) => + new NotificationEmailAddress(mailboxAddress.Address, mailboxAddress.Name); + private static void AddAddresses(MimeMessage message, string[] addresses, Func addressListGetter, bool throwIfNoneValid = false) { var foundValid = false; From d2dae7f35b87803d728858556dd7b5893865c855 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 10:57:14 +0200 Subject: [PATCH 09/36] Add null check when sending SendEmailNotification --- src/Umbraco.Infrastructure/EmailSender.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/EmailSender.cs b/src/Umbraco.Infrastructure/EmailSender.cs index 6b51a9e56d..72daad7de1 100644 --- a/src/Umbraco.Infrastructure/EmailSender.cs +++ b/src/Umbraco.Infrastructure/EmailSender.cs @@ -53,7 +53,8 @@ namespace Umbraco.Cms.Infrastructure { if (enableNotification) { - await _eventAggregator.PublishAsync(new SendEmailNotification(message.ToNotificationEmail(_globalSettings.Smtp.From))); + await _eventAggregator.PublishAsync( + new SendEmailNotification(message.ToNotificationEmail(_globalSettings.Smtp?.From))); } return; } From cd284fd2633f198ae265454e64d300d76a5d2af9 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 11:06:59 +0200 Subject: [PATCH 10/36] Include IsBodyHtml in NotificationEmailModel --- src/Umbraco.Core/Models/Email/NotificationEmailModel.cs | 6 +++++- .../Extensions/EmailMessageExtensions.cs | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs b/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs index a7fe0bd846..a606e8e680 100644 --- a/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs +++ b/src/Umbraco.Core/Models/Email/NotificationEmailModel.cs @@ -22,6 +22,8 @@ namespace Umbraco.Cms.Core.Models.Email public string Body { get; } + public bool IsBodyHtml { get; } + public IList Attachments { get; } public bool HasAttachments => Attachments != null && Attachments.Count > 0; @@ -34,7 +36,8 @@ namespace Umbraco.Cms.Core.Models.Email IEnumerable replyTo, string subject, string body, - IEnumerable attachments) + IEnumerable attachments, + bool isBodyHtml) { From = from; To = to; @@ -43,6 +46,7 @@ namespace Umbraco.Cms.Core.Models.Email ReplyTo = replyTo; Subject = subject; Body = body; + IsBodyHtml = isBodyHtml; Attachments = attachments?.ToList(); } diff --git a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs index 62e94917a8..075c476afe 100644 --- a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs +++ b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs @@ -77,7 +77,8 @@ namespace Umbraco.Cms.Infrastructure.Extensions mimeMessage.ReplyTo.Mailboxes.Select(ToNotificationAddress), mimeMessage.Subject, emailMessage.Body, - emailMessage.Attachments); + emailMessage.Attachments, + emailMessage.IsBodyHtml); } private static NotificationEmailAddress ToNotificationAddress(MailboxAddress mailboxAddress) => From 3d0a72c39b09a53f6a7213f7f9ced530b4ad1cf9 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 11:17:35 +0200 Subject: [PATCH 11/36] Allow fallback to configured sender --- src/Umbraco.Core/Models/Email/EmailMessage.cs | 1 - .../Extensions/EmailMessageExtensionsTests.cs | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Models/Email/EmailMessage.cs b/src/Umbraco.Core/Models/Email/EmailMessage.cs index 74aaf0184c..55e30f2150 100644 --- a/src/Umbraco.Core/Models/Email/EmailMessage.cs +++ b/src/Umbraco.Core/Models/Email/EmailMessage.cs @@ -33,7 +33,6 @@ namespace Umbraco.Cms.Core.Models.Email public EmailMessage(string from, string[] to, string[] cc, string[] bcc, string[] replyTo, string subject, string body, bool isBodyHtml, IEnumerable attachments) { - ArgumentIsNotNullOrEmpty(from, nameof(from)); ArgumentIsNotNullOrEmpty(to, nameof(to)); ArgumentIsNotNullOrEmpty(subject, nameof(subject)); ArgumentIsNotNullOrEmpty(body, nameof(body)); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs index 5dc66e284f..43a17c2fb4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs @@ -78,5 +78,25 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions Assert.AreEqual(body, result.TextBody.ToString()); Assert.AreEqual(1, result.Attachments.Count()); } + + [Test] + public void Can_Construct_MimeMessage_With_ConfiguredSender() + { + const string to = "to@email.com"; + const string subject = "Subject"; + const string body = "

Message

"; + const bool isBodyHtml = true; + var emailMesasge = new EmailMessage(null, to, subject, body, isBodyHtml); + + var result = emailMesasge.ToMimeMessage(ConfiguredSender); + + Assert.AreEqual(1, result.From.Count()); + Assert.AreEqual(ConfiguredSender, result.From.First().ToString()); + Assert.AreEqual(1, result.To.Count()); + Assert.AreEqual(to, result.To.First().ToString()); + Assert.AreEqual(subject, result.Subject); + Assert.IsNull(result.TextBody); + Assert.AreEqual(body, result.HtmlBody.ToString()); + } } } From ba129b045bc527f3313bd9c4970e7ab185c79db6 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 11:39:25 +0200 Subject: [PATCH 12/36] Add unit tests --- .../Extensions/EmailMessageExtensionsTests.cs | 112 +++++++++++++++++- 1 file changed, 106 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs index 43a17c2fb4..d53ecbf3f0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs @@ -25,9 +25,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions const string subject = "Subject"; const string body = "

Message

"; const bool isBodyHtml = true; - var emailMesasge = new EmailMessage(from, to, subject, body, isBodyHtml); + var emailMessage = new EmailMessage(from, to, subject, body, isBodyHtml); - var result = emailMesasge.ToMimeMessage(ConfiguredSender); + var result = emailMessage.ToMimeMessage(ConfiguredSender); Assert.AreEqual(1, result.From.Count()); Assert.AreEqual(from, result.From.First().ToString()); @@ -55,9 +55,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions { new EmailMessageAttachment(attachmentStream, "test.txt"), }; - var emailMesasge = new EmailMessage(from, to, cc, bcc, replyTo, subject, body, isBodyHtml, attachments); + var emailMessage = new EmailMessage(from, to, cc, bcc, replyTo, subject, body, isBodyHtml, attachments); - var result = emailMesasge.ToMimeMessage(ConfiguredSender); + var result = emailMessage.ToMimeMessage(ConfiguredSender); Assert.AreEqual(1, result.From.Count()); Assert.AreEqual(from, result.From.First().ToString()); @@ -86,9 +86,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions const string subject = "Subject"; const string body = "

Message

"; const bool isBodyHtml = true; - var emailMesasge = new EmailMessage(null, to, subject, body, isBodyHtml); + var emailMessage = new EmailMessage(null, to, subject, body, isBodyHtml); - var result = emailMesasge.ToMimeMessage(ConfiguredSender); + var result = emailMessage.ToMimeMessage(ConfiguredSender); Assert.AreEqual(1, result.From.Count()); Assert.AreEqual(ConfiguredSender, result.From.First().ToString()); @@ -98,5 +98,105 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions Assert.IsNull(result.TextBody); Assert.AreEqual(body, result.HtmlBody.ToString()); } + + [Test] + public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage() + { + const string from = "from@email.com"; + const string to = "to@email.com"; + const string subject = "Subject"; + const string body = "

Message

"; + const bool isBodyHtml = true; + var emailMessage = new EmailMessage(from, to, subject, body, isBodyHtml); + + NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender); + + Assert.AreEqual(from, result.From.Adress); + Assert.AreEqual("", result.From.DisplayName); + Assert.AreEqual(1, result.To.Count()); + Assert.AreEqual(to, result.To.First().Adress); + Assert.AreEqual("", result.To.First().DisplayName); + Assert.AreEqual(subject, result.Subject); + Assert.AreEqual(body, result.Body); + Assert.IsTrue(result.IsBodyHtml); + Assert.IsFalse(result.HasAttachments); + } + + [Test] + public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage_With_DisplayName() + { + const string from = "\"From Email\" "; + const string to = "\"To Email\" "; + const string subject = "Subject"; + const string body = "

Message

"; + const bool isBodyHtml = true; + var emailMessage = new EmailMessage(from, to, subject, body, isBodyHtml); + + NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender); + + Assert.AreEqual("from@from.com", result.From.Adress); + Assert.AreEqual("From Email", result.From.DisplayName); + Assert.AreEqual(1, result.To.Count()); + Assert.AreEqual("to@to.com", result.To.First().Adress); + Assert.AreEqual("To Email", result.To.First().DisplayName); + Assert.AreEqual(subject, result.Subject); + Assert.AreEqual(body, result.Body); + Assert.IsTrue(result.IsBodyHtml); + Assert.IsFalse(result.HasAttachments); + } + + + [Test] + public void Can_Construct_NotificationEmailModel_From_Full_EmailMessage() + { + const string from = "\"From Email\" "; + string[] to = new[] { "to@email.com", "\"Second Email\" " }; + string[] cc = new[] { "\"First CC\" ", "cc2@email.com" }; + string[] bcc = new[] { "bcc@email.com", "bcc2@email.com", "\"Third BCC\" ", "invalid@email@address" }; + string[] replyTo = new[] { "replyto@email.com" }; + const string subject = "Subject"; + const string body = "Message"; + const bool isBodyHtml = false; + + using var attachmentStream = new MemoryStream(Encoding.UTF8.GetBytes("test")); + var attachments = new List + { + new EmailMessageAttachment(attachmentStream, "test.txt"), + }; + var emailMessage = new EmailMessage(from, to, cc, bcc, replyTo, subject, body, isBodyHtml, attachments); + + var result = emailMessage.ToNotificationEmail(ConfiguredSender); + + Assert.AreEqual("from@from.com", result.From.Adress); + Assert.AreEqual("From Email", result.From.DisplayName); + + Assert.AreEqual(2, result.To.Count()); + Assert.AreEqual("to@email.com", result.To.First().Adress); + Assert.AreEqual("", result.To.First().DisplayName); + Assert.AreEqual("to2@email.com", result.To.Skip(1).First().Adress); + Assert.AreEqual("Second Email", result.To.Skip(1).First().DisplayName); + + Assert.AreEqual(2, result.Cc.Count()); + Assert.AreEqual("cc@email.com", result.Cc.First().Adress); + Assert.AreEqual("First CC", result.Cc.First().DisplayName); + Assert.AreEqual("cc2@email.com", result.Cc.Skip(1).First().Adress); + Assert.AreEqual("", result.Cc.Skip(1).First().DisplayName); + + Assert.AreEqual(3, result.Bcc.Count()); + Assert.AreEqual("bcc@email.com", result.Bcc.First().Adress); + Assert.AreEqual("", result.Bcc.First().DisplayName); + Assert.AreEqual("bcc2@email.com", result.Bcc.Skip(1).First().Adress); + Assert.AreEqual("", result.Bcc.Skip(1).First().DisplayName); + Assert.AreEqual("bcc3@email.com", result.Bcc.Skip(2).First().Adress); + Assert.AreEqual("Third BCC", result.Bcc.Skip(2).First().DisplayName); + + Assert.AreEqual(1, result.ReplyTo.Count()); + Assert.AreEqual("replyto@email.com", result.ReplyTo.First().Adress); + Assert.AreEqual("", result.ReplyTo.First().DisplayName); + + Assert.AreEqual(subject, result.Subject); + Assert.AreEqual(body, result.Body); + Assert.AreEqual(1, result.Attachments.Count()); + } } } From baf13adef898a66c99e917e71d53c61cb4b2d787 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 13:10:28 +0200 Subject: [PATCH 13/36] Don't convert to MimeMessage --- .../Extensions/EmailMessageExtensions.cs | 55 ++++++++++++++----- .../Extensions/EmailMessageExtensionsTests.cs | 8 +-- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs index 075c476afe..b4a9d4942e 100644 --- a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs +++ b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs @@ -1,5 +1,5 @@ using System; -using System.Linq; +using System.Collections.Generic; using MimeKit; using MimeKit.Text; using Umbraco.Cms.Core.Models.Email; @@ -62,27 +62,52 @@ namespace Umbraco.Cms.Infrastructure.Extensions public static NotificationEmailModel ToNotificationEmail(this EmailMessage emailMessage, string configuredFromAddress) { - var mimeMessage = emailMessage.ToMimeMessage(configuredFromAddress); - if (mimeMessage.From.Any() is false || mimeMessage.To.Any() is false) - { - throw new InvalidOperationException("There must be a valid from address and recipient address."); - } - // EmailMessage only supports a single from mail, so take the first. - NotificationEmailAddress from = ToNotificationAddress(mimeMessage.From.Mailboxes.First()); + NotificationEmailAddress from = ToNotificationAddress(emailMessage.From); return new NotificationEmailModel(from, - mimeMessage.To.Mailboxes.Select(ToNotificationAddress), - mimeMessage.Cc.Mailboxes.Select(ToNotificationAddress), - mimeMessage.Bcc.Mailboxes.Select(ToNotificationAddress), - mimeMessage.ReplyTo.Mailboxes.Select(ToNotificationAddress), - mimeMessage.Subject, + GetNotificationAddresses(emailMessage.To), + GetNotificationAddresses(emailMessage.Cc), + GetNotificationAddresses(emailMessage.Bcc), + GetNotificationAddresses(emailMessage.ReplyTo), + emailMessage.Subject, emailMessage.Body, emailMessage.Attachments, emailMessage.IsBodyHtml); } - private static NotificationEmailAddress ToNotificationAddress(MailboxAddress mailboxAddress) => - new NotificationEmailAddress(mailboxAddress.Address, mailboxAddress.Name); + private static NotificationEmailAddress ToNotificationAddress(string address) + { + if (InternetAddress.TryParse(address, out InternetAddress internetAddress)) + { + if (internetAddress is MailboxAddress mailboxAddress) + { + return new NotificationEmailAddress(mailboxAddress.Address, internetAddress.Name); + } + } + + return null; + } + + private static IEnumerable GetNotificationAddresses(IEnumerable addresses) + { + if (addresses is null) + { + return null; + } + + var notificationAddresses = new List(); + + foreach (var address in addresses) + { + NotificationEmailAddress notificationAddress = ToNotificationAddress(address); + if (notificationAddress is not null) + { + notificationAddresses.Add(notificationAddress); + } + } + + return notificationAddresses; + } private static void AddAddresses(MimeMessage message, string[] addresses, Func addressListGetter, bool throwIfNoneValid = false) { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs index d53ecbf3f0..5112615431 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs @@ -150,10 +150,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions public void Can_Construct_NotificationEmailModel_From_Full_EmailMessage() { const string from = "\"From Email\" "; - string[] to = new[] { "to@email.com", "\"Second Email\" " }; - string[] cc = new[] { "\"First CC\" ", "cc2@email.com" }; - string[] bcc = new[] { "bcc@email.com", "bcc2@email.com", "\"Third BCC\" ", "invalid@email@address" }; - string[] replyTo = new[] { "replyto@email.com" }; + string[] to = { "to@email.com", "\"Second Email\" ", "invalid@invalid@invalid" }; + string[] cc = { "\"First CC\" ", "cc2@email.com", "invalid@invalid@invalid" }; + string[] bcc = { "bcc@email.com", "bcc2@email.com", "\"Third BCC\" ", "invalid@email@address" }; + string[] replyTo = { "replyto@email.com", "invalid@invalid@invalid" }; const string subject = "Subject"; const string body = "Message"; const bool isBodyHtml = false; From a56de298a324eb216478e0bfd5ec4a5f2552e881 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 14:18:49 +0200 Subject: [PATCH 14/36] Allow fallback to configured email --- .../Extensions/EmailMessageExtensions.cs | 10 ++++----- .../Extensions/EmailMessageExtensionsTests.cs | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs index b4a9d4942e..3e1483c744 100644 --- a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs +++ b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs @@ -10,11 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Extensions { public static MimeMessage ToMimeMessage(this EmailMessage mailMessage, string configuredFromAddress) { - var fromEmail = mailMessage.From; - if (string.IsNullOrEmpty(fromEmail)) - { - fromEmail = configuredFromAddress; - } + var fromEmail = string.IsNullOrEmpty(mailMessage.From) ? configuredFromAddress : mailMessage.From; if (!InternetAddress.TryParse(fromEmail, out InternetAddress fromAddress)) { @@ -62,7 +58,9 @@ namespace Umbraco.Cms.Infrastructure.Extensions public static NotificationEmailModel ToNotificationEmail(this EmailMessage emailMessage, string configuredFromAddress) { - NotificationEmailAddress from = ToNotificationAddress(emailMessage.From); + var fromEmail = string.IsNullOrEmpty(emailMessage.From) ? configuredFromAddress : emailMessage.From; + + NotificationEmailAddress from = ToNotificationAddress(fromEmail); return new NotificationEmailModel(from, GetNotificationAddresses(emailMessage.To), diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs index 5112615431..f348a6e9a1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs @@ -122,6 +122,28 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions Assert.IsFalse(result.HasAttachments); } + [Test] + public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage_With_Configured_Sender() + { + const string to = "to@email.com"; + const string subject = "Subject"; + const string body = "

Message

"; + const bool isBodyHtml = true; + var emailMessage = new EmailMessage(null, to, subject, body, isBodyHtml); + + NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender); + + Assert.AreEqual(ConfiguredSender, result.From.Adress); + Assert.AreEqual("", result.From.DisplayName); + Assert.AreEqual(1, result.To.Count()); + Assert.AreEqual(to, result.To.First().Adress); + Assert.AreEqual("", result.To.First().DisplayName); + Assert.AreEqual(subject, result.Subject); + Assert.AreEqual(body, result.Body); + Assert.IsTrue(result.IsBodyHtml); + Assert.IsFalse(result.HasAttachments); + } + [Test] public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage_With_DisplayName() { From 96f88ac990c6423756582dffaa05a5d0c4c154e5 Mon Sep 17 00:00:00 2001 From: Mole Date: Fri, 4 Jun 2021 15:47:34 +0200 Subject: [PATCH 15/36] Apply suggestions from PR --- .../Models/Email/NotificationEmailAddress.cs | 4 +- .../Extensions/EmailMessageExtensions.cs | 42 +++++++++---------- .../Extensions/EmailMessageExtensionsTests.cs | 30 ++++++------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs b/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs index 04da915fab..755947c6a4 100644 --- a/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs +++ b/src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs @@ -7,11 +7,11 @@ namespace Umbraco.Cms.Core.Models.Email { public string DisplayName { get; } - public string Adress { get; } + public string Address { get; } public NotificationEmailAddress(string address, string displayName) { - Adress = address; + Address = address; DisplayName = displayName; } } diff --git a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs index 3e1483c744..f7bed9d74c 100644 --- a/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs +++ b/src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs @@ -55,6 +55,27 @@ namespace Umbraco.Cms.Infrastructure.Extensions return messageToSend; } + private static void AddAddresses(MimeMessage message, string[] addresses, Func addressListGetter, bool throwIfNoneValid = false) + { + var foundValid = false; + if (addresses != null) + { + foreach (var address in addresses) + { + if (InternetAddress.TryParse(address, out InternetAddress internetAddress)) + { + addressListGetter(message).Add(internetAddress); + foundValid = true; + } + } + } + + if (throwIfNoneValid && foundValid == false) + { + throw new InvalidOperationException($"Email could not be sent. Could not parse a valid recipient address."); + } + } + public static NotificationEmailModel ToNotificationEmail(this EmailMessage emailMessage, string configuredFromAddress) { @@ -106,26 +127,5 @@ namespace Umbraco.Cms.Infrastructure.Extensions return notificationAddresses; } - - private static void AddAddresses(MimeMessage message, string[] addresses, Func addressListGetter, bool throwIfNoneValid = false) - { - var foundValid = false; - if (addresses != null) - { - foreach (var address in addresses) - { - if (InternetAddress.TryParse(address, out InternetAddress internetAddress)) - { - addressListGetter(message).Add(internetAddress); - foundValid = true; - } - } - } - - if (throwIfNoneValid && foundValid == false) - { - throw new InvalidOperationException($"Email could not be sent. Could not parse a valid recipient address."); - } - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs index f348a6e9a1..709873e8a3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Extensions/EmailMessageExtensionsTests.cs @@ -111,10 +111,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender); - Assert.AreEqual(from, result.From.Adress); + Assert.AreEqual(from, result.From.Address); Assert.AreEqual("", result.From.DisplayName); Assert.AreEqual(1, result.To.Count()); - Assert.AreEqual(to, result.To.First().Adress); + Assert.AreEqual(to, result.To.First().Address); Assert.AreEqual("", result.To.First().DisplayName); Assert.AreEqual(subject, result.Subject); Assert.AreEqual(body, result.Body); @@ -133,10 +133,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender); - Assert.AreEqual(ConfiguredSender, result.From.Adress); + Assert.AreEqual(ConfiguredSender, result.From.Address); Assert.AreEqual("", result.From.DisplayName); Assert.AreEqual(1, result.To.Count()); - Assert.AreEqual(to, result.To.First().Adress); + Assert.AreEqual(to, result.To.First().Address); Assert.AreEqual("", result.To.First().DisplayName); Assert.AreEqual(subject, result.Subject); Assert.AreEqual(body, result.Body); @@ -156,10 +156,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender); - Assert.AreEqual("from@from.com", result.From.Adress); + Assert.AreEqual("from@from.com", result.From.Address); Assert.AreEqual("From Email", result.From.DisplayName); Assert.AreEqual(1, result.To.Count()); - Assert.AreEqual("to@to.com", result.To.First().Adress); + Assert.AreEqual("to@to.com", result.To.First().Address); Assert.AreEqual("To Email", result.To.First().DisplayName); Assert.AreEqual(subject, result.Subject); Assert.AreEqual(body, result.Body); @@ -189,31 +189,31 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions var result = emailMessage.ToNotificationEmail(ConfiguredSender); - Assert.AreEqual("from@from.com", result.From.Adress); + Assert.AreEqual("from@from.com", result.From.Address); Assert.AreEqual("From Email", result.From.DisplayName); Assert.AreEqual(2, result.To.Count()); - Assert.AreEqual("to@email.com", result.To.First().Adress); + Assert.AreEqual("to@email.com", result.To.First().Address); Assert.AreEqual("", result.To.First().DisplayName); - Assert.AreEqual("to2@email.com", result.To.Skip(1).First().Adress); + Assert.AreEqual("to2@email.com", result.To.Skip(1).First().Address); Assert.AreEqual("Second Email", result.To.Skip(1).First().DisplayName); Assert.AreEqual(2, result.Cc.Count()); - Assert.AreEqual("cc@email.com", result.Cc.First().Adress); + Assert.AreEqual("cc@email.com", result.Cc.First().Address); Assert.AreEqual("First CC", result.Cc.First().DisplayName); - Assert.AreEqual("cc2@email.com", result.Cc.Skip(1).First().Adress); + Assert.AreEqual("cc2@email.com", result.Cc.Skip(1).First().Address); Assert.AreEqual("", result.Cc.Skip(1).First().DisplayName); Assert.AreEqual(3, result.Bcc.Count()); - Assert.AreEqual("bcc@email.com", result.Bcc.First().Adress); + Assert.AreEqual("bcc@email.com", result.Bcc.First().Address); Assert.AreEqual("", result.Bcc.First().DisplayName); - Assert.AreEqual("bcc2@email.com", result.Bcc.Skip(1).First().Adress); + Assert.AreEqual("bcc2@email.com", result.Bcc.Skip(1).First().Address); Assert.AreEqual("", result.Bcc.Skip(1).First().DisplayName); - Assert.AreEqual("bcc3@email.com", result.Bcc.Skip(2).First().Adress); + Assert.AreEqual("bcc3@email.com", result.Bcc.Skip(2).First().Address); Assert.AreEqual("Third BCC", result.Bcc.Skip(2).First().DisplayName); Assert.AreEqual(1, result.ReplyTo.Count()); - Assert.AreEqual("replyto@email.com", result.ReplyTo.First().Adress); + Assert.AreEqual("replyto@email.com", result.ReplyTo.First().Address); Assert.AreEqual("", result.ReplyTo.First().DisplayName); Assert.AreEqual(subject, result.Subject); From 7d6defd4438deae4add6e32ec5b17addb1563faf Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 9 Jun 2021 14:17:54 +0100 Subject: [PATCH 16/36] Adds in missing overload for IsAllowedTemplate using only template alias which was available in V8 (#10425) --- .../Extensions/FriendlyPublishedContentExtensions.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs index 2a0b77461d..e991a6a6ed 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -109,6 +109,9 @@ namespace Umbraco.Extensions public static bool IsAllowedTemplate(this IPublishedContent content, int templateId) => content.IsAllowedTemplate(ContentTypeService, WebRoutingSettings.Value, templateId); + public static bool IsAllowedTemplate(this IPublishedContent content, string templateAlias) + => content.IsAllowedTemplate(WebRoutingSettings.Value.DisableAlternativeTemplates, WebRoutingSettings.Value.ValidateAlternativeTemplates, templateAlias); + public static bool IsAllowedTemplate( this IPublishedContent content, bool disableAlternativeTemplates, From cfdf11b1956a8be3b613d23d6a4ed08dac05ac2c Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 10 Jun 2021 12:18:10 +0200 Subject: [PATCH 17/36] Renamed build to buildTransitive --- build/NuSpecs/UmbracoCms.StaticAssets.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/NuSpecs/UmbracoCms.StaticAssets.nuspec b/build/NuSpecs/UmbracoCms.StaticAssets.nuspec index b8109dbfa9..cd8367d8c8 100644 --- a/build/NuSpecs/UmbracoCms.StaticAssets.nuspec +++ b/build/NuSpecs/UmbracoCms.StaticAssets.nuspec @@ -28,6 +28,6 @@ - + From 0b3eeafb47a35b794d88194777ab1735ff2e8ea3 Mon Sep 17 00:00:00 2001 From: Jason Elkin Date: Fri, 11 Jun 2021 13:09:41 +0100 Subject: [PATCH 18/36] fixed a typo in the UmbracoProject template (#10432) * fixed a typo in the UmbracoProject template * Update build/templates/UmbracoProject/UmbracoProject.csproj Co-authored-by: Bjarke Berg --- build/templates/UmbracoProject/UmbracoProject.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/templates/UmbracoProject/UmbracoProject.csproj b/build/templates/UmbracoProject/UmbracoProject.csproj index 9798a40ff2..6850940edd 100644 --- a/build/templates/UmbracoProject/UmbracoProject.csproj +++ b/build/templates/UmbracoProject/UmbracoProject.csproj @@ -44,7 +44,7 @@ - + false From 20f3b223c5ccf04790dfef9b4f225c8eda2b1531 Mon Sep 17 00:00:00 2001 From: Jose Marcenaro <923289+JoseMarcenaro@users.noreply.github.com> Date: Fri, 11 Jun 2021 09:17:12 -0300 Subject: [PATCH 19/36] Use default( ) instead of null for model value (#10435) --- src/Umbraco.Web.Common/Views/UmbracoViewPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs b/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs index c2608efc41..97ba933838 100644 --- a/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs +++ b/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs @@ -228,7 +228,7 @@ namespace Umbraco.Cms.Web.Common.Views // if not possible or it is not generic then we need to create a new ViewDataDictionary Type nViewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType); - var tViewData = new ViewDataDictionary(viewData) { Model = null }; // temp view data to copy values + var tViewData = new ViewDataDictionary(viewData) { Model = default(TModel) }; // temp view data to copy values var nViewData = (ViewDataDictionary)Activator.CreateInstance(nViewDataType, tViewData); return nViewData; } From e70c3628513ca720c4b4098f60a0a3a43df399f2 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 14 Jun 2021 12:20:06 +0100 Subject: [PATCH 20/36] Run `npm update caniuse-lite` --- src/Umbraco.Web.UI.Client/package-lock.json | 205 +++++--------------- src/Umbraco.Web.UI.Client/package.json | 4 +- 2 files changed, 55 insertions(+), 154 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 3f53638fc6..b2d811df89 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1836,8 +1836,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true, - "optional": true + "dev": true }, "base64id": { "version": "1.0.0", @@ -2084,7 +2083,6 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -2126,7 +2124,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -2136,15 +2133,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2160,7 +2155,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -2301,7 +2295,6 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -2327,8 +2320,7 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "optional": true + "dev": true }, "buffer-equal": { "version": "1.0.0", @@ -2503,9 +2495,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001168", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", - "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==", + "version": "1.0.30001237", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz", + "integrity": "sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw==", "dev": true }, "caseless": { @@ -2519,7 +2511,6 @@ "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", "dev": true, - "optional": true, "requires": { "get-proxy": "^2.0.0", "isurl": "^1.0.0-alpha5", @@ -2953,7 +2944,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, - "optional": true, "requires": { "graceful-readlink": ">= 1.0.0" } @@ -3048,7 +3038,6 @@ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "dev": true, - "optional": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -3104,7 +3093,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", "dev": true, - "optional": true, "requires": { "safe-buffer": "5.1.2" } @@ -3548,7 +3536,6 @@ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.0.0", "decompress-tarbz2": "^4.0.0", @@ -3565,7 +3552,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, - "optional": true, "requires": { "pify": "^3.0.0" }, @@ -3574,8 +3560,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } } @@ -3586,7 +3571,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, - "optional": true, "requires": { "mimic-response": "^1.0.0" } @@ -3596,7 +3580,6 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, - "optional": true, "requires": { "file-type": "^5.2.0", "is-stream": "^1.1.0", @@ -3607,8 +3590,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3617,7 +3599,6 @@ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.1.0", "file-type": "^6.1.0", @@ -3630,8 +3611,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "dev": true, - "optional": true + "dev": true } } }, @@ -3640,7 +3620,6 @@ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.1.1", "file-type": "^5.2.0", @@ -3651,8 +3630,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3661,7 +3639,6 @@ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, - "optional": true, "requires": { "file-type": "^3.8.0", "get-stream": "^2.2.0", @@ -3673,15 +3650,13 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, - "optional": true, "requires": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" @@ -3691,8 +3666,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3974,8 +3948,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3992,8 +3965,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true, - "optional": true + "dev": true }, "duplexify": { "version": "3.7.1", @@ -4596,7 +4568,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, - "optional": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", @@ -4612,7 +4583,6 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, - "optional": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", @@ -4752,7 +4722,6 @@ "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", "dev": true, - "optional": true, "requires": { "mime-db": "^1.28.0" } @@ -4762,7 +4731,6 @@ "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", "dev": true, - "optional": true, "requires": { "ext-list": "^2.0.0", "sort-keys-length": "^1.0.0" @@ -4997,7 +4965,6 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, - "optional": true, "requires": { "pend": "~1.2.0" } @@ -5036,15 +5003,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", - "dev": true, - "optional": true + "dev": true }, "filenamify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", "dev": true, - "optional": true, "requires": { "filename-reserved-regex": "^2.0.0", "strip-outer": "^1.0.0", @@ -5405,8 +5370,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", - "dev": true, - "optional": true + "dev": true }, "fs-mkdirp-stream": { "version": "1.0.0", @@ -5453,8 +5417,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5475,14 +5438,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5497,20 +5458,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5627,8 +5585,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5640,7 +5597,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5655,7 +5611,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5663,14 +5618,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5689,7 +5642,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5770,8 +5722,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5783,7 +5734,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5869,8 +5819,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5906,7 +5855,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5926,7 +5874,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5970,14 +5917,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -6004,7 +5949,6 @@ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", "dev": true, - "optional": true, "requires": { "npm-conf": "^1.1.0" } @@ -6013,15 +5957,13 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true + "dev": true }, "get-value": { "version": "2.0.6", @@ -6336,8 +6278,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true, - "optional": true + "dev": true }, "growly": { "version": "1.3.0", @@ -7108,8 +7049,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "dev": true, - "optional": true + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -7122,7 +7062,6 @@ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dev": true, - "optional": true, "requires": { "has-symbol-support-x": "^1.4.1" } @@ -7322,8 +7261,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true, - "optional": true + "dev": true }, "ignore": { "version": "4.0.6", @@ -7453,7 +7391,6 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, - "optional": true, "requires": { "repeating": "^2.0.0" } @@ -7781,7 +7718,6 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7834,8 +7770,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", - "dev": true, - "optional": true + "dev": true }, "is-negated-glob": { "version": "1.0.0", @@ -7873,15 +7808,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true, - "optional": true + "dev": true }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "optional": true + "dev": true }, "is-plain-object": { "version": "2.0.4", @@ -7951,15 +7884,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true, - "optional": true + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "optional": true + "dev": true }, "is-svg": { "version": "3.0.0", @@ -8056,7 +7987,6 @@ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, - "optional": true, "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" @@ -8969,8 +8899,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", - "dev": true, - "optional": true + "dev": true }, "lpad-align": { "version": "1.1.2", @@ -9040,8 +8969,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "optional": true + "dev": true }, "map-visit": { "version": "1.0.0", @@ -9211,8 +9139,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "optional": true + "dev": true }, "minimatch": { "version": "3.0.4", @@ -9435,9 +9362,9 @@ "dev": true }, "nouislider": { - "version": "14.6.3", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.6.3.tgz", - "integrity": "sha512-/3tAqsWY2JYW9vd7bC14bFRA1P9A+pRHOtKmoMsyfnB0fQcd1UFx2pdY1Ey5wAUzTnXTesmYaEo/ecLVETijIQ==" + "version": "14.6.4", + "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.6.4.tgz", + "integrity": "sha512-PVCGYl+aC7/nVEbW61ypJWfuW3UCpvctz/luxpt4byxxli1FFyjBX9NIiy4Yak9AaO6a5BkPGfFYMCW4eg3eeQ==" }, "now-and-later": { "version": "2.0.1", @@ -12547,7 +12474,6 @@ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", "dev": true, - "optional": true, "requires": { "config-chain": "^1.1.11", "pify": "^3.0.0" @@ -12557,8 +12483,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -12567,7 +12492,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, - "optional": true, "requires": { "path-key": "^2.0.0" } @@ -12929,8 +12853,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true + "dev": true }, "p-is-promise": { "version": "1.1.0", @@ -12967,7 +12890,6 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -13158,8 +13080,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true, - "optional": true + "dev": true }, "performance-now": { "version": "2.1.0", @@ -13667,8 +13588,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true, - "optional": true + "dev": true }, "prr": { "version": "1.0.1", @@ -14024,7 +13944,6 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, - "optional": true, "requires": { "is-finite": "^1.0.0" } @@ -14386,7 +14305,6 @@ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", "dev": true, - "optional": true, "requires": { "commander": "~2.8.1" } @@ -14789,7 +14707,6 @@ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", "dev": true, - "optional": true, "requires": { "is-plain-obj": "^1.0.0" } @@ -14799,7 +14716,6 @@ "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", "dev": true, - "optional": true, "requires": { "sort-keys": "^1.0.0" } @@ -15130,7 +15046,6 @@ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "dev": true, - "optional": true, "requires": { "is-natural-number": "^4.0.1" } @@ -15139,8 +15054,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "optional": true + "dev": true }, "strip-indent": { "version": "1.0.1", @@ -15163,7 +15077,6 @@ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15289,7 +15202,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha1-jqVdqzeXIlPZqa+Q/c1VmuQ1xVU=", "dev": true, - "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -15304,15 +15216,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15328,7 +15238,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15339,15 +15248,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", - "dev": true, - "optional": true + "dev": true }, "tempfile": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", "dev": true, - "optional": true, "requires": { "temp-dir": "^1.0.0", "uuid": "^3.0.1" @@ -15442,8 +15349,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true, - "optional": true + "dev": true }, "timers-ext": { "version": "0.1.7", @@ -15500,8 +15406,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", - "dev": true, - "optional": true + "dev": true }, "to-fast-properties": { "version": "2.0.0", @@ -15605,7 +15510,6 @@ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15742,7 +15646,6 @@ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", "dev": true, - "optional": true, "requires": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -15943,8 +15846,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true, - "optional": true + "dev": true }, "use": { "version": "3.1.1", @@ -16440,7 +16342,6 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, - "optional": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 6514f2f217..d0f1c1cb99 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -54,7 +54,7 @@ "@babel/core": "7.6.4", "@babel/preset-env": "7.6.3", "autoprefixer": "9.6.5", - "caniuse-lite": "^1.0.30001037", + "caniuse-lite": "^1.0.30001237", "cssnano": "4.1.10", "fs": "0.0.2", "gulp": "4.0.2", @@ -77,8 +77,8 @@ "jasmine-core": "3.5.0", "jsdom": "16.4.0", "karma": "4.4.1", - "karma-jsdom-launcher": "^8.0.2", "karma-jasmine": "2.0.1", + "karma-jsdom-launcher": "^8.0.2", "karma-junit-reporter": "2.0.1", "karma-spec-reporter": "0.0.32", "less": "3.10.3", From 6f3a83c50746f5ce1d26790b4c730699d18e8e1a Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 15 Jun 2021 15:12:39 +1000 Subject: [PATCH 21/36] Fix interface inheritance (#10470) --- .../ApplicationBuilder/IUmbracoApplicationBuilder.cs | 2 +- .../ApplicationBuilder/UmbracoApplicationBuilder.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.Common/ApplicationBuilder/IUmbracoApplicationBuilder.cs b/src/Umbraco.Web.Common/ApplicationBuilder/IUmbracoApplicationBuilder.cs index 68ba148f49..090ef52790 100644 --- a/src/Umbraco.Web.Common/ApplicationBuilder/IUmbracoApplicationBuilder.cs +++ b/src/Umbraco.Web.Common/ApplicationBuilder/IUmbracoApplicationBuilder.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Web.Common.ApplicationBuilder { - public interface IUmbracoApplicationBuilder : IUmbracoMiddlewareBuilder + public interface IUmbracoApplicationBuilder { /// /// Called to include umbraco middleware diff --git a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs index 05fc38cc71..b7acc45d22 100644 --- a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs +++ b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Web.Common.ApplicationBuilder /// /// A builder to allow encapsulating the enabled endpoints in Umbraco /// - internal class UmbracoApplicationBuilder : IUmbracoApplicationBuilder + internal class UmbracoApplicationBuilder : IUmbracoApplicationBuilder, IUmbracoMiddlewareBuilder { public UmbracoApplicationBuilder(IServiceProvider services, IRuntimeState runtimeState, IApplicationBuilder appBuilder) { From 8d3434d7d8a2314410920b60aaf63985c869f25b Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 15 Jun 2021 08:42:52 +0100 Subject: [PATCH 22/36] dotnet new template - Escape JSON special characters for password & connection string (#10467) * Fix sourceName to match UmbracoProject and use a generated symbol to replace the Umbraco.Cms.Web.UI.NetCore in Program and Startup files * Update template.json * Run `npm update caniuse-lite` * Regex replacement for Password & Connection strings that gets placed into AppSettings.Development.json So escaping \ and " for JSON strings * Escaping input and handle namespace replacing. + Updated to beta004 Co-authored-by: Elitsa Marinovska Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Co-authored-by: Bjarke Berg --- build/build.ps1 | 25 ---- .../.template.config/template.json | 141 +++++++++++++++++- src/Directory.Build.props | 2 +- src/Umbraco.Web.UI.Client/package.json | 6 +- 4 files changed, 138 insertions(+), 36 deletions(-) diff --git a/build/build.ps1 b/build/build.ps1 index ba99e1e660..fb869738f3 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -351,29 +351,6 @@ $this.RemoveDirectory("$tmp\Templates\UmbracoProject\bin") }) - $ubuild.DefineMethod("PackageZip", - { - - Write-Host "Create Zip packages" - - $src = "$($this.SolutionRoot)\src" - $tmp = $this.BuildTemp - $out = $this.BuildOutput - - Write-Host "Zip all binaries" - &$this.BuildEnv.Zip a -r "$out\UmbracoCms.AllBinaries.$($this.Version.Semver).zip" ` - "$tmp\bin\*" ` - "-x!dotless.Core.*" ` - > $null - if (-not $?) { throw "Failed to zip UmbracoCms.AllBinaries." } - - Write-Host "Zip cms" - &$this.BuildEnv.Zip a -r "$out\UmbracoCms.$($this.Version.Semver).zip" ` - "$tmp\WebApp\*" ` - "-x!dotless.Core.*" "-x!Content_Types.xml" "-x!*.pdb" ` - > $null - if (-not $?) { throw "Failed to zip UmbracoCms." } - }) $ubuild.DefineMethod("PrepareBuild", { @@ -541,8 +518,6 @@ # not running tests $this.PreparePackages() if ($this.OnError()) { return } - $this.PackageZip() - if ($this.OnError()) { return } $this.VerifyNuGet() if ($this.OnError()) { return } $this.PackageNuGet() diff --git a/build/templates/UmbracoProject/.template.config/template.json b/build/templates/UmbracoProject/.template.config/template.json index 4f2454706d..fa652af767 100644 --- a/build/templates/UmbracoProject/.template.config/template.json +++ b/build/templates/UmbracoProject/.template.config/template.json @@ -15,7 +15,7 @@ }, "primaryOutputs": [ { - "path": "UmbracoProject.csproj" + "path": "UmbracoProject.csproj" } ], "postActions": [ @@ -29,12 +29,35 @@ "continueOnError": true } ], - "sourceName": "Umbraco.Cms.Web.UI.NetCore", + "sourceName": "UmbracoProject", "symbols": { + "namespaceReplacer": { + "type": "generated", + "generator": "regex", + "dataType": "string", + "replaces": "Umbraco.Cms.Web.UI.NetCore", + "parameters": { + "source": "name", + "steps": [ + { + "regex": "\\s", // whitespaces are not valid. Replace with _ + "replacement": "_" + }, + { + "regex": "-", // - are not valid. Replace with _ + "replacement": "_" + }, + { + "regex": "^[^a-zA-Z_]+", // should start with a-z, A-Z or _ to be a valid namespace + "replacement": "_" + } + ] + } + }, "version": { "type": "parameter", "datatype": "string", - "defaultValue": "9.0.0-beta003", + "defaultValue": "9.0.0-beta004", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, @@ -98,30 +121,134 @@ "type": "parameter", "datatype":"text", "description": "The friendly name of the user for Umbraco login when using Unattended install (Without installer wizard UI)", - "replaces": "FRIENDLY_NAME_FROM_TEMPLATE", "defaultValue": "" }, + "FriendlyNameReplaced":{ + "type": "generated", + "generator": "regex", + "dataType": "string", + "replaces": "FRIENDLY_NAME_FROM_TEMPLATE", + "parameters": { + "source": "FriendlyName", + "steps": [ + { + "regex": "\\\\", + "replacement": "\\\\" + }, + { + "regex": "\\\"", + "replacement": "\\\"" + }, + { + "regex": "\\\n", + "replacement": "\\\n" + }, + { + "regex": "\\\t", + "replacement": "\\\t" + } + ] + } + }, "Email":{ "type": "parameter", "datatype":"text", "description": "Email to use for Umbraco login when using Unattended install (Without installer wizard UI)", - "replaces": "EMAIL_FROM_TEMPLATE", "defaultValue": "" }, + "EmailReplaced":{ + "type": "generated", + "generator": "regex", + "dataType": "string", + "replaces": "EMAIL_FROM_TEMPLATE", + "parameters": { + "source": "Email", + "steps": [ + { + "regex": "\\\\", + "replacement": "\\\\" + }, + { + "regex": "\\\"", + "replacement": "\\\"" + }, + { + "regex": "\\\n", + "replacement": "\\\n" + }, + { + "regex": "\\\t", + "replacement": "\\\t" + } + ] + } + }, "Password":{ "type": "parameter", "datatype":"text", "description": "Password to use for Umbraco login when using Unattended install (Without installer wizard UI)", - "replaces": "PASSWORD_FROM_TEMPLATE", "defaultValue": "" }, + "PasswordReplaced":{ + "type": "generated", + "generator": "regex", + "dataType": "string", + "replaces": "PASSWORD_FROM_TEMPLATE", + "parameters": { + "source": "Password", + "steps": [ + { + "regex": "\\\\", + "replacement": "\\\\" + }, + { + "regex": "\\\"", + "replacement": "\\\"" + }, + { + "regex": "\\\n", + "replacement": "\\\n" + }, + { + "regex": "\\\t", + "replacement": "\\\t" + } + ] + } + }, "ConnectionString":{ "type": "parameter", "datatype":"text", "description": "Database connection string when using Unattended install (Without installer wizard UI)", - "replaces": "CONNECTION_FROM_TEMPLATE", "defaultValue": "" }, + "ConnectionStringReplaced":{ + "type": "generated", + "generator": "regex", + "dataType": "string", + "replaces": "CONNECTION_FROM_TEMPLATE", + "parameters": { + "source": "ConnectionString", + "steps": [ + { + "regex": "\\\\", + "replacement": "\\\\" + }, + { + "regex": "\\\"", + "replacement": "\\\"" + }, + { + "regex": "\\\n", + "replacement": "\\\n" + }, + { + "regex": "\\\t", + "replacement": "\\\t" + } + ] + } + }, "UsingUnattenedInstall":{ "type": "computed", "value": "(FriendlyName != \"\" && Email != \"\" && Password != \"\" && ConnectionString != \"\")" diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 66b7cb4bb5..a1220f9b3f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ 9.0.0 9.0.0 - 9.0.0-beta003 + 9.0.0-beta004 9.0.0 9.0 en-US diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 9474cdf3d4..813ba75095 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -52,8 +52,8 @@ }, "devDependencies": { "@babel/core": "7.6.4", - "@babel/preset-env": "7.6.3", "@babel/plugin-proposal-object-rest-spread": "7.13.8", + "@babel/preset-env": "7.6.3", "autoprefixer": "9.6.5", "caniuse-lite": "^1.0.30001237", "cssnano": "4.1.10", @@ -67,6 +67,7 @@ "gulp-eslint": "6.0.0", "gulp-imagemin": "7.1.0", "gulp-less": "4.0.1", + "gulp-minify": "3.1.0", "gulp-notify": "^3.0.0", "gulp-postcss": "8.0.0", "gulp-rename": "1.4.0", @@ -75,12 +76,11 @@ "gulp-watch": "5.0.1", "gulp-wrap": "0.15.0", "gulp-wrap-js": "0.4.1", - "gulp-minify": "3.1.0", "jasmine-core": "3.5.0", "jsdom": "16.4.0", "karma": "4.4.1", - "karma-jsdom-launcher": "^8.0.2", "karma-jasmine": "2.0.1", + "karma-jsdom-launcher": "^8.0.2", "karma-junit-reporter": "2.0.1", "karma-spec-reporter": "0.0.32", "less": "3.10.3", From ceb4db4f4539a4d23ea7520689d4e718db3217be Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 15 Jun 2021 08:54:46 +0100 Subject: [PATCH 23/36] Adds dotnetRunMessages flag to launch settings for Kestrel (#10472) https://github.com/dotnet/sdk/issues/12227 https://github.com/dotnet/sdk/pull/12581 https://github.com/dotnet/aspnetcore/blob/v6.0.0-preview.5.21301.17/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Properties/launchSettings.json#L22 --- .../templates/UmbracoProject/Properties/launchSettings.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/templates/UmbracoProject/Properties/launchSettings.json b/build/templates/UmbracoProject/Properties/launchSettings.json index 5f9252d553..f40916f4d1 100644 --- a/build/templates/UmbracoProject/Properties/launchSettings.json +++ b/build/templates/UmbracoProject/Properties/launchSettings.json @@ -18,11 +18,12 @@ }, "Umbraco.Web.UI.NetCore": { "commandName": "Project", + "dotnetRunMessages": true, "launchBrowser": true, + "applicationUrl": "https://localhost:HTTPS_PORT_FROM_TEMPLATE;http://localhost:HTTP_PORT_FROM_TEMPLATE", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:HTTPS_PORT_FROM_TEMPLATE;http://localhost:HTTP_PORT_FROM_TEMPLATE" + } } } } From 418ba569f11ae1afacb8b091d3ab73f517645dad Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jun 2021 10:47:04 +0200 Subject: [PATCH 24/36] remove comments as build script cannot use these in json --- .../templates/UmbracoProject/.template.config/template.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/templates/UmbracoProject/.template.config/template.json b/build/templates/UmbracoProject/.template.config/template.json index fa652af767..8a8c396dcb 100644 --- a/build/templates/UmbracoProject/.template.config/template.json +++ b/build/templates/UmbracoProject/.template.config/template.json @@ -40,15 +40,15 @@ "source": "name", "steps": [ { - "regex": "\\s", // whitespaces are not valid. Replace with _ + "regex": "\\s", "replacement": "_" }, { - "regex": "-", // - are not valid. Replace with _ + "regex": "-", "replacement": "_" }, { - "regex": "^[^a-zA-Z_]+", // should start with a-z, A-Z or _ to be a valid namespace + "regex": "^[^a-zA-Z_]+", "replacement": "_" } ] From e0a9397d92bcf475f35ea402dc885949a68b6ea2 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jun 2021 11:02:55 +0200 Subject: [PATCH 25/36] V9: Fix issue with recurring services that executes too often (#10473) * Fix exception in ReportSiteTask.cs, when running multiple times.. Also fixes issue with how often the tasks are executed * Fix timeout --- .../RecurringHostedServiceBase.cs | 5 +++-- .../HostedServices/ReportSiteTask.cs | 22 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs b/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs index 131b81322a..70dcb3a04e 100644 --- a/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs +++ b/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs @@ -62,8 +62,9 @@ namespace Umbraco.Cms.Infrastructure.HostedServices } finally { - // Resume now that the task is complete - _timer?.Change((int)_delay.TotalMilliseconds, (int)_period.TotalMilliseconds); + // Resume now that the task is complete - Note we use period in both because we don't want to execute again after the delay. + // So first execution is after _delay, and the we wait _period between each + _timer?.Change((int)_period.TotalMilliseconds, (int)_period.TotalMilliseconds); } } diff --git a/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs b/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs index b1411270c3..6eab3a60bc 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs @@ -52,13 +52,24 @@ namespace Umbraco.Cms.Infrastructure.HostedServices try { - // Send data to LIVE telemetry - s_httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); + + if (s_httpClient.BaseAddress is null) + { + // Send data to LIVE telemetry + s_httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); + + // Set a low timeout - no need to use a larger default timeout for this POST request + s_httpClient.Timeout = new TimeSpan(0, 0, 1); #if DEBUG - // Send data to DEBUG telemetry service - s_httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); + // Send data to DEBUG telemetry service + s_httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); + + + #endif + } + s_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); @@ -67,9 +78,6 @@ namespace Umbraco.Cms.Infrastructure.HostedServices var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = _umbracoVersion.SemanticVersion.ToSemanticStringWithoutBuild() }; request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header - // Set a low timeout - no need to use a larger default timeout for this POST request - s_httpClient.Timeout = new TimeSpan(0, 0, 1); - // Make a HTTP Post to telemetry service // https://telemetry.umbraco.com/installs/ // Fire & Forget, do not need to know if its a 200, 500 etc From 0c347706959148197b3d9a33d5442698d64aa769 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jun 2021 11:06:07 +0200 Subject: [PATCH 26/36] https://github.com/umbraco/Umbraco-CMS/issues/10438 - Adds missing `DataContract` to `FileExtensionConfigItem` --- src/Umbraco.Core/PropertyEditors/FileExtensionConfigItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Core/PropertyEditors/FileExtensionConfigItem.cs b/src/Umbraco.Core/PropertyEditors/FileExtensionConfigItem.cs index c777aedd89..d653a831cb 100644 --- a/src/Umbraco.Core/PropertyEditors/FileExtensionConfigItem.cs +++ b/src/Umbraco.Core/PropertyEditors/FileExtensionConfigItem.cs @@ -2,6 +2,7 @@ namespace Umbraco.Cms.Core.PropertyEditors { + [DataContract] public class FileExtensionConfigItem : IFileExtensionConfigItem { [DataMember(Name = "id")] From f2c1c30e7696f2ac531f0985dd0730feeacd729c Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 15 Jun 2021 12:07:11 +0200 Subject: [PATCH 27/36] Remove zips from azure build --- build/azure-pipelines.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index 893c62509a..b2824d8237 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -401,7 +401,7 @@ stages: publishJUnitResults: true testResultsFiles: '**\TESTS-*.xml' - task: PowerShell@1 - displayName: Prepare Packages & Zip + displayName: Prepare Packages inputs: scriptType: inlineScript inlineScript: | @@ -410,19 +410,6 @@ stages: $ubuild.CompileUmbraco() $ubuild.PreparePackages() - $ubuild.PackageZip() - - task: CopyFiles@2 - displayName: Copy Zip Files to Staging - inputs: - SourceFolder: build.out - Contents: '*.zip' - TargetFolder: $(build.artifactstagingdirectory) - CleanTargetFolder: true - - task: PublishBuildArtifacts@1 - displayName: Publish Zip Files - inputs: - PathtoPublish: $(build.artifactstagingdirectory) - ArtifactName: zips - task: PowerShell@1 displayName: Verify & Package NuGet inputs: From 22de16a691c46506d9162e8d639335de64794740 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 15 Jun 2021 12:43:03 +0200 Subject: [PATCH 28/36] Added two further notifications to the boot process for custom functionality that may need to run at different stages. (#10471) --- ...icationComponentsInstallingNotification.cs | 22 +++++++++++++++++++ ...oApplicationMainDomAcquiredNotification.cs | 19 ++++++++++++++++ .../Runtime/CoreRuntime.cs | 12 +++++----- 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Core/Notifications/UmbracoApplicationComponentsInstallingNotification.cs create mode 100644 src/Umbraco.Core/Notifications/UmbracoApplicationMainDomAcquiredNotification.cs diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationComponentsInstallingNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationComponentsInstallingNotification.cs new file mode 100644 index 0000000000..c29df4e85f --- /dev/null +++ b/src/Umbraco.Core/Notifications/UmbracoApplicationComponentsInstallingNotification.cs @@ -0,0 +1,22 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Cms.Core.Notifications +{ + /// + /// Notification that occurs during the Umbraco boot process, before instances of initialize. + /// + public class UmbracoApplicationComponentsInstallingNotification : INotification + { + /// + /// Initializes a new instance of the class. + /// + /// The runtime level + public UmbracoApplicationComponentsInstallingNotification(RuntimeLevel runtimeLevel) => RuntimeLevel = runtimeLevel; + + /// + /// Gets the runtime level of execution. + /// + public RuntimeLevel RuntimeLevel { get; } + } +} diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationMainDomAcquiredNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationMainDomAcquiredNotification.cs new file mode 100644 index 0000000000..6a66e2413f --- /dev/null +++ b/src/Umbraco.Core/Notifications/UmbracoApplicationMainDomAcquiredNotification.cs @@ -0,0 +1,19 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Cms.Core.Notifications +{ + /// + /// Notification that occurs during Umbraco boot after the MainDom has been acquired. + /// + public class UmbracoApplicationMainDomAcquiredNotification : INotification + { + /// + /// Initializes a new instance of the class. + /// + /// The runtime level + public UmbracoApplicationMainDomAcquiredNotification() + { + } + } +} diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index f7065fe0b5..0a262b58c5 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -103,6 +103,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate AcquireMainDom(); + await _eventAggregator.PublishAsync(new UmbracoApplicationMainDomAcquiredNotification(), cancellationToken); + DoUnattendedInstall(); DetermineRuntimeLevel(); @@ -117,8 +119,6 @@ namespace Umbraco.Cms.Infrastructure.Runtime throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(StartAsync)}"); } - - // if level is Run and reason is UpgradeMigrations, that means we need to perform an unattended upgrade if (State.Reason == RuntimeLevelReason.UpgradeMigrations && State.Level == RuntimeLevel.Run) { @@ -127,9 +127,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime // upgrade is done, set reason to Run DetermineRuntimeLevel(); - } + await _eventAggregator.PublishAsync(new UmbracoApplicationComponentsInstallingNotification(State.Level), cancellationToken); + // create & initialize the components _components.Initialize(); @@ -148,10 +149,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime } - private void DoUnattendedInstall() - { - State.DoUnattendedInstall(); - } + private void DoUnattendedInstall() => State.DoUnattendedInstall(); public async Task StopAsync(CancellationToken cancellationToken) { From 0c3db013d54b9f8256e2088fc5557e462db833a7 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Tue, 15 Jun 2021 13:51:39 +0200 Subject: [PATCH 29/36] Approve member when created with built-in macros (#10428) * Allow members created with built-in macros to be approved * Cleanup * Newly created members are always approved like in v8. Co-authored-by: Bjarke Berg --- src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs | 3 ++- src/Umbraco.Web.BackOffice/Controllers/MemberController.cs | 1 + src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs index 459417b289..724eb77030 100644 --- a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Core.Security /// /// Used to construct a new instance without an identity /// - public static MemberIdentityUser CreateNew(string username, string email, string memberTypeAlias, string name = null) + public static MemberIdentityUser CreateNew(string username, string email, string memberTypeAlias, bool isApproved, string name = null) { if (string.IsNullOrWhiteSpace(username)) { @@ -46,6 +46,7 @@ namespace Umbraco.Cms.Core.Security user.UserName = username; user.Email = email; user.MemberTypeAlias = memberTypeAlias; + user.IsApproved = isApproved; user.Id = null; user.HasIdentity = false; user.Name = name; diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs index 3d435322b8..6045cec8f9 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs @@ -366,6 +366,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers contentItem.Username, contentItem.Email, memberType.Alias, + contentItem.IsApproved, contentItem.Name); IdentityResult created = await _memberManager.CreateAsync(identityMember, contentItem.Password.NewPassword); diff --git a/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs index 2a8dd6a71a..1e6c417ed3 100644 --- a/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs @@ -127,7 +127,7 @@ namespace Umbraco.Cms.Web.Website.Controllers model.Username = (model.UsernameIsEmail || model.Username == null) ? model.Email : model.Username; - var identityUser = MemberIdentityUser.CreateNew(model.Username, model.Email, model.MemberTypeAlias, model.Name); + var identityUser = MemberIdentityUser.CreateNew(model.Username, model.Email, model.MemberTypeAlias, true, model.Name); IdentityResult identityResult = await _memberManager.CreateAsync( identityUser, model.Password); @@ -142,6 +142,7 @@ namespace Umbraco.Cms.Web.Website.Controllers // should never happen throw new InvalidOperationException($"Could not find a member with key: {member.Key}."); } + if (model.MemberProperties != null) { foreach (MemberPropertyModel property in model.MemberProperties.Where(p => p.Value != null) @@ -159,7 +160,6 @@ namespace Umbraco.Cms.Web.Website.Controllers } return identityResult; - } } } From 067395b0ff3715a0a2c3fcba8b101c4d48077ebf Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 15 Jun 2021 12:57:14 +0100 Subject: [PATCH 30/36] Fix for #10401 to allow you to chaneg your own password if using user section & fixes notification errors to be displayed in the UI (#10422) --- src/Umbraco.Web.BackOffice/Controllers/UsersController.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index cdd00913e7..19def88456 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -680,15 +680,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers IUser currentUser = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser; - // if it's the current user, the current user cannot reset their own password - if (currentUser.Username == found.Username) + // if it's the current user, the current user cannot reset their own password without providing their old password + if (currentUser.Username == found.Username && string.IsNullOrEmpty(changingPasswordModel.OldPassword)) { - return new ValidationErrorResult("Password reset is not allowed"); + return ValidationErrorResult.CreateNotificationValidationErrorResult("Password reset is not allowed without providing old password"); } if (!currentUser.IsAdmin() && found.IsAdmin()) { - return new ValidationErrorResult("The current user cannot change the password for the specified user"); + return ValidationErrorResult.CreateNotificationValidationErrorResult("The current user cannot change the password for the specified user"); } Attempt passwordChangeResult = await _passwordChanger.ChangePasswordWithIdentityAsync(changingPasswordModel, _userManager); From 348d1676cd7b82a70f82496619ad34722c0bdadf Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Sat, 29 May 2021 07:29:00 +0200 Subject: [PATCH 31/36] Handle only single content type event to avoid reloading the content and media cache multiple times after a deployment containing more than one changed document type. --- .../Cache/DistributedCacheBinderTests.cs | 16 +++++- .../Cache/DistributedCacheBinder.cs | 54 +++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index e446e049b6..00a33c0b6c 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; +using Umbraco.Core.Services.Changes; using Umbraco.Tests.Testing; using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; @@ -148,7 +149,6 @@ namespace Umbraco.Tests.Cache { // works because that event definition maps to an empty handler new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), - }; var umbracoContextFactory = new UmbracoContextFactory( @@ -166,5 +166,19 @@ namespace Umbraco.Tests.Cache var refreshers = new DistributedCacheBinder(null, umbracoContextFactory, null); refreshers.HandleEvents(definitions); } + + [Test] + public void OnlyHandlesOnContentTypeEvent() + { + var definitions = new IEventDefinition[] + { + new EventDefinition.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange.EventArgs(Enumerable.Empty>()), "Changed"), + new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), + new EventDefinition.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange.EventArgs(Enumerable.Empty>()), "Changed"), + new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), + }; + var result = DistributedCacheBinder.GetReducedEventList(definitions); + Assert.AreEqual(1, result.Count()); + } } } diff --git a/src/Umbraco.Web/Cache/DistributedCacheBinder.cs b/src/Umbraco.Web/Cache/DistributedCacheBinder.cs index 3ee24a23bf..e3a5a01d54 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheBinder.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheBinder.cs @@ -61,11 +61,15 @@ namespace Umbraco.Web.Cache /// public void HandleEvents(IEnumerable events) { - // ensure we run with an UmbracoContext, because this may run in a background task, - // yet developers may be using the 'current' UmbracoContext in the event handlers + // Ensure we run with an UmbracoContext, because this may run in a background task, + // yet developers may be using the 'current' UmbracoContext in the event handlers. using (_umbracoContextFactory.EnsureUmbracoContext()) { - foreach (var e in events) + // When it comes to content types types, a change to any single one will trigger a reload of the content and media caches. + // As far as I (AB) can tell, there's no type specific logic here, they all clear caches for all content types, and trigger a reload of all content and media. + // We also have events registered for Changed and Saved, which do the same thing, so really only need one of these. + // Hence if we have more than one document or media types, we can and should only handle one of the events for one, to avoid repeated cache reloads. + foreach (var e in GetReducedEventList(events)) { var handler = FindHandler(e); if (handler == null) @@ -80,5 +84,49 @@ namespace Umbraco.Web.Cache } } } + + // Internal for tests + internal static IEnumerable GetReducedEventList(IEnumerable events) + { + var reducedEvents = new List(); + + var gotDoumentType = false; + var gotMediaType = false; + var gotMemberType = false; + + foreach (var evt in events) + { + if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.ContentTypeService))) + { + if (gotDoumentType == false) + { + reducedEvents.Add(evt); + gotDoumentType = true; + } + } + else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MediaTypeService))) + { + if (gotMediaType == false) + { + reducedEvents.Add(evt); + gotMediaType = true; + } + } + else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MemberTypeService))) + { + if (gotMemberType == false) + { + reducedEvents.Add(evt); + gotMemberType = true; + } + } + else + { + reducedEvents.Add(evt); + } + } + + return reducedEvents; + } } } From 0f6732f03ce9bfb70d2467831149428746d84d53 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 15 Jun 2021 19:33:34 +0200 Subject: [PATCH 32/36] Made the AppendQueryStringToUrl method public to allow use from packages. (#10476) * Made the AppendQueryStringToUrl method public to allow use from packages. * Removed AssemblyInfo.cs file. --- .../Extensions/StringExtensions.cs | 2 +- src/Umbraco.Core/Properties/AssemblyInfo.cs | 29 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 src/Umbraco.Core/Properties/AssemblyInfo.cs diff --git a/src/Umbraco.Core/Extensions/StringExtensions.cs b/src/Umbraco.Core/Extensions/StringExtensions.cs index e815f219ca..0494224614 100644 --- a/src/Umbraco.Core/Extensions/StringExtensions.cs +++ b/src/Umbraco.Core/Extensions/StringExtensions.cs @@ -186,7 +186,7 @@ namespace Umbraco.Extensions /// This methods ensures that the resulting URL is structured correctly, that there's only one '?' and that things are /// delimited properly with '&' /// - internal static string AppendQueryStringToUrl(this string url, params string[] queryStrings) + public static string AppendQueryStringToUrl(this string url, params string[] queryStrings) { //remove any prefixed '&' or '?' for (var i = 0; i < queryStrings.Length; i++) diff --git a/src/Umbraco.Core/Properties/AssemblyInfo.cs b/src/Umbraco.Core/Properties/AssemblyInfo.cs deleted file mode 100644 index 9f49dade80..0000000000 --- a/src/Umbraco.Core/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: ComVisible(false)] -[assembly: Guid("DA322714-FB89-4943-92BD-BB122B82F66B")] - -// Umbraco Cms -[assembly: InternalsVisibleTo("Umbraco.Web")] -[assembly: InternalsVisibleTo("Umbraco.Web.UI")] - -[assembly: InternalsVisibleTo("Umbraco.Tests")] -[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")] - -// Allow this to be mocked in our unit tests -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] - -// Umbraco Deploy -[assembly: InternalsVisibleTo("Umbraco.Deploy")] -[assembly: InternalsVisibleTo("Umbraco.Deploy.UI")] -[assembly: InternalsVisibleTo("Umbraco.Deploy.Cloud")] - -// Umbraco Forms -[assembly: InternalsVisibleTo("Umbraco.Forms.Core")] -[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")] -[assembly: InternalsVisibleTo("Umbraco.Forms.Web")] - -// Umbraco Headless -[assembly: InternalsVisibleTo("Umbraco.Cloud.Headless")] From dc334c10154820cf0958e901dd6c00906084727a Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 16 Jun 2021 10:00:29 +0100 Subject: [PATCH 33/36] Automated install user with Environment Variables & unattended.user.json (#9930) * Try to update admin user unattended This will fail because we're not in install runtime state * Create a new user instead of trying to update the default admin * Create a new user instead of trying to update the default admin * Use same logic from NewInstallStep to modify the SuperUser aka -1 * Add back stuff after merge conflict from v8/dev * Add event to be raised * Trying to wire up events * Remove commented out code - just need to figure out why event is not hit/triggered * Read Appsettings as opposed to ENV variables * Use a JSON file that deletes itself as storing secrets in web.config will be accidently committed * Remove component based event - Component were only initialized after DB creation * Move UnattendedInstall down after _factory * Remove commented out code * Fixed issue where upgrader UI would show up - needed to recheck the Runtimelevel after UnattenedInstall * Apply suggestions from code review - Thanks Marc :) Co-authored-by: Marc Goodson Co-authored-by: Mole Co-authored-by: Marc Goodson --- .../Events/UnattendedInstallEventArgs.cs | 9 ++ src/Umbraco.Core/Runtime/CoreRuntime.cs | 137 +++++++++++++++++- src/Umbraco.Core/Umbraco.Core.csproj | 1 + 3 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs diff --git a/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs b/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs new file mode 100644 index 0000000000..3029126dea --- /dev/null +++ b/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Events +{ + /// + /// Used to notify that an Unattended install has completed + /// + public class UnattendedInstallEventArgs : System.ComponentModel.CancelEventArgs + { + } +} diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 25bb5d3151..4345469f54 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -1,13 +1,17 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Web; using System.Web.Hosting; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -16,6 +20,9 @@ using Umbraco.Core.Migrations.Install; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Scoping; +using Umbraco.Core.Security; +using Umbraco.Core.Services; using Umbraco.Core.Sync; namespace Umbraco.Core.Runtime @@ -119,6 +126,9 @@ namespace Umbraco.Core.Runtime try { + // Setup event listener + UnattendedInstalled += CoreRuntime_UnattendedInstalled; + // throws if not full-trust new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand(); @@ -162,8 +172,7 @@ namespace Umbraco.Core.Runtime // run handlers RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory); - // determines if unattended install is enabled and performs it if required - DoUnattendedInstall(databaseFactory); + // register runtime-level services // there should be none, really - this is here "just in case" @@ -190,6 +199,13 @@ namespace Umbraco.Core.Runtime // create the factory _factory = Current.Factory = composition.CreateFactory(); + // determines if unattended install is enabled and performs it if required + DoUnattendedInstall(databaseFactory); + + // determine our runtime level (AFTER UNATTENDED INSTALL) + // TODO: Feels kinda weird to call this again + DetermineRuntimeLevel(databaseFactory, ProfilingLogger); + // if level is Run and reason is UpgradeMigrations, that means we need to perform an unattended upgrade if (_state.Reason == RuntimeLevelReason.UpgradeMigrations && _state.Level == RuntimeLevel.Run) { @@ -203,8 +219,6 @@ namespace Umbraco.Core.Runtime // create & initialize the components _components = _factory.GetInstance(); _components.Initialize(); - - } catch (Exception e) { @@ -242,6 +256,93 @@ namespace Umbraco.Core.Runtime return _factory; } + private void CoreRuntime_UnattendedInstalled(IRuntime sender, UnattendedInstallEventArgs e) + { + var unattendedName = Environment.GetEnvironmentVariable("UnattendedUserName"); + var unattendedEmail = Environment.GetEnvironmentVariable("UnattendedUserEmail"); + var unattendedPassword = Environment.GetEnvironmentVariable("UnattendedUserPassword"); + + var fileExists = false; + var filePath = IOHelper.MapPath("~/App_Data/unattended.user.json"); + + // No values store in ENV vars - try fallback file of /app_data/unattended.user.json + if (unattendedName.IsNullOrWhiteSpace() + || unattendedEmail.IsNullOrWhiteSpace() + || unattendedPassword.IsNullOrWhiteSpace()) + { + + fileExists = File.Exists(filePath); + if (fileExists == false) + { + return; + } + + // Attempt to deserialize JSON + try + { + var fileContents = File.ReadAllText(filePath); + var credentials = JsonConvert.DeserializeObject(fileContents); + + unattendedName = credentials.Name; + unattendedEmail = credentials.Email; + unattendedPassword = credentials.Password; + } + catch (Exception ex) + { + + throw; + } + } + + // ENV Variables & JSON still empty + if (unattendedName.IsNullOrWhiteSpace() + || unattendedEmail.IsNullOrWhiteSpace() + || unattendedPassword.IsNullOrWhiteSpace()) + { + return; + } + + + // Update user details + var currentProvider = MembershipProviderExtensions.GetUsersMembershipProvider(); + var admin = Current.Services.UserService.GetUserById(Constants.Security.SuperUserId); + if (admin == null) + { + throw new InvalidOperationException("Could not find the super user!"); + } + + var membershipUser = currentProvider.GetUser(Constants.Security.SuperUserId, true); + if (membershipUser == null) + { + throw new InvalidOperationException($"No user found in membership provider with id of {Constants.Security.SuperUserId}."); + } + + try + { + var success = membershipUser.ChangePassword("default", unattendedPassword.Trim()); + if (success == false) + { + throw new FormatException("Password must be at least " + currentProvider.MinRequiredPasswordLength + " characters long and contain at least " + currentProvider.MinRequiredNonAlphanumericCharacters + " symbols"); + } + } + catch (Exception) + { + throw new FormatException("Password must be at least " + currentProvider.MinRequiredPasswordLength + " characters long and contain at least " + currentProvider.MinRequiredNonAlphanumericCharacters + " symbols"); + } + + admin.Email = unattendedEmail.Trim(); + admin.Name = unattendedName.Trim(); + admin.Username = unattendedEmail.Trim(); + + Current.Services.UserService.Save(admin); + + // Delete JSON file if it existed to tidy + if (fileExists) + { + File.Delete(filePath); + } + } + private void DoUnattendedInstall(IUmbracoDatabaseFactory databaseFactory) { // unattended install is not enabled @@ -285,6 +386,11 @@ namespace Umbraco.Core.Runtime var creator = new DatabaseSchemaCreator(database, Logger); creator.InitializeDatabaseSchema(); database.CompleteTransaction(); + + // Emit an event that unattended install completed + // Then this event can be listened for and create an unattended user + UnattendedInstalled?.Invoke(this, new UnattendedInstallEventArgs()); + Logger.Info("Unattended install completed."); } catch (Exception ex) @@ -397,6 +503,7 @@ namespace Umbraco.Core.Runtime public virtual void Terminate() { _components?.Terminate(); + UnattendedInstalled -= CoreRuntime_UnattendedInstalled; } /// @@ -404,7 +511,7 @@ namespace Umbraco.Core.Runtime /// public virtual void Compose(Composition composition) { - // nothing + // Nothing } #region Getters @@ -465,5 +572,23 @@ namespace Umbraco.Core.Runtime } #endregion + + /// + /// Event to be used to notify when the Unattended Install has finished + /// + public static event TypedEventHandler UnattendedInstalled; + + [DataContract] + public class UnattendedUserConfig + { + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "email")] + public string Email { get; set; } + + [DataMember(Name = "password")] + public string Password { get; set; } + } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 0a453ad75f..14444f5d59 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -131,6 +131,7 @@ + From 585f7bb57135ab31e36b782b78e0e151d8503625 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 17 Jun 2021 09:40:07 +0200 Subject: [PATCH 34/36] Make dashboards support deep linking (#10283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ronald Barendse Co-authored-by: Niels Lyngsø --- .../src/views/common/dashboard.controller.js | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js index e788e6fc9b..d7d5153956 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js @@ -7,38 +7,59 @@ * Controls the dashboards of the application * */ - -function DashboardController($scope, $routeParams, dashboardResource, localizationService) { + +function DashboardController($scope, $q, $routeParams, $location, dashboardResource, localizationService) { + const DASHBOARD_QUERY_PARAM = 'dashboard'; $scope.page = {}; $scope.page.nameLocked = true; $scope.page.loading = true; $scope.dashboard = {}; - localizationService.localize("sections_" + $routeParams.section).then(function(name){ - $scope.dashboard.name = name; - }); - - dashboardResource.getDashboard($routeParams.section).then(function(tabs){ - $scope.dashboard.tabs = tabs; - - // set first tab to active - if($scope.dashboard.tabs && $scope.dashboard.tabs.length > 0) { - $scope.dashboard.tabs[0].active = true; - } + var promises = []; + + promises.push(localizationService.localize("sections_" + $routeParams.section).then(function (name) { + $scope.dashboard.name = name; + })); + + promises.push(dashboardResource.getDashboard($routeParams.section).then(function (tabs) { + $scope.dashboard.tabs = tabs; + + if ($scope.dashboard.tabs && $scope.dashboard.tabs.length > 0) { + initActiveTab(); + } + })); + + $q.all(promises).then(function () { $scope.page.loading = false; }); - $scope.changeTab = function(tab) { - $scope.dashboard.tabs.forEach(function(tab) { - tab.active = false; - }); + $scope.changeTab = function (tab) { + if ($scope.dashboard.tabs && $scope.dashboard.tabs.length > 0) { + $scope.dashboard.tabs.forEach(function (tab) { + tab.active = false; + }); + } + tab.active = true; + $location.search(DASHBOARD_QUERY_PARAM, tab.alias); }; + function initActiveTab() { + // Check the query parameter for a dashboard alias + const dashboardAlias = $location.search()[DASHBOARD_QUERY_PARAM]; + const dashboardIndex = $scope.dashboard.tabs.findIndex(tab => tab.alias === dashboardAlias); + + // Set the first dashboard to active if there is no query parameter or we can't find a matching dashboard for the alias + const activeIndex = dashboardIndex !== -1 ? dashboardIndex : 0; + + const tab = $scope.dashboard.tabs[activeIndex]; + + tab.active = true; + $location.search(DASHBOARD_QUERY_PARAM, tab.alias); + } } - -//register it +// Register it angular.module('umbraco').controller("Umbraco.DashboardController", DashboardController); From 6a35e0c62bd8803056ec5cfb45816585c0a71fa3 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 17 Jun 2021 11:04:16 +0200 Subject: [PATCH 35/36] Moves extension methods from HtmlHelper to IHtmlHelper --- .../Extensions/HtmlHelperRenderExtensions.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs index ddca7f37aa..123ed6801a 100644 --- a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs @@ -791,73 +791,73 @@ namespace Umbraco.Extensions /// /// Strips all HTML tags from a given string, all contents of the tags will remain. /// - public static IHtmlContent StripHtml(this HtmlHelper helper, IHtmlContent html, params string[] tags) + public static IHtmlContent StripHtml(this IHtmlHelper helper, IHtmlContent html, params string[] tags) => helper.StripHtml(html.ToHtmlString(), tags); /// /// Strips all HTML tags from a given string, all contents of the tags will remain. /// - public static IHtmlContent StripHtml(this HtmlHelper helper, string html, params string[] tags) + public static IHtmlContent StripHtml(this IHtmlHelper helper, string html, params string[] tags) => StringUtilities.StripHtmlTags(html, tags); /// /// Will take the first non-null value in the collection and return the value of it. /// - public static string Coalesce(this HtmlHelper helper, params object[] args) + public static string Coalesce(this IHtmlHelper helper, params object[] args) => StringUtilities.Coalesce(args); /// /// Joins any number of int/string/objects into one string /// - public static string Concatenate(this HtmlHelper helper, params object[] args) + public static string Concatenate(this IHtmlHelper helper, params object[] args) => StringUtilities.Concatenate(args); /// /// Joins any number of int/string/objects into one string and separates them with the string separator parameter. /// - public static string Join(this HtmlHelper helper, string separator, params object[] args) + public static string Join(this IHtmlHelper helper, string separator, params object[] args) => StringUtilities.Join(separator, args); /// /// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent Truncate(this HtmlHelper helper, IHtmlContent html, int length) + public static IHtmlContent Truncate(this IHtmlHelper helper, IHtmlContent html, int length) => helper.Truncate(html.ToHtmlString(), length, true, false); /// /// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent Truncate(this HtmlHelper helper, IHtmlContent html, int length, bool addElipsis) + public static IHtmlContent Truncate(this IHtmlHelper helper, IHtmlContent html, int length, bool addElipsis) => helper.Truncate(html.ToHtmlString(), length, addElipsis, false); /// /// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent Truncate(this HtmlHelper helper, IHtmlContent html, int length, bool addElipsis, bool treatTagsAsContent) + public static IHtmlContent Truncate(this IHtmlHelper helper, IHtmlContent html, int length, bool addElipsis, bool treatTagsAsContent) => helper.Truncate(html.ToHtmlString(), length, addElipsis, treatTagsAsContent); /// /// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent Truncate(this HtmlHelper helper, string html, int length) + public static IHtmlContent Truncate(this IHtmlHelper helper, string html, int length) => helper.Truncate(html, length, true, false); /// /// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent Truncate(this HtmlHelper helper, string html, int length, bool addElipsis) + public static IHtmlContent Truncate(this IHtmlHelper helper, string html, int length, bool addElipsis) => helper.Truncate(html, length, addElipsis, false); /// /// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent Truncate(this HtmlHelper helper, string html, int length, bool addElipsis, bool treatTagsAsContent) + public static IHtmlContent Truncate(this IHtmlHelper helper, string html, int length, bool addElipsis, bool treatTagsAsContent) => StringUtilities.Truncate(html, length, addElipsis, treatTagsAsContent); /// /// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent TruncateByWords(this HtmlHelper helper, string html, int words) + public static IHtmlContent TruncateByWords(this IHtmlHelper helper, string html, int words) { int length = StringUtilities.WordsToLength(html, words); @@ -867,7 +867,7 @@ namespace Umbraco.Extensions /// /// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent TruncateByWords(this HtmlHelper helper, string html, int words, bool addElipsis) + public static IHtmlContent TruncateByWords(this IHtmlHelper helper, string html, int words, bool addElipsis) { int length = StringUtilities.WordsToLength(html, words); @@ -877,7 +877,7 @@ namespace Umbraco.Extensions /// /// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent TruncateByWords(this HtmlHelper helper, IHtmlContent html, int words) + public static IHtmlContent TruncateByWords(this IHtmlHelper helper, IHtmlContent html, int words) { int length = StringUtilities.WordsToLength(html.ToHtmlString(), words); @@ -887,7 +887,7 @@ namespace Umbraco.Extensions /// /// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them /// - public static IHtmlContent TruncateByWords(this HtmlHelper helper, IHtmlContent html, int words, bool addElipsis) + public static IHtmlContent TruncateByWords(this IHtmlHelper helper, IHtmlContent html, int words, bool addElipsis) { int length = StringUtilities.WordsToLength(html.ToHtmlString(), words); From 5eb94736578b4efe0fccfa8890283ce66d2fd0cc Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 17 Jun 2021 14:55:36 +0200 Subject: [PATCH 36/36] https://github.com/umbraco/Umbraco-CMS/issues/10479 https://github.com/umbraco/Umbraco-CMS/issues/10427 fixes issue with with saving data types --- .../datatypesettings.controller.js | 235 +++++++++--------- 1 file changed, 117 insertions(+), 118 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js index 4e1b3e868d..e2a6e30405 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js @@ -8,141 +8,140 @@ */ (function () { - "use strict"; + "use strict"; - function DataTypeSettingsController($scope, dataTypeResource, dataTypeHelper, - localizationService, notificationsService, overlayService, formHelper, eventsService) { + function DataTypeSettingsController($scope, dataTypeResource, dataTypeHelper, + localizationService, notificationsService, overlayService, formHelper, eventsService) { - var vm = this; + var vm = this; - vm.dataType = {}; - vm.loadingDataType = false; - vm.saveButtonState = "init"; + vm.dataType = {}; + vm.loadingDataType = false; + vm.saveButtonState = "init"; - vm.close = close; - vm.submit = submit; + vm.close = close; + vm.submit = submit; - function onInit() { + function onInit() { - setTitle(); + setTitle(); - if($scope.model.create) { - createNewDataType(); - } else { - getDataType(); - } + if($scope.model.create) { + createNewDataType(); + } else { + getDataType(); + } + } + + function setTitle() { + if(!$scope.model.title) { + localizationService.localize("contentTypeEditor_editorSettings") + .then(function(data){ + $scope.model.title = data; + }); + } + } + + function createNewDataType() { + + vm.loadingDataType = true; + + var parentId = -1; + var newDataType = {}; + + dataTypeResource.getScaffold(parentId).then(function(dataType) { + + newDataType = dataType; + + // set alias + newDataType.selectedEditor = $scope.model.propertyEditor.alias; + + // set name + var nameArray = []; + + if ($scope.model.contentTypeName) { + nameArray.push($scope.model.contentTypeName); } - function setTitle() { - if(!$scope.model.title) { - localizationService.localize("contentTypeEditor_editorSettings") - .then(function(data){ - $scope.model.title = data; - }); - } + if ($scope.model.property.label) { + nameArray.push($scope.model.property.label); } - function createNewDataType() { - - vm.loadingDataType = true; - - var parentId = -1; - var newDataType = {}; - - dataTypeResource.getScaffold(parentId).then(function(dataType) { - - newDataType = dataType; - - // set alias - newDataType.selectedEditor = $scope.model.propertyEditor.alias; - - // set name - var nameArray = []; - - if ($scope.model.contentTypeName) { - nameArray.push($scope.model.contentTypeName); - } - - if ($scope.model.property.label) { - nameArray.push($scope.model.property.label); - } - - if ($scope.model.propertyEditor.name) { - nameArray.push($scope.model.propertyEditor.name); - } - - // make name - newDataType.name = nameArray.join(" - "); - - // get pre values - dataTypeResource.getPreValues(newDataType.selectedEditor).then(function(preValues) { - newDataType.preValues = dataTypeHelper.createPreValueProps(preValues); - vm.dataType = newDataType; - vm.loadingDataType = false; - }); - - }); - + if ($scope.model.propertyEditor.name) { + nameArray.push($scope.model.propertyEditor.name); } - function getDataType() { - vm.loadingDataType = true; - dataTypeResource.getById($scope.model.id).then(function (dataType) { - dataType.preValues = dataTypeHelper.createPreValueProps(dataType.preValues); - vm.dataType = dataType; - vm.loadingDataType = false; - }); - } + // make name + newDataType.name = nameArray.join(" - "); - function close() { - if ($scope.model && $scope.model.close) { - $scope.model.close(); - } - } + // get pre values + dataTypeResource.getPreValues(newDataType.selectedEditor).then(function(preValues) { + newDataType.preValues = preValues; + vm.dataType = newDataType; + vm.loadingDataType = false; + }); - function submit() { - if (!formHelper.submitForm({ scope: $scope })) { - return; - } - - vm.saveButtonState = "busy"; - - var preValues = dataTypeHelper.createPreValueProps(vm.dataType.preValues); - - dataTypeResource.save(vm.dataType, preValues, $scope.model.create).then( - function(newDataType) { - $scope.model.dataType = newDataType; - - var args = { dataType: newDataType }; - eventsService.emit("editors.dataTypeSettings.saved", args); - - vm.saveButtonState = "success"; - - if ($scope.model && $scope.model.submit) { - $scope.model.submit($scope.model); - } - }, function(err) { - vm.saveButtonState = "error"; - - if(err.status === 400) { - if (err.data && (err.data.ModelState)) { - - formHelper.handleServerValidation(err.data.ModelState); - - for (var e in err.data.ModelState) { - notificationsService.error("Validation", err.data.ModelState[e][0]); - } - } - } - } - ); - - } - - onInit(); + }); } - angular.module("umbraco").controller("Umbraco.Editors.DataTypeSettingsController", DataTypeSettingsController); + function getDataType() { + vm.loadingDataType = true; + dataTypeResource.getById($scope.model.id).then(function (dataType) { + vm.dataType = dataType; + vm.loadingDataType = false; + }); + } + + function close() { + if ($scope.model && $scope.model.close) { + $scope.model.close(); + } + } + + function submit() { + if (!formHelper.submitForm({ scope: $scope })) { + return; + } + + vm.saveButtonState = "busy"; + + var preValues = dataTypeHelper.createPreValueProps(vm.dataType.preValues); + + dataTypeResource.save(vm.dataType, preValues, $scope.model.create).then( + function(newDataType) { + $scope.model.dataType = newDataType; + + var args = { dataType: newDataType }; + eventsService.emit("editors.dataTypeSettings.saved", args); + + vm.saveButtonState = "success"; + + if ($scope.model && $scope.model.submit) { + $scope.model.submit($scope.model); + } + }, function(err) { + vm.saveButtonState = "error"; + + if(err.status === 400) { + if (err.data && (err.data.ModelState)) { + + formHelper.handleServerValidation(err.data.ModelState); + + for (var e in err.data.ModelState) { + notificationsService.error("Validation", err.data.ModelState[e][0]); + } + } + } + } + ); + + } + + onInit(); + + } + + angular.module("umbraco").controller("Umbraco.Editors.DataTypeSettingsController", DataTypeSettingsController); })();