Merge remote-tracking branch 'origin/v9/9.0' into v9/dev

# Conflicts:
#	build/templates/UmbracoPackage/.template.config/template.json
#	build/templates/UmbracoProject/.template.config/template.json
#	src/Directory.Build.props
#	src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
This commit is contained in:
Bjarke Berg
2021-10-07 07:16:32 +02:00
29 changed files with 313 additions and 83 deletions

View File

@@ -8,6 +8,12 @@
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot/media/**;</DefaultItemExcludes>
</PropertyGroup>
<!-- Force windows to use ICU. Otherwise Windows 10 2019H1+ will do it, but older windows 10 and most if not all winodws servers will run NLS -->
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.6" />
<RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Umbraco.Cms" Version="UMBRACO_VERSION_FROM_TEMPLATE" />
<PackageReference Include="Umbraco.Cms.SqlCe" Version="UMBRACO_VERSION_FROM_TEMPLATE" Condition="'$(UseSqlCe)' == 'true'" />
@@ -30,6 +36,10 @@
<Compile Include="umbraco/models/**" Exclude="**/*.flag" />
</ItemGroup>
<PropertyGroup>
<CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>
</PropertyGroup>
<!-- Set this to true if ModelsBuilder mode is not InMemoryAuto-->
<PropertyGroup>
<RazorCompileOnBuild>false</RazorCompileOnBuild>

View File

@@ -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; }
}
/// <summary>

View File

@@ -0,0 +1,40 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.ComponentModel;
namespace Umbraco.Cms.Core.Configuration.Models
{
/// <summary>
/// Typed configuration options for package migration settings.
/// </summary>
[UmbracoOptions(Constants.Configuration.ConfigPackageMigration)]
public class PackageMigrationSettings
{
private const bool StaticRunSchemaAndContentMigrations = true;
private const bool StaticAllowComponentOverrideOfRunSchemaAndContentMigrations = true;
/// <summary>
/// Gets or sets a value indicating whether package migration steps that install schema and content should run.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
[DefaultValue(StaticRunSchemaAndContentMigrations)]
public bool RunSchemaAndContentMigrations { get; set; } = StaticRunSchemaAndContentMigrations;
/// <summary>
/// Gets or sets a value indicating whether components can override the configured value for <see cref="RunSchemaAndContentMigrations"/>.
/// </summary>
/// <remarks>
/// By default this is true and components can override the configured setting for <see cref="RunSchemaAndContentMigrations"/>.
/// 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.
/// </remarks>
[DefaultValue(StaticAllowComponentOverrideOfRunSchemaAndContentMigrations)]
public bool AllowComponentOverrideOfRunSchemaAndContentMigrations { get; set; } = StaticAllowComponentOverrideOfRunSchemaAndContentMigrations;
}
}

View File

@@ -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;
/// <summary>
/// Use in memory cache
@@ -19,5 +20,11 @@ namespace Umbraco.Cms.Core.Configuration.Models
/// </summary>
[DefaultValue(StaticCacheBuster)]
public RuntimeMinificationCacheBuster CacheBuster { get; set; } = Enum<RuntimeMinificationCacheBuster>.Parse(StaticCacheBuster);
/// <summary>
/// The unique version string used if CacheBuster is 'Version'.
/// </summary>
[DefaultValue(StaticVersion)]
public string Version { get; set; } = StaticVersion;
}
}

View File

@@ -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
{
/// <summary>
/// Typed configuration options for unattended settings.
/// </summary>
[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;
/// <summary>
/// Gets or sets a value indicating whether unattended installs are enabled.

View File

@@ -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";
}
}
}

View File

@@ -4,22 +4,22 @@ using System.ComponentModel;
namespace Umbraco.Cms.Web.Common.DependencyInjection
{
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class StaticServiceProvider
public static class StaticServiceProvider
{
/// <summary>
/// The service locator.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static IServiceProvider Instance { get; set; }
public static IServiceProvider Instance { get; set; }
}
}

View File

@@ -72,7 +72,8 @@ namespace Umbraco.Cms.Core.DependencyInjection
.AddUmbracoOptions<UnattendedSettings>()
.AddUmbracoOptions<RichTextEditorSettings>()
.AddUmbracoOptions<BasicAuthSettings>()
.AddUmbracoOptions<RuntimeMinificationSettings>();
.AddUmbracoOptions<RuntimeMinificationSettings>()
.AddUmbracoOptions<PackageMigrationSettings>();
return builder;
}

