From a4400f04a5e7932a032a1a74d298936e91f1aecd Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 26 Apr 2021 21:09:06 +0200 Subject: [PATCH 01/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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 ca72fb01ec781de44c416726364f2efc604562e8 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 17 Jun 2021 16:15:38 +1000 Subject: [PATCH 34/38] Fixes packager to ensure the GUIDs are used for all entities where possible (#10477) * Clean up and changes to backoffice for the nuget only packages * temp commit of package logic removal * Lots of package code cleanup and removal * Removes old package data from the test package xml * Updates packaging code to take in XDocument instead of a file since we'll not be dealing with files, starts creating expressions for the package migrations scripting. * fixing tests * Fixes runtime state and boot failed middleware so that it actually runs. Separates out unattended install/upgrade into notification handlers. * Gets unattended package migrations working and running * Gets embedded package.xml resources able to install from package migration. * Implements automatic package migrations for package that just declare an xml data manifest. * fix build * small cleanups * fix build * adds some tests * Fix export test * Fix newlines in test for linux * Typo * removes old todos and updates AutomaticPackgeMigrationPlan to use getter with backing field. * Update dictionary package data to use GUID * Ensures macros are packaged and used with their GUID * Ensures the GUID for doc types and media types remains consistent for package installation based on what is in the xml. * fix automatic migrations to not validate initial state, fixes packaging GUIDs for multiple entities. * Added guids to embedded test packages (Some tests are still failing) * Fix one more test * Fixes up Key vs Id, moves tests to correct namespace, fix tests * Fixes Dictionary packaging to ensure an xml hierarchy * Fixes tests * fixes package xml Co-authored-by: Bjarke Berg --- src/Umbraco.Core/Extensions/XmlExtensions.cs | 30 +- src/Umbraco.Core/Migrations/MigrationPlan.cs | 6 + .../Packaging/InstallationSummary.cs | 4 +- .../Packaging/PackageMigrationPlan.cs | 6 + .../Packaging/PackagesRepository.cs | 139 +++- .../Install/UnattendedUpgrader.cs | 2 - .../Migrations/Upgrade/Upgrader.cs | 8 +- .../Packaging/PackageDataInstallation.cs | 152 +++- .../Persistence/Dtos/DictionaryDto.cs | 1 + .../Persistence/Dtos/LanguageTextDto.cs | 1 + .../Services/Implement/EntityXmlSerializer.cs | 72 +- .../CreatedPackagesRepositoryTests.cs | 71 +- .../Packaging/PackageDataInstallationTests.cs | 30 +- .../Packaging/PackageInstallationTest.cs | 7 +- .../Services/EntityXmlSerializerTests.cs | 5 +- .../CheckboxList-Content-Package.xml | 7 +- .../CompositionsTestPackage-Random.xml | 8 +- .../Importing/CompositionsTestPackage.xml | 31 +- .../Services/Importing/Dictionary-Package.xml | 6 +- .../Services/Importing/Fanoe-Package.xml | 10 +- .../Importing/ImportResources.Designer.cs | 757 ++++++++---------- .../Importing/InheritedDocTypes-Package.xml | 6 +- .../Importing/MediaTypesAndMedia-Package.xml | 6 +- .../Services/Importing/SingleDocType.xml | 3 +- .../Importing/StandardMvc-Package.xml | 64 +- .../Services/Importing/XsltSearch-Package.xml | 66 +- .../Services/Importing/uBlogsy-Package.xml | 157 ++-- .../Controllers/PackageController.cs | 3 - 28 files changed, 955 insertions(+), 703 deletions(-) rename src/Umbraco.Tests.Integration/{Umbraco.Core => Umbraco.Infrastructure}/Packaging/PackageDataInstallationTests.cs (96%) rename src/Umbraco.Tests.Integration/{Umbraco.Core => Umbraco.Infrastructure}/Packaging/PackageInstallationTest.cs (93%) diff --git a/src/Umbraco.Core/Extensions/XmlExtensions.cs b/src/Umbraco.Core/Extensions/XmlExtensions.cs index a5356e07f6..8ad37bd93e 100644 --- a/src/Umbraco.Core/Extensions/XmlExtensions.cs +++ b/src/Umbraco.Core/Extensions/XmlExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -234,6 +234,33 @@ namespace Umbraco.Extensions } } + public static T RequiredAttributeValue(this XElement xml, string attributeName) + { + if (xml == null) + { + throw new ArgumentNullException("xml"); + } + + if (xml.HasAttributes == false) + { + throw new InvalidOperationException($"{attributeName} not found in xml"); + } + + if (xml.Attribute(attributeName) == null) + { + throw new InvalidOperationException($"{attributeName} not found in xml"); + } + + var val = xml.Attribute(attributeName).Value; + var result = val.TryConvertTo(); + if (result.Success) + { + return result.Result; + } + + throw new InvalidOperationException($"{val} attribute value cannot be converted to {typeof(T)}"); + } + public static T AttributeValue(this XElement xml, string attributeName) { if (xml == null) throw new ArgumentNullException("xml"); @@ -249,6 +276,7 @@ namespace Umbraco.Extensions return default(T); } + public static T AttributeValue(this XmlNode xml, string attributeName) { if (xml == null) throw new ArgumentNullException("xml"); diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 8a35e21c67..c998be2037 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -37,6 +37,12 @@ namespace Umbraco.Cms.Core.Migrations Name = name; } + /// + /// If set to true the plan executor will ignore any current state persisted and + /// run the plan from its initial state to its end state. + /// + public virtual bool IgnoreCurrentState { get; } = false; + /// /// Gets the transitions. /// diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs index fa906ad1cc..3c519a4a4c 100644 --- a/src/Umbraco.Core/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs @@ -49,7 +49,7 @@ namespace Umbraco.Cms.Core.Packaging if (templateConflicts.Count > 0) { sb.Append("Conflicting templates found, they will be overwritten:"); - foreach (IMacro m in templateConflicts) + foreach (ITemplate m in templateConflicts) { sb.Append(m.Alias); sb.Append(','); @@ -60,7 +60,7 @@ namespace Umbraco.Cms.Core.Packaging if (stylesheetConflicts.Count > 0) { sb.Append("Conflicting stylesheets found, they will be overwritten:"); - foreach (IMacro m in stylesheetConflicts) + foreach (IFile m in stylesheetConflicts) { sb.Append(m.Alias); sb.Append(','); diff --git a/src/Umbraco.Core/Packaging/PackageMigrationPlan.cs b/src/Umbraco.Core/Packaging/PackageMigrationPlan.cs index 97cdcafba6..71c333d1cf 100644 --- a/src/Umbraco.Core/Packaging/PackageMigrationPlan.cs +++ b/src/Umbraco.Core/Packaging/PackageMigrationPlan.cs @@ -19,6 +19,12 @@ namespace Umbraco.Cms.Core.Packaging DefinePlan(); } + /// + /// Inform the plan executor to ignore all saved package state and + /// run the migration from initial state to it's end state. + /// + public override bool IgnoreCurrentState => true; + protected abstract void DefinePlan(); } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index 6fbca7f98b..b86f5d8695 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -71,7 +71,8 @@ namespace Umbraco.Cms.Core.Packaging string packagesFolderPath = null, string mediaFolderPath = null) { - if (string.IsNullOrWhiteSpace(packageRepositoryFileName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(packageRepositoryFileName)); + if (string.IsNullOrWhiteSpace(packageRepositoryFileName)) + throw new ArgumentException("Value cannot be null or whitespace.", nameof(packageRepositoryFileName)); _contentService = contentService; _contentTypeService = contentTypeService; _dataTypeService = dataTypeService; @@ -114,7 +115,8 @@ namespace Umbraco.Cms.Core.Packaging { var packagesXml = EnsureStorage(out var packagesFile); var packageXml = packagesXml?.Root?.Elements("package").FirstOrDefault(x => x.AttributeValue("id") == id); - if (packageXml == null) return; + if (packageXml == null) + return; packageXml.Remove(); @@ -123,7 +125,8 @@ namespace Umbraco.Cms.Core.Packaging public bool SavePackage(PackageDefinition definition) { - if (definition == null) throw new ArgumentNullException(nameof(definition)); + if (definition == null) + throw new ArgumentNullException(nameof(definition)); var packagesXml = EnsureStorage(out var packagesFile); @@ -162,8 +165,10 @@ namespace Umbraco.Cms.Core.Packaging public string ExportPackage(PackageDefinition definition) { - if (definition.Id == default) throw new ArgumentException("The package definition does not have an ID, it must be saved before being exported"); - if (definition.PackageId == default) throw new ArgumentException("the package definition does not have a GUID, it must be saved before being exported"); + if (definition.Id == default) + throw new ArgumentException("The package definition does not have an ID, it must be saved before being exported"); + if (definition.PackageId == default) + throw new ArgumentException("the package definition does not have a GUID, it must be saved before being exported"); //ensure it's valid ValidatePackage(definition); @@ -248,9 +253,11 @@ namespace Umbraco.Cms.Core.Packaging var dataTypes = new XElement("DataTypes"); foreach (var dtId in definition.DataTypes) { - if (!int.TryParse(dtId, out var outInt)) continue; + if (!int.TryParse(dtId, out var outInt)) + continue; var dataType = _dataTypeService.GetDataType(outInt); - if (dataType == null) continue; + if (dataType == null) + continue; dataTypes.Add(_serializer.Serialize(dataType)); } root.Add(dataTypes); @@ -261,9 +268,11 @@ namespace Umbraco.Cms.Core.Packaging var languages = new XElement("Languages"); foreach (var langId in definition.Languages) { - if (!int.TryParse(langId, out var outInt)) continue; + if (!int.TryParse(langId, out var outInt)) + continue; var lang = _languageService.GetLanguageById(outInt); - if (lang == null) continue; + if (lang == null) + continue; languages.Add(_serializer.Serialize(lang)); } root.Add(languages); @@ -271,15 +280,74 @@ namespace Umbraco.Cms.Core.Packaging private void PackageDictionaryItems(PackageDefinition definition, XContainer root) { - var dictionaryItems = new XElement("DictionaryItems"); + var rootDictionaryItems = new XElement("DictionaryItems"); + var items = new Dictionary(); + foreach (var dictionaryId in definition.DictionaryItems) { - if (!int.TryParse(dictionaryId, out var outInt)) continue; - var di = _languageService.GetDictionaryItemById(outInt); - if (di == null) continue; - dictionaryItems.Add(_serializer.Serialize(di, false)); + if (!int.TryParse(dictionaryId, out var outInt)) + { + continue; + } + + IDictionaryItem di = _languageService.GetDictionaryItemById(outInt); + + if (di == null) + { + continue; + } + + items[di.Key] = (di, _serializer.Serialize(di, false)); + } + + // organize them in hierarchy ... + var itemCount = items.Count; + var processed = new Dictionary(); + while (processed.Count < itemCount) + { + foreach(Guid key in items.Keys.ToList()) + { + (IDictionaryItem dictionaryItem, XElement serializedDictionaryValue) = items[key]; + + if (!dictionaryItem.ParentId.HasValue) + { + // if it has no parent, its definitely just at the root + AppendDictionaryElement(rootDictionaryItems, items, processed, key, serializedDictionaryValue); + } + else + { + if (processed.ContainsKey(dictionaryItem.ParentId.Value)) + { + // we've processed this parent element already so we can just append this xml child to it + AppendDictionaryElement(processed[dictionaryItem.ParentId.Value], items, processed, key, serializedDictionaryValue); + } + else if (items.ContainsKey(dictionaryItem.ParentId.Value)) + { + // we know the parent exists in the dictionary but + // we haven't processed it yet so we'll leave it for the next loop + continue; + } + else + { + // in this case, the parent of this item doesn't exist in our collection, we have no + // choice but to add it to the root. + AppendDictionaryElement(rootDictionaryItems, items, processed, key, serializedDictionaryValue); + } + } + } + } + + root.Add(rootDictionaryItems); + + static void AppendDictionaryElement(XElement rootDictionaryItems, Dictionary items, Dictionary processed, Guid key, XElement serializedDictionaryValue) + { + // track it + processed.Add(key, serializedDictionaryValue); + // append it + rootDictionaryItems.Add(serializedDictionaryValue); + // remove it so its not re-processed + items.Remove(key); } - root.Add(dictionaryItems); } private void PackageMacros(PackageDefinition definition, XContainer root) @@ -287,11 +355,13 @@ namespace Umbraco.Cms.Core.Packaging var macros = new XElement("Macros"); foreach (var macroId in definition.Macros) { - if (!int.TryParse(macroId, out var outInt)) continue; + if (!int.TryParse(macroId, out var outInt)) + continue; var macroXml = GetMacroXml(outInt, out var macro); - if (macroXml == null) continue; - macros.Add(macroXml); + if (macroXml == null) + continue; + macros.Add(macroXml); } root.Add(macros); } @@ -301,7 +371,8 @@ namespace Umbraco.Cms.Core.Packaging var stylesheetsXml = new XElement("Stylesheets"); foreach (var stylesheetName in definition.Stylesheets) { - if (stylesheetName.IsNullOrWhiteSpace()) continue; + if (stylesheetName.IsNullOrWhiteSpace()) + continue; var xml = GetStylesheetXml(stylesheetName, true); if (xml != null) stylesheetsXml.Add(xml); @@ -314,9 +385,11 @@ namespace Umbraco.Cms.Core.Packaging var templatesXml = new XElement("Templates"); foreach (var templateId in definition.Templates) { - if (!int.TryParse(templateId, out var outInt)) continue; + if (!int.TryParse(templateId, out var outInt)) + continue; var template = _fileService.GetTemplate(outInt); - if (template == null) continue; + if (template == null) + continue; templatesXml.Add(_serializer.Serialize(template)); } root.Add(templatesXml); @@ -328,9 +401,11 @@ namespace Umbraco.Cms.Core.Packaging var docTypesXml = new XElement("DocumentTypes"); foreach (var dtId in definition.DocumentTypes) { - if (!int.TryParse(dtId, out var outInt)) continue; + if (!int.TryParse(dtId, out var outInt)) + continue; var contentType = _contentTypeService.Get(outInt); - if (contentType == null) continue; + if (contentType == null) + continue; AddDocumentType(contentType, contentTypes); } foreach (var contentType in contentTypes) @@ -345,9 +420,11 @@ namespace Umbraco.Cms.Core.Packaging var mediaTypesXml = new XElement("MediaTypes"); foreach (var mediaTypeId in definition.MediaTypes) { - if (!int.TryParse(mediaTypeId, out var outInt)) continue; + if (!int.TryParse(mediaTypeId, out var outInt)) + continue; var mediaType = _mediaTypeService.Get(outInt); - if (mediaType == null) continue; + if (mediaType == null) + continue; AddMediaType(mediaType, mediaTypes); } foreach (var mediaType in mediaTypes) @@ -456,7 +533,8 @@ namespace Umbraco.Cms.Core.Packaging private XElement GetMacroXml(int macroId, out IMacro macro) { macro = _macroService.GetById(macroId); - if (macro == null) return null; + if (macro == null) + return null; var xml = _serializer.Serialize(macro); return xml; } @@ -469,15 +547,18 @@ namespace Umbraco.Cms.Core.Packaging /// private XElement GetStylesheetXml(string name, bool includeProperties) { - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); var sts = _fileService.GetStylesheetByName(name); - if (sts == null) return null; + if (sts == null) + return null; var stylesheetXml = new XElement("Stylesheet"); stylesheetXml.Add(new XElement("Name", sts.Alias)); stylesheetXml.Add(new XElement("FileName", sts.Name)); stylesheetXml.Add(new XElement("Content", new XCData(sts.Content))); - if (!includeProperties) return stylesheetXml; + if (!includeProperties) + return stylesheetXml; var properties = new XElement("Properties"); foreach (var ssP in sts.Properties) diff --git a/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs b/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs index eeae566cc9..24cbce273f 100644 --- a/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs +++ b/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs @@ -55,8 +55,6 @@ namespace Umbraco.Cms.Infrastructure.Install { if (_runtimeState.RunUnattendedBootLogic()) { - // TODO: Here is also where we would run package migrations! - switch (_runtimeState.Reason) { case RuntimeLevelReason.UpgradeMigrations: diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs index 27ff665e11..fc0e01c3d9 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs @@ -41,22 +41,20 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade if (scopeProvider == null) throw new ArgumentNullException(nameof(scopeProvider)); if (keyValueService == null) throw new ArgumentNullException(nameof(keyValueService)); - var plan = Plan; - using (var scope = scopeProvider.CreateScope()) { // read current state var currentState = keyValueService.GetValue(StateValueKey); var forceState = false; - if (currentState == null) + if (currentState == null || Plan.IgnoreCurrentState) { - currentState = plan.InitialState; + currentState = Plan.InitialState; forceState = true; } // execute plan - var state = migrationPlanExecutor.Execute(plan, currentState); + var state = migrationPlanExecutor.Execute(Plan, currentState); if (string.IsNullOrWhiteSpace(state)) { throw new Exception("Plan execution returned an invalid null or empty state."); diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 6b13358fe9..e680471486 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -272,12 +272,12 @@ namespace Umbraco.Cms.Infrastructure.Packaging where T : class, IContentBase where S : IContentTypeComposition { - var key = Guid.Empty; - if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key)) + Guid key = element.RequiredAttributeValue("key"); + + // we need to check if the content already exists and if so we ignore the installation for this item + if (service.GetById(key) != null) { - //if a Key is supplied, then we need to check if the content already exists and if so we ignore the installation for this item - if (service.GetById(key) != null) - return null; + return null; } var id = element.Attribute("id").Value; @@ -477,17 +477,19 @@ namespace Umbraco.Cms.Infrastructure.Packaging } //Sorting the Document Types based on dependencies - if its not a single doc type import ref. #U4-5921 - var documentTypes = isSingleDocTypeImport + List documentTypes = isSingleDocTypeImport ? unsortedDocumentTypes.ToList() : graph.GetSortedItems().Select(x => x.Item).ToList(); //Iterate the sorted document types and create them as IContentType objects - foreach (var documentType in documentTypes) + foreach (XElement documentType in documentTypes) { - var alias = documentType.Element("Info").Element("Alias").Value; + var alias = documentType.Element("Info").Element("Alias").Value; + if (importedContentTypes.ContainsKey(alias) == false) { - var contentType = service.Get(alias); + T contentType = service.Get(alias); + importedContentTypes.Add(alias, contentType == null ? CreateContentTypeFromXml(documentType, importedContentTypes, service) : UpdateContentTypeFromXml(documentType, contentType, importedContentTypes, service)); @@ -526,7 +528,9 @@ namespace Umbraco.Cms.Infrastructure.Packaging } //Update ContentTypes with a newly added structure/list of allowed children if (updatedContentTypes.Any()) + { service.Save(updatedContentTypes, userId); + } } return list; @@ -595,13 +599,19 @@ namespace Umbraco.Cms.Infrastructure.Packaging return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); } - private T CreateContentTypeFromXml(XElement documentType, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) - where T : class, IContentTypeComposition + private T CreateContentTypeFromXml( + XElement documentType, + IReadOnlyDictionary importedContentTypes, + IContentTypeBaseService service) + where T : class, IContentTypeComposition { - var infoElement = documentType.Element("Info"); + var key = Guid.Parse(documentType.Element("Info").Element("Key").Value); + + XElement infoElement = documentType.Element("Info"); //Name of the master corresponds to the parent - var masterElement = infoElement.Element("Master"); + XElement masterElement = infoElement.Element("Master"); + T parent = default; if (masterElement != null) { @@ -612,26 +622,35 @@ namespace Umbraco.Cms.Infrastructure.Packaging } var alias = infoElement.Element("Alias").Value; - T contentType = CreateContentType(parent, -1, alias); + T contentType = CreateContentType(key, parent, -1, alias); if (parent != null) + { contentType.AddContentType(parent); + } return UpdateContentTypeFromXml(documentType, contentType, importedContentTypes, service); } - private T CreateContentType(T parent, int parentId, string alias) + private T CreateContentType(Guid key, T parent, int parentId, string alias) where T : class, IContentTypeComposition { if (typeof(T) == typeof(IContentType)) { if (parent is null) { - return new ContentType(_shortStringHelper, parentId) { Alias = alias } as T; + return new ContentType(_shortStringHelper, parentId) + { + Alias = alias, + Key = key + } as T; } else { - return new ContentType(_shortStringHelper, (IContentType)parent, alias) as T; + return new ContentType(_shortStringHelper, (IContentType)parent, alias) + { + Key = key + } as T; } } @@ -640,11 +659,18 @@ namespace Umbraco.Cms.Infrastructure.Packaging { if (parent is null) { - return new MediaType(_shortStringHelper, parentId) { Alias = alias } as T; + return new MediaType(_shortStringHelper, parentId) + { + Alias = alias, + Key = key + } as T; } else { - return new MediaType(_shortStringHelper, (IMediaType)parent, alias) as T; + return new MediaType(_shortStringHelper, (IMediaType)parent, alias) + { + Key = key + } as T; } } @@ -652,12 +678,19 @@ namespace Umbraco.Cms.Infrastructure.Packaging throw new NotSupportedException($"Type {typeof(T)} is not supported"); } - private T UpdateContentTypeFromXml(XElement documentType, T contentType, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) - where T : IContentTypeComposition + private T UpdateContentTypeFromXml( + XElement documentType, + T contentType, + IReadOnlyDictionary importedContentTypes, + IContentTypeBaseService service) + where T : IContentTypeComposition { + var key = Guid.Parse(documentType.Element("Info").Element("Key").Value); + var infoElement = documentType.Element("Info"); var defaultTemplateElement = infoElement.Element("DefaultTemplate"); + contentType.Key = key; contentType.Name = infoElement.Element("Name").Value; if (infoElement.Element("Key") != null) contentType.Key = new Guid(infoElement.Element("Key").Value); @@ -771,7 +804,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging var tabs = tabElement.Elements("Tab"); foreach (var tab in tabs) { - var id = tab.Element("Id").Value;//Do we need to use this for tracking? var caption = tab.Element("Caption").Value; if (contentType.PropertyGroups.Contains(caption) == false) @@ -780,8 +812,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging } - int sortOrder; - if (tab.Element("SortOrder") != null && int.TryParse(tab.Element("SortOrder").Value, out sortOrder)) + if (tab.Element("SortOrder") != null && int.TryParse(tab.Element("SortOrder").Value, out int sortOrder)) { // Override the sort order with the imported value contentType.PropertyGroups[caption].SortOrder = sortOrder; @@ -844,7 +875,10 @@ namespace Umbraco.Cms.Infrastructure.Packaging var sortOrder = 0; var sortOrderElement = property.Element("SortOrder"); if (sortOrderElement != null) + { int.TryParse(sortOrderElement.Value, out sortOrder); + } + var propertyType = new PropertyType(_shortStringHelper, dataTypeDefinition, property.Element("Alias").Value) { Name = property.Element("Name").Value, @@ -868,8 +902,11 @@ namespace Umbraco.Cms.Infrastructure.Packaging ? property.Element("LabelOnTop").Value.ToLowerInvariant().Equals("true") : false }; + if (property.Element("Key") != null) + { propertyType.Key = new Guid(property.Element("Key").Value); + } var tab = (string)property.Element("Tab"); if (string.IsNullOrEmpty(tab)) @@ -948,7 +985,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging { var dataTypeDefinitionName = dataTypeElement.AttributeValue("Name"); - var dataTypeDefinitionId = dataTypeElement.AttributeValue("Definition"); + var dataTypeDefinitionId = dataTypeElement.RequiredAttributeValue("Definition"); var databaseTypeAttribute = dataTypeElement.Attribute("DatabaseType"); var parentId = -1; @@ -1076,8 +1113,10 @@ namespace Umbraco.Cms.Infrastructure.Packaging private IReadOnlyList ImportDictionaryItems(IEnumerable dictionaryItemElementList, List languages, Guid? parentId, int userId) { var items = new List(); - foreach (var dictionaryItemElement in dictionaryItemElementList) + foreach (XElement dictionaryItemElement in dictionaryItemElementList) + { items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, parentId, userId)); + } return items; } @@ -1087,11 +1126,19 @@ namespace Umbraco.Cms.Infrastructure.Packaging var items = new List(); IDictionaryItem dictionaryItem; - var key = dictionaryItemElement.Attribute("Key").Value; - if (_localizationService.DictionaryItemExists(key)) - dictionaryItem = GetAndUpdateDictionaryItem(key, dictionaryItemElement, languages); + var itemName = dictionaryItemElement.Attribute("Name").Value; + Guid key = dictionaryItemElement.RequiredAttributeValue("Key"); + + dictionaryItem = _localizationService.GetDictionaryItemById(key); + if (dictionaryItem != null) + { + dictionaryItem = UpdateDictionaryItem(dictionaryItem, dictionaryItemElement, languages); + } else - dictionaryItem = CreateNewDictionaryItem(key, dictionaryItemElement, languages, parentId); + { + dictionaryItem = CreateNewDictionaryItem(key, itemName, dictionaryItemElement, languages, parentId); + } + _localizationService.Save(dictionaryItem, userId); items.Add(dictionaryItem); @@ -1099,23 +1146,29 @@ namespace Umbraco.Cms.Infrastructure.Packaging return items; } - private IDictionaryItem GetAndUpdateDictionaryItem(string key, XElement dictionaryItemElement, List languages) + private IDictionaryItem UpdateDictionaryItem(IDictionaryItem dictionaryItem, XElement dictionaryItemElement, List languages) { - var dictionaryItem = _localizationService.GetDictionaryItemByKey(key); var translations = dictionaryItem.Translations.ToList(); foreach (var valueElement in dictionaryItemElement.Elements("Value").Where(v => DictionaryValueIsNew(translations, v))) + { AddDictionaryTranslation(translations, valueElement, languages); + } + dictionaryItem.Translations = translations; return dictionaryItem; } - private static DictionaryItem CreateNewDictionaryItem(string key, XElement dictionaryItemElement, List languages, Guid? parentId) + private static DictionaryItem CreateNewDictionaryItem(Guid itemId, string itemName, XElement dictionaryItemElement, List languages, Guid? parentId) { - var dictionaryItem = parentId.HasValue ? new DictionaryItem(parentId.Value, key) : new DictionaryItem(key); + DictionaryItem dictionaryItem = parentId.HasValue ? new DictionaryItem(parentId.Value, itemName) : new DictionaryItem(itemName); + dictionaryItem.Key = itemId; + var translations = new List(); - foreach (var valueElement in dictionaryItemElement.Elements("Value")) + foreach (XElement valueElement in dictionaryItemElement.Elements("Value")) + { AddDictionaryTranslation(translations, valueElement, languages); + } dictionaryItem.Translations = translations; return dictionaryItem; @@ -1134,7 +1187,10 @@ namespace Umbraco.Cms.Infrastructure.Packaging var languageId = valueElement.Attribute("LanguageCultureAlias").Value; var language = languages.SingleOrDefault(l => l.IsoCode == languageId); if (language == null) + { return; + } + var translation = new DictionaryTranslation(language, valueElement.Value); translations.Add(translation); } @@ -1186,10 +1242,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (var macro in macros) { - var existing = _macroService.GetByAlias(macro.Alias); - if (existing != null) - macro.Id = existing.Id; - _macroService.Save(macro, userId); } @@ -1198,6 +1250,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging private IMacro ParseMacroElement(XElement macroElement) { + var macroKey = Guid.Parse(macroElement.Element("key").Value); var macroName = macroElement.Element("name").Value; var macroAlias = macroElement.Element("alias").Value; var macroSource = macroElement.Element("macroSource").Value; @@ -1234,28 +1287,39 @@ namespace Umbraco.Cms.Infrastructure.Packaging dontRender = bool.Parse(dontRenderElement.Value); } - var existingMacro = _macroService.GetByAlias(macroAlias) as Macro; + var existingMacro = _macroService.GetById(macroKey) as Macro; var macro = existingMacro ?? new Macro(_shortStringHelper, macroAlias, macroName, macroSource, - cacheByPage, cacheByMember, dontRender, useInEditor, cacheDuration); + cacheByPage, cacheByMember, dontRender, useInEditor, cacheDuration) + { + Key = macroKey + }; var properties = macroElement.Element("properties"); if (properties != null) { int sortOrder = 0; - foreach (var property in properties.Elements()) + foreach (XElement property in properties.Elements()) { + var propertyKey = property.RequiredAttributeValue("key"); var propertyName = property.Attribute("name").Value; var propertyAlias = property.Attribute("alias").Value; var editorAlias = property.Attribute("propertyType").Value; - var sortOrderAttribute = property.Attribute("sortOrder"); + XAttribute sortOrderAttribute = property.Attribute("sortOrder"); if (sortOrderAttribute != null) { sortOrder = int.Parse(sortOrderAttribute.Value); } if (macro.Properties.Values.Any(x => string.Equals(x.Alias, propertyAlias, StringComparison.OrdinalIgnoreCase))) + { continue; - macro.Properties.Add(new MacroProperty(propertyAlias, propertyName, sortOrder, editorAlias)); + } + + macro.Properties.Add(new MacroProperty(propertyAlias, propertyName, sortOrder, editorAlias) + { + Key = propertyKey + }); + sortOrder++; } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/DictionaryDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/DictionaryDto.cs index f63b0e3de5..cec6e86f83 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/DictionaryDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/DictionaryDto.cs @@ -25,6 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Parent")] public Guid? Parent { get; set; } + // TODO: This needs to have a unique index. [Column("key")] [Length(450)] [Index(IndexTypes.NonClustered, Name = "IX_cmsDictionary_key")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageTextDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageTextDto.cs index e7b3857582..58b0f21542 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageTextDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageTextDto.cs @@ -21,6 +21,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [ForeignKey(typeof(DictionaryDto), Column = "id")] public Guid UniqueId { get; set; } + // TODO: Need a unique constraint on LanguageId, UniqueId, Value [Column("value")] [Length(1000)] public string Value { get; set; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs index 859a2b6327..88b19e6270 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -242,8 +242,11 @@ namespace Umbraco.Cms.Core.Services.Implement private XElement Serialize(IDictionaryItem dictionaryItem) { - var xml = new XElement("DictionaryItem", new XAttribute("Key", dictionaryItem.ItemKey)); - foreach (var translation in dictionaryItem.Translations) + var xml = new XElement("DictionaryItem", + new XAttribute("Key", dictionaryItem.Key), + new XAttribute("Name", dictionaryItem.ItemKey)); + + foreach (IDictionaryTranslation translation in dictionaryItem.Translations) { xml.Add(new XElement("Value", new XAttribute("LanguageId", translation.Language.Id), @@ -341,6 +344,7 @@ namespace Umbraco.Cms.Core.Services.Implement var info = new XElement("Info", new XElement("Name", mediaType.Name), new XElement("Alias", mediaType.Alias), + new XElement("Key", mediaType.Key), new XElement("Icon", mediaType.Icon), new XElement("Thumbnail", mediaType.Thumbnail), new XElement("Description", mediaType.Description), @@ -348,7 +352,9 @@ namespace Umbraco.Cms.Core.Services.Implement var masterContentType = mediaType.CompositionAliases().FirstOrDefault(); if (masterContentType != null) + { info.Add(new XElement("Master", masterContentType)); + } var structure = new XElement("Structure"); foreach (var allowedType in mediaType.AllowedContentTypes) @@ -365,18 +371,7 @@ namespace Umbraco.Cms.Core.Services.Implement ? null : mediaType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value); - var genericProperty = new XElement("GenericProperty", - new XElement("Name", propertyType.Name), - new XElement("Alias", propertyType.Alias), - new XElement("Type", propertyType.PropertyEditorAlias), - new XElement("Definition", definition.Key), - new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), - new XElement("Mandatory", propertyType.Mandatory.ToString()), - new XElement("MandatoryMessage", propertyType.MandatoryMessage), - new XElement("Validation", propertyType.ValidationRegExp), - new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage), - new XElement("LabelOnTop", propertyType.LabelOnTop), - new XElement("Description", new XCData(propertyType.Description ?? string.Empty))); + XElement genericProperty = SerializePropertyType(propertyType, definition, propertyGroup); genericProperties.Add(genericProperty); } @@ -419,6 +414,7 @@ namespace Umbraco.Cms.Core.Services.Implement { var xml = new XElement("macro"); xml.Add(new XElement("name", macro.Name)); + xml.Add(new XElement("key", macro.Key)); xml.Add(new XElement("alias", macro.Alias)); xml.Add(new XElement("macroSource", macro.MacroSource)); xml.Add(new XElement("useInEditor", macro.UseInEditor.ToString())); @@ -431,6 +427,7 @@ namespace Umbraco.Cms.Core.Services.Implement foreach (var property in macro.Properties) { properties.Add(new XElement("property", + new XAttribute("key", property.Key), new XAttribute("name", property.Name), new XAttribute("alias", property.Alias), new XAttribute("sortOrder", property.SortOrder), @@ -456,8 +453,10 @@ namespace Umbraco.Cms.Core.Services.Implement new XElement("Variations", contentType.Variations.ToString())); var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId); - if(masterContentType != null) + if (masterContentType != null) + { info.Add(new XElement("Master", masterContentType.Alias)); + } var compositionsElement = new XElement("Compositions"); var compositions = contentType.ContentTypeComposition; @@ -475,9 +474,13 @@ namespace Umbraco.Cms.Core.Services.Implement info.Add(allowedTemplates); if (contentType.DefaultTemplate != null && contentType.DefaultTemplate.Id != 0) + { info.Add(new XElement("DefaultTemplate", contentType.DefaultTemplate.Alias)); + } else + { info.Add(new XElement("DefaultTemplate", "")); + } var structure = new XElement("Structure"); foreach (var allowedType in contentType.AllowedContentTypes) @@ -494,21 +497,8 @@ namespace Umbraco.Cms.Core.Services.Implement ? null : contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value); - var genericProperty = new XElement("GenericProperty", - new XElement("Name", propertyType.Name), - new XElement("Alias", propertyType.Alias), - new XElement("Key", propertyType.Key), - new XElement("Type", propertyType.PropertyEditorAlias), - new XElement("Definition", definition.Key), - new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), - new XElement("SortOrder", propertyType.SortOrder), - new XElement("Mandatory", propertyType.Mandatory.ToString()), - new XElement("LabelOnTop", propertyType.LabelOnTop.ToString()), - propertyType.MandatoryMessage != null ? new XElement("MandatoryMessage", propertyType.MandatoryMessage) : null, - propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, - propertyType.ValidationRegExpMessage != null ? new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage) : null, - propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null, - new XElement("Variations", propertyType.Variations.ToString())); + XElement genericProperty = SerializePropertyType(propertyType, definition, propertyGroup); + genericProperty.Add(new XElement("Variations", propertyType.Variations.ToString())); genericProperties.Add(genericProperty); } @@ -534,7 +524,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (contentType.Level != 1 && masterContentType == null) { //get URL encoded folder names - var folders = _contentTypeService.GetContainers(contentType) + IEnumerable folders = _contentTypeService.GetContainers(contentType) .OrderBy(x => x.Level) .Select(x => WebUtility.UrlEncode(x.Name)); @@ -542,11 +532,29 @@ namespace Umbraco.Cms.Core.Services.Implement } if (string.IsNullOrWhiteSpace(folderNames) == false) + { xml.Add(new XAttribute("Folders", folderNames)); + } return xml; } + private XElement SerializePropertyType(IPropertyType propertyType, IDataType definition, PropertyGroup propertyGroup) + => new XElement("GenericProperty", + new XElement("Name", propertyType.Name), + new XElement("Alias", propertyType.Alias), + new XElement("Key", propertyType.Key), + new XElement("Type", propertyType.PropertyEditorAlias), + new XElement("Definition", definition.Key), + new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), + new XElement("SortOrder", propertyType.SortOrder), + new XElement("Mandatory", propertyType.Mandatory.ToString()), + new XElement("LabelOnTop", propertyType.LabelOnTop.ToString()), + propertyType.MandatoryMessage != null ? new XElement("MandatoryMessage", propertyType.MandatoryMessage) : null, + propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, + propertyType.ValidationRegExpMessage != null ? new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage) : null, + propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null); + // exports an IContentBase (IContent, IMedia or IMember) as an XElement. private XElement SerializeContentBase(IContentBase contentBase, string urlValue, string nodeName, bool published) { diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs index 746bd271c5..9565c77258 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs @@ -35,8 +35,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging [TearDown] public void DeleteTestFolder() => Directory.Delete(HostingEnvironment.MapPathContentRoot("~/" + _testBaseFolder), true); - - private IShortStringHelper ShortStringHelper => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); private IContentTypeService ContentTypeService => GetRequiredService(); @@ -53,8 +52,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging private IHostingEnvironment HostingEnvironment => GetRequiredService(); - private IUmbracoVersion UmbracoVersion => GetRequiredService(); - private IMediaService MediaService => GetRequiredService(); private IMediaTypeService MediaTypeService => GetRequiredService(); @@ -155,6 +152,72 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging // TODO: There's a whole lot more assertions to be done } + [Test] + public void GivenNestedDictionaryItems_WhenPackageExported_ThenTheXmlIsNested() + { + var parent = new DictionaryItem("Parent") + { + Key = Guid.NewGuid() + }; + LocalizationService.Save(parent); + var child1 = new DictionaryItem(parent.Key, "Child1") + { + Key = Guid.NewGuid() + }; + LocalizationService.Save(child1); + var child2 = new DictionaryItem(child1.Key, "Child2") + { + Key = Guid.NewGuid() + }; + LocalizationService.Save(child2); + var child3 = new DictionaryItem(child2.Key, "Child3") + { + Key = Guid.NewGuid() + }; + LocalizationService.Save(child3); + var child4 = new DictionaryItem(child3.Key, "Child4") + { + Key = Guid.NewGuid() + }; + LocalizationService.Save(child4); + + var def = new PackageDefinition + { + Name = "test", + + // put these out of order to ensure that it doesn't matter. + DictionaryItems = new List + { + child2.Id.ToString(), + child1.Id.ToString(), + // we are missing 3 here so 4 will be orphaned and end up in the root + child4.Id.ToString(), + parent.Id.ToString() + } + }; + + PackageBuilder.SavePackage(def); + + string packageXmlPath = PackageBuilder.ExportPackage(def); + + using (var stream = File.OpenRead(packageXmlPath)) + { + var xml = XDocument.Load(stream); + var dictionaryItems = xml.Root.Element("DictionaryItems"); + Assert.IsNotNull(dictionaryItems); + var rootItems = dictionaryItems.Elements("DictionaryItem").ToList(); + Assert.AreEqual(2, rootItems.Count); + Assert.AreEqual("Child4", rootItems[0].AttributeValue("Name")); + Assert.AreEqual("Parent", rootItems[1].AttributeValue("Name")); + var children = rootItems[1].Elements("DictionaryItem").ToList(); + Assert.AreEqual(1, children.Count); + Assert.AreEqual("Child1", children[0].AttributeValue("Name")); + children = children[0].Elements("DictionaryItem").ToList(); + Assert.AreEqual(1, children.Count); + Assert.AreEqual("Child2", children[0].AttributeValue("Name")); + } + } + [Test] public void Export() { diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageDataInstallationTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs similarity index 96% rename from src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageDataInstallationTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs index f75c359498..cd2f438c14 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs @@ -21,7 +21,7 @@ using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing; using Umbraco.Extensions; using Constants = Umbraco.Cms.Core.Constants; -namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging { [TestFixture] [Category("Slow")] @@ -333,10 +333,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging IReadOnlyList dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); IReadOnlyList contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); - IReadOnlyList contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService); + IReadOnlyList contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService); int numberOfDocs = (from doc in element.Descendants() - where (string)doc.Attribute("isDoc") == string.Empty - select doc).Count(); + where (string)doc.Attribute("isDoc") == string.Empty + select doc).Count(); // Assert Assert.That(contents, Is.Not.Null); @@ -359,10 +359,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging // Act IReadOnlyList mediaTypes = PackageDataInstallation.ImportMediaTypes(mediaTypesElement.Elements("MediaType"), 0); var importedMediaTypes = mediaTypes.ToDictionary(x => x.Alias, x => x); - IReadOnlyList medias = PackageDataInstallation.ImportContentBase(packageMedia.Yield(), importedMediaTypes, 0, MediaTypeService, MediaService); + IReadOnlyList medias = PackageDataInstallation.ImportContentBase(packageMedia.Yield(), importedMediaTypes, 0, MediaTypeService, MediaService); int numberOfDocs = (from doc in element.Descendants() - where (string)doc.Attribute("isDoc") == string.Empty - select doc).Count(); + where (string)doc.Attribute("isDoc") == string.Empty + select doc).Count(); // Assert Assert.That(medias, Is.Not.Null); @@ -372,8 +372,8 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging } [Test] - public void Can_Import_CheckboxList_Content_Package_Xml_With_Property_Editor_Aliases() => - AssertCheckBoxListTests(ImportResources.CheckboxList_Content_Package); + public void Can_Import_CheckboxList_Content_Package_Xml_With_Property_Editor_Aliases() + => AssertCheckBoxListTests(ImportResources.CheckboxList_Content_Package); private void AssertCheckBoxListTests(string strXml) { @@ -388,13 +388,13 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging IReadOnlyList dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); IReadOnlyList contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); - IReadOnlyList contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService); + IReadOnlyList contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService); int numberOfDocs = (from doc in element.Descendants() where (string)doc.Attribute("isDoc") == string.Empty select doc).Count(); string configuration; - using (global::Umbraco.Cms.Core.Scoping.IScope scope = ScopeProvider.CreateScope()) + using (IScope scope = ScopeProvider.CreateScope()) { List dtos = scope.Database.Fetch("WHERE nodeId = @Id", new { dataTypeDefinitions.First().Id }); configuration = dtos.Single().Configuration; @@ -743,10 +743,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging LocalizationService.Save(english, 0); } - private void AssertDictionaryItem(string key, string expectedValue, string cultureCode) + private void AssertDictionaryItem(string dictionaryItemName, string expectedValue, string cultureCode) { - Assert.That(LocalizationService.DictionaryItemExists(key), "DictionaryItem key does not exist"); - IDictionaryItem dictionaryItem = LocalizationService.GetDictionaryItemByKey(key); + Assert.That(LocalizationService.DictionaryItemExists(dictionaryItemName), "DictionaryItem key does not exist"); + IDictionaryItem dictionaryItem = LocalizationService.GetDictionaryItemByKey(dictionaryItemName); IDictionaryTranslation translation = dictionaryItem.Translations.SingleOrDefault(i => i.Language.IsoCode == cultureCode); Assert.IsNotNull(translation, "Translation to {0} was not added", cultureCode); string value = translation.Value; @@ -760,6 +760,8 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging LocalizationService.Save( new DictionaryItem("Parent") { + // This matches what is in the package.xml file + Key = new System.Guid("28f2e02a-8c66-4fcd-85e3-8524d551c0d3"), Translations = new List { new DictionaryTranslation(englishLanguage, expectedEnglishParentValue), diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageInstallationTest.cs similarity index 93% rename from src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageInstallationTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageInstallationTest.cs index bffd4006a3..d0999a0abc 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageInstallationTest.cs @@ -9,10 +9,11 @@ using NUnit.Framework; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Models.Packaging; using Umbraco.Cms.Core.Packaging; +using Umbraco.Cms.Infrastructure.Packaging; using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; -namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] @@ -20,7 +21,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging { private IHostingEnvironment HostingEnvironment => GetRequiredService(); - private IPackageInstallation PackageInstallation => GetRequiredService(); + private PackageInstallation PackageInstallation => (PackageInstallation)GetRequiredService(); private const string DocumentTypePickerPackage = "Document_Type_Picker_1.1.package.xml"; private const string HelloPackage = "Hello_1.0.0.package.xml"; @@ -76,7 +77,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging var testPackageFile = new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage)); using var fileStream = testPackageFile.OpenRead(); CompiledPackage package = PackageInstallation.ReadPackage(XDocument.Load(fileStream)); - + InstallationSummary summary = PackageInstallation.InstallPackageData(package, -1, out PackageDefinition def); Assert.AreEqual(1, summary.DataTypesInstalled.Count()); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs index 60496e52c1..31a4ee2c0d 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -103,7 +104,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services .Build(); localizationService.Save(languageEnGb); - var parentItem = new DictionaryItem("Parent"); + var parentItem = new DictionaryItem("Parent") {Key = Guid.Parse("28f2e02a-8c66-4fcd-85e3-8524d551c0d3")}; var parentTranslations = new List { new DictionaryTranslation(languageNbNo, "ForelderVerdi"), @@ -112,7 +113,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services parentItem.Translations = parentTranslations; localizationService.Save(parentItem); - var childItem = new DictionaryItem(parentItem.Key, "Child"); + var childItem = new DictionaryItem(parentItem.Key, "Child"){Key = Guid.Parse("e7dba0a9-d517-4ba4-8e18-2764d392c611")}; var childTranslations = new List { new DictionaryTranslation(languageNbNo, "BarnVerdi"), diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CheckboxList-Content-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CheckboxList-Content-Package.xml index 6f2ae0812c..8622d524ed 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CheckboxList-Content-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CheckboxList-Content-Package.xml @@ -3,12 +3,12 @@ - CheckboxListTest - + CheckboxListTest + - + @@ -17,6 +17,7 @@ NewType + e52d7dfa-1509-4e49-8f01-c27ed55e791e NewType .sprTreeFolder folder.png diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage-Random.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage-Random.xml index aa61633218..6b04996c4b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage-Random.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage-Random.xml @@ -1,9 +1,9 @@ - + - Composite Test + Composite Test @@ -20,6 +20,7 @@ Composite Test + eebd6e3a-91bc-4bac-be16-3c8d47ee3359 CompositeTest .sprTreeFolder folder.png @@ -43,6 +44,7 @@ Content + 1c51fc0a-79f7-4d3f-9174-95a2628505de Content .sprTreeFolder folder.png @@ -77,6 +79,7 @@ Meta + 0e0ad7de-aff1-4e4b-af8c-85e790669412 Meta .sprTreeFolder folder.png @@ -121,6 +124,7 @@ SEO + cc58b45e-369c-4429-be1b-1b9f7acfd360 Seo .sprTreeFolder folder.png diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage.xml index 89c940f7d1..6540e5a6d7 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage.xml @@ -3,12 +3,12 @@ - Compositions Packaged - + Compositions Packaged + - + 0 <![CDATA[Txt: A responsive starter kit for Umbraco]]> @@ -26,7 +26,7 @@ - + 0 1 @@ -38,7 +38,7 @@

Once you're happy with your site's design, you might want to add more functionality, such as maps, image galleries or forms. This is done by installing Umbraco modules.

]]>
- + 0 1 @@ -51,7 +51,7 @@

