diff --git a/build/templates/UmbracoProject/UmbracoProject.csproj b/build/templates/UmbracoProject/UmbracoProject.csproj
index 6b0f92858d..99e72bae0f 100644
--- a/build/templates/UmbracoProject/UmbracoProject.csproj
+++ b/build/templates/UmbracoProject/UmbracoProject.csproj
@@ -8,6 +8,12 @@
$(DefaultItemExcludes);wwwroot/media/**;
+
+
+
+
+
+
@@ -30,6 +36,10 @@
+
+ true
+
+
false
diff --git a/src/JsonSchema/AppSettings.cs b/src/JsonSchema/AppSettings.cs
index 4045421eb1..1b7c6d46fc 100644
--- a/src/JsonSchema/AppSettings.cs
+++ b/src/JsonSchema/AppSettings.cs
@@ -47,6 +47,7 @@ namespace JsonSchema
public RichTextEditorSettings RichTextEditor { get; set; }
public RuntimeMinificationSettings RuntimeMinification { get; set; }
public BasicAuthSettings BasicAuth { get; set; }
+ public PackageMigrationSettings PackageMigration { get; set; }
}
///
diff --git a/src/Umbraco.Core/Configuration/Models/PackageMigrationSettings.cs b/src/Umbraco.Core/Configuration/Models/PackageMigrationSettings.cs
new file mode 100644
index 0000000000..27968fdcd2
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/Models/PackageMigrationSettings.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Umbraco.
+// See LICENSE for more details.
+
+using System.ComponentModel;
+
+namespace Umbraco.Cms.Core.Configuration.Models
+{
+ ///
+ /// Typed configuration options for package migration settings.
+ ///
+ [UmbracoOptions(Constants.Configuration.ConfigPackageMigration)]
+ public class PackageMigrationSettings
+ {
+ private const bool StaticRunSchemaAndContentMigrations = true;
+ private const bool StaticAllowComponentOverrideOfRunSchemaAndContentMigrations = true;
+
+ ///
+ /// Gets or sets a value indicating whether package migration steps that install schema and content should run.
+ ///
+ ///
+ /// By default this is true and schema and content defined in a package migration are installed.
+ /// Using configuration, administrators can optionally switch this off in certain environments.
+ /// Deployment tools such as Umbraco Deploy can also configure this option to run or not run these migration
+ /// steps as is appropriate for normal use of the tool.
+ ///
+ [DefaultValue(StaticRunSchemaAndContentMigrations)]
+ public bool RunSchemaAndContentMigrations { get; set; } = StaticRunSchemaAndContentMigrations;
+
+ ///
+ /// Gets or sets a value indicating whether components can override the configured value for .
+ ///
+ ///
+ /// By default this is true and components can override the configured setting for .
+ /// If an administrator wants explicit control over which environments migration steps installing schema and content can run,
+ /// they can set this to false. Components should respect this and not override the configuration.
+ ///
+ [DefaultValue(StaticAllowComponentOverrideOfRunSchemaAndContentMigrations)]
+ public bool AllowComponentOverrideOfRunSchemaAndContentMigrations { get; set; } = StaticAllowComponentOverrideOfRunSchemaAndContentMigrations;
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/Models/RuntimeMinificationSettings.cs b/src/Umbraco.Core/Configuration/Models/RuntimeMinificationSettings.cs
index b03528fd0a..fe999f7bc0 100644
--- a/src/Umbraco.Core/Configuration/Models/RuntimeMinificationSettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/RuntimeMinificationSettings.cs
@@ -7,6 +7,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
{
internal const bool StaticUseInMemoryCache = false;
internal const string StaticCacheBuster = "Version";
+ internal const string StaticVersion = null;
///
/// Use in memory cache
@@ -19,5 +20,11 @@ namespace Umbraco.Cms.Core.Configuration.Models
///
[DefaultValue(StaticCacheBuster)]
public RuntimeMinificationCacheBuster CacheBuster { get; set; } = Enum.Parse(StaticCacheBuster);
+
+ ///
+ /// The unique version string used if CacheBuster is 'Version'.
+ ///
+ [DefaultValue(StaticVersion)]
+ public string Version { get; set; } = StaticVersion;
}
}
diff --git a/src/Umbraco.Core/Configuration/Models/UnattendedSettings.cs b/src/Umbraco.Core/Configuration/Models/UnattendedSettings.cs
index 08020f6e89..7103a9534e 100644
--- a/src/Umbraco.Core/Configuration/Models/UnattendedSettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/UnattendedSettings.cs
@@ -1,17 +1,19 @@
-using System.ComponentModel;
+// Copyright (c) Umbraco.
+// See LICENSE for more details.
+
+using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Umbraco.Cms.Core.Configuration.Models
{
-
///
/// Typed configuration options for unattended settings.
///
[UmbracoOptions(Constants.Configuration.ConfigUnattended)]
public class UnattendedSettings
{
- internal const bool StaticInstallUnattended = false;
- internal const bool StaticUpgradeUnattended = false;
+ private const bool StaticInstallUnattended = false;
+ private const bool StaticUpgradeUnattended = false;
///
/// Gets or sets a value indicating whether unattended installs are enabled.
diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs
index 0c7657d07e..c36f5813ab 100644
--- a/src/Umbraco.Core/Constants-Configuration.cs
+++ b/src/Umbraco.Core/Constants-Configuration.cs
@@ -52,6 +52,7 @@
public const string ConfigWebRouting = ConfigPrefix + "WebRouting";
public const string ConfigUserPassword = ConfigPrefix + "Security:UserPassword";
public const string ConfigRichTextEditor = ConfigPrefix + "RichTextEditor";
+ public const string ConfigPackageMigration = ConfigPrefix + "PackageMigration";
}
}
}
diff --git a/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs b/src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs
similarity index 64%
rename from src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs
rename to src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs
index c73685b41d..8d195c56f4 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs
+++ b/src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs
@@ -4,22 +4,22 @@ using System.ComponentModel;
namespace Umbraco.Cms.Web.Common.DependencyInjection
{
///
- /// INTERNAL Service locator. Should only be used if no other ways exist.
+ /// Service locator for internal (umbraco cms) only purposes. Should only be used if no other ways exist.
///
///
/// It is created with only two goals in mind
/// 1) Continue to have the same extension methods on IPublishedContent and IPublishedElement as in V8. To make migration easier.
- /// 2) To have a tool to avoid breaking changes in minor versions. All methods using this should in theory be obsolete.
+ /// 2) To have a tool to avoid breaking changes in minor and patch versions. All methods using this should in theory be obsolete.
///
/// Keep in mind, every time this is used, the code becomes basically untestable.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- internal static class StaticServiceProvider
+ public static class StaticServiceProvider
{
///
/// The service locator.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- internal static IServiceProvider Instance { get; set; }
+ public static IServiceProvider Instance { get; set; }
}
}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs
index 77902cc5c1..9b31ed7056 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs
@@ -72,7 +72,8 @@ namespace Umbraco.Cms.Core.DependencyInjection
.AddUmbracoOptions()
.AddUmbracoOptions()
.AddUmbracoOptions()
- .AddUmbracoOptions();
+ .AddUmbracoOptions()
+ .AddUmbracoOptions();
return builder;
}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
index 6f6a53df66..bf3b3edaf9 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
@@ -38,6 +38,7 @@ using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Core.Templates;
using Umbraco.Cms.Core.Web;
+using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.DependencyInjection
diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs
index 2aa74474d1..42ac9f7ef0 100644
--- a/src/Umbraco.Core/Packaging/InstallationSummary.cs
+++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs
@@ -32,6 +32,7 @@ namespace Umbraco.Cms.Core.Packaging
public IEnumerable PartialViewsInstalled { get; set; } = Enumerable.Empty();
public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty();
public IEnumerable MediaInstalled { get; set; } = Enumerable.Empty();
+ public IEnumerable EntityContainersInstalled { get; set; } = Enumerable.Empty();
public override string ToString()
{
@@ -77,6 +78,7 @@ namespace Umbraco.Cms.Core.Packaging
WriteCount("Stylesheets installed: ", StylesheetsInstalled);
WriteCount("Scripts installed: ", ScriptsInstalled);
WriteCount("Partial views installed: ", PartialViewsInstalled);
+ WriteCount("Entity containers installed: ", EntityContainersInstalled);
WriteCount("Content items installed: ", ContentInstalled);
WriteCount("Media items installed: ", MediaInstalled, false);
diff --git a/src/Umbraco.Core/Routing/PublishedRouter.cs b/src/Umbraco.Core/Routing/PublishedRouter.cs
index 548387a675..590262946d 100644
--- a/src/Umbraco.Core/Routing/PublishedRouter.cs
+++ b/src/Umbraco.Core/Routing/PublishedRouter.cs
@@ -237,7 +237,7 @@ namespace Umbraco.Cms.Core.Routing
// re-route
await RouteRequestInternalAsync(builder);
-
+
// return if we are redirect
if (builder.IsRedirect())
{
@@ -252,6 +252,11 @@ namespace Umbraco.Cms.Core.Routing
builder.SetPublishedContent(content);
}
+ if (!builder.HasDomain())
+ {
+ FindDomain(builder);
+ }
+
return BuildRequest(builder);
}
diff --git a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs
index c14d3e5119..fef61a54c3 100644
--- a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs
+++ b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs
@@ -1,8 +1,9 @@
using System;
using System.Xml.Linq;
+using Microsoft.Extensions.Options;
+using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.PropertyEditors;
-using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.Migrations;
@@ -20,7 +21,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
MediaUrlGeneratorCollection mediaUrlGenerators,
IShortStringHelper shortStringHelper,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
- IMigrationContext context)
+ IMigrationContext context,
+ IOptions options)
: base(new ImportPackageBuilderExpression(
packagingService,
mediaService,
@@ -28,7 +30,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
mediaUrlGenerators,
shortStringHelper,
contentTypeBaseServiceProvider,
- context))
+ context,
+ options))
{
}
diff --git a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs
index 8eda0f0b45..838d59e14e 100644
--- a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs
+++ b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs
@@ -5,7 +5,9 @@ using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Packaging;
@@ -25,7 +27,9 @@ namespace Umbraco.Cms.Infrastructure.Packaging
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly IPackagingService _packagingService;
private readonly IShortStringHelper _shortStringHelper;
- private bool _executed;
+ private readonly PackageMigrationSettings _packageMigrationSettings;
+
+ private bool _executed;
public ImportPackageBuilderExpression(
IPackagingService packagingService,
@@ -34,7 +38,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
MediaUrlGeneratorCollection mediaUrlGenerators,
IShortStringHelper shortStringHelper,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
- IMigrationContext context) : base(context)
+ IMigrationContext context,
+ IOptions packageMigrationSettings) : base(context)
{
_packagingService = packagingService;
_mediaService = mediaService;
@@ -42,6 +47,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_mediaUrlGenerators = mediaUrlGenerators;
_shortStringHelper = shortStringHelper;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
+ _packageMigrationSettings = packageMigrationSettings.Value;
}
///
@@ -59,6 +65,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
}
_executed = true;
+
Context.BuildingExpression = false;
if (EmbeddedResourceMigrationType == null && PackageDataManifest == null)
@@ -67,6 +74,12 @@ namespace Umbraco.Cms.Infrastructure.Packaging
$"Nothing to execute, neither {nameof(EmbeddedResourceMigrationType)} or {nameof(PackageDataManifest)} has been set.");
}
+ if (!_packageMigrationSettings.RunSchemaAndContentMigrations)
+ {
+ Logger.LogInformation("Skipping import of embedded schema file, due to configuration");
+ return;
+ }
+
InstallationSummary installationSummary;
if (EmbeddedResourceMigrationType != null)
{
diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs
index c691b74a0c..5c9942f945 100644
--- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs
+++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs
@@ -91,19 +91,25 @@ namespace Umbraco.Cms.Infrastructure.Packaging
var installationSummary = new InstallationSummary(compiledPackage.Name)
{
Warnings = compiledPackage.Warnings,
- DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId),
+ DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId, out IEnumerable dataTypeEntityContainersInstalled),
LanguagesInstalled = ImportLanguages(compiledPackage.Languages, userId),
DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId),
MacrosInstalled = ImportMacros(compiledPackage.Macros, userId),
MacroPartialViewsInstalled = ImportMacroPartialViews(compiledPackage.MacroPartialViews, userId),
TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId),
- DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId),
- MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId),
+ DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId, out IEnumerable documentTypeEntityContainersInstalled),
+ MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId, out IEnumerable mediaTypeEntityContainersInstalled),
StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId),
ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId),
PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId)
};
+ var entityContainersInstalled = new List();
+ entityContainersInstalled.AddRange(dataTypeEntityContainersInstalled);
+ entityContainersInstalled.AddRange(documentTypeEntityContainersInstalled);
+ entityContainersInstalled.AddRange(mediaTypeEntityContainersInstalled);
+ installationSummary.EntityContainersInstalled = entityContainersInstalled;
+
// We need a reference to the imported doc types to continue
var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x);
var importedMediaTypes = installationSummary.MediaTypesInstalled.ToDictionary(x => x.Alias, x => x);
@@ -116,6 +122,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
return installationSummary;
}
}
+
///
/// Imports and saves package xml as
///
@@ -123,7 +130,17 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// Optional id of the User performing the operation. Default is zero (admin).
/// An enumerable list of generated ContentTypes
public IReadOnlyList ImportMediaTypes(IEnumerable docTypeElements, int userId)
- => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService);
+ => ImportMediaTypes(docTypeElements, userId, out _);
+
+ ///
+ /// Imports and saves package xml as
+ ///
+ /// Xml to import
+ /// Optional id of the User performing the operation. Default is zero (admin).
+ /// Collection of entity containers installed by the package to be populated with those created in installing data types.
+ /// An enumerable list of generated ContentTypes
+ public IReadOnlyList ImportMediaTypes(IEnumerable docTypeElements, int userId, out IEnumerable entityContainersInstalled)
+ => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService, out entityContainersInstalled);
#endregion
@@ -408,7 +425,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
#region DocumentTypes
public IReadOnlyList ImportDocumentType(XElement docTypeElement, int userId)
- => ImportDocumentTypes(new[] { docTypeElement }, userId);
+ => ImportDocumentTypes(new[] { docTypeElement }, userId, out _);
///
/// Imports and saves package xml as
@@ -417,7 +434,17 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// Optional id of the User performing the operation. Default is zero (admin).
/// An enumerable list of generated ContentTypes
public IReadOnlyList ImportDocumentTypes(IEnumerable docTypeElements, int userId)
- => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService);
+ => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService, out _);
+
+ ///
+ /// Imports and saves package xml as
+ ///
+ /// Xml to import
+ /// Optional id of the User performing the operation. Default is zero (admin).
+ /// Collection of entity containers installed by the package to be populated with those created in installing data types.
+ /// An enumerable list of generated ContentTypes
+ public IReadOnlyList ImportDocumentTypes(IEnumerable docTypeElements, int userId, out IEnumerable entityContainersInstalled)
+ => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService, out entityContainersInstalled);
///
/// Imports and saves package xml as
@@ -428,6 +455,18 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// An enumerable list of generated ContentTypes
public IReadOnlyList ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService service)
where T : class, IContentTypeComposition
+ => ImportDocumentTypes(unsortedDocumentTypes, importStructure, userId, service);
+
+ ///
+ /// Imports and saves package xml as
+ ///
+ /// Xml to import
+ /// Boolean indicating whether or not to import the
+ /// Optional id of the User performing the operation. Default is zero (admin).
+ /// Collection of entity containers installed by the package to be populated with those created in installing data types.
+ /// An enumerable list of generated ContentTypes
+ public IReadOnlyList ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService service, out IEnumerable entityContainersInstalled)
+ where T : class, IContentTypeComposition
{
var importedContentTypes = new Dictionary();
@@ -436,7 +475,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
var graph = new TopoGraph>(x => x.Key, x => x.Dependencies);
var isSingleDocTypeImport = unsortedDocumentTypes.Count == 1;
- var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes);
+ var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes, out entityContainersInstalled);
if (isSingleDocTypeImport == false)
{
@@ -532,9 +571,10 @@ namespace Umbraco.Cms.Infrastructure.Packaging
return list;
}
- private Dictionary CreateContentTypeFolderStructure(IEnumerable unsortedDocumentTypes)
+ private Dictionary CreateContentTypeFolderStructure(IEnumerable unsortedDocumentTypes, out IEnumerable entityContainersInstalled)
{
var importedFolders = new Dictionary();
+ var trackEntityContainersInstalled = new List();
foreach (var documentType in unsortedDocumentTypes)
{
var foldersAttribute = documentType.Attribute("Folders");
@@ -578,8 +618,10 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder);
throw tryCreateFolder.Exception;
}
+
var rootFolderId = tryCreateFolder.Result.Entity.Id;
current = _contentTypeService.GetContainer(rootFolderId);
+ trackEntityContainersInstalled.Add(current);
}
importedFolders.Add(alias, current.Id);
@@ -589,11 +631,13 @@ namespace Umbraco.Cms.Infrastructure.Packaging
var folderName = WebUtility.UrlDecode(folders[i]);
Guid? folderKey = (folderKeys.Length == folders.Length) ? folderKeys[i] : null;
current = CreateContentTypeChildFolder(folderName, folderKey ?? Guid.NewGuid(), current);
+ trackEntityContainersInstalled.Add(current);
importedFolders[alias] = current.Id;
}
}
}
+ entityContainersInstalled = trackEntityContainersInstalled;
return importedFolders;
}
@@ -1012,10 +1056,20 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// Optional id of the user
/// An enumerable list of generated DataTypeDefinitions
public IReadOnlyList ImportDataTypes(IReadOnlyCollection dataTypeElements, int userId)
+ => ImportDataTypes(dataTypeElements, userId, out _);
+
+ ///
+ /// Imports and saves package xml as
+ ///
+ /// Xml to import
+ /// Optional id of the user
+ /// Collection of entity containers installed by the package to be populated with those created in installing data types.
+ /// An enumerable list of generated DataTypeDefinitions
+ public IReadOnlyList ImportDataTypes(IReadOnlyCollection dataTypeElements, int userId, out IEnumerable entityContainersInstalled)
{
var dataTypes = new List();
- var importedFolders = CreateDataTypeFolderStructure(dataTypeElements);
+ var importedFolders = CreateDataTypeFolderStructure(dataTypeElements, out entityContainersInstalled);
foreach (var dataTypeElement in dataTypeElements)
{
@@ -1072,9 +1126,10 @@ namespace Umbraco.Cms.Infrastructure.Packaging
return dataTypes;
}
- private Dictionary CreateDataTypeFolderStructure(IEnumerable datatypeElements)
+ private Dictionary CreateDataTypeFolderStructure(IEnumerable datatypeElements, out IEnumerable entityContainersInstalled)
{
var importedFolders = new Dictionary();
+ var trackEntityContainersInstalled = new List();
foreach (var datatypeElement in datatypeElements)
{
var foldersAttribute = datatypeElement.Attribute("Folders");
@@ -1103,7 +1158,9 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder);
throw tryCreateFolder.Exception;
}
+
current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
+ trackEntityContainersInstalled.Add(current);
}
importedFolders.Add(name, current.Id);
@@ -1113,11 +1170,12 @@ namespace Umbraco.Cms.Infrastructure.Packaging
var folderName = WebUtility.UrlDecode(folders[i]);
Guid? folderKey = (folderKeys.Length == folders.Length) ? folderKeys[i] : null;
current = CreateDataTypeChildFolder(folderName, folderKey ?? Guid.NewGuid(), current);
+ trackEntityContainersInstalled.Add(current);
importedFolders[name] = current.Id;
}
}
}
-
+ entityContainersInstalled = trackEntityContainersInstalled;
return importedFolders;
}
diff --git a/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs b/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs
index 3166cdbd4f..54b96955d4 100644
--- a/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs
+++ b/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs
@@ -1,12 +1,17 @@
+using System;
+using System.ComponentModel;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.Migrations;
+using Umbraco.Cms.Web.Common.DependencyInjection;
namespace Umbraco.Cms.Infrastructure.Packaging
{
-
public abstract class PackageMigrationBase : MigrationBase
{
private readonly IPackagingService _packagingService;
@@ -15,6 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly IShortStringHelper _shortStringHelper;
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
+ private readonly IOptions _packageMigrationsSettings;
public PackageMigrationBase(
IPackagingService packagingService,
@@ -23,7 +29,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
MediaUrlGeneratorCollection mediaUrlGenerators,
IShortStringHelper shortStringHelper,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
- IMigrationContext context)
+ IMigrationContext context,
+ IOptions packageMigrationsSettings)
: base(context)
{
_packagingService = packagingService;
@@ -32,6 +39,29 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_mediaUrlGenerators = mediaUrlGenerators;
_shortStringHelper = shortStringHelper;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
+ _packageMigrationsSettings = packageMigrationsSettings;
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete("Use ctor with all params")]
+ public PackageMigrationBase(
+ IPackagingService packagingService,
+ IMediaService mediaService,
+ MediaFileManager mediaFileManager,
+ MediaUrlGeneratorCollection mediaUrlGenerators,
+ IShortStringHelper shortStringHelper,
+ IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
+ IMigrationContext context)
+ : this(
+ packagingService,
+ mediaService,
+ mediaFileManager,
+ mediaUrlGenerators,
+ shortStringHelper,
+ contentTypeBaseServiceProvider,
+ context,
+ StaticServiceProvider.Instance.GetRequiredService>())
+ {
}
public IImportPackageBuilder ImportPackage => BeginBuild(
@@ -42,7 +72,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_mediaUrlGenerators,
_shortStringHelper,
_contentTypeBaseServiceProvider,
- Context));
+ Context,
+ _packageMigrationsSettings));
}
}
diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs
index 2e9fb6cebc..0b874a80c2 100644
--- a/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs
+++ b/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs
@@ -1,7 +1,5 @@
using System;
-using System.Reflection;
using NPoco;
-using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Persistence
{
@@ -18,6 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence
/// So far, this is very manual. We don't try to be clever and figure out whether the
/// columns exist already. We just ignore it.
/// Beware, the application MUST restart when this class behavior changes.
+ /// You can override the GetColmunnInfo method to control which columns this includes
///
internal class UmbracoPocoDataBuilder : PocoDataBuilder
{
@@ -28,19 +27,5 @@ namespace Umbraco.Cms.Infrastructure.Persistence
{
_upgrading = upgrading;
}
-
- protected override ColumnInfo GetColumnInfo(MemberInfo mi, Type type)
- {
- var columnInfo = base.GetColumnInfo(mi, type);
-
- // TODO: Is this upgrade flag still relevant? It's a lot of hacking to just set this value
- // including the interface method ConfigureForUpgrade for this one circumstance.
- if (_upgrading)
- {
- if (type == typeof(UserDto) && mi.Name == "TourData") columnInfo.IgnoreColumn = true;
- }
-
- return columnInfo;
- }
}
}
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index ad35cbf30a..4ec87dfde7 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -1,9 +1,9 @@
using System;
+using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
-using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Exceptions;
@@ -13,7 +13,9 @@ using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Runtime;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence;
+using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
+using ComponentCollection = Umbraco.Cms.Core.Composing.ComponentCollection;
namespace Umbraco.Cms.Infrastructure.Runtime
{
@@ -27,6 +29,9 @@ namespace Umbraco.Cms.Infrastructure.Runtime
private readonly IMainDom _mainDom;
private readonly IUmbracoDatabaseFactory _databaseFactory;
private readonly IEventAggregator _eventAggregator;
+ private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IUmbracoVersion _umbracoVersion;
+ private readonly IServiceProvider _serviceProvider;
private CancellationToken _cancellationToken;
///
@@ -40,7 +45,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime
IProfilingLogger profilingLogger,
IMainDom mainDom,
IUmbracoDatabaseFactory databaseFactory,
- IEventAggregator eventAggregator)
+ IEventAggregator eventAggregator,
+ IHostingEnvironment hostingEnvironment,
+ IUmbracoVersion umbracoVersion,
+ IServiceProvider serviceProvider)
{
State = state;
_loggerFactory = loggerFactory;
@@ -50,9 +58,42 @@ namespace Umbraco.Cms.Infrastructure.Runtime
_mainDom = mainDom;
_databaseFactory = databaseFactory;
_eventAggregator = eventAggregator;
+ _hostingEnvironment = hostingEnvironment;
+ _umbracoVersion = umbracoVersion;
+ _serviceProvider = serviceProvider;
_logger = _loggerFactory.CreateLogger();
}
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete]
+ public CoreRuntime(
+ ILoggerFactory loggerFactory,
+ IRuntimeState state,
+ ComponentCollection components,
+ IApplicationShutdownRegistry applicationShutdownRegistry,
+ IProfilingLogger profilingLogger,
+ IMainDom mainDom,
+ IUmbracoDatabaseFactory databaseFactory,
+ IEventAggregator eventAggregator,
+ IHostingEnvironment hostingEnvironment,
+ IUmbracoVersion umbracoVersion
+ ):this(
+ loggerFactory,
+ state,
+ components,
+ applicationShutdownRegistry,
+ profilingLogger,
+ mainDom,
+ databaseFactory,
+ eventAggregator,
+ hostingEnvironment,
+ umbracoVersion,
+ null
+ )
+ {
+
+ }
+
///
/// Gets the state of the Umbraco runtime.
///
@@ -70,6 +111,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
{
_cancellationToken = cancellationToken;
StaticApplicationLogging.Initialize(_loggerFactory);
+ StaticServiceProvider.Instance = _serviceProvider;
AppDomain.CurrentDomain.UnhandledException += (_, args) =>
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs
index a982ed1744..58f3622e67 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs
@@ -279,6 +279,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
"memberTypeApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl(
controller => controller.GetAllTypes())
},
+ {
+ "memberTypeQueryApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl(
+ controller => controller.GetAllTypes())
+ },
{
"memberGroupApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl(
controller => controller.GetAllGroups())
diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs
index 4af907bdfc..7c1f6f4187 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs
@@ -182,6 +182,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
///
/// Returns all member types
///
+ [Obsolete("Use MemberTypeQueryController.GetAllTypes instead as it only requires AuthorizationPolicies.TreeAccessMembersOrMemberTypes and not both this and AuthorizationPolicies.TreeAccessMemberTypes")]
[Authorize(Policy = AuthorizationPolicies.TreeAccessMembersOrMemberTypes)]
public IEnumerable GetAllTypes()
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeQueryController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeQueryController.cs
new file mode 100644
index 0000000000..1d15a6448a
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeQueryController.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.AspNetCore.Authorization;
+using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Models.ContentEditing;
+using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Web.Common.Attributes;
+using Umbraco.Cms.Web.Common.Authorization;
+using Constants = Umbraco.Cms.Core.Constants;
+
+namespace Umbraco.Cms.Web.BackOffice.Controllers
+{
+ ///
+ /// An API controller used for dealing with member types
+ ///
+ [PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
+ [Authorize(Policy = AuthorizationPolicies.TreeAccessMembersOrMemberTypes)]
+ public class MemberTypeQueryController : BackOfficeNotificationsController
+ {
+ private readonly IMemberTypeService _memberTypeService;
+ private readonly IUmbracoMapper _umbracoMapper;
+
+
+ public MemberTypeQueryController(
+ IMemberTypeService memberTypeService,
+ IUmbracoMapper umbracoMapper)
+ {
+ _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService));
+ _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
+ }
+
+ ///
+ /// Returns all member types
+ ///
+ public IEnumerable GetAllTypes() =>
+ _memberTypeService.GetAll()
+ .Select(_umbracoMapper.Map);
+
+ }
+}
diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs
index 7e62e514f7..672495c7eb 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs
@@ -557,7 +557,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
// i.e. "Some Person"
var toMailBoxAddress = new MailboxAddress(to.Name, to.Email);
- var mailMessage = new EmailMessage(fromEmail, toMailBoxAddress.ToString(), emailSubject, emailBody, true);
+ var mailMessage = new EmailMessage(null /*use info from smtp settings*/, toMailBoxAddress.ToString(), emailSubject, emailBody, true);
await _emailSender.SendAsync(mailMessage, Constants.Web.EmailTypes.UserInvite, true);
}
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoApplicationServicesCapture.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoApplicationServicesCapture.cs
deleted file mode 100644
index fa5adf7aeb..0000000000
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoApplicationServicesCapture.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-
-namespace Umbraco.Cms.Web.Common.DependencyInjection
-{
- ///
- /// A registered to automatically capture application services
- ///
- internal class UmbracoApplicationServicesCapture : IStartupFilter
- {
- ///
- public Action Configure(Action next) =>
- app =>
- {
- StaticServiceProvider.Instance = app.ApplicationServices;
- next(app);
- };
- }
-}
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs
index 62573cfc7b..6755159fc1 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs
+++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs
@@ -54,8 +54,14 @@ namespace Umbraco.Extensions
.Configure(options => options.CacheFolder = builder.BuilderHostingEnvironment.MapPathContentRoot(imagingSettings.Cache.CacheFolder))
// We need to add CropWebProcessor before ResizeWebProcessor (until https://github.com/SixLabors/ImageSharp.Web/issues/182 is fixed)
.RemoveProcessor()
+ .RemoveProcessor()
+ .RemoveProcessor()
+ .RemoveProcessor()
.AddProcessor()
- .AddProcessor();
+ .AddProcessor()
+ .AddProcessor()
+ .AddProcessor()
+ .AddProcessor();
builder.Services.AddTransient, ImageSharpConfigurationOptions>();
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
index ef98553ba2..2d584f198e 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -123,10 +123,6 @@ namespace Umbraco.Extensions
config,
profiler);
- // adds the umbraco startup filter which will call UseUmbraco early on before
- // other start filters are applied (depending on the ordering of IStartupFilters in DI).
- services.AddTransient();
-
return new UmbracoBuilder(services, config, typeLoader, loggerFactory, profiler, appCaches, tempHostingEnvironment);
}
diff --git a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs
index 4817956ef8..cc07b6bd28 100644
--- a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs
+++ b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs
@@ -362,7 +362,7 @@ namespace Umbraco.Cms.Web.Common.Security
{
// Store the userId for use after two factor check
var userId = await UserManager.GetUserIdAsync(user);
- await Context.SignInAsync(IdentityConstants.TwoFactorUserIdScheme, StoreTwoFactorInfo(userId, loginProvider));
+ await Context.SignInAsync(TwoFactorAuthenticationType, StoreTwoFactorInfo(userId, loginProvider));
return SignInResult.TwoFactorRequired;
}
}
@@ -372,7 +372,7 @@ namespace Umbraco.Cms.Web.Common.Security
await Context.SignOutAsync(ExternalAuthenticationType);
}
if (loginProvider == null)
- {
+ {
await SignInWithClaimsAsync(user, isPersistent, new Claim[] { new Claim("amr", "pwd") });
}
else
diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
index fcd62febf4..537df5aab4 100644
--- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
+++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
@@ -48,5 +48,4 @@
<_Parameter1>Umbraco.Tests.UnitTests
-
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js
index bf02d9618e..e1d0fbe8ac 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js
@@ -46,10 +46,10 @@ function memberTypeResource($q, $http, umbRequestHelper, umbDataFormatter, local
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
- "memberTypeApiBaseUrl",
+ "memberTypeQueryApiBaseUrl",
"GetAllTypes")),
'Failed to retrieve data for member types id');
- },
+ },
getById: function (id) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js
index 1a2f0735ce..aa10d5bf2f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js
@@ -16,7 +16,7 @@
partialViewName = parentId + "/" + partialViewName;
}
- return "@Html.Partial(\"" + partialViewName + "\")";
+ return "@await Html.PartialAsync(\"" + partialViewName + "\")";
}
function getQuerySnippet(queryExpression) {
diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js
index 316cfa7c59..69da0ce786 100644
--- a/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js
+++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js
@@ -26,28 +26,28 @@ describe('service: templateHelper', function () {
it('should return the snippet for inserting a partial from the root', function () {
var parentId = "";
var nodeName = "Footer.cshtml";
- var snippet = '@Html.Partial("Footer")';
+ var snippet = '@await Html.PartialAsync("Footer")';
expect(templateHelper.getInsertPartialSnippet(parentId, nodeName)).toBe(snippet);
});
it('should return the snippet for inserting a partial from a folder', function () {
var parentId = "Folder";
var nodeName = "Footer.cshtml";
- var snippet = '@Html.Partial("Folder/Footer")';
+ var snippet = '@await Html.PartialAsync("Folder/Footer")';
expect(templateHelper.getInsertPartialSnippet(parentId, nodeName)).toBe(snippet);
});
it('should return the snippet for inserting a partial from a nested folder', function () {
var parentId = "Folder/NestedFolder";
var nodeName = "Footer.cshtml";
- var snippet = '@Html.Partial("Folder/NestedFolder/Footer")';
+ var snippet = '@await Html.PartialAsync("Folder/NestedFolder/Footer")';
expect(templateHelper.getInsertPartialSnippet(parentId, nodeName)).toBe(snippet);
});
it('should return the snippet for inserting a partial from a folder with spaces in its name', function () {
var parentId = "Folder with spaces";
var nodeName = "Footer.cshtml";
- var snippet = '@Html.Partial("Folder with spaces/Footer")';
+ var snippet = '@await Html.PartialAsync("Folder with spaces/Footer")';
expect(templateHelper.getInsertPartialSnippet(parentId, nodeName)).toBe(snippet);
});