View File

@@ -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

View File

@@ -32,6 +32,7 @@ namespace Umbraco.Cms.Core.Packaging
public IEnumerable<IPartialView> PartialViewsInstalled { get; set; } = Enumerable.Empty<IPartialView>();
public IEnumerable<IContent> ContentInstalled { get; set; } = Enumerable.Empty<IContent>();
public IEnumerable<IMedia> MediaInstalled { get; set; } = Enumerable.Empty<IMedia>();
public IEnumerable<EntityContainer> EntityContainersInstalled { get; set; } = Enumerable.Empty<EntityContainer>();
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);

View File

@@ -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);
}

View File

@@ -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<PackageMigrationSettings> options)
: base(new ImportPackageBuilderExpression(
packagingService,
mediaService,
@@ -28,7 +30,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
mediaUrlGenerators,
shortStringHelper,
contentTypeBaseServiceProvider,
context))
context,
options))
{
}

View File

@@ -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> 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;
}
/// <summary>
@@ -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)
{

View File

@@ -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<EntityContainer> 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<EntityContainer> documentTypeEntityContainersInstalled),
MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId, out IEnumerable<EntityContainer> mediaTypeEntityContainersInstalled),
StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId),
ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId),
PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId)
};
var entityContainersInstalled = new List<EntityContainer>();
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;
}
}
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
@@ -123,7 +130,17 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IMediaType> ImportMediaTypes(IEnumerable<XElement> docTypeElements, int userId)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService);
=> ImportMediaTypes(docTypeElements, userId, out _);
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="docTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IMediaType> ImportMediaTypes(IEnumerable<XElement> docTypeElements, int userId, out IEnumerable<EntityContainer> entityContainersInstalled)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService, out entityContainersInstalled);
#endregion
@@ -408,7 +425,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
#region DocumentTypes
public IReadOnlyList<IContentType> ImportDocumentType(XElement docTypeElement, int userId)
=> ImportDocumentTypes(new[] { docTypeElement }, userId);
=> ImportDocumentTypes(new[] { docTypeElement }, userId, out _);
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
@@ -417,7 +434,17 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService);
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService, out _);
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="docTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId, out IEnumerable<EntityContainer> entityContainersInstalled)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService, out entityContainersInstalled);
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
@@ -428,6 +455,18 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<T> ImportDocumentTypes<T>(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService<T> service)
where T : class, IContentTypeComposition
=> ImportDocumentTypes(unsortedDocumentTypes, importStructure, userId, service);
/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="unsortedDocumentTypes">Xml to import</param>
/// <param name="importStructure">Boolean indicating whether or not to import the </param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<T> ImportDocumentTypes<T>(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService<T> service, out IEnumerable<EntityContainer> entityContainersInstalled)
where T : class, IContentTypeComposition
{
var importedContentTypes = new Dictionary<string, T>();
@@ -436,7 +475,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
var graph = new TopoGraph<string, TopoGraph.Node<string, XElement>>(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<string, int> CreateContentTypeFolderStructure(IEnumerable<XElement> unsortedDocumentTypes)
private Dictionary<string, int> CreateContentTypeFolderStructure(IEnumerable<XElement> unsortedDocumentTypes, out IEnumerable<EntityContainer> entityContainersInstalled)
{
var importedFolders = new Dictionary<string, int>();
var trackEntityContainersInstalled = new List<EntityContainer>();
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
/// <param name="userId">Optional id of the user</param>
/// <returns>An enumerable list of generated DataTypeDefinitions</returns>
public IReadOnlyList<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> dataTypeElements, int userId)
=> ImportDataTypes(dataTypeElements, userId, out _);
/// <summary>
/// Imports and saves package xml as <see cref="IDataType"/>
/// </summary>
/// <param name="dataTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the user</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated DataTypeDefinitions</returns>
public IReadOnlyList<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> dataTypeElements, int userId, out IEnumerable<EntityContainer> entityContainersInstalled)
{
var dataTypes = new List<IDataType>();
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<string, int> CreateDataTypeFolderStructure(IEnumerable<XElement> datatypeElements)
private Dictionary<string, int> CreateDataTypeFolderStructure(IEnumerable<XElement> datatypeElements, out IEnumerable<EntityContainer> entityContainersInstalled)
{
var importedFolders = new Dictionary<string, int>();
var trackEntityContainersInstalled = new List<EntityContainer>();
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;
}

View File

@@ -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<PackageMigrationSettings> _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<PackageMigrationSettings> 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<IOptions<PackageMigrationSettings>>())
{
}
public IImportPackageBuilder ImportPackage => BeginBuild(
@@ -42,7 +72,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_mediaUrlGenerators,
_shortStringHelper,
_contentTypeBaseServiceProvider,
Context));
Context,
_packageMigrationsSettings));
}
}