The sky is the limit with Umbraco, and you have the benefit a friendly community, training, and guaranteed support. Find out how to get help.

]]>
- + 0 1 @@ -64,7 +64,7 @@

Get more information about the umbraco way.

]]>
- + 0 1 @@ -73,31 +73,31 @@

Now that you know what the Txt Starter Kit is, it is time to get started using Umbraco.

]]>
- + 0 <![CDATA[Adventure log]]> - + 0 Ita prorsus, inquam; Hanc ergo intuens debet institutum illud quasi signum absolvere. Ergo adhuc, quantum equidem intellego, causa non videtur fuisse mutandi nominis. Quia dolori non voluptas contraria est, sed doloris privatio. Nos autem non solum beatae vitae istam esse oblectationem videmus, sed etiam levamentum miseriarum. Quodsi ipsam honestatem undique pertectam atque absolutam. Nos cum te, M. Quod vestri non item.

Cum id quoque, ut cupiebat, audivisset, evelli iussit eam, qua erat transfixus, hastam. Quarum ambarum rerum cum medicinam pollicetur, luxuriae licentiam pollicetur. Quid iudicant sensus? Quo tandem modo?

]]>
- + 0 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Commoda autem et incommoda in eo genere sunt, quae praeposita et reiecta diximus; Bestiarum vero nullum iudicium puto. Est enim effectrix multarum et magnarum voluptatum. Duo Reges: constructio interrete. Claudii libidini, qui tum erat summo ne imperio, dederetur. Quarum ambarum rerum cum medicinam pollicetur, luxuriae licentiam pollicetur. Sed virtutem ipsam inchoavit, nihil amplius.