View File

@@ -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
/// <para>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.</para>
/// <para>Beware, the application MUST restart when this class behavior changes.</para>
/// <para>You can override the GetColmunnInfo method to control which columns this includes</para>
/// </remarks>
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;
}
}
}

View File

@@ -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;
/// <summary>
@@ -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<CoreRuntime>();
}
[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
)
{
}
/// <summary>
/// Gets the state of the Umbraco runtime.
/// </summary>
@@ -70,6 +111,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
{
_cancellationToken = cancellationToken;
StaticApplicationLogging.Initialize(_loggerFactory);
StaticServiceProvider.Instance = _serviceProvider;
AppDomain.CurrentDomain.UnhandledException += (_, args) =>
{

View File

@@ -279,6 +279,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
"memberTypeApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<MemberTypeController>(
controller => controller.GetAllTypes())
},
{
"memberTypeQueryApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<MemberTypeQueryController>(
controller => controller.GetAllTypes())
},
{
"memberGroupApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<MemberGroupController>(
controller => controller.GetAllGroups())

View File

@@ -182,6 +182,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
/// <summary>
/// Returns all member types
/// </summary>
[Obsolete("Use MemberTypeQueryController.GetAllTypes instead as it only requires AuthorizationPolicies.TreeAccessMembersOrMemberTypes and not both this and AuthorizationPolicies.TreeAccessMemberTypes")]
[Authorize(Policy = AuthorizationPolicies.TreeAccessMembersOrMemberTypes)]
public IEnumerable<ContentTypeBasic> GetAllTypes()
{

View File

@@ -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
{
/// <summary>
/// An API controller used for dealing with member types
/// </summary>
[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));
}
/// <summary>
/// Returns all member types
/// </summary>
public IEnumerable<ContentTypeBasic> GetAllTypes() =>
_memberTypeService.GetAll()
.Select(_umbracoMapper.Map<IMemberType, ContentTypeBasic>);
}
}

View File

@@ -557,7 +557,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
// i.e. "Some Person" <hello@example.com>
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);
}

View File

@@ -1,20 +0,0 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace Umbraco.Cms.Web.Common.DependencyInjection
{
/// <summary>
/// A <see cref="IStartupFilter"/> registered to automatically capture application services
/// </summary>
internal class UmbracoApplicationServicesCapture : IStartupFilter
{
/// <inheritdoc/>
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) =>
app =>
{
StaticServiceProvider.Instance = app.ApplicationServices;
next(app);
};
}
}

View File

@@ -54,8 +54,14 @@ namespace Umbraco.Extensions
.Configure<PhysicalFileSystemCacheOptions>(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<ResizeWebProcessor>()
.RemoveProcessor<FormatWebProcessor>()
.RemoveProcessor<BackgroundColorWebProcessor>()
.RemoveProcessor<JpegQualityWebProcessor>()
.AddProcessor<CropWebProcessor>()
.AddProcessor<ResizeWebProcessor>();
.AddProcessor<ResizeWebProcessor>()
.AddProcessor<FormatWebProcessor>()
.AddProcessor<BackgroundColorWebProcessor>()
.AddProcessor<JpegQualityWebProcessor>();
builder.Services.AddTransient<IConfigureOptions<ImageSharpMiddlewareOptions>, ImageSharpConfigurationOptions>();

View File

@@ -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<IStartupFilter, UmbracoApplicationServicesCapture>();
return new UmbracoBuilder(services, config, typeLoader, loggerFactory, profiler, appCaches, tempHostingEnvironment);
}

View File

@@ -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

View File

@@ -48,5 +48,4 @@
<_Parameter1>Umbraco.Tests.UnitTests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project>

View File

@@ -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) {

View File

@@ -16,7 +16,7 @@
partialViewName = parentId + "/" + partialViewName;
}
return "@Html.Partial(\"" + partialViewName + "\")";
return "@await Html.PartialAsync(\"" + partialViewName + "\")";
}
function getQuerySnippet(queryExpression) {

View File

@@ -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);
});