Ita redarguitur ipse a sese, convincunturque scripta eius probitate ipsius ac moribus. Istam voluptatem, inquit, Epicurus ignorat? Sed venio ad inconstantiae crimen, ne saepius dicas me aberrare; Sic, et quidem diligentius saepiusque ista loquemur inter nos agemusque communiter. Primum in nostrane potestate est, quid meminerimus? Consequens enim est et post oritur, ut dixi. Hoc mihi cum tuo fratre convenit. Immo videri fortasse. Itaque in rebus minime obscuris non multus est apud eos disserendi labor. Aliud igitur esse censet gaudere, aliud non dolere.

]]>
- + 0 Ut aliquid scire se gaudeant? Hanc ergo intuens debet institutum illud quasi signum absolvere. Vestri haec verecundius, illi fortasse constantius. Itaque sensibus rationem adiunxit et ratione effecta sensus non reliquit. Sed ea mala virtuti magnitudine obruebantur. Quasi ego id curem, quid ille aiat aut neget. Verum tamen cum de rebus grandioribus dicas, ipsae res verba rapiunt; Apparet statim, quae sint officia, quae actiones.

Virtutibus igitur rectissime mihi videris et ad consuetudinem nostrae orationis vitia posuisse contraria. Nonne videmus quanta perturbatio rerum omnium consequatur, quanta confusio? Sed eum qui audiebant, quoad poterant, defendebant sententiam suam. Ut necesse sit omnium rerum, quae natura vigeant, similem esse finem, non eundem.

]]>
- + 0 2021-09-20T00:00:00 @@ -115,6 +115,7 @@ Master + 111adde6-9741-407e-ab35-b46b53471382 umbMaster folder.gif folder.png @@ -159,6 +160,7 @@ Home + e2f9e463-904a-4c0d-a7f3-f7c9fa31272b umbHomePage .sprTreeSettingDomain docWithImage.png @@ -375,6 +377,7 @@ Meta + 8adeed0a-489e-4e74-be6e-2e2f219a04a9 Meta icon-truck folder.png @@ -409,6 +412,7 @@ News Item + b43c90ef-f0d4-448e-b2aa-7915b743cab1 umbNewsItem .sprTreeDocPic docWithImage.png @@ -478,6 +482,7 @@ News Overview + a22ca7e7-bdc4-4c3f-9193-b8773664e61d umbNewsOverview package.png folder_media.png @@ -502,6 +507,7 @@ Seo + 67f4dfe3-c505-43b9-86a4-6d23481c5e87 Seo icon-wifi folder.png @@ -536,6 +542,7 @@ Text Page + d8ab5350-3064-487f-92fe-9735c015f631 umbTextyPage .sprTreeDoc doc.png diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Dictionary-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Dictionary-Package.xml index 915492dea8..2f2360037c 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Dictionary-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Dictionary-Package.xml @@ -3,14 +3,14 @@ - Dictionary-Package + Dictionary-Package - + - + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Fanoe-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Fanoe-Package.xml index 6b96eed2ed..f1b887b928 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Fanoe-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Fanoe-Package.xml @@ -2,7 +2,7 @@ - Fanoe + Fanoe @@ -1201,6 +1201,7 @@ Master + b96c565b-0490-4b34-aed2-ffa0c7f63f2a Master icon-desktop folder.png @@ -1252,6 +1253,7 @@ Blogpost + 10dbe2ef-ee50-4ea6-b4d0-dc0c08919424 Blogpost icon-edit folder.png @@ -1288,6 +1290,7 @@ Blogpost Repository + 7d58f0d9-bfe3-4dfe-be18-9f48cc53c768 BlogpostRepository .sprTreeFolder folder.png @@ -1306,6 +1309,7 @@ Home + 61100eb2-92c7-43d9-9fd8-94707dcbb142 Home icon-home folder.png @@ -1328,6 +1332,7 @@ Landing page + dd8c9f38-9847-465a-924d-87983fcec124 LandingPage icon-stamp folder.png @@ -1366,6 +1371,7 @@ Text page + 8fe738e3-8724-484f-944f-cb0d8fa78aa1 TextPage icon-document folder.png @@ -3903,6 +3909,7 @@ nav > ul li.active ul li a { + E4F0830F-26AB-4CE9-BD71-98273875C4CB Insert form umbracoforms.RenderForm @@ -3919,6 +3926,7 @@ nav > ul li.active ul li a { + E4F0830F-26AB-4CE9-BD71-98273875C4C0 Render Forms Scripts umbracoforms.RenderScripts diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs index b7d74985ad..b49d02d159 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs @@ -1,410 +1,347 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ImportResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ImportResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing.ImportRes" + - "ources", typeof(ImportResources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>CheckboxListTest</name> - /// <version>1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>1</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>1</name> - /// <website>1</website> - /// </author> - /// <r [rest of string was truncated]";. - /// - internal static string CheckboxList_Content_Package { - get { - return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Compositions Packaged</name> - /// <version>1.0</version> - /// <license url="http://opensource.org/licenses/MIT">MIT License</license> - /// <url>http://blog.sitereactor.dk</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Morten Christensen</name> - /// <website>h [rest of string was truncated]";. - /// - internal static string CompositionsTestPackage { - get { - return ResourceManager.GetString("CompositionsTestPackage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Composite Test</name> - /// <version>dfsfd</version> - /// <license url="http://opensource.org/licenses/MIT">MIT License</license> - /// <url>ddsff</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>fsdfds</name> - /// <website>sfdf</website> - /// </author> - /// <rea [rest of string was truncated]";. - /// - internal static string CompositionsTestPackage_Random { - get { - return ResourceManager.GetString("CompositionsTestPackage_Random", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Dictionary-Package</name> - /// <version>1.0</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>http://not.available</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Test</name> - /// <website>http://not.available</w [rest of string was truncated]";. - /// - internal static string Dictionary_Package { - get { - return ResourceManager.GetString("Dictionary_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>bootstrap.min.js</guid> - /// <orgPath>/js</orgPath> - /// <orgName>bootstrap.min.js</orgName> - /// </file> - /// <file> - /// <guid>jquery.min.js</guid> - /// <orgPath>/js</orgPath> - /// <orgName>jquery.min.js</orgName> - /// </file> - /// <file> - /// <guid>top-image.jpg</guid> - /// <orgPath>/Media/1001</orgPath> - /// <orgName>top-image.jpg</orgName> - /// </file> - /// <file> - /// <guid>top-im [rest of string was truncated]";. - /// - internal static string Fanoe_Package { - get { - return ResourceManager.GetString("Fanoe_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>DocTypeError</name> - /// <version>1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">Personal license</license> - /// <url>http://www.iseli-webconsulting.de</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Iseli Webconsulting</name> [rest of string was truncated]";. - /// - internal static string InheritedDocTypes_Package { - get { - return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Package With MediaTypes And Media + Folder</name> - /// <version>1.0.0</version> - /// <iconUrl></iconUrl> - /// <license url="http://opensource.org/licenses/MIT">MIT License</license> - /// <url>http://www.umbraco.com</url> - /// <requirements type="Strict"> - /// <major>0</major> - /// <minor>5</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name [rest of string was truncated]";. - /// - internal static string MediaTypesAndMedia_Package_xml { - get { - return ResourceManager.GetString("MediaTypesAndMedia_Package.xml", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - ///<DocumentType> - /// <Info> - /// <Name>test</Name> - /// <Alias>test</Alias> - /// <Icon>folder.gif</Icon> - /// <Thumbnail>folder.png</Thumbnail> - /// <Description> - /// </Description> - /// <AllowAtRoot>False</AllowAtRoot> - /// <AllowedTemplates> - /// <Template>test</Template> - /// </AllowedTemplates> - /// <DefaultTemplate>test</DefaultTemplate> - /// </Info> - /// <Structure> - /// <DocumentType>test</DocumentType> - /// </Structure> - /// <GenericProperties> - /// <GenericProperty> [rest of string was truncated]";. - /// - internal static string SingleDocType { - get { - return ResourceManager.GetString("SingleDocType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>Map.cshtml</guid> - /// <orgPath>/macroScripts</orgPath> - /// <orgName>Map.cshtml</orgName> - /// </file> - /// <file> - /// <guid>AccountController.cs</guid> - /// <orgPath>/App_Code</orgPath> - /// <orgName>AccountController.cs</orgName> - /// </file> - /// <file> - /// <guid>ContactController.cs</guid> - /// <orgPath>/App_Code</orgPath> - /// <orgName>ContactController.cs</orgName> - /// </file> - /// [rest of string was truncated]";. - /// - internal static string StandardMvc_Package { - get { - return ResourceManager.GetString("StandardMvc_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Template-Update</name> - /// <version>0.1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>https://our.umbraco.com/projects</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Morten Christensen</name> - /// [rest of string was truncated]";. - /// - internal static string TemplateOnly_Package { - get { - return ResourceManager.GetString("TemplateOnly_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Template-Update</name> - /// <version>0.1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>https://our.umbraco.com/projects</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Morten Christensen</name> - /// [rest of string was truncated]";. - /// - internal static string TemplateOnly_Updated_Package { - get { - return ResourceManager.GetString("TemplateOnly_Updated_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>uBlogsy.BusinessLogic.dll</guid> - /// <orgPath>/bin</orgPath> - /// <orgName>uBlogsy.BusinessLogic.dll</orgName> - /// </file> - /// <file> - /// <guid>uBlogsy.BusinessLogic.pdb</guid> - /// <orgPath>/bin</orgPath> - /// <orgName>uBlogsy.BusinessLogic.pdb</orgName> - /// </file> - /// <file> - /// <guid>uBlogsy.Common.dll</guid> - /// <orgPath>/bin</orgPath> - /// <orgName>uBlogsy.Common.dll</orgNam [rest of string was truncated]";. - /// - internal static string uBlogsy_Package { - get { - return ResourceManager.GetString("uBlogsy_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>XSLTsearch.xslt</guid> - /// <orgPath>/xslt</orgPath> - /// <orgName>XSLTsearch.xslt</orgName> - /// </file> - /// <file> - /// <guid>XSLTsearch.cs</guid> - /// <orgPath>/App_Code</orgPath> - /// <orgName>XSLTsearch.cs</orgName> - /// </file> - /// </files> - /// <info> - /// <package> - /// <name>XSLTsearch</name> - /// <version>3.0.4</version> - /// <license url="http://www.opensource.org/licenses/mit-li [rest of string was truncated]";. - /// - internal static string XsltSearch_Package { - get { - return ResourceManager.GetString("XsltSearch_Package", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ImportResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ImportResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing.ImportRes" + + "ources", typeof(ImportResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>CheckboxListTest</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <NewType id="1148" parentID="-1" level="1" creatorID="0" sortOrder="9" createDate="2013-07-23T12:06:07" updateDate="2013-07-23T15:56:37" nodeName="DoIt" urlName="doit" path="-1,1148" isDoc="" nodeType="1134" creatorName="admin" writerName="admin" writerID="0" template="1133" nodeTy [rest of string was truncated]";. + /// + internal static string CheckboxList_Content_Package { + get { + return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Compositions Packaged</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <umbHomePage id="1068" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2014-11-26T12:52:35" updateDate="2014-11-26T12:52:36" nodeName="Home" urlName="home" path="-1,1068" isDoc="" nodeType="1056" creatorName="Morten Christensen" writerName="Morten Christensen" [rest of string was truncated]";. + /// + internal static string CompositionsTestPackage { + get { + return ResourceManager.GetString("CompositionsTestPackage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Composite Test</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <CompositeTest id="1083" parentID="-1" level="1" creatorID="0" sortOrder="1" createDate="2014-11-26T15:02:43" updateDate="2014-11-26T15:02:43" nodeName="Composite test" urlName="composite-test" path="-1,1083" isDoc="" nodeType="1082" creatorName="Niels Hartvig" writerName="Niels Hart [rest of string was truncated]";. + /// + internal static string CompositionsTestPackage_Random { + get { + return ResourceManager.GetString("CompositionsTestPackage_Random", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Dictionary-Package</name> + /// </package> + /// </info> + /// <DictionaryItems> + /// <DictionaryItem Key="Parent"> + /// <Value LanguageId="2" LanguageCultureAlias="nb-NO"><![CDATA[ForelderVerdi]]></Value> + /// <Value LanguageId="3" LanguageCultureAlias="en-GB"><![CDATA[ParentValue]]></Value> + /// <DictionaryItem Key="Child"> + /// <Value LanguageId="2" LanguageCultureAlias="nb-NO"><![CDATA[BarnV [rest of string was truncated]";. + /// + internal static string Dictionary_Package { + get { + return ResourceManager.GetString("Dictionary_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <info> + /// <package> + /// <name>Fanoe</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <Home id="1057" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2014-11-25T12:23:30" updateDate="2014-12-01T13:45:08" nodeName="Home" urlName="home" path="-1,1057" isDoc="" nodeType="1055" creatorName="Rune Strand" writerName="Rune Strand" writerID="0" template="1054" nodeTypeAlias="Home"> [rest of string was truncated]";. + /// + internal static string Fanoe_Package { + get { + return ResourceManager.GetString("Fanoe_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>DocTypeError</name> + /// </package> + /// </info> + /// <DocumentTypes> + /// <DocumentType> + /// <Info> + /// <Name>MR Basisseite</Name> + /// <Key>02e4e119-2eeb-4b92-9880-0c35d66a16b2</Key> + /// <Alias>MRBasePage</Alias> + /// <Icon>folder.gif</Icon> + /// <Thumbnail>folder.png</Thumbnail> + /// <Description>Basistyp für alle Seiten der MR-Racing Website.</Description> + /// [rest of string was truncated]";. + /// + internal static string InheritedDocTypes_Package { + get { + return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Package With MediaTypes And Media + Folder</name> + /// </package> + /// </info> + /// <DocumentTypes /> + /// <MediaTypes> + /// <MediaType> + /// <Info> + /// <Name>Folder</Name> + /// <Key>c3ddc08e-3b5e-42b2-9f0b-6e5c79a2e2e0</Key> + /// <Alias>Folder</Alias> + /// <Icon>icon-folder</Icon> + /// <Thumbnail>icon-folder</Thumbnail> + /// <Description /> + /// <AllowAtRoot>True</AllowAtRoot> + /// [rest of string was truncated]";. + /// + internal static string MediaTypesAndMedia_Package_xml { + get { + return ResourceManager.GetString("MediaTypesAndMedia_Package.xml", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<DocumentType> + /// <Info> + /// <Name>test</Name> + /// <Key>150ead17-d359-42a2-ac33-6504cc52ced1</Key> + /// <Alias>test</Alias> + /// <Icon>folder.gif</Icon> + /// <Thumbnail>folder.png</Thumbnail> + /// <Description> + /// </Description> + /// <AllowAtRoot>False</AllowAtRoot> + /// <AllowedTemplates> + /// <Template>test</Template> + /// </AllowedTemplates> + /// <DefaultTemplate>test</DefaultTemplate> + /// </Info> + /// <Structure> + /// <DocumentType>test</DocumentType> + /// </Str [rest of string was truncated]";. + /// + internal static string SingleDocType { + get { + return ResourceManager.GetString("SingleDocType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <info> + /// <package> + /// <name>StandardWebsiteMVC</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <Homepage id="1072" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:39" updateDate="2013-02-17T09:10:47" nodeName="Home" urlName="home" path="-1,1072" isDoc="" nodeType="1062" creatorName="admin" writerName="admin" writerID="0" template="1049"> + /// <slide [rest of string was truncated]";. + /// + internal static string StandardMvc_Package { + get { + return ResourceManager.GetString("StandardMvc_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Template-Update</name> + /// </package> + /// </info> + /// <DocumentTypes /> + /// <Templates> + /// <Template> + /// <Name>Homepage</Name> + /// <Alias>umbHomepage</Alias> + /// <Master>umbMaster</Master> + /// <Design> + /// <![CDATA[<%@ Master Language="C#" MasterPageFile="~/masterpages/umbMaster.master" AutoEventWireup="true" %> + ///<asp:content id="Content1" contentplaceholderid="cp_content [rest of string was truncated]";. + /// + internal static string TemplateOnly_Package { + get { + return ResourceManager.GetString("TemplateOnly_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Template-Update</name> + /// </package> + /// </info> + /// <DocumentTypes /> + /// <Templates> + /// <Template> + /// <Name>Homepage</Name> + /// <Alias>umbHomepage</Alias> + /// <Master>umbMaster</Master> + /// <Design> + /// <![CDATA[<%@ Master Language="C#" MasterPageFile="~/masterpages/umbMaster.master" AutoEventWireup="true" %> + ///<asp:content id="Content1" contentplaceholderid="cp_content [rest of string was truncated]";. + /// + internal static string TemplateOnly_Updated_Package { + get { + return ResourceManager.GetString("TemplateOnly_Updated_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <info> + /// <package> + /// <name>uBlogsy</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <uBlogsySiteRoot id="1266" parentID="-1" level="1" creatorID="0" sortOrder="1" createDate="2013-02-21T18:38:53" updateDate="2013-03-18T22:35:23" nodeName="Sample Site Root" urlName="sample-site-root" path="-1,1266" isDoc="" nodeType="1263" creatorName="admin" writerName="admin" writerID="0" template="12 [rest of string was truncated]";. + /// + internal static string uBlogsy_Package { + get { + return ResourceManager.GetString("uBlogsy_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <info> + /// <package> + /// <name>XSLTsearch</name> + /// </package> + /// </info> + /// <Documents> + /// <DocumentSet importMode="root"> + /// <XSLTsearch id="1090" parentID="-1" level="1" writerID="0" creatorID="0" nodeType="1087" template="1086" sortOrder="39" createDate="2010-11-09T13:45:22" updateDate="2010-11-09T14:18:04" nodeName="Search" urlName="search" writerName="Administrator" creatorName="Administrator" path="-1,1090" isDoc=""> /// [rest of string was truncated]";. + /// + internal static string XsltSearch_Package { + get { + return ResourceManager.GetString("XsltSearch_Package", resourceCulture); + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/InheritedDocTypes-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/InheritedDocTypes-Package.xml index 7e30bb8525..cde09ba65e 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/InheritedDocTypes-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/InheritedDocTypes-Package.xml @@ -1,15 +1,16 @@ - + - DocTypeError + DocTypeError MR Basisseite + 02e4e119-2eeb-4b92-9880-0c35d66a16b2 MRBasePage folder.gif folder.png @@ -66,6 +67,7 @@ MR Startseite + 4ecde940-89bd-47c2-9c9c-3cfcc32e8e52 MRStartPage folder.gif folder.png diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml index ae37d5a337..6adbea254c 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml @@ -1,9 +1,9 @@ - + - Package With MediaTypes And Media + Folder + Package With MediaTypes And Media + Folder @@ -11,6 +11,7 @@ Folder + c3ddc08e-3b5e-42b2-9f0b-6e5c79a2e2e0 Folder icon-folder icon-folder @@ -28,6 +29,7 @@ Image + ee78bb5b-3734-4b86-bd48-d9ca2e6d6846 Image icon-picture icon-picture diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/SingleDocType.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/SingleDocType.xml index b7909a51cf..170b7f5b65 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/SingleDocType.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/SingleDocType.xml @@ -2,6 +2,7 @@ test + 150ead17-d359-42a2-ac33-6504cc52ced1 test folder.gif folder.png @@ -31,4 +32,4 @@ - \ No newline at end of file + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/StandardMvc-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/StandardMvc-Package.xml index 347bfe060b..5bba7cfa4e 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/StandardMvc-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/StandardMvc-Package.xml @@ -3,11 +3,11 @@ StandardWebsiteMVC - + - + Built by Creative Founds @@ -36,7 +36,7 @@ 0 - + About Us

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dictum, nisi non gravida blandit, odio nulla ultrices orci, quis blandit tortor libero vitae massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla at velit lacus.

@@ -62,14 +62,14 @@ 0 - + <description><![CDATA[]]></description> <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> - <Standard id="1075" parentID="1074" level="4" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="3rd level nav 2" urlName="3rd-level-nav-2" path="-1,1072,1073,1074,1075" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="9c9b55d0-2fbf-4f12-afea-023bd7b25198" id="1075" parentID="1074" level="4" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="3rd level nav 2" urlName="3rd-level-nav-2" path="-1,1072,1073,1074,1075" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText><![CDATA[]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -78,7 +78,7 @@ <umbracoNaviHide>0</umbracoNaviHide> </Standard> </Standard> - <Standard id="1076" parentID="1073" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="Sub Navigation 2" urlName="sub-navigation-2" path="-1,1072,1073,1076" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="9c9b55d0-2fbf-4f12-afea-023bd7b25197" id="1076" parentID="1073" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="Sub Navigation 2" urlName="sub-navigation-2" path="-1,1072,1073,1076" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText><![CDATA[]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -87,14 +87,14 @@ <umbracoNaviHide>0</umbracoNaviHide> </Standard> </Standard> - <Standard id="1077" parentID="1072" level="2" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:10:47" nodeName="News" urlName="news" path="-1,1072,1077" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1046"> + <Standard key="9c9b55d0-2fbf-4f12-afea-023bd7b25196" id="1077" parentID="1072" level="2" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:10:47" nodeName="News" urlName="news" path="-1,1072,1077" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1046"> <bodyText><![CDATA[<h2>News</h2>]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> <description><![CDATA[]]></description> <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> - <NewsArticle id="1078" parentID="1077" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:11:22" nodeName="Article 1" urlName="article-1" path="-1,1072,1077,1078" isDoc="" nodeType="1063" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <NewsArticle key="9c9b55d0-2fbf-4f12-afea-023bd7b25195" id="1078" parentID="1077" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:11:22" nodeName="Article 1" urlName="article-1" path="-1,1072,1077,1078" isDoc="" nodeType="1063" creatorName="admin" writerName="admin" writerID="0" template="1053"> <articleSummary><![CDATA[Here is an article summary, you can add as much of a description as you require.]]></articleSummary> <articleDate>2012-11-08T00:00:00</articleDate> <bodyText> @@ -109,7 +109,7 @@ <umbracoNaviHide>0</umbracoNaviHide> </NewsArticle> </Standard> - <Standard id="1079" parentID="1072" level="2" creatorID="0" sortOrder="2" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:10:55" nodeName="Clients" urlName="clients" path="-1,1072,1079" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="9c9b55d0-2fbf-4f12-afea-023bd7b25194" id="1079" parentID="1072" level="2" creatorID="0" sortOrder="2" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:10:55" nodeName="Clients" urlName="clients" path="-1,1072,1079" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText> <![CDATA[<h2>Clients</h2> <p><strong>This is a standard content page.</strong></p> @@ -123,7 +123,7 @@ <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> </Standard> - <ContactForm id="1080" parentID="1072" level="2" creatorID="0" sortOrder="3" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:04:46" nodeName="Contact Us" urlName="contact-us" path="-1,1072,1080" isDoc="" nodeType="1059" creatorName="admin" writerName="admin" writerID="0" template="1048"> + <ContactForm key="9c9b55d0-2fbf-4f12-afea-023bd7b25193" id="1080" parentID="1072" level="2" creatorID="0" sortOrder="3" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:04:46" nodeName="Contact Us" urlName="contact-us" path="-1,1072,1080" isDoc="" nodeType="1059" creatorName="admin" writerName="admin" writerID="0" template="1048"> <recipientEmailAddress>chriskoiak@gmail.com</recipientEmailAddress> <emailSubject>Standard Website Contact Form</emailSubject> <thankYouPage>1124</thankYouPage> @@ -138,7 +138,7 @@ <description><![CDATA[]]></description> <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> - <Standard id="1081" parentID="1080" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:04:46" nodeName="Thank You" urlName="thank-you" path="-1,1072,1080,1081" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="9c9b55d0-2fbf-4f12-afea-023bd7b25192" id="1081" parentID="1080" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:04:46" nodeName="Thank You" urlName="thank-you" path="-1,1072,1080,1081" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText><![CDATA[<p><strong>Email sent successfully</strong></p>]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -147,7 +147,7 @@ <umbracoNaviHide>1</umbracoNaviHide> </Standard> </ContactForm> - <Standard id="1082" parentID="1072" level="2" creatorID="0" sortOrder="4" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:10:47" nodeName="Search" urlName="search" path="-1,1072,1082" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1051"> + <Standard key="9c9b55d0-2fbf-4f12-afea-023bd7b25191" id="1082" parentID="1072" level="2" creatorID="0" sortOrder="4" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:10:47" nodeName="Search" urlName="search" path="-1,1072,1082" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1051"> <bodyText><![CDATA[<h2>Search</h2>]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -155,7 +155,7 @@ <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> </Standard> - <Standard id="1083" parentID="1072" level="2" creatorID="0" sortOrder="5" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:10:47" nodeName="Sitemap" urlName="sitemap" path="-1,1072,1083" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1052"> + <Standard key="8c9b55d0-2fbf-4f12-afea-023bd7b25190" id="1083" parentID="1072" level="2" creatorID="0" sortOrder="5" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:10:47" nodeName="Sitemap" urlName="sitemap" path="-1,1072,1083" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1052"> <bodyText> <![CDATA[<h2>Sitemap</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dictum, nisi non gravida blandit, odio nulla ultrices orci, quis blandit tortor libero vitae massa.<a href="/contact-us.aspx"><br /></a></p>]]> @@ -166,16 +166,16 @@ <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> </Standard> - <ClientArea id="1084" parentID="1072" level="2" creatorID="0" sortOrder="6" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area" urlName="client-area" path="-1,1072,1084" isDoc="" nodeType="1056" creatorName="admin" writerName="admin" writerID="0" template="1047"> + <ClientArea key="8c9b55d0-2fbf-4f12-afea-023bd7b25199" id="1084" parentID="1072" level="2" creatorID="0" sortOrder="6" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area" urlName="client-area" path="-1,1072,1084" isDoc="" nodeType="1056" creatorName="admin" writerName="admin" writerID="0" template="1047"> <umbracoNaviHide>0</umbracoNaviHide> - <Standard id="1085" parentID="1084" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area 1" urlName="client-area-1" path="-1,1072,1084,1085" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="8c9b55d0-2fbf-4f12-afea-023bd7b25198" id="1085" parentID="1084" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area 1" urlName="client-area-1" path="-1,1072,1084,1085" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText><![CDATA[]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> <description><![CDATA[]]></description> <keywords><![CDATA[]]></keywords> <umbracoNaviHide>0</umbracoNaviHide> - <Standard id="1086" parentID="1085" level="4" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Page 1" urlName="page-1" path="-1,1072,1084,1085,1086" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="8c9b55d0-2fbf-4f12-afea-023bd7b25197" id="1086" parentID="1085" level="4" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Page 1" urlName="page-1" path="-1,1072,1084,1085,1086" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText><![CDATA[]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -184,7 +184,7 @@ <umbracoNaviHide>0</umbracoNaviHide> </Standard> </Standard> - <Standard id="1087" parentID="1084" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area 2" urlName="client-area-2" path="-1,1072,1084,1087" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="8c9b55d0-2fbf-4f12-afea-023bd7b25196" id="1087" parentID="1084" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area 2" urlName="client-area-2" path="-1,1072,1084,1087" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText><![CDATA[]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -193,7 +193,7 @@ <umbracoNaviHide>0</umbracoNaviHide> </Standard> </ClientArea> - <Standard id="1088" parentID="1072" level="2" creatorID="0" sortOrder="7" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Insufficent Access" urlName="insufficent-access" path="-1,1072,1088" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <Standard key="8c9b55d0-2fbf-4f12-afea-023bd7b25195" id="1088" parentID="1072" level="2" creatorID="0" sortOrder="7" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Insufficent Access" urlName="insufficent-access" path="-1,1072,1088" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> <bodyText> <![CDATA[<h2>Insufficent Access</h2> <p>You have tried to access a page you do not have access to.</p>]]> @@ -204,7 +204,7 @@ <keywords><![CDATA[]]></keywords> <umbracoNaviHide>1</umbracoNaviHide> </Standard> - <Standard id="1089" parentID="1072" level="2" creatorID="0" sortOrder="8" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:10:47" nodeName="Login" urlName="login" path="-1,1072,1089" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1050"> + <Standard key="8c9b55d0-2fbf-4f12-afea-023bd7b25194" id="1089" parentID="1072" level="2" creatorID="0" sortOrder="8" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:10:47" nodeName="Login" urlName="login" path="-1,1072,1089" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1050"> <bodyText><![CDATA[<h2>Login</h2>]]></bodyText> <contentPanels><![CDATA[]]></contentPanels> <title /> @@ -212,9 +212,9 @@ <keywords><![CDATA[]]></keywords> <umbracoNaviHide>1</umbracoNaviHide> </Standard> - <Slideshow id="1090" parentID="1072" level="2" creatorID="0" sortOrder="9" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Slideshow" urlName="slideshow" path="-1,1072,1090" isDoc="" nodeType="1065" creatorName="admin" writerName="admin" writerID="0" template="0"> + <Slideshow key="8c9b55d0-2fbf-4f12-afea-023bd7b25193" id="1090" parentID="1072" level="2" creatorID="0" sortOrder="9" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Slideshow" urlName="slideshow" path="-1,1072,1090" isDoc="" nodeType="1065" creatorName="admin" writerName="admin" writerID="0" template="0"> <umbracoNaviHide>0</umbracoNaviHide> - <Slide id="1091" parentID="1090" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Purple Hat" urlName="purple-hat" path="-1,1072,1090,1091" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> + <Slide key="8c9b55d0-2fbf-4f12-afea-023bd7b25192" id="1091" parentID="1090" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Purple Hat" urlName="purple-hat" path="-1,1072,1090,1091" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> <mainImage>/media/1813/cap.png</mainImage> <bodyText> <![CDATA[<h3>Standard Website MVC</h3> @@ -224,7 +224,7 @@ </bodyText> <umbracoNaviHide>1</umbracoNaviHide> </Slide> - <Slide id="1092" parentID="1090" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Red Dice" urlName="red-dice" path="-1,1072,1090,1092" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> + <Slide key="8c9b55d0-2fbf-4f12-afea-023bd7b25191" id="1092" parentID="1090" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Red Dice" urlName="red-dice" path="-1,1072,1090,1092" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> <mainImage>/media/1824/dice.png</mainImage> <bodyText> <![CDATA[<h3>Secure Client Areas</h3> @@ -234,7 +234,7 @@ </bodyText> <umbracoNaviHide>1</umbracoNaviHide> </Slide> - <Slide id="1093" parentID="1090" level="3" creatorID="0" sortOrder="2" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Umbraco Speechbubble" urlName="umbraco-speechbubble" path="-1,1072,1090,1093" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> + <Slide key="7c9b55d0-2fbf-4f12-afea-023bd7b25190" id="1093" parentID="1090" level="3" creatorID="0" sortOrder="2" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Umbraco Speechbubble" urlName="umbraco-speechbubble" path="-1,1072,1090,1093" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> <mainImage>/media/2075/chat.jpg</mainImage> <bodyText> <![CDATA[<h3>News List</h3> @@ -245,9 +245,9 @@ <umbracoNaviHide>1</umbracoNaviHide> </Slide> </Slideshow> - <ContentPanels id="1094" parentID="1072" level="2" creatorID="0" sortOrder="10" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Content Panels" urlName="content-panels" path="-1,1072,1094" isDoc="" nodeType="1061" creatorName="admin" writerName="admin" writerID="0" template="0"> + <ContentPanels key="7c9b55d0-2fbf-4f12-afea-023bd7b25199" id="1094" parentID="1072" level="2" creatorID="0" sortOrder="10" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Content Panels" urlName="content-panels" path="-1,1072,1094" isDoc="" nodeType="1061" creatorName="admin" writerName="admin" writerID="0" template="0"> <umbracoNaviHide>1</umbracoNaviHide> - <ContentPanel id="1095" parentID="1094" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Introductory Offers" urlName="introductory-offers" path="-1,1072,1094,1095" isDoc="" nodeType="1060" creatorName="admin" writerName="admin" writerID="0" template="0"> + <ContentPanel key="7c9b55d0-2fbf-4f12-afea-023bd7b25198" id="1095" parentID="1094" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Introductory Offers" urlName="introductory-offers" path="-1,1072,1094,1095" isDoc="" nodeType="1060" creatorName="admin" writerName="admin" writerID="0" template="0"> <bodyText> <![CDATA[ <h3>Introductory Offers</h3> @@ -263,7 +263,7 @@ </bodyText> <umbracoNaviHide>1</umbracoNaviHide> </ContentPanel> - <ContentPanel id="1096" parentID="1094" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Sample Panel" urlName="sample-panel" path="-1,1072,1094,1096" isDoc="" nodeType="1060" creatorName="admin" writerName="admin" writerID="0" template="0"> + <ContentPanel key="7c9b55d0-2fbf-4f12-afea-023bd7b25197" id="1096" parentID="1094" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Sample Panel" urlName="sample-panel" path="-1,1072,1094,1096" isDoc="" nodeType="1060" creatorName="admin" writerName="admin" writerID="0" template="0"> <bodyText> <![CDATA[<p><strong>Sample Panel</strong></p> <p>Don't you just love MVC?</p> @@ -282,6 +282,7 @@ <DocumentType> <Info> <Name>Base</Name> + <Key>2db296c1-5c60-45e9-b6d3-8148926dd863</Key> <Alias>Base</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -312,6 +313,7 @@ <DocumentType> <Info> <Name>Client Area Folder</Name> + <Key>84d692d2-11fe-45ba-927e-2c4ecdb11400</Key> <Alias>ClientArea</Alias> <Icon>.sprTreeFolder</Icon> <Thumbnail>folder.png</Thumbnail> @@ -334,6 +336,7 @@ <DocumentType> <Info> <Name>Content Master</Name> + <Key>f6d25616-9f16-4c70-9e8c-e0ad4cd92dfc</Key> <Alias>ContentMaster</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -391,6 +394,7 @@ <DocumentType> <Info> <Name>Standard</Name> + <Key>95a532e7-064f-4651-a619-786f4beac7c1</Key> <Alias>Standard</Alias> <Icon>.sprTreeDoc</Icon> <Thumbnail>doc.png</Thumbnail> @@ -449,6 +453,7 @@ <DocumentType> <Info> <Name>ContactForm</Name> + <Key>67ce11c5-0493-4d8f-9678-d131bd8996ea</Key> <Alias>ContactForm</Alias> <Icon>newsletter.gif</Icon> <Thumbnail>doc.png</Thumbnail> @@ -520,6 +525,7 @@ <DocumentType> <Info> <Name>ContentPanel</Name> + <Key>503b6a5e-69b6-444a-a728-074a1b201b84</Key> <Alias>ContentPanel</Alias> <Icon>.sprTreeDoc</Icon> <Thumbnail>doc.png</Thumbnail> @@ -555,6 +561,7 @@ <DocumentType> <Info> <Name>ContentPanels</Name> + <Key>3d1433fc-22a2-4a70-b7cb-b7fafe4a0622</Key> <Alias>ContentPanels</Alias> <Icon>.sprTreeFolder</Icon> <Thumbnail>folder.png</Thumbnail> @@ -575,6 +582,7 @@ <DocumentType> <Info> <Name>Homepage</Name> + <Key>a5f79cf6-9a2f-4672-ab56-f8bb31fdbb20</Key> <Alias>Homepage</Alias> <Icon>.sprTreeSettingDomain</Icon> <Thumbnail>folder.png</Thumbnail> @@ -784,6 +792,7 @@ <DocumentType> <Info> <Name>NewsArticle</Name> + <Key>c4662a2d-4698-4880-9243-2e449d9e0cfd</Key> <Alias>NewsArticle</Alias> <Icon>doc.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -831,6 +840,7 @@ <DocumentType> <Info> <Name>Slide</Name> + <Key>cf2153f2-4881-442b-ab58-50c1c786522b</Key> <Alias>Slide</Alias> <Icon>.sprTreeMediaPhoto</Icon> <Thumbnail>docWithImage.png</Thumbnail> @@ -877,6 +887,7 @@ <DocumentType> <Info> <Name>Slideshow</Name> + <Key>9acb68aa-03e1-4474-823d-c21af8356756</Key> <Alias>Slideshow</Alias> <Icon>.sprTreeFolder</Icon> <Thumbnail>folder.png</Thumbnail> @@ -2041,6 +2052,7 @@ table th, td {border: 0px solid #fff;} </Stylesheets> <Macros> <macro> + <key>E4F0830F-26AB-4CE9-BD71-98273875C4C0</key> <name>Map</name> <alias>Map</alias> <scriptType> diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/XsltSearch-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/XsltSearch-Package.xml index b97c62825c..37844e37cb 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/XsltSearch-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/XsltSearch-Package.xml @@ -2,7 +2,7 @@ <umbPackage> <info> <package> - <name>XSLTsearch</name> + <name>XSLTsearch</name> </package> </info> <Documents> @@ -16,6 +16,7 @@ <DocumentType> <Info> <Name>XSLTsearch</Name> + <Key>c7d19488-f11c-4c28-be14-da8be9c9a675</Key> <Alias>XSLTsearch</Alias> <Icon>.sprTreeDoc2</Icon> <Thumbnail>doc.png</Thumbnail> @@ -54,10 +55,10 @@ <Design> <![CDATA[<%@ Master Language="C#" MasterPageFile="~/masterpages/RunwayMaster.master" AutoEventWireup="true" %> - + <asp:Content ContentPlaceHolderId="RunwayMasterContentPlaceHolder" runat="server"> <div id="content"> - <div id="contentHeader"> + <div id="contentHeader"> <h2><umbraco:Item runat="server" field="pageName"/></h2> </div> @@ -107,6 +108,7 @@ p.xsltsearch_result_description {padding-bottom: 10px;} <Macros> <macro> <name>XSLTsearch</name> + <key>0712FAC7-ADD7-48F7-9098-C80220B0D2F0</key> <alias>XSLTsearch</alias> <macroType>Unknown</macroType> <macroSource /> @@ -116,72 +118,72 @@ p.xsltsearch_result_description {padding-bottom: 10px;} <scriptingFile> </scriptingFile> <properties> - <property name="Source" alias="source" show="True" propertyType="contentTree" /> - <property name="Umbraco fields to search" alias="searchFields" show="True" propertyType="text" /> - <property name="Umbraco fields shown in results preview" alias="previewFields" show="True" propertyType="text" /> - <property name="Display search box at TOP, BOTTOM, BOTH, or NONE" alias="searchBoxLocation" show="True" propertyType="text" /> - <property name="Display BEGINNING or CONTEXT of each result" alias="previewType" show="True" propertyType="text" /> - <property name="Number of search results to display per page" alias="resultsPerPage" show="True" propertyType="number" /> - <property name="Number of characters of preview text to display" alias="previewChars" show="True" propertyType="number" /> - <property name="Display 'Showing result X to Y'?" alias="showPageRange" show="True" propertyType="bool" /> - <property name="Display numbers before each result?" alias="showOrdinals" show="True" propertyType="bool" /> - <property name="Display search score for each result?" alias="showScores" show="True" propertyType="bool" /> - <property name="Display 'Searched X documents in Y seconds'?" alias="showStats" show="True" propertyType="bool" /> + <property name="Source" alias="source" show="True" propertyType="contentTree" key="921e17a2-1b70-4d90-9448-85a378938096" /> + <property name="Umbraco fields to search" alias="searchFields" show="True" propertyType="text" key="230669fd-5cc3-4946-a307-474ebcf904c4" /> + <property name="Umbraco fields shown in results preview" alias="previewFields" show="True" propertyType="text" key="6b9168b8-d70a-4950-8d8d-056688b33dc9" /> + <property name="Display search box at TOP, BOTTOM, BOTH, or NONE" alias="searchBoxLocation" show="True" propertyType="text" key="6fc99a63-2f17-4906-a007-5aa918b526af" /> + <property name="Display BEGINNING or CONTEXT of each result" alias="previewType" show="True" propertyType="text" key="a89b2320-fabe-48d0-8949-a2d66fb9cd31" /> + <property name="Number of search results to display per page" alias="resultsPerPage" show="True" propertyType="number" key="fac01eb0-2cca-4980-b68d-eb1eb44e6896" /> + <property name="Number of characters of preview text to display" alias="previewChars" show="True" propertyType="number" key="ccb30dfa-3c00-452d-8a51-22bc2f3efd51" /> + <property name="Display 'Showing result X to Y'?" alias="showPageRange" show="True" propertyType="bool" key="0a10391a-b174-4980-bb6d-35a656687aca" /> + <property name="Display numbers before each result?" alias="showOrdinals" show="True" propertyType="bool" key="305d3c2d-f062-420c-83b8-be91f2efd56b" /> + <property name="Display search score for each result?" alias="showScores" show="True" propertyType="bool" key="ff8bc866-f58b-4d02-9bfe-87461f08ce39" /> + <property name="Display 'Searched X documents in Y seconds'?" alias="showStats" show="True" propertyType="bool" key="a3c8b300-9726-468e-b199-544f0f9145c7" /> </properties> </macro> </Macros> <DictionaryItems> - <DictionaryItem Key="XSLTsearch"> + <DictionaryItem Name="XSLTsearch" Key="26F5C64A-0BE5-448F-A443-3B09D6162D90"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[]]></Value> - <DictionaryItem Key="[XSLTsearch]Button-Search"> + <DictionaryItem Name="[XSLTsearch]Button-Search" Key="26F5C64A-0BE5-448F-A443-3B09D6162D99"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Search]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Description-Context"> + <DictionaryItem Name="[XSLTsearch]Description-Context" Key="26F5C64A-0BE5-448F-A443-3B09D6162D98"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Context]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Description-ContextUnavailable"> + <DictionaryItem Name="[XSLTsearch]Description-ContextUnavailable" Key="26F5C64A-0BE5-448F-A443-3B09D6162D97"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[unavailable]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Heading-SearchResults"> + <DictionaryItem Name="[XSLTsearch]Heading-SearchResults" Key="26F5C64A-0BE5-448F-A443-3B09D6162D96"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Search Results]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Navigation-Next"> + <DictionaryItem Name="[XSLTsearch]Navigation-Next" Key="26F5C64A-0BE5-448F-A443-3B09D6162D95"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Next]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Navigation-Previous"> + <DictionaryItem Name="[XSLTsearch]Navigation-Previous" Key="26F5C64A-0BE5-448F-A443-3B09D6162D94"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Previous]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]PageRange-ShowingResults"> + <DictionaryItem Name="[XSLTsearch]PageRange-ShowingResults" Key="26F5C64A-0BE5-448F-A443-3B09D6162D93"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Showing results]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]PageRange-To"> + <DictionaryItem Name="[XSLTsearch]PageRange-To" Key="26F5C64A-0BE5-448F-A443-3B09D6162D92"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[to]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Score-Score"> + <DictionaryItem Name="[XSLTsearch]Score-Score" Key="26F5C64A-0BE5-448F-A443-3B09D6162D91"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[score]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Stats-PagesIn"> + <DictionaryItem Name="[XSLTsearch]Stats-PagesIn" Key="56F5C64A-0BE5-448F-A443-3B09D6162D90"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[pages in]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Stats-Searched"> + <DictionaryItem Name="[XSLTsearch]Stats-Searched" Key="56F5C64A-0BE5-448F-A443-3B09D6162D99"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Searched]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Stats-Seconds"> + <DictionaryItem Name="[XSLTsearch]Stats-Seconds" Key="56F5C64A-0BE5-448F-A443-3B09D6162D98"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[seconds]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Summary-Matches"> + <DictionaryItem Name="[XSLTsearch]Summary-Matches" Key="56F5C64A-0BE5-448F-A443-3B09D6162D97"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[matches]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Summary-NoMatchesWereFoundFor"> + <DictionaryItem Name="[XSLTsearch]Summary-NoMatchesWereFoundFor" Key="56F5C64A-0BE5-448F-A443-3B09D6162D96"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[No matches were found for]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Summary-Page"> + <DictionaryItem Name="[XSLTsearch]Summary-Page" Key="56F5C64A-0BE5-448F-A443-3B09D6162D95"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[page]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Summary-Pages"> + <DictionaryItem Name="[XSLTsearch]Summary-Pages" Key="56F5C64A-0BE5-448F-A443-3B09D6162D94"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[pages]]></Value> </DictionaryItem> - <DictionaryItem Key="[XSLTsearch]Summary-YourSearchFor"> + <DictionaryItem Name="[XSLTsearch]Summary-YourSearchFor" Key="56F5C64A-0BE5-448F-A443-3B09D6162D93"> <Value LanguageId="1" LanguageCultureAlias="en-US"><![CDATA[Your search for]]></Value> </DictionaryItem> </DictionaryItem> diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/uBlogsy-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/uBlogsy-Package.xml index 175d5a5927..e5409ea1f6 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/uBlogsy-Package.xml +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/uBlogsy-Package.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<umbPackage> +<umbPackage> <info> <package> - <name>uBlogsy</name> + <name>uBlogsy</name> </package> </info> <Documents> @@ -148,6 +148,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] [Base]</Name> + <Key>4cc72906-14b1-4c98-a4f9-1720bb9bc2fd</Key> <Alias>uBlogsyBaseDocType</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -225,6 +226,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] [Base] Container</Name> + <Key>734354fd-dcda-4d5b-bf23-353534424484</Key> <Alias>uBlogsyBaseContainer</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -243,6 +245,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] [Base] Page</Name> + <Key>03c134a7-7ba9-4e60-95f3-9358c2a88235</Key> <Alias>uBlogsyBasePage</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -351,6 +354,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] Author</Name> + <Key>a148d057-e68f-455c-afb1-eacaa69de147</Key> <Alias>uBlogsyAuthor</Alias> <Icon>user.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -397,6 +401,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] Container - Author</Name> + <Key>e2aff474-6fb7-4ec1-8271-33214ac2ddd6</Key> <Alias>uBlogsyContainerAuthor</Alias> <Icon>folder_user.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -417,6 +422,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] Container - Email Template</Name> + <Key>42af53c7-df89-49cd-b84d-94b978defed5</Key> <Alias>uBlogsyContainerEmailTemplate</Alias> <Icon>folder_page_white.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -435,6 +441,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] Container - Label</Name> + <Key>277fe1af-9719-436e-8bb9-8aa31af6695d</Key> <Alias>uBlogsyContainerLabel</Alias> <Icon>folder_table.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -455,6 +462,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] Label</Name> + <Key>4e45c8dd-f5b1-454f-8042-43cb245e6764</Key> <Alias>uBlogsyLabel</Alias> <Icon>tag.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -490,6 +498,7 @@ http://feeds.feedburner.com/midcodecrisis <DocumentType> <Info> <Name>[uBlogsy] Landing</Name> + <Key>8789c927-0a55-408f-81b4-48a00cc3bb5b</Key> <Alias>uBlogsyLanding</Alias> <Icon>feed.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -523,7 +532,7 @@ http://feeds.feedburner.com/midcodecrisis <Description> <![CDATA[A list of blogs you want to follow. Make sure it's one per line. -e.g +e.g http://feeds.feedburner.com/midcodecrisis http://feeds.feedburner.com/umbracoblog]]> </Description> @@ -596,6 +605,7 @@ Selected by default.]]> <DocumentType> <Info> <Name>[uBlogsy] Page</Name> + <Key>38b8c863-915a-4f9e-aaa6-4c191c933fb6</Key> <Alias>uBlogsyPage</Alias> <Icon>page_white_cup.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -614,6 +624,7 @@ Selected by default.]]> <DocumentType> <Info> <Name>[uBlogsy] Post</Name> + <Key>937bb833-acef-4adc-8168-bf8e8f648d9d</Key> <Alias>uBlogsyPost</Alias> <Icon>page_green.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -704,6 +715,7 @@ Selected by default.]]> <DocumentType> <Info> <Name>[uBlogsy] RSS</Name> + <Key>74cb10d5-60e5-401a-a839-e7eb1140ea8a</Key> <Alias>uBlogsyRSS</Alias> <Icon>rss.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -766,6 +778,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uBlogsy] Site Root</Name> + <Key>8a4a40d1-0207-4f5f-aef1-cbcf57d6a408</Key> <Alias>uBlogsySiteRoot</Alias> <Icon>house.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -788,6 +801,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uDateFoldersy] [Base]</Name> + <Key>22b97d7d-a619-4193-8e30-3cb1c62d6af9</Key> <Alias>uDateFoldersyBase</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -805,6 +819,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uDateFoldersy] Folder - Day</Name> + <Key>629e17b1-e7f7-46a2-8125-7af73e584c8d</Key> <Alias>uDateFoldersyFolderDay</Alias> <Icon>calendar_view_day.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -826,6 +841,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uDateFoldersy] Folder - Month</Name> + <Key>5d0ce254-41b4-467d-9576-e760ac0a1df1</Key> <Alias>uDateFoldersyFolderMonth</Alias> <Icon>date.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -847,6 +863,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uDateFoldersy] Folder - Year</Name> + <Key>b1d6036a-c679-4d09-abc3-01d2153dde9c</Key> <Alias>uDateFoldersyFolderYear</Alias> <Icon>folder_table.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -868,6 +885,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uTagsy] [Base]</Name> + <Key>5d3d0cb1-bff8-49af-94a2-a22d9d2b2e80</Key> <Alias>uTagsyBaseDocType</Alias> <Icon>folder.gif</Icon> <Thumbnail>folder.png</Thumbnail> @@ -885,6 +903,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uTagsy] Tag</Name> + <Key>fd188722-5d01-46bc-9c34-4385c7fce5b4</Key> <Alias>uTagsyTag</Alias> <Icon>tag_blue.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -920,6 +939,7 @@ e.g Mid-code Crisis <DocumentType> <Info> <Name>[uTagsy] Tag Container</Name> + <Key>758dc50b-72ed-43cb-90e4-c3f9479cf535</Key> <Alias>uTagsyTagContainer</Alias> <Icon>tag_blue_add.png</Icon> <Thumbnail>folder.png</Thumbnail> @@ -971,9 +991,9 @@ e.g Mid-code Crisis @section uBlogsyMain { - <div id="uBlogsy"> + <div id="uBlogsy"> <div id="uBlogsy_main"> - + <section id="uBlogsy_left_col"> @RenderSection("uBlogsyLeftCol") </section> @@ -992,7 +1012,7 @@ e.g Mid-code Crisis @*the awesome tag cloud*@ @Html.CachedPartial("uBlogsy/Widgets/uBlogsyWidgetListTags", Model, 0, false, false, new ViewDataDictionary(ViewData) { { "ShowCount", true } }) - + @*list of latest posts*@ @Html.CachedPartial("uBlogsy/Widgets/uBlogsyWidgetListPosts", Model, 0, false, false, new ViewDataDictionary(ViewData) { { "ItemLimit", 5 } }) @@ -1000,7 +1020,7 @@ e.g Mid-code Crisis @try{ @Html.CachedPartial("uCommentsy/Widgets/uCommentsyWidgetListComments", Model, 0, false, false, new ViewDataDictionary(ViewData) { { "ItemLimit", 5 } }) }catch (Exception){} - + @*archive*@ @Html.CachedPartial("uBlogsy/Widgets/uBlogsyWidgetListPostArchive", Model, 600, false, false, new ViewDataDictionary(ViewData) { { "AltLayout", false } }) @@ -1008,7 +1028,7 @@ e.g Mid-code Crisis @Html.CachedPartial("uBlogsy/Widgets/uBlogsyWidgetListBlogRoll", Model, 600, false, false, new ViewDataDictionary(ViewData) { { "ItemLimit", 5 } }) </aside> </div> - + @Html.CachedPartial("uBlogsy/Global/uBlogsyGlobalFooter", Model, 0) </div> } @@ -1035,20 +1055,20 @@ e.g Mid-code Crisis <!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html lang="en-GB" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB" dir="ltr"> <head> - <title>My Site + My Site @RenderSection("uBlogsyHead") - + @*top navigation*@ @Html.CachedPartial("uBlogsy/Global/uBlogsyGlobalHeader", Model, 60, true) - + @*top navigation*@ @Html.CachedPartial("uBlogsy/Global/uBlogsyGlobalNavigation", Model, 60, true) - - + + @RenderSection("uBlogsyMain") - + }]]> @@ -1094,11 +1114,11 @@ e.g Mid-code Crisis @Umbraco.Field("uBlogsyContentBody") } - + @*list posts*@
- @Html.CachedPartial("uBlogsy/Landing/uBlogsyLandingListPosts", Model, 0, false, false, new ViewDataDictionary(ViewData) { { "ItemsPerPage", 20 } }) -
+ @Html.CachedPartial("uBlogsy/Landing/uBlogsyLandingListPosts", Model, 0, false, false, new ViewDataDictionary(ViewData) { { "ItemsPerPage", 20 } }) + } ]]> @@ -1152,7 +1172,7 @@ e.g Mid-code Crisis @inherits UmbracoTemplatePage @{ Layout = "_uBlogsyBaseBlog.cshtml"; - + var tag = Request.QueryString["tag"]; var label = Request.QueryString["label"]; var author = Request.QueryString["author"]; @@ -1165,7 +1185,7 @@ e.g Mid-code Crisis var prev = PostService.Instance.GetNextPost(Model.Content, tag, label, author, searchTerm, commenter, year, month, day); var next = PostService.Instance.GetPreviousPost(Model.Content, tag, label, author, searchTerm, commenter, year, month, day); } - + @section uBlogsyHead{} @section uBlogsyLeftCol{ @@ -1178,22 +1198,22 @@ e.g Mid-code Crisis var prevUrl = prev.Url.GetUrlWithQueryString(Request.QueryString, new[] { "action", "success" }); < @Umbraco.GetDictionaryValue("uBlogsyDicPaginationOlder") } - + @if (next != null) { - var nextUrl = next.Url.GetUrlWithQueryString(Request.QueryString, new[] { "action", "success" }); + var nextUrl = next.Url.GetUrlWithQueryString(Request.QueryString, new[] { "action", "success" }); @Umbraco.GetDictionaryValue("uBlogsyDicPaginationNewer") > } - + @Html.Partial("uBlogsy/Post/uBlogsyPostShowPost", new ViewDataDictionary(ViewData) { {"Node", Model.Content }, { "UseAddthis", true }, { "GravatarSize", 50 } }) - - + + @*list of related posts*@ @Html.Partial("uBlogsy/Post/uBlogsyPostListRelatedPosts", new ViewDataDictionary(ViewData) { { "Node", Model.Content }, { "ItemLimit", 5 }, { "MatchCount", 1 }, { "RelatedAlias", string.Empty } }) - + @*list comments - install uCommentsy, then uncomment this line*@ @try @@ -1201,7 +1221,7 @@ e.g Mid-code Crisis @Html.Partial("uCommentsy/uCommentsyListComments", new ViewDataDictionary(ViewData) { { "ItemLimit", -1 } }) } catch (Exception) { } - + @*render contact form - install uCommentsy, then uncomment this line**@ @try { @@ -1307,25 +1327,25 @@ e.g Mid-code Crisis } @section uBlogsyHead -{ +{ } @section uBlogsyMain { -
+

@Umbraco.Field("uBlogsyContentTitle")

- +
@Umbraco.Field("uBlogsyContentBody")
- + @* list posts for home - this only works if the home page is a parent, or sibling of uBlogsyLanding *@ - @Html.CachedPartial("uBlogsy/Widgets/uBlogsyWidgetListPostsForHome", Model, 0, false, true, new ViewDataDictionary(ViewData) { { "ItemLimit", 5 } }) + @Html.CachedPartial("uBlogsy/Widgets/uBlogsyWidgetListPostsForHome", Model, 0, false, true, new ViewDataDictionary(ViewData) { { "ItemLimit", 5 } })
} @@ -1353,18 +1373,18 @@ e.g Mid-code Crisis uBlogsy [uBlogsy] Show Some Love + 91AD32D5-7381-4C5A-BD03-97F3CE2511D2 uBlogsyShowSomeLove Unknown @@ -1695,56 +1716,56 @@ e.g Mid-code Crisis - + - + > - + > - + > - + > - + - + > - + > - + - + - + - + - + - + - + - + - + - + diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs index 66eba2d631..6395237ca9 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs @@ -29,16 +29,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [Authorize(Policy = AuthorizationPolicies.SectionAccessPackages)] public class PackageController : UmbracoAuthorizedJsonController { - private readonly IHostingEnvironment _hostingEnvironment; private readonly IPackagingService _packagingService; private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor; public PackageController( - IHostingEnvironment hostingEnvironment, IPackagingService packagingService, IBackOfficeSecurityAccessor backofficeSecurityAccessor) { - _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } From 585f7bb57135ab31e36b782b78e0e151d8503625 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 17 Jun 2021 09:40:07 +0200 Subject: [PATCH 35/38] 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 d7c0c6a93287d05257073a85d4cd4a491a4573c8 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 17 Jun 2021 18:00:49 +1000 Subject: [PATCH 36/38] Adjust the runtime state and keep disabling unattended package migrations simple (#10486) * Clean up and changes to backoffice for the nuget only packages * temp commit of package logic removal * Lots of package code cleanup and removal * Removes old package data from the test package xml * Updates packaging code to take in XDocument instead of a file since we'll not be dealing with files, starts creating expressions for the package migrations scripting. * fixing tests * Fixes runtime state and boot failed middleware so that it actually runs. Separates out unattended install/upgrade into notification handlers. * Gets unattended package migrations working and running * Gets embedded package.xml resources able to install from package migration. * Implements automatic package migrations for package that just declare an xml data manifest. * fix build * small cleanups * fix build * adds some tests * Fix export test * Fix newlines in test for linux * Typo * removes old todos and updates AutomaticPackgeMigrationPlan to use getter with backing field. * Update dictionary package data to use GUID * Ensures macros are packaged and used with their GUID * Ensures the GUID for doc types and media types remains consistent for package installation based on what is in the xml. * fix automatic migrations to not validate initial state, fixes packaging GUIDs for multiple entities. * Added guids to embedded test packages (Some tests are still failing) * Fix one more test * Fixes up Key vs Id, moves tests to correct namespace, fix tests * Fixes Dictionary packaging to ensure an xml hierarchy * Fixes tests * fixes package xml * Removes the runtime PackageMigrations state, the state is just run if unattended migrations are disabled. * change log level * Small clean up and reuse of attribute Co-authored-by: Bjarke Berg --- src/Umbraco.Core/Extensions/XmlExtensions.cs | 11 ++++++----- src/Umbraco.Core/RuntimeLevel.cs | 7 +------ .../Runtime/RuntimeState.cs | 17 ++++++++++++++--- .../Umbraco.Core/RuntimeStateTests.cs | 6 +++--- .../Routing/BackOfficeAreaRoutes.cs | 1 - .../Routing/PreviewRoutes.cs | 1 - 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Core/Extensions/XmlExtensions.cs b/src/Umbraco.Core/Extensions/XmlExtensions.cs index 8ad37bd93e..aa3fe25eef 100644 --- a/src/Umbraco.Core/Extensions/XmlExtensions.cs +++ b/src/Umbraco.Core/Extensions/XmlExtensions.cs @@ -8,6 +8,7 @@ using System.Text; using System.Xml; using System.Xml.Linq; using System.Xml.XPath; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Xml; namespace Umbraco.Extensions @@ -238,7 +239,7 @@ namespace Umbraco.Extensions { if (xml == null) { - throw new ArgumentNullException("xml"); + throw new ArgumentNullException(nameof(xml)); } if (xml.HasAttributes == false) @@ -246,19 +247,19 @@ namespace Umbraco.Extensions throw new InvalidOperationException($"{attributeName} not found in xml"); } - if (xml.Attribute(attributeName) == null) + XAttribute attribute = xml.Attribute(attributeName); + if (attribute is null) { throw new InvalidOperationException($"{attributeName} not found in xml"); } - var val = xml.Attribute(attributeName).Value; - var result = val.TryConvertTo(); + Attempt result = attribute.Value.TryConvertTo(); if (result.Success) { return result.Result; } - throw new InvalidOperationException($"{val} attribute value cannot be converted to {typeof(T)}"); + throw new InvalidOperationException($"{attribute.Value} attribute value cannot be converted to {typeof(T)}"); } public static T AttributeValue(this XElement xml, string attributeName) diff --git a/src/Umbraco.Core/RuntimeLevel.cs b/src/Umbraco.Core/RuntimeLevel.cs index 4330c33d94..d6687d4628 100644 --- a/src/Umbraco.Core/RuntimeLevel.cs +++ b/src/Umbraco.Core/RuntimeLevel.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Cms.Core +namespace Umbraco.Cms.Core { /// /// Describes the levels in which the runtime can run. @@ -32,11 +32,6 @@ /// Upgrade = 3, - /// - /// The runtime has detected that Package Migrations need to be executed. - /// - PackageMigrations = 4, - /// /// The runtime has detected an up-to-date Umbraco install and is running. /// diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index add276760f..42a7e0812d 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -144,9 +144,20 @@ namespace Umbraco.Cms.Infrastructure.Runtime break; case UmbracoDatabaseState.NeedsPackageMigration: - _logger.LogDebug("Package migrations need to execute."); - Level = _unattendedSettings.Value.PackageMigrationsUnattended ? RuntimeLevel.Run : RuntimeLevel.PackageMigrations; - Reason = RuntimeLevelReason.UpgradePackageMigrations; + // no matter what the level is run for package migrations. + // they either run unattended, or only manually via the back office. + Level = RuntimeLevel.Run; + + if (_unattendedSettings.Value.PackageMigrationsUnattended) + { + _logger.LogDebug("Package migrations need to execute."); + Reason = RuntimeLevelReason.UpgradePackageMigrations; + } + else + { + _logger.LogInformation("Package migrations need to execute but unattended package migrations is disabled. They will need to be run from the back office."); + Reason = RuntimeLevelReason.Run; + } break; case UmbracoDatabaseState.Ok: diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs index c9838361c6..60d36cb87b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs @@ -60,15 +60,15 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core } [Test] - public void GivenPackageMigrationsExist_WhenNotUnattendedMigrations_ThenLevelIsPackageMigrations() + public void GivenPackageMigrationsExist_WhenNotUnattendedMigrations_ThenLevelIsRun() { var unattendedOptions = Services.GetRequiredService>(); unattendedOptions.Value.PackageMigrationsUnattended = false; RuntimeState.DetermineRuntimeLevel(); - Assert.AreEqual(RuntimeLevel.PackageMigrations, RuntimeState.Level); - Assert.AreEqual(RuntimeLevelReason.UpgradePackageMigrations, RuntimeState.Reason); + Assert.AreEqual(RuntimeLevel.Run, RuntimeState.Level); + Assert.AreEqual(RuntimeLevelReason.Run, RuntimeState.Reason); } private class TestMigrationPlan : PackageMigrationPlan diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index 3f171d6439..13d57ccc43 100644 --- a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -48,7 +48,6 @@ namespace Umbraco.Cms.Web.BackOffice.Routing { case RuntimeLevel.Install: case RuntimeLevel.Upgrade: - case RuntimeLevel.PackageMigrations: case RuntimeLevel.Run: MapMinimalBackOffice(endpoints); diff --git a/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs index 15012728d9..bda08d0d87 100644 --- a/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs @@ -36,7 +36,6 @@ namespace Umbraco.Cms.Web.BackOffice.Routing { case RuntimeLevel.Install: case RuntimeLevel.Upgrade: - case RuntimeLevel.PackageMigrations: case RuntimeLevel.Run: endpoints.MapHub(GetPreviewHubRoute()); endpoints.MapUmbracoRoute(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, null); From 6a35e0c62bd8803056ec5cfb45816585c0a71fa3 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 17 Jun 2021 11:04:16 +0200 Subject: [PATCH 37/38] 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 38/38] 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); })();