diff --git a/.gitignore b/.gitignore index 12ad3299ad..5390da67dd 100644 --- a/.gitignore +++ b/.gitignore @@ -164,3 +164,6 @@ build/temp/ # eof /src/Umbraco.Web.UI.Client/TESTS-*.xml /src/ApiDocs/api/* +/src/Umbraco.Web.UI.NetCore/wwwroot/Media/* +/src/Umbraco.Web.UI.NetCore/wwwroot/is-cache/* +/src/Umbraco.Tests.Integration/App_Data/* diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index 7199f414b1..969ac5be3d 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -25,7 +25,7 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - + diff --git a/build/build-bootstrap.ps1 b/build/build-bootstrap.ps1 index 71a25bfd7e..82c789ff22 100644 --- a/build/build-bootstrap.ps1 +++ b/build/build-bootstrap.ps1 @@ -22,6 +22,8 @@ # get NuGet $cache = 4 $nuget = "$scriptTemp\nuget.exe" + # ensure the correct NuGet-source is used. This one is used by Umbraco + $nugetsourceUmbraco = "https://www.myget.org/F/umbracocore/api/v3/index.json" if (-not $local) { $source = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" @@ -61,7 +63,7 @@ # get the build system if (-not $local) { - $params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease" + $params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease", "-Source", $nugetsourceUmbraco &$nuget install Umbraco.Build @params if (-not $?) { throw "Failed to download Umbraco.Build." } } diff --git a/build/build.ps1 b/build/build.ps1 index ea07e4516f..6e124d1508 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -375,11 +375,14 @@ }) + $nugetsourceUmbraco = "https://api.nuget.org/v3/index.json" + $ubuild.DefineMethod("RestoreNuGet", { Write-Host "Restore NuGet" Write-Host "Logging to $($this.BuildTemp)\nuget.restore.log" - &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log" + $params = "-Source", $nugetsourceUmbraco + &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log" @params if (-not $?) { throw "Failed to restore NuGet packages." } }) diff --git a/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs new file mode 100644 index 0000000000..0cacab9e1d --- /dev/null +++ b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs @@ -0,0 +1,50 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Configuration.Models; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.Configuration.UmbracoSettings; +using ConnectionStrings = Umbraco.Configuration.Models.ConnectionStrings; +using CoreDebugSettings = Umbraco.Configuration.Models.CoreDebugSettings; + +namespace Umbraco.Configuration +{ + public class AspNetCoreConfigsFactory : IConfigsFactory + { + private readonly IConfiguration _configuration; + + public AspNetCoreConfigsFactory(IConfiguration configuration) + { + _configuration = configuration ?? throw new System.ArgumentNullException(nameof(configuration)); + } + + public Configs Create() + { + var configs = new Configs(); + + configs.Add(() => new TourSettings(_configuration)); + configs.Add(() => new CoreDebugSettings(_configuration)); + configs.Add(() => new RequestHandlerSettings(_configuration)); + configs.Add(() => new SecuritySettings(_configuration)); + configs.Add(() => new UserPasswordConfigurationSettings(_configuration)); + configs.Add(() => new MemberPasswordConfigurationSettings(_configuration)); + configs.Add(() => new KeepAliveSettings(_configuration)); + configs.Add(() => new ContentSettings(_configuration)); + configs.Add(() => new HealthChecksSettings(_configuration)); + configs.Add(() => new LoggingSettings(_configuration)); + configs.Add(() => new ExceptionFilterSettings(_configuration)); + configs.Add(() => new ActiveDirectorySettings(_configuration)); + configs.Add(() => new RuntimeSettings(_configuration)); + configs.Add(() => new TypeFinderSettings(_configuration)); + configs.Add(() => new NuCacheSettings(_configuration)); + configs.Add(() => new WebRoutingSettings(_configuration)); + configs.Add(() => new IndexCreatorSettings(_configuration)); + configs.Add(() => new ModelsBuilderConfig(_configuration)); + configs.Add(() => new HostingSettings(_configuration)); + configs.Add(() => new GlobalSettings(_configuration)); + configs.Add(() => new ConnectionStrings(_configuration)); + configs.Add(() => new ImagingSettings(_configuration)); + + return configs; + } + } +} diff --git a/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs b/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs deleted file mode 100644 index f07e5133ef..0000000000 --- a/src/Umbraco.Configuration/CaseInsensitiveEnumConfigConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Configuration; - -namespace Umbraco.Core.Configuration -{ - /// - /// A case-insensitive configuration converter for enumerations. - /// - /// The type of the enumeration. - public class CaseInsensitiveEnumConfigConverter : ConfigurationConverterBase - where T : struct - { - public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data) - { - if (data == null) - throw new ArgumentNullException("data"); - - //return Enum.Parse(typeof(T), (string)data, true); - - T value; - if (Enum.TryParse((string)data, true, out value)) - return value; - - throw new Exception(string.Format("\"{0}\" is not valid {1} value. Valid values are: {2}.", - data, typeof(T).Name, - string.Join(", ", Enum.GetValues(typeof(T)).Cast()))); - } - } -} diff --git a/src/Umbraco.Configuration/ConfigsFactory.cs b/src/Umbraco.Configuration/ConfigsFactory.cs index 3742b7d7fa..be6cee2d0c 100644 --- a/src/Umbraco.Configuration/ConfigsFactory.cs +++ b/src/Umbraco.Configuration/ConfigsFactory.cs @@ -1,53 +1,62 @@ -using System.Configuration; using Umbraco.Configuration; +using Umbraco.Configuration.Implementations; +using Umbraco.Configuration.Legacy; using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.Configuration.Legacy; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; namespace Umbraco.Core.Configuration { public class ConfigsFactory : IConfigsFactory { public IHostingSettings HostingSettings { get; } = new HostingSettings(); - - public ICoreDebug CoreDebug { get; } = new CoreDebug(); - public IMachineKeyConfig MachineKeyConfig { get; } = new MachineKeyConfig(); + public ICoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings(); public IIndexCreatorSettings IndexCreatorSettings { get; } = new IndexCreatorSettings(); public INuCacheSettings NuCacheSettings { get; } = new NuCacheSettings(); public ITypeFinderSettings TypeFinderSettings { get; } = new TypeFinderSettings(); public IRuntimeSettings RuntimeSettings { get; } = new RuntimeSettings(); public IActiveDirectorySettings ActiveDirectorySettings { get; } = new ActiveDirectorySettings(); public IExceptionFilterSettings ExceptionFilterSettings { get; } = new ExceptionFilterSettings(); + public ITourSettings TourSettings { get; } = new TourSettings(); + public ILoggingSettings LoggingSettings { get; } = new LoggingSettings(); + public IKeepAliveSettings KeepAliveSettings { get; } = new KeepAliveSettings(); + public IWebRoutingSettings WebRoutingSettings { get; } = new WebRoutingSettings(); + public IRequestHandlerSettings RequestHandlerSettings { get; } = new RequestHandlerSettings(); + public ISecuritySettings SecuritySettings { get; } = new SecuritySettings(); + public IUserPasswordConfiguration UserPasswordConfigurationSettings { get; } = new UserPasswordConfigurationSettings(); + public IMemberPasswordConfiguration MemberPasswordConfigurationSettings { get; } = new MemberPasswordConfigurationSettings(); + public IContentSettings ContentSettings { get; } = new ContentSettings(); + public IGlobalSettings GlobalSettings { get; } = new GlobalSettings(); + public IHealthChecksSettings HealthChecksSettings { get; } = new HealthChecksSettings(); + public IConnectionStrings ConnectionStrings { get; } = new ConnectionStrings(); + public IModelsBuilderConfig ModelsBuilderConfig { get; } = new ModelsBuilderConfig(); - public IUmbracoSettingsSection UmbracoSettings { get; } - - public Configs Create(IIOHelper ioHelper) + public Configs Create() { - var configs = new Configs(section => ConfigurationManager.GetSection(section)); - configs.Add(() => new GlobalSettings(ioHelper)); - configs.Add(() => HostingSettings); - - configs.Add("umbracoConfiguration/settings"); - configs.Add("umbracoConfiguration/HealthChecks"); - - // Password configuration is held within IUmbracoSettingsSection from umbracoConfiguration/settings but we'll add explicitly - // so it can be independently retrieved in classes that need it. - configs.AddPasswordConfigurations(); - - configs.Add(() => CoreDebug); - configs.Add(() => MachineKeyConfig); - configs.Add(() => new ConnectionStrings(ioHelper)); - configs.Add(() => new ModelsBuilderConfig(ioHelper)); - + var configs = new Configs(); + configs.Add(() => GlobalSettings); + configs.Add(() => HostingSettings); + configs.Add(() => HealthChecksSettings); + configs.Add(() => CoreDebugSettings); + configs.Add(() => ConnectionStrings); + configs.Add(() => ModelsBuilderConfig); configs.Add(() => IndexCreatorSettings); configs.Add(() => NuCacheSettings); configs.Add(() => TypeFinderSettings); configs.Add(() => RuntimeSettings); configs.Add(() => ActiveDirectorySettings); configs.Add(() => ExceptionFilterSettings); + configs.Add(() => TourSettings); + configs.Add(() => LoggingSettings); + configs.Add(() => KeepAliveSettings); + configs.Add(() => WebRoutingSettings); + configs.Add(() => RequestHandlerSettings); + configs.Add(() => SecuritySettings); + configs.Add(() => UserPasswordConfigurationSettings); + configs.Add(() => MemberPasswordConfigurationSettings); + configs.Add(() => ContentSettings); - configs.AddCoreConfigs(ioHelper); return configs; } } diff --git a/src/Umbraco.Configuration/ConnectionStrings.cs b/src/Umbraco.Configuration/ConnectionStrings.cs deleted file mode 100644 index 6a00974831..0000000000 --- a/src/Umbraco.Configuration/ConnectionStrings.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Configuration; -using System.Linq; -using System.Xml.Linq; -using Umbraco.Core.IO; - -namespace Umbraco.Core.Configuration -{ - public class ConnectionStrings : IConnectionStrings - { - private readonly IIOHelper _ioHelper; - - public ConnectionStrings(IIOHelper ioHelper) - { - _ioHelper = ioHelper; - } - - public ConfigConnectionString this[string key] - { - get - { - var settings = ConfigurationManager.ConnectionStrings[key]; - if (settings == null) return null; - return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name); - } - } - - public void RemoveConnectionString(string key) - { - var fileName = _ioHelper.MapPath(string.Format("{0}/web.config", _ioHelper.Root)); - var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - - var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single(); - var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key); - - if (setting != null) - { - setting.Remove(); - xml.Save(fileName, SaveOptions.DisableFormatting); - ConfigurationManager.RefreshSection("appSettings"); - } - var settings = ConfigurationManager.ConnectionStrings[key]; - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs index 90a7d8c567..373d846567 100644 --- a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs +++ b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs @@ -1,10 +1,9 @@ using System; -using System.Collections.Generic; using System.Configuration; namespace Umbraco.Core.Configuration.HealthChecks { - public class HealthChecksSection : ConfigurationSection, IHealthChecks + public class HealthChecksSection : ConfigurationSection { private const string DisabledChecksKey = "disabledChecks"; private const string NotificationSettingsKey = "notificationSettings"; @@ -21,14 +20,5 @@ namespace Umbraco.Core.Configuration.HealthChecks get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); } } - IEnumerable IHealthChecks.DisabledChecks - { - get { return DisabledChecks; } - } - - IHealthCheckNotificationSettings IHealthChecks.NotificationSettings - { - get { return NotificationSettings; } - } } } diff --git a/src/Umbraco.Configuration/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs similarity index 90% rename from src/Umbraco.Configuration/ActiveDirectorySettings.cs rename to src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs index d85def7f33..ef100afed6 100644 --- a/src/Umbraco.Configuration/ActiveDirectorySettings.cs +++ b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs @@ -1,7 +1,7 @@ using System.Configuration; using Umbraco.Core.Configuration; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { public class ActiveDirectorySettings : IActiveDirectorySettings { diff --git a/src/Umbraco.Configuration/CommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs similarity index 100% rename from src/Umbraco.Configuration/CommaDelimitedConfigurationElement.cs rename to src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs diff --git a/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs new file mode 100644 index 0000000000..0302a7ea31 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs @@ -0,0 +1,22 @@ +using System.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal abstract class ConfigurationManagerConfigBase + { + private UmbracoSettingsSection _umbracoSettingsSection; + + protected UmbracoSettingsSection UmbracoSettingsSection + { + get + { + if (_umbracoSettingsSection is null) + { + _umbracoSettingsSection = ConfigurationManager.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection; + } + return _umbracoSettingsSection; + } + } + } +} diff --git a/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs b/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs new file mode 100644 index 0000000000..a02c351118 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs @@ -0,0 +1,17 @@ +using System.Configuration; + +namespace Umbraco.Core.Configuration +{ + public class ConnectionStrings : IConnectionStrings + { + public ConfigConnectionString this[string key] + { + get + { + var settings = ConfigurationManager.ConnectionStrings[key]; + if (settings == null) return null; + return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name); + } + } + } +} diff --git a/src/Umbraco.Configuration/Legacy/ContentSettings.cs b/src/Umbraco.Configuration/Legacy/ContentSettings.cs new file mode 100644 index 0000000000..1c3f543bfe --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/ContentSettings.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Macros; + +namespace Umbraco.Configuration.Implementations +{ + internal class ContentSettings : ConfigurationManagerConfigBase, IContentSettings + { + public string NotificationEmailAddress => UmbracoSettingsSection.Content.Notifications.NotificationEmailAddress; + public bool DisableHtmlEmail => UmbracoSettingsSection.Content.Notifications.DisableHtmlEmail; + public IEnumerable ImageFileTypes => UmbracoSettingsSection.Content.Imaging.ImageFileTypes; + public IEnumerable ImageAutoFillProperties => UmbracoSettingsSection.Content.Imaging.ImageAutoFillProperties; + public bool ResolveUrlsFromTextString => UmbracoSettingsSection.Content.ResolveUrlsFromTextString; + public IEnumerable Error404Collection => UmbracoSettingsSection.Content.Error404Collection; + public string PreviewBadge => UmbracoSettingsSection.Content.PreviewBadge; + public MacroErrorBehaviour MacroErrorBehaviour => UmbracoSettingsSection.Content.MacroErrors; + public IEnumerable DisallowedUploadFiles => UmbracoSettingsSection.Content.DisallowedUploadFiles; + public IEnumerable AllowedUploadFiles => UmbracoSettingsSection.Content.AllowedUploadFiles; + public bool ShowDeprecatedPropertyEditors => UmbracoSettingsSection.Content.ShowDeprecatedPropertyEditors; + public string LoginBackgroundImage => UmbracoSettingsSection.Content.LoginBackgroundImage; + } +} diff --git a/src/Umbraco.Configuration/CoreDebug.cs b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs similarity index 87% rename from src/Umbraco.Configuration/CoreDebug.cs rename to src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs index 0ff3274565..4902d4489f 100644 --- a/src/Umbraco.Configuration/CoreDebug.cs +++ b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs @@ -3,9 +3,9 @@ using System.Configuration; namespace Umbraco.Core.Configuration { - public class CoreDebug : ICoreDebug + public class CoreDebugSettings : ICoreDebugSettings { - public CoreDebug() + public CoreDebugSettings() { var appSettings = ConfigurationManager.AppSettings; LogUncompletedScopes = string.Equals("true", appSettings[Constants.AppSettings.Debug.LogUncompletedScopes], StringComparison.OrdinalIgnoreCase); diff --git a/src/Umbraco.Configuration/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs similarity index 92% rename from src/Umbraco.Configuration/ExceptionFilterSettings.cs rename to src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs index 628b8755cc..50e2207485 100644 --- a/src/Umbraco.Configuration/ExceptionFilterSettings.cs +++ b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs @@ -1,7 +1,7 @@ using System.Configuration; using Umbraco.Core.Configuration; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { public class ExceptionFilterSettings : IExceptionFilterSettings { diff --git a/src/Umbraco.Configuration/GlobalSettings.cs b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs similarity index 87% rename from src/Umbraco.Configuration/GlobalSettings.cs rename to src/Umbraco.Configuration/Legacy/GlobalSettings.cs index 56e64fff31..78036f9e42 100644 --- a/src/Umbraco.Configuration/GlobalSettings.cs +++ b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs @@ -3,59 +3,12 @@ using System.Configuration; using System.Linq; using System.Net.Mail; using System.Xml.Linq; +using Umbraco.Composing; using Umbraco.Configuration; using Umbraco.Core.IO; -namespace Umbraco.Core.Configuration +namespace Umbraco.Core.Configuration.Legacy { - public class HostingSettings : IHostingSettings - { - private bool? _debugMode; - - /// - public LocalTempStorage LocalTempStorageLocation - { - get - { - var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage]; - if (!string.IsNullOrWhiteSpace(setting)) - return Enum.Parse(setting); - - return LocalTempStorage.Default; - } - } - - /// - /// Gets a value indicating whether umbraco is running in [debug mode]. - /// - /// true if [debug mode]; otherwise, false. - public bool DebugMode - { - get - { - if (!_debugMode.HasValue) - { - try - { - if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation) - { - var debugElement = compilation.ElementInformation.Properties["debug"]; - - _debugMode = debugElement != null && (debugElement.Value is bool debug && debug); - - } - } - catch - { - _debugMode = false; - } - } - - return _debugMode.GetValueOrDefault(); - } - } - } - // TODO: Replace checking for if the app settings exist and returning an empty string, instead return the defaults! // TODO: need to massively cleanup these configuration classes @@ -64,7 +17,6 @@ namespace Umbraco.Core.Configuration /// public class GlobalSettings : IGlobalSettings { - private readonly IIOHelper _ioHelper; // TODO these should not be static private static string _reservedPaths; @@ -74,11 +26,6 @@ namespace Umbraco.Core.Configuration internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma! internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma! - public GlobalSettings(IIOHelper ioHelper) - { - _ioHelper = ioHelper; - } - /// /// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config) /// @@ -203,15 +150,7 @@ namespace Umbraco.Core.Configuration /// Gets the path to umbraco's root directory (/umbraco by default). /// /// The path. - public string Path - { - get - { - return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path) - ? _ioHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path]) - : string.Empty; - } - } + public string Path => ConfigurationManager.AppSettings[Constants.AppSettings.Path]; /// /// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance. @@ -227,7 +166,7 @@ namespace Umbraco.Core.Configuration } set { - SaveSetting(Constants.AppSettings.ConfigurationStatus, value, _ioHelper); + SaveSetting(Constants.AppSettings.ConfigurationStatus, value, Current.IOHelper); //TODO remove } } @@ -254,7 +193,7 @@ namespace Umbraco.Core.Configuration ConfigurationManager.RefreshSection("appSettings"); } - + /// /// Gets the time out in minutes. /// @@ -411,5 +350,22 @@ namespace Umbraco.Core.Configuration return backingField; } + + /// + /// Gets the path to the razor file used when no published content is available. + /// + public string NoNodesViewPath + { + get + { + var configuredValue = ConfigurationManager.AppSettings[Constants.AppSettings.NoNodesViewPath]; + if (!string.IsNullOrWhiteSpace(configuredValue)) + { + return configuredValue; + } + + return "~/config/splashes/NoNodes.cshtml"; + } + } } } diff --git a/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs b/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs new file mode 100644 index 0000000000..23385d1378 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Configuration; +using Umbraco.Core.Configuration.HealthChecks; + +namespace Umbraco.Core.Configuration.Legacy +{ + public class HealthChecksSettings : IHealthChecksSettings + { + private HealthChecksSection _healthChecksSection; + + private HealthChecksSection HealthChecksSection + { + get + { + if (_healthChecksSection is null) + { + _healthChecksSection = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as HealthChecksSection; + } + return _healthChecksSection; + } + } + + public IEnumerable DisabledChecks => HealthChecksSection.DisabledChecks; + public IHealthCheckNotificationSettings NotificationSettings => HealthChecksSection.NotificationSettings; + } +} diff --git a/src/Umbraco.Configuration/Legacy/HostingSettings.cs b/src/Umbraco.Configuration/Legacy/HostingSettings.cs new file mode 100644 index 0000000000..d0d09ea86f --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/HostingSettings.cs @@ -0,0 +1,52 @@ +using System.Configuration; + +namespace Umbraco.Core.Configuration.Legacy +{ + public class HostingSettings : IHostingSettings + { + private bool? _debugMode; + + /// + public LocalTempStorage LocalTempStorageLocation + { + get + { + var setting = ConfigurationManager.AppSettings[Constants.AppSettings.LocalTempStorage]; + if (!string.IsNullOrWhiteSpace(setting)) + return Enum.Parse(setting); + + return LocalTempStorage.Default; + } + } + + /// + /// Gets a value indicating whether umbraco is running in [debug mode]. + /// + /// true if [debug mode]; otherwise, false. + public bool DebugMode + { + get + { + if (!_debugMode.HasValue) + { + try + { + if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection compilation) + { + var debugElement = compilation.ElementInformation.Properties["debug"]; + + _debugMode = debugElement != null && (debugElement.Value is bool debug && debug); + + } + } + catch + { + _debugMode = false; + } + } + + return _debugMode.GetValueOrDefault(); + } + } + } +} diff --git a/src/Umbraco.Configuration/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs similarity index 78% rename from src/Umbraco.Configuration/IndexCreatorSettings.cs rename to src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs index 00d1a29dba..d023d46246 100644 --- a/src/Umbraco.Configuration/IndexCreatorSettings.cs +++ b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs @@ -1,13 +1,13 @@ using System.Configuration; using Umbraco.Core.Configuration; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { public class IndexCreatorSettings : IIndexCreatorSettings { public IndexCreatorSettings() { - LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"]; + LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"]; } public string LuceneDirectoryFactory { get; } diff --git a/src/Umbraco.Configuration/InnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs similarity index 100% rename from src/Umbraco.Configuration/InnerTextConfigurationElement.cs rename to src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs diff --git a/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs b/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs new file mode 100644 index 0000000000..0b8315d447 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal class KeepAliveSettings : ConfigurationManagerConfigBase, IKeepAliveSettings + { + public bool DisableKeepAliveTask => UmbracoSettingsSection.KeepAlive.DisableKeepAliveTask; + public string KeepAlivePingUrl => UmbracoSettingsSection.KeepAlive.KeepAlivePingUrl; + } +} diff --git a/src/Umbraco.Configuration/Legacy/LoggingSettings.cs b/src/Umbraco.Configuration/Legacy/LoggingSettings.cs new file mode 100644 index 0000000000..020b0c0e64 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/LoggingSettings.cs @@ -0,0 +1,9 @@ +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal class LoggingSettings : ConfigurationManagerConfigBase, ILoggingSettings + { + public int MaxLogAge => UmbracoSettingsSection.Logging.MaxLogAge; + } +} diff --git a/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs new file mode 100644 index 0000000000..e42b02de73 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs @@ -0,0 +1,16 @@ +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Implementations +{ + internal class MemberPasswordConfigurationSettings : ConfigurationManagerConfigBase, IMemberPasswordConfiguration + { + public int RequiredLength => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequiredLength; + public bool RequireNonLetterOrDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit; + public bool RequireDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireDigit; + public bool RequireLowercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireLowercase; + public bool RequireUppercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireUppercase; + public bool UseLegacyEncoding=> UmbracoSettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding; + public string HashAlgorithmType=> UmbracoSettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType; + public int MaxFailedAccessAttemptsBeforeLockout => UmbracoSettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout; + } +} diff --git a/src/Umbraco.Configuration/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs similarity index 80% rename from src/Umbraco.Configuration/ModelsBuilderConfig.cs rename to src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs index 151e9908a1..f6395b23b4 100644 --- a/src/Umbraco.Configuration/ModelsBuilderConfig.cs +++ b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs @@ -6,14 +6,14 @@ using Umbraco.Core.Configuration; using Umbraco.Core; using Umbraco.Core.IO; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { /// /// Represents the models builder configuration. /// public class ModelsBuilderConfig : IModelsBuilderConfig { - private readonly IIOHelper _ioHelper; + private const string Prefix = "Umbraco.ModelsBuilder."; private object _modelsModelLock; private bool _modelsModelConfigured; @@ -23,15 +23,13 @@ namespace Umbraco.Configuration private bool _flagOutOfDateModels; - public string DefaultModelsDirectory => _ioHelper.MapPath("~/App_Data/Models"); + public string DefaultModelsDirectory => "~/App_Data/Models"; /// /// Initializes a new instance of the class. /// - public ModelsBuilderConfig(IIOHelper ioHelper) + public ModelsBuilderConfig() { - _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); - // giant kill switch, default: false // must be explicitely set to true for anything else to happen Enable = ConfigurationManager.AppSettings[Prefix + "Enable"] == "true"; @@ -59,12 +57,8 @@ namespace Umbraco.Configuration value = ConfigurationManager.AppSettings[Prefix + "ModelsDirectory"]; if (!string.IsNullOrWhiteSpace(value)) { - var root = _ioHelper.MapPath("~/"); - if (root == null) - throw new ConfigurationErrorsException("Could not determine root directory."); - // GetModelsDirectory will ensure that the path is safe - ModelsDirectory = GetModelsDirectory(root, value, AcceptUnsafeModelsDirectory); + ModelsDirectory = value; } // default: 0 @@ -81,7 +75,7 @@ namespace Umbraco.Configuration /// /// Initializes a new instance of the class. /// - public ModelsBuilderConfig(IIOHelper ioHelper, + public ModelsBuilderConfig( bool enable = false, ModelsMode modelsMode = ModelsMode.Nothing, string modelsNamespace = null, @@ -91,7 +85,6 @@ namespace Umbraco.Configuration bool acceptUnsafeModelsDirectory = false, int debugLevel = 0) { - _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); Enable = enable; _modelsMode = modelsMode; @@ -103,36 +96,7 @@ namespace Umbraco.Configuration DebugLevel = debugLevel; } - // internal for tests - internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe) - { - // making sure it is safe, ie under the website root, - // unless AcceptUnsafeModelsDirectory and then everything is OK. - if (!Path.IsPathRooted(root)) - throw new ConfigurationErrorsException($"Root is not rooted \"{root}\"."); - - if (config.StartsWith("~/")) - { - var dir = Path.Combine(root, config.TrimStart("~/")); - - // sanitize - GetFullPath will take care of any relative - // segments in path, eg '../../foo.tmp' - it may throw a SecurityException - // if the combined path reaches illegal parts of the filesystem - dir = Path.GetFullPath(dir); - root = Path.GetFullPath(root); - - if (!dir.StartsWith(root) && !acceptUnsafe) - throw new ConfigurationErrorsException($"Invalid models directory \"{config}\"."); - - return dir; - } - - if (acceptUnsafe) - return Path.GetFullPath(config); - - throw new ConfigurationErrorsException($"Invalid models directory \"{config}\"."); - } /// /// Gets a value indicating whether the whole models experience is enabled. diff --git a/src/Umbraco.Configuration/NuCacheSettings.cs b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs similarity index 89% rename from src/Umbraco.Configuration/NuCacheSettings.cs rename to src/Umbraco.Configuration/Legacy/NuCacheSettings.cs index c3a286d33d..25f52a5c7d 100644 --- a/src/Umbraco.Configuration/NuCacheSettings.cs +++ b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs @@ -1,7 +1,7 @@ using System.Configuration; using Umbraco.Core.Configuration; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { public class NuCacheSettings : INuCacheSettings { diff --git a/src/Umbraco.Configuration/OptionalCommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs similarity index 100% rename from src/Umbraco.Configuration/OptionalCommaDelimitedConfigurationElement.cs rename to src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs diff --git a/src/Umbraco.Configuration/OptionalInnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs similarity index 100% rename from src/Umbraco.Configuration/OptionalInnerTextConfigurationElement.cs rename to src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs diff --git a/src/Umbraco.Configuration/RawXmlConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs similarity index 100% rename from src/Umbraco.Configuration/RawXmlConfigurationElement.cs rename to src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs diff --git a/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs new file mode 100644 index 0000000000..0cd011c863 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal class RequestHandlerSettings : ConfigurationManagerConfigBase, IRequestHandlerSettings + { + public bool AddTrailingSlash => UmbracoSettingsSection.RequestHandler.AddTrailingSlash; + public bool ConvertUrlsToAscii => UmbracoSettingsSection.RequestHandler.UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true"); + public bool TryConvertUrlsToAscii => UmbracoSettingsSection.RequestHandler.UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try"); + public IEnumerable CharCollection => UmbracoSettingsSection.RequestHandler.UrlReplacing.CharCollection; + } +} diff --git a/src/Umbraco.Configuration/RuntimeSettings.cs b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs similarity index 96% rename from src/Umbraco.Configuration/RuntimeSettings.cs rename to src/Umbraco.Configuration/Legacy/RuntimeSettings.cs index 6dc8d6f832..200642a819 100644 --- a/src/Umbraco.Configuration/RuntimeSettings.cs +++ b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs @@ -1,7 +1,7 @@ using System.Configuration; using Umbraco.Core.Configuration; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { public class RuntimeSettings : IRuntimeSettings { @@ -24,6 +24,6 @@ namespace Umbraco.Configuration } public int? MaxQueryStringLength { get; } public int? MaxRequestLength { get; } - + } } diff --git a/src/Umbraco.Configuration/Legacy/SecuritySettings.cs b/src/Umbraco.Configuration/Legacy/SecuritySettings.cs new file mode 100644 index 0000000000..b7e39b0608 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/SecuritySettings.cs @@ -0,0 +1,14 @@ +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal class SecuritySettings : ConfigurationManagerConfigBase, ISecuritySettings + { + public bool KeepUserLoggedIn => UmbracoSettingsSection.Security.KeepUserLoggedIn; + public bool HideDisabledUsersInBackoffice => UmbracoSettingsSection.Security.HideDisabledUsersInBackoffice; + public bool AllowPasswordReset => UmbracoSettingsSection.Security.AllowPasswordReset; + public string AuthCookieName => UmbracoSettingsSection.Security.AuthCookieName; + public string AuthCookieDomain => UmbracoSettingsSection.Security.AuthCookieDomain; + public bool UsernameIsEmail => UmbracoSettingsSection.Security.UsernameIsEmail; + } +} diff --git a/src/Umbraco.Configuration/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs similarity index 100% rename from src/Umbraco.Configuration/SmtpSettings.cs rename to src/Umbraco.Configuration/Legacy/SmtpSettings.cs diff --git a/src/Umbraco.Configuration/Legacy/TourSettings.cs b/src/Umbraco.Configuration/Legacy/TourSettings.cs new file mode 100644 index 0000000000..134c3c48d5 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/TourSettings.cs @@ -0,0 +1,9 @@ +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal class TourSettings : ConfigurationManagerConfigBase, ITourSettings + { + public bool EnableTours => UmbracoSettingsSection.BackOffice.Tours.EnableTours; + } +} diff --git a/src/Umbraco.Configuration/TypeFinderSettings.cs b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs similarity index 91% rename from src/Umbraco.Configuration/TypeFinderSettings.cs rename to src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs index bb3063d7bf..b1009f754b 100644 --- a/src/Umbraco.Configuration/TypeFinderSettings.cs +++ b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs @@ -1,8 +1,8 @@ using System.Configuration; -using Umbraco.Core.Configuration; using Umbraco.Core; +using Umbraco.Core.Configuration; -namespace Umbraco.Configuration +namespace Umbraco.Configuration.Legacy { public class TypeFinderSettings : ITypeFinderSettings { diff --git a/src/Umbraco.Configuration/UmbracoConfigurationSection.cs b/src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs similarity index 100% rename from src/Umbraco.Configuration/UmbracoConfigurationSection.cs rename to src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs diff --git a/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs new file mode 100644 index 0000000000..51dd645c42 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs @@ -0,0 +1,15 @@ +using Umbraco.Core.Configuration; +namespace Umbraco.Configuration.Implementations +{ + internal class UserPasswordConfigurationSettings : ConfigurationManagerConfigBase, IUserPasswordConfiguration + { + public int RequiredLength => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequiredLength; + public bool RequireNonLetterOrDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit; + public bool RequireDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireDigit; + public bool RequireLowercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireLowercase; + public bool RequireUppercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireUppercase; + public bool UseLegacyEncoding=> UmbracoSettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding; + public string HashAlgorithmType=> UmbracoSettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType; + public int MaxFailedAccessAttemptsBeforeLockout => UmbracoSettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout; + } +} diff --git a/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs b/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs new file mode 100644 index 0000000000..5da3de20a0 --- /dev/null +++ b/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs @@ -0,0 +1,16 @@ +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Implementations +{ + internal class WebRoutingSettings : ConfigurationManagerConfigBase, IWebRoutingSettings + { + public bool TrySkipIisCustomErrors => UmbracoSettingsSection.WebRouting.TrySkipIisCustomErrors; + public bool InternalRedirectPreservesTemplate => UmbracoSettingsSection.WebRouting.InternalRedirectPreservesTemplate; + public bool DisableAlternativeTemplates => UmbracoSettingsSection.WebRouting.DisableAlternativeTemplates; + public bool ValidateAlternativeTemplates => UmbracoSettingsSection.WebRouting.ValidateAlternativeTemplates; + public bool DisableFindContentByIdPath => UmbracoSettingsSection.WebRouting.DisableFindContentByIdPath; + public bool DisableRedirectUrlTracking => UmbracoSettingsSection.WebRouting.DisableRedirectUrlTracking; + public string UrlProviderMode => UmbracoSettingsSection.WebRouting.UrlProviderMode; + public string UmbracoApplicationUrl => UmbracoSettingsSection.WebRouting.UmbracoApplicationUrl; + } +} diff --git a/src/Umbraco.Configuration/MachineKeyConfig.cs b/src/Umbraco.Configuration/MachineKeyConfig.cs deleted file mode 100644 index 4e3401e015..0000000000 --- a/src/Umbraco.Configuration/MachineKeyConfig.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration -{ - public class MachineKeyConfig : IMachineKeyConfig - { - //TODO all the machineKey stuff should be replaced: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/replacing-machinekey?view=aspnetcore-3.1 - - public bool HasMachineKey - { - get - { - var machineKeySection = - ConfigurationManager.GetSection("system.web/machineKey") as ConfigurationSection; - return !(machineKeySection?.ElementInformation?.Source is null); - } - } - } -} diff --git a/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs new file mode 100644 index 0000000000..015fb17a8e --- /dev/null +++ b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class ActiveDirectorySettings : IActiveDirectorySettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "ActiveDirectory:"; + private readonly IConfiguration _configuration; + + public ActiveDirectorySettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string ActiveDirectoryDomain => _configuration.GetValue(Prefix+"Domain"); + } +} diff --git a/src/Umbraco.Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Configuration/Models/ConnectionStrings.cs new file mode 100644 index 0000000000..22a0bde571 --- /dev/null +++ b/src/Umbraco.Configuration/Models/ConnectionStrings.cs @@ -0,0 +1,59 @@ +using System; +using System.Data.Common; +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + public class ConnectionStrings : IConnectionStrings + { + private readonly IConfiguration _configuration; + + public ConnectionStrings(IConfiguration configuration) + { + _configuration = configuration; + } + + public ConfigConnectionString this[string key] + { + get + { + var connectionString = _configuration.GetConnectionString(key); + var provider = ParseProvider(connectionString); + return new ConfigConnectionString(connectionString, provider, key); + } + set => throw new NotImplementedException(); + } + + private string ParseProvider(string connectionString) + { + if (string.IsNullOrEmpty(connectionString)) + { + return null; + } + + var builder = new DbConnectionStringBuilder(); + + builder.ConnectionString = connectionString; + + if (builder.TryGetValue("Data Source", out var ds) && ds is string dataSource) + { + if (dataSource.EndsWith(".sdf")) + { + return Constants.DbProviderNames.SqlCe; + } + } + + if (builder.TryGetValue("Server", out var s) && s is string server && builder.TryGetValue("Database", out var db) && db is string database) + { + if (!string.IsNullOrEmpty(server) && !string.IsNullOrEmpty(database)) + { + return Constants.DbProviderNames.SqlServer; + } + } + + throw new ArgumentException("Cannot determine provider name from connection string", nameof(connectionString)); + } + } +} diff --git a/src/Umbraco.Configuration/Models/ContentSettings.cs b/src/Umbraco.Configuration/Models/ContentSettings.cs new file mode 100644 index 0000000000..5bc31814b7 --- /dev/null +++ b/src/Umbraco.Configuration/Models/ContentSettings.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Macros; + +namespace Umbraco.Configuration.Models +{ + internal class ContentSettings : IContentSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Content:"; + private const string NotificationsPrefix = Prefix + "Notifications:"; + private const string ImagingPrefix = Prefix + "Imaging:"; + private const string DefaultPreviewBadge = + @"
Preview modeClick to end
"; + + private static readonly ImagingAutoFillUploadField[] DefaultImagingAutoFillUploadField = + { + new ImagingAutoFillUploadField + { + Alias = "umbracoFile" + } + }; + + private readonly IConfiguration _configuration; + + public ContentSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string NotificationEmailAddress => + _configuration.GetValue(NotificationsPrefix+"Email"); + + public bool DisableHtmlEmail => + _configuration.GetValue(NotificationsPrefix+"DisableHtmlEmail", false); + + public IEnumerable ImageFileTypes => _configuration.GetValue( + ImagingPrefix+"ImageFileTypes", new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }); + + public IEnumerable ImageAutoFillProperties => + _configuration.GetValue(ImagingPrefix+"AutoFillImageProperties", + DefaultImagingAutoFillUploadField); + + + public bool ResolveUrlsFromTextString => + _configuration.GetValue(Prefix+"ResolveUrlsFromTextString", false); + + public IEnumerable Error404Collection => _configuration + .GetSection(Prefix+"Errors:Error404") + .GetChildren() + .Select(x => new ContentErrorPage(x)); + + public string PreviewBadge => _configuration.GetValue(Prefix+"PreviewBadge", DefaultPreviewBadge); + + public MacroErrorBehaviour MacroErrorBehaviour => + _configuration.GetValue(Prefix+"MacroErrors", MacroErrorBehaviour.Inline); + + public IEnumerable DisallowedUploadFiles => _configuration.GetValue( + Prefix+"DisallowedUploadFiles", + new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" }); + + public IEnumerable AllowedUploadFiles => + _configuration.GetValue(Prefix+"AllowedUploadFiles", Array.Empty()); + + public bool ShowDeprecatedPropertyEditors => + _configuration.GetValue(Prefix+"ShowDeprecatedPropertyEditors", false); + + public string LoginBackgroundImage => + _configuration.GetValue(Prefix+"LoginBackgroundImage", string.Empty); + + private class ContentErrorPage : IContentErrorPage + { + public ContentErrorPage(IConfigurationSection configurationSection) + { + Culture = configurationSection.Key; + + var value = configurationSection.Value; + + if (int.TryParse(value, out var contentId)) + { + HasContentId = true; + ContentId = contentId; + } + else if (Guid.TryParse(value, out var contentKey)) + { + HasContentKey = true; + ContentKey = contentKey; + } + else + { + ContentXPath = value; + } + } + + public int ContentId { get; } + public Guid ContentKey { get; } + public string ContentXPath { get; } + public bool HasContentId { get; } + public bool HasContentKey { get; } + public string Culture { get; set; } + } + + private class ImagingAutoFillUploadField : IImagingAutoFillUploadField + { + public string Alias { get; set; } + public string WidthFieldAlias { get; set; } + public string HeightFieldAlias { get; set; } + public string LengthFieldAlias { get; set; } + public string ExtensionFieldAlias { get; set; } + } + } +} diff --git a/src/Umbraco.Configuration/Models/CoreDebugSettings.cs b/src/Umbraco.Configuration/Models/CoreDebugSettings.cs new file mode 100644 index 0000000000..6d6c0eaf0d --- /dev/null +++ b/src/Umbraco.Configuration/Models/CoreDebugSettings.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class CoreDebugSettings : ICoreDebugSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Core:Debug:"; + private readonly IConfiguration _configuration; + + public CoreDebugSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public bool LogUncompletedScopes => + _configuration.GetValue(Prefix+"LogUncompletedScopes", false); + + public bool DumpOnTimeoutThreadAbort => + _configuration.GetValue(Prefix+"DumpOnTimeoutThreadAbort", false); + } +} diff --git a/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs new file mode 100644 index 0000000000..581daf9f40 --- /dev/null +++ b/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class ExceptionFilterSettings : IExceptionFilterSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "ExceptionFilter:"; + private readonly IConfiguration _configuration; + + public ExceptionFilterSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public bool Disabled => _configuration.GetValue(Prefix+"Disabled", false); + } +} diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs new file mode 100644 index 0000000000..4dc764a974 --- /dev/null +++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs @@ -0,0 +1,97 @@ +using System; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + /// + /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information + /// from web.config appsettings + /// + internal class GlobalSettings : IGlobalSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Global:"; + + internal const string + StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma! + + internal const string + StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma! + + private readonly IConfiguration _configuration; + + public GlobalSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string ReservedUrls => _configuration.GetValue(Prefix + "ReservedUrls", StaticReservedUrls); + public string ReservedPaths => _configuration.GetValue(Prefix + "ReservedPaths", StaticReservedPaths); + + public string Path => _configuration.GetValue(Prefix + "Path"); + + // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings + public string ConfigurationStatus + { + get => _configuration.GetValue(Prefix + "ConfigurationStatus"); + set => throw new NotImplementedException("We should remove this and only use the value from database"); + } + + public int TimeOutInMinutes => _configuration.GetValue(Prefix + "TimeOutInMinutes", 20); + public string DefaultUILanguage => _configuration.GetValue(Prefix + "TimeOutInMinutes", "en-US"); + + public bool HideTopLevelNodeFromPath => + _configuration.GetValue(Prefix + "HideTopLevelNodeFromPath", false); + + public bool UseHttps => _configuration.GetValue(Prefix + "UseHttps", false); + public int VersionCheckPeriod => _configuration.GetValue(Prefix + "VersionCheckPeriod", 7); + public string UmbracoPath => _configuration.GetValue(Prefix + "UmbracoPath", "~/umbraco"); + public string UmbracoCssPath => _configuration.GetValue(Prefix + "UmbracoCssPath", "~/css"); + + public string UmbracoScriptsPath => + _configuration.GetValue(Prefix + "UmbracoScriptsPath", "~/scripts"); + + public string UmbracoMediaPath => _configuration.GetValue(Prefix + "UmbracoMediaPath", "~/media"); + + public bool InstallMissingDatabase => + _configuration.GetValue(Prefix + "InstallMissingDatabase", false); + + public bool InstallEmptyDatabase => _configuration.GetValue(Prefix + "InstallEmptyDatabase", false); + + public bool DisableElectionForSingleServer => + _configuration.GetValue(Prefix + "DisableElectionForSingleServer", false); + + public string RegisterType => _configuration.GetValue(Prefix + "RegisterType", string.Empty); + + public string DatabaseFactoryServerVersion => + _configuration.GetValue(Prefix + "DatabaseFactoryServerVersion", string.Empty); + + public string MainDomLock => _configuration.GetValue(Prefix + "MainDomLock", string.Empty); + + public string NoNodesViewPath => + _configuration.GetValue(Prefix + "NoNodesViewPath", "~/config/splashes/NoNodes.cshtml"); + + public bool IsSmtpServerConfigured => + _configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")?.GetChildren().Any() ?? false; + + public ISmtpSettings SmtpSettings => + new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")); + + private class SmtpSettingsImpl : ISmtpSettings + { + private readonly IConfigurationSection _configurationSection; + + public SmtpSettingsImpl(IConfigurationSection configurationSection) + { + _configurationSection = configurationSection; + } + + public string From => _configurationSection.GetValue("From"); + public string Host => _configurationSection.GetValue("Host"); + public int Port => _configurationSection.GetValue("Port"); + public string PickupDirectoryLocation => _configurationSection.GetValue("PickupDirectoryLocation"); + } + } +} diff --git a/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs new file mode 100644 index 0000000000..1d73051ec8 --- /dev/null +++ b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.HealthChecks; + +namespace Umbraco.Configuration.Models +{ + internal class HealthChecksSettings : IHealthChecksSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "HealthChecks:"; + private readonly IConfiguration _configuration; + + public HealthChecksSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public IEnumerable DisabledChecks => _configuration + .GetSection(Prefix+"DisabledChecks") + .GetChildren() + .Select( + x => new DisabledHealthCheck + { + Id = x.GetValue("Id"), + DisabledOn = x.GetValue("DisabledOn"), + DisabledBy = x.GetValue("DisabledBy") + }); + + public IHealthCheckNotificationSettings NotificationSettings => + new HealthCheckNotificationSettings( + _configuration.GetSection(Prefix+"NotificationSettings")); + + private class DisabledHealthCheck : IDisabledHealthCheck + { + public Guid Id { get; set; } + public DateTime DisabledOn { get; set; } + public int DisabledBy { get; set; } + } + + private class HealthCheckNotificationSettings : IHealthCheckNotificationSettings + { + private readonly IConfigurationSection _configurationSection; + + public HealthCheckNotificationSettings(IConfigurationSection configurationSection) + { + _configurationSection = configurationSection; + } + + public bool Enabled => _configurationSection.GetValue("Enabled", false); + public string FirstRunTime => _configurationSection.GetValue("FirstRunTime"); + public int PeriodInHours => _configurationSection.GetValue("PeriodInHours", 24); + + public IReadOnlyDictionary NotificationMethods => _configurationSection + .GetSection("NotificationMethods") + .GetChildren() + .ToDictionary(x => x.Key, x => (INotificationMethod) new NotificationMethod(x.Key, x)); + + public IEnumerable DisabledChecks => _configurationSection + .GetSection("DisabledChecks").GetChildren().Select( + x => new DisabledHealthCheck + { + Id = x.GetValue("Id"), + DisabledOn = x.GetValue("DisabledOn"), + DisabledBy = x.GetValue("DisabledBy") + }); + } + + private class NotificationMethod : INotificationMethod + { + private readonly IConfigurationSection _configurationSection; + + public NotificationMethod(string alias, IConfigurationSection configurationSection) + { + Alias = alias; + _configurationSection = configurationSection; + } + + public string Alias { get; } + public bool Enabled => _configurationSection.GetValue("Enabled", false); + + public HealthCheckNotificationVerbosity Verbosity => + _configurationSection.GetValue("Verbosity", HealthCheckNotificationVerbosity.Summary); + + public bool FailureOnly => _configurationSection.GetValue("FailureOnly", true); + + public IReadOnlyDictionary Settings => _configurationSection + .GetSection("Settings").GetChildren().ToDictionary(x => x.Key, + x => (INotificationMethodSettings) new NotificationMethodSettings(x.Key, x.Value)); + } + + private class NotificationMethodSettings : INotificationMethodSettings + { + public NotificationMethodSettings(string key, string value) + { + Key = key; + Value = value; + } + + public string Key { get; } + public string Value { get; } + } + } +} diff --git a/src/Umbraco.Configuration/Models/HostingSettings.cs b/src/Umbraco.Configuration/Models/HostingSettings.cs new file mode 100644 index 0000000000..4a156cee6a --- /dev/null +++ b/src/Umbraco.Configuration/Models/HostingSettings.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class HostingSettings : IHostingSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Hosting:"; + private readonly IConfiguration _configuration; + + public HostingSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + /// + public LocalTempStorage LocalTempStorageLocation => + _configuration.GetValue(Prefix+"LocalTempStorage", LocalTempStorage.Default); + + /// + /// Gets a value indicating whether umbraco is running in [debug mode]. + /// + /// true if [debug mode]; otherwise, false. + public bool DebugMode => _configuration.GetValue(Prefix+":Debug", false); + } +} diff --git a/src/Umbraco.Configuration/Models/ImagingSettings.cs b/src/Umbraco.Configuration/Models/ImagingSettings.cs new file mode 100644 index 0000000000..4a9501b2ba --- /dev/null +++ b/src/Umbraco.Configuration/Models/ImagingSettings.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class ImagingSettings : IImagingSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Imaging:"; + private const string CachePrefix = Prefix + "Cache:"; + private const string ResizePrefix = Prefix + "Resize:"; + private readonly IConfiguration _configuration; + + public ImagingSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public int MaxBrowserCacheDays => _configuration.GetValue(CachePrefix + "MaxBrowserCacheDays", 7); + public int MaxCacheDays => _configuration.GetValue(CachePrefix + "MaxCacheDays", 365); + public uint CachedNameLength => _configuration.GetValue(CachePrefix + "CachedNameLength", (uint) 8); + public string CacheFolder => _configuration.GetValue(CachePrefix + "Folder", "../App_Data/Cache"); + public int MaxResizeWidth => _configuration.GetValue(ResizePrefix + "MaxWidth", 5000); + public int MaxResizeHeight => _configuration.GetValue(ResizePrefix + "MaxHeight", 5000); + } +} diff --git a/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs new file mode 100644 index 0000000000..b4bb000552 --- /dev/null +++ b/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class IndexCreatorSettings : IIndexCreatorSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Examine:"; + private readonly IConfiguration _configuration; + + public IndexCreatorSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string LuceneDirectoryFactory => + _configuration.GetValue(Prefix + "LuceneDirectoryFactory"); + } +} diff --git a/src/Umbraco.Configuration/Models/KeepAliveSettings.cs b/src/Umbraco.Configuration/Models/KeepAliveSettings.cs new file mode 100644 index 0000000000..04194e1a3c --- /dev/null +++ b/src/Umbraco.Configuration/Models/KeepAliveSettings.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Models +{ + internal class KeepAliveSettings : IKeepAliveSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "KeepAlive:"; + private readonly IConfiguration _configuration; + + public KeepAliveSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public bool DisableKeepAliveTask => + _configuration.GetValue(Prefix + "DisableKeepAliveTask", false); + + public string KeepAlivePingUrl => _configuration.GetValue(Prefix + "KeepAlivePingUrl", + "{umbracoApplicationUrl}/api/keepalive/ping"); + } +} diff --git a/src/Umbraco.Configuration/Models/LoggingSettings.cs b/src/Umbraco.Configuration/Models/LoggingSettings.cs new file mode 100644 index 0000000000..b05fe03875 --- /dev/null +++ b/src/Umbraco.Configuration/Models/LoggingSettings.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Models +{ + internal class LoggingSettings : ILoggingSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Logging:"; + private readonly IConfiguration _configuration; + + public LoggingSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public int MaxLogAge => _configuration.GetValue(Prefix + "MaxLogAge", -1); + } +} diff --git a/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs new file mode 100644 index 0000000000..c7b147349e --- /dev/null +++ b/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class MemberPasswordConfigurationSettings : IMemberPasswordConfiguration + { + private const string Prefix = Constants.Configuration.ConfigSecurityPrefix + "MemberPassword:"; + private readonly IConfiguration _configuration; + + public MemberPasswordConfigurationSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public int RequiredLength => + _configuration.GetValue(Prefix + "RequiredLength", 10); + + public bool RequireNonLetterOrDigit => + _configuration.GetValue(Prefix + "RequireNonLetterOrDigit", false); + + public bool RequireDigit => + _configuration.GetValue(Prefix + "RequireDigit", false); + + public bool RequireLowercase => + _configuration.GetValue(Prefix + "RequireLowercase", false); + + public bool RequireUppercase => + _configuration.GetValue(Prefix + "RequireUppercase", false); + + public string HashAlgorithmType => + _configuration.GetValue(Prefix + "HashAlgorithmType", "HMACSHA256"); + + public int MaxFailedAccessAttemptsBeforeLockout => + _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5); + } +} diff --git a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs new file mode 100644 index 0000000000..d111dbba70 --- /dev/null +++ b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs @@ -0,0 +1,86 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + /// + /// Represents the models builder configuration. + /// + internal class ModelsBuilderConfig : IModelsBuilderConfig + { + private const string Prefix = Constants.Configuration.ConfigModelsBuilderPrefix; + private readonly IConfiguration _configuration; + + /// + /// Initializes a new instance of the class. + /// + public ModelsBuilderConfig(IConfiguration configuration) + { + _configuration = configuration; + } + + public string DefaultModelsDirectory => "~/App_Data/Models"; + + /// + /// Gets a value indicating whether the whole models experience is enabled. + /// + /// + /// If this is false then absolutely nothing happens. + /// Default value is false which means that unless we have this setting, nothing happens. + /// + public bool Enable => _configuration.GetValue(Prefix+"Enable", false); + + /// + /// Gets the models mode. + /// + public ModelsMode ModelsMode => + _configuration.GetValue(Prefix+"ModelsMode", ModelsMode.Nothing); + + /// + /// Gets the models namespace. + /// + /// That value could be overriden by other (attribute in user's code...). Return default if no value was supplied. + public string ModelsNamespace => _configuration.GetValue(Prefix+"ModelsNamespace"); + + /// + /// Gets a value indicating whether we should enable the models factory. + /// + /// Default value is true because no factory is enabled by default in Umbraco. + public bool EnableFactory => _configuration.GetValue(Prefix+"EnableFactory", true); + + /// + /// Gets a value indicating whether we should flag out-of-date models. + /// + /// + /// Models become out-of-date when data types or content types are updated. When this + /// setting is activated the ~/App_Data/Models/ood.txt file is then created. When models are + /// generated through the dashboard, the files is cleared. Default value is false. + /// + public bool FlagOutOfDateModels => + _configuration.GetValue(Prefix+"FlagOutOfDateModels", false) && !ModelsMode.IsLive(); + + /// + /// Gets the models directory. + /// + /// Default is ~/App_Data/Models but that can be changed. + public string ModelsDirectory => + _configuration.GetValue(Prefix+"ModelsDirectory", "~/App_Data/Models"); + + /// + /// Gets a value indicating whether to accept an unsafe value for ModelsDirectory. + /// + /// + /// An unsafe value is an absolute path, or a relative path pointing outside + /// of the website root. + /// + public bool AcceptUnsafeModelsDirectory => + _configuration.GetValue(Prefix+"AcceptUnsafeModelsDirectory", false); + + /// + /// Gets a value indicating the debug log level. + /// + /// 0 means minimal (safe on live site), anything else means more and more details (maybe not safe). + public int DebugLevel => _configuration.GetValue(Prefix+"DebugLevel", 0); + } +} diff --git a/src/Umbraco.Configuration/Models/NuCacheSettings.cs b/src/Umbraco.Configuration/Models/NuCacheSettings.cs new file mode 100644 index 0000000000..51b8b1fe08 --- /dev/null +++ b/src/Umbraco.Configuration/Models/NuCacheSettings.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class NuCacheSettings : INuCacheSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "NuCache:"; + private readonly IConfiguration _configuration; + + public NuCacheSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string BTreeBlockSize => _configuration.GetValue(Prefix+"BTreeBlockSize"); + } +} diff --git a/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs new file mode 100644 index 0000000000..ce5cd65c20 --- /dev/null +++ b/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Models +{ + internal class RequestHandlerSettings : IRequestHandlerSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "RequestHandler:"; + private static readonly CharItem[] DefaultCharCollection = + { + new CharItem { Char = " ", Replacement = "-" }, + new CharItem { Char = "\"", Replacement = "" }, + new CharItem { Char = "'", Replacement = "" }, + new CharItem { Char = "%", Replacement = "" }, + new CharItem { Char = ".", Replacement = "" }, + new CharItem { Char = ";", Replacement = "" }, + new CharItem { Char = "/", Replacement = "" }, + new CharItem { Char = "\\", Replacement = "" }, + new CharItem { Char = ":", Replacement = "" }, + new CharItem { Char = "#", Replacement = "" }, + new CharItem { Char = "+", Replacement = "plus" }, + new CharItem { Char = "*", Replacement = "star" }, + new CharItem { Char = "&", Replacement = "" }, + new CharItem { Char = "?", Replacement = "" }, + new CharItem { Char = "æ", Replacement = "ae" }, + new CharItem { Char = "ä", Replacement = "ae" }, + new CharItem { Char = "ø", Replacement = "oe" }, + new CharItem { Char = "ö", Replacement = "oe" }, + new CharItem { Char = "å", Replacement = "aa" }, + new CharItem { Char = "ü", Replacement = "ue" }, + new CharItem { Char = "ß", Replacement = "ss" }, + new CharItem { Char = "|", Replacement = "-" }, + new CharItem { Char = "<", Replacement = "" }, + new CharItem { Char = ">", Replacement = "" } + }; + + private readonly IConfiguration _configuration; + + public RequestHandlerSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public bool AddTrailingSlash => + _configuration.GetValue(Prefix+"AddTrailingSlash", true); + + public bool ConvertUrlsToAscii => _configuration + .GetValue(Prefix+"ConvertUrlsToAscii").InvariantEquals("true"); + + public bool TryConvertUrlsToAscii => _configuration + .GetValue(Prefix+"ConvertUrlsToAscii").InvariantEquals("try"); + + + //We need to special handle ":", as this character is special in keys + public IEnumerable CharCollection + { + get + { + var collection = _configuration.GetSection(Prefix + "CharCollection").GetChildren() + .Select(x => new CharItem() + { + Char = x.GetValue("Char"), + Replacement = x.GetValue("Replacement"), + }).ToArray(); + + if (collection.Any() || _configuration.GetSection("Prefix").GetChildren().Any(x => + x.Key.Equals("CharCollection", StringComparison.OrdinalIgnoreCase))) + { + return collection; + } + + return DefaultCharCollection; + } + } + + + public class CharItem : IChar + { + public string Char { get; set; } + public string Replacement { get; set; } + } + } +} diff --git a/src/Umbraco.Configuration/Models/RuntimeSettings.cs b/src/Umbraco.Configuration/Models/RuntimeSettings.cs new file mode 100644 index 0000000000..ef129030b6 --- /dev/null +++ b/src/Umbraco.Configuration/Models/RuntimeSettings.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class RuntimeSettings : IRuntimeSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Runtime:"; + private readonly IConfiguration _configuration; + public RuntimeSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public int? MaxQueryStringLength => _configuration.GetValue(Prefix+"MaxRequestLength"); + public int? MaxRequestLength => _configuration.GetValue(Prefix+"MaxRequestLength"); + } +} diff --git a/src/Umbraco.Configuration/Models/SecuritySettings.cs b/src/Umbraco.Configuration/Models/SecuritySettings.cs new file mode 100644 index 0000000000..9244eace96 --- /dev/null +++ b/src/Umbraco.Configuration/Models/SecuritySettings.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Models +{ + internal class SecuritySettings : ISecuritySettings + { + private const string Prefix = Constants.Configuration.ConfigSecurityPrefix; + private readonly IConfiguration _configuration; + + public SecuritySettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public bool KeepUserLoggedIn => _configuration.GetValue(Prefix + "KeepUserLoggedIn", true); + + public bool HideDisabledUsersInBackoffice => + _configuration.GetValue(Prefix + "HideDisabledUsersInBackoffice", false); + + public bool AllowPasswordReset => + _configuration.GetValue(Prefix + "AllowPasswordResetAllowPasswordReset", true); + + public string AuthCookieName => + _configuration.GetValue(Prefix + "AuthCookieName", "UMB_UCONTEXT"); + + public string AuthCookieDomain => + _configuration.GetValue(Prefix + "AuthCookieDomain"); + + public bool UsernameIsEmail => _configuration.GetValue(Prefix + "UsernameIsEmail", true); + } +} diff --git a/src/Umbraco.Configuration/Models/TourSettings.cs b/src/Umbraco.Configuration/Models/TourSettings.cs new file mode 100644 index 0000000000..9fe1814ff5 --- /dev/null +++ b/src/Umbraco.Configuration/Models/TourSettings.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Configuration.Models +{ + internal class TourSettings : ITourSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "Tours:"; + private readonly IConfiguration _configuration; + + public TourSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string Type { get; set; } + + public bool EnableTours => _configuration.GetValue(Prefix+"EnableTours", true); + } +} diff --git a/src/Umbraco.Configuration/Models/TypeFinderSettings.cs b/src/Umbraco.Configuration/Models/TypeFinderSettings.cs new file mode 100644 index 0000000000..8a1f7ac9e0 --- /dev/null +++ b/src/Umbraco.Configuration/Models/TypeFinderSettings.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class TypeFinderSettings : ITypeFinderSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "TypeFinder:"; + private readonly IConfiguration _configuration; + + public TypeFinderSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public string AssembliesAcceptingLoadExceptions => + _configuration.GetValue(Prefix+"AssembliesAcceptingLoadExceptions"); + } +} diff --git a/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs new file mode 100644 index 0000000000..5e68b16203 --- /dev/null +++ b/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration; + +namespace Umbraco.Configuration.Models +{ + internal class UserPasswordConfigurationSettings : IUserPasswordConfiguration + { + private const string Prefix = Constants.Configuration.ConfigSecurityPrefix + "UserPassword:"; + private readonly IConfiguration _configuration; + + public UserPasswordConfigurationSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public int RequiredLength => _configuration.GetValue(Prefix + "RequiredLength", 10); + + public bool RequireNonLetterOrDigit => + _configuration.GetValue(Prefix + "RequireNonLetterOrDigit", false); + + public bool RequireDigit => _configuration.GetValue(Prefix + "RequireDigit", false); + + public bool RequireLowercase => + _configuration.GetValue(Prefix + "RequireLowercase", false); + + public bool RequireUppercase => + _configuration.GetValue(Prefix + "RequireUppercase", false); + + public string HashAlgorithmType => + _configuration.GetValue(Prefix + "HashAlgorithmType", "HMACSHA256"); + + public int MaxFailedAccessAttemptsBeforeLockout => + _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5); + } +} diff --git a/src/Umbraco.Configuration/Models/WebRoutingSettings.cs b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs new file mode 100644 index 0000000000..9ac856ca9f --- /dev/null +++ b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Configuration; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Configuration.Models +{ + internal class WebRoutingSettings : IWebRoutingSettings + { + private const string Prefix = Constants.Configuration.ConfigPrefix + "WebRouting:"; + private readonly IConfiguration _configuration; + + public WebRoutingSettings(IConfiguration configuration) + { + _configuration = configuration; + } + + public bool TrySkipIisCustomErrors => + _configuration.GetValue(Prefix + "TrySkipIisCustomErrors", false); + + public bool InternalRedirectPreservesTemplate => + _configuration.GetValue(Prefix + "InternalRedirectPreservesTemplate", false); + + public bool DisableAlternativeTemplates => + _configuration.GetValue(Prefix + "DisableAlternativeTemplates", false); + + public bool ValidateAlternativeTemplates => + _configuration.GetValue(Prefix + "ValidateAlternativeTemplates", false); + + public bool DisableFindContentByIdPath => + _configuration.GetValue(Prefix + "DisableFindContentByIdPath", false); + + public bool DisableRedirectUrlTracking => + _configuration.GetValue(Prefix + "DisableRedirectUrlTracking", false); + + public string UrlProviderMode => + _configuration.GetValue(Prefix + "UrlProviderMode", UrlMode.Auto.ToString()); + + public string UmbracoApplicationUrl => + _configuration.GetValue(Prefix + "UmbracoApplicationUrl"); + } +} diff --git a/src/Umbraco.Configuration/Properties/AssemblyInfo.cs b/src/Umbraco.Configuration/Properties/AssemblyInfo.cs index d10dd929da..b77c087e22 100644 --- a/src/Umbraco.Configuration/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Configuration/Properties/AssemblyInfo.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; // Umbraco Cms [assembly: InternalsVisibleTo("Umbraco.Tests")] +[assembly: InternalsVisibleTo("Umbraco.Tests.Common")] [assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")] // Allow this to be mocked in our unit tests diff --git a/src/Umbraco.Configuration/Umbraco.Configuration.csproj b/src/Umbraco.Configuration/Umbraco.Configuration.csproj index 57fca1dfd6..88bb3639d0 100644 --- a/src/Umbraco.Configuration/Umbraco.Configuration.csproj +++ b/src/Umbraco.Configuration/Umbraco.Configuration.csproj @@ -22,6 +22,9 @@ + + + diff --git a/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs b/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs index 79bff51d05..46b9bf32a9 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs @@ -7,6 +7,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings [ConfigurationProperty("tours")] internal TourConfigElement Tours => (TourConfigElement)this["tours"]; - ITourSection IBackOfficeSection.Tours => Tours; + ITourSettings IBackOfficeSection.Tours => Tours; } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs index 8e4f0edd8f..28b4314c9a 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Macros; namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class ContentElement : UmbracoConfigurationElement, IContentSection + internal class ContentElement : UmbracoConfigurationElement, IContentSettings { private const string DefaultPreviewBadge = @"
Preview modeClick to end
"; @@ -40,26 +40,26 @@ namespace Umbraco.Core.Configuration.UmbracoSettings [ConfigurationProperty("loginBackgroundImage")] internal InnerTextConfigurationElement LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty); - string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress; + string IContentSettings.NotificationEmailAddress => Notifications.NotificationEmailAddress; - bool IContentSection.DisableHtmlEmail => Notifications.DisableHtmlEmail; + bool IContentSettings.DisableHtmlEmail => Notifications.DisableHtmlEmail; - IEnumerable IContentSection.ImageFileTypes => Imaging.ImageFileTypes; + IEnumerable IContentSettings.ImageFileTypes => Imaging.ImageFileTypes; - IEnumerable IContentSection.ImageAutoFillProperties => Imaging.ImageAutoFillProperties; + IEnumerable IContentSettings.ImageAutoFillProperties => Imaging.ImageAutoFillProperties; - bool IContentSection.ResolveUrlsFromTextString => ResolveUrlsFromTextString; + bool IContentSettings.ResolveUrlsFromTextString => ResolveUrlsFromTextString; - string IContentSection.PreviewBadge => PreviewBadge; + string IContentSettings.PreviewBadge => PreviewBadge; - MacroErrorBehaviour IContentSection.MacroErrorBehaviour => MacroErrors; + MacroErrorBehaviour IContentSettings.MacroErrorBehaviour => MacroErrors; - IEnumerable IContentSection.DisallowedUploadFiles => DisallowedUploadFiles; + IEnumerable IContentSettings.DisallowedUploadFiles => DisallowedUploadFiles; - IEnumerable IContentSection.AllowedUploadFiles => AllowedUploadFiles; + IEnumerable IContentSettings.AllowedUploadFiles => AllowedUploadFiles; - bool IContentSection.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors; + bool IContentSettings.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors; - string IContentSection.LoginBackgroundImage => LoginBackgroundImage; + string IContentSettings.LoginBackgroundImage => LoginBackgroundImage; } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs b/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs index 89ba9be54d..2297fb4e20 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class KeepAliveElement : ConfigurationElement, IKeepAliveSection + internal class KeepAliveElement : ConfigurationElement, IKeepAliveSettings { [ConfigurationProperty("disableKeepAliveTask", DefaultValue = "false")] public bool DisableKeepAliveTask => (bool)base["disableKeepAliveTask"]; diff --git a/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs index 106b6cc134..2fdd61e169 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs @@ -3,12 +3,12 @@ using System.Configuration; namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class LoggingElement : UmbracoConfigurationElement, ILoggingSection + internal class LoggingElement : UmbracoConfigurationElement, ILoggingSettings { [ConfigurationProperty("maxLogAge")] internal InnerTextConfigurationElement MaxLogAge => GetOptionalTextElement("maxLogAge", -1); - int ILoggingSection.MaxLogAge => MaxLogAge; + int ILoggingSettings.MaxLogAge => MaxLogAge; } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs index 93c7c20159..92cd112630 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfigurationSection + internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfiguration { } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs b/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs index 80fcb6ca1a..f959a56e71 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSection + internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSettings { [ConfigurationProperty("addTrailingSlash")] public InnerTextConfigurationElement AddTrailingSlash => GetOptionalTextElement("addTrailingSlash", true); @@ -85,12 +85,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings return collection; } - bool IRequestHandlerSection.AddTrailingSlash => AddTrailingSlash; + bool IRequestHandlerSettings.AddTrailingSlash => AddTrailingSlash; - bool IRequestHandlerSection.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true"); + bool IRequestHandlerSettings.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true"); - bool IRequestHandlerSection.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try"); + bool IRequestHandlerSettings.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try"); - IEnumerable IRequestHandlerSection.CharCollection => UrlReplacing.CharCollection; + IEnumerable IRequestHandlerSettings.CharCollection => UrlReplacing.CharCollection; } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs b/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs index 82012cfd0f..aec6809298 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class SecurityElement : UmbracoConfigurationElement, ISecuritySection + internal class SecurityElement : UmbracoConfigurationElement, ISecuritySettings { [ConfigurationProperty("keepUserLoggedIn")] internal InnerTextConfigurationElement KeepUserLoggedIn => GetOptionalTextElement("keepUserLoggedIn", true); @@ -38,14 +38,14 @@ namespace Umbraco.Core.Configuration.UmbracoSettings [ConfigurationProperty("memberPasswordConfiguration")] public MemberPasswordConfigurationElement MemberPasswordConfiguration => (MemberPasswordConfigurationElement)this["memberPasswordConfiguration"]; - bool ISecuritySection.KeepUserLoggedIn => KeepUserLoggedIn; + bool ISecuritySettings.KeepUserLoggedIn => KeepUserLoggedIn; - bool ISecuritySection.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice; + bool ISecuritySettings.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice; /// /// Used to enable/disable the forgot password functionality on the back office login screen /// - bool ISecuritySection.AllowPasswordReset => AllowPasswordReset; + bool ISecuritySettings.AllowPasswordReset => AllowPasswordReset; /// /// A boolean indicating that by default the email address will be the username @@ -54,14 +54,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings /// Even if this is true and the username is different from the email in the database, the username field will still be shown. /// When this is false, the username and email fields will be shown in the user section. /// - bool ISecuritySection.UsernameIsEmail => UsernameIsEmail; + bool ISecuritySettings.UsernameIsEmail => UsernameIsEmail; - string ISecuritySection.AuthCookieName => AuthCookieName; + string ISecuritySettings.AuthCookieName => AuthCookieName; - string ISecuritySection.AuthCookieDomain => AuthCookieDomain; - - IUserPasswordConfigurationSection ISecuritySection.UserPasswordConfiguration => UserPasswordConfiguration; - - IMemberPasswordConfigurationSection ISecuritySection.MemberPasswordConfiguration => MemberPasswordConfiguration; + string ISecuritySettings.AuthCookieDomain => AuthCookieDomain; } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs b/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs index dab69f3da0..f75b71fc57 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class TourConfigElement : UmbracoConfigurationElement, ITourSection + internal class TourConfigElement : UmbracoConfigurationElement, ITourSettings { //disabled by default so that upgraders don't get it enabled by default // TODO: we probably just want to disable the initial one from automatically loading ? diff --git a/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs b/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs index e605b86edf..781d00b979 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection + internal class UmbracoSettingsSection : ConfigurationSection { [ConfigurationProperty("backOffice")] public BackOfficeElement BackOffice => (BackOfficeElement)this["backOffice"]; @@ -24,19 +24,5 @@ namespace Umbraco.Core.Configuration.UmbracoSettings [ConfigurationProperty("keepAlive")] internal KeepAliveElement KeepAlive => (KeepAliveElement)this["keepAlive"]; - - IContentSection IUmbracoSettingsSection.Content => Content; - - ISecuritySection IUmbracoSettingsSection.Security => Security; - - IRequestHandlerSection IUmbracoSettingsSection.RequestHandler => RequestHandler; - - IBackOfficeSection IUmbracoSettingsSection.BackOffice => BackOffice; - - ILoggingSection IUmbracoSettingsSection.Logging => Logging; - - IWebRoutingSection IUmbracoSettingsSection.WebRouting => WebRouting; - - IKeepAliveSection IUmbracoSettingsSection.KeepAlive => KeepAlive; } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs index 8128f3d8e7..a1d2aa8842 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfigurationSection + internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfiguration { } } diff --git a/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs index 7b7102f2e7..206fc213d2 100644 --- a/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs +++ b/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - internal class WebRoutingElement : ConfigurationElement, IWebRoutingSection + internal class WebRoutingElement : ConfigurationElement, IWebRoutingSettings { [ConfigurationProperty("trySkipIisCustomErrors", DefaultValue = "false")] public bool TrySkipIisCustomErrors => (bool) base["trySkipIisCustomErrors"]; diff --git a/src/Umbraco.Configuration/UmbracoVersionExtensions.cs b/src/Umbraco.Configuration/UmbracoVersionExtensions.cs deleted file mode 100644 index 168bb16f57..0000000000 --- a/src/Umbraco.Configuration/UmbracoVersionExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Configuration; -using Semver; -using Umbraco.Core; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration -{ - public static class UmbracoVersionExtensions - { - /// - /// Gets the "local" version of the site. - /// - /// - /// Three things have a version, really: the executing code, the database model, - /// and the site/files. The database model version is entirely managed via migrations, - /// and changes during an upgrade. The executing code version changes when new code is - /// deployed. The site/files version changes during an upgrade. - /// - public static SemVersion LocalVersion(this IUmbracoVersion umbracoVersion) - { - try - { - // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings - var value = ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus]; - return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null; - } - catch - { - return null; - } - } - } -} diff --git a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs index 452f897372..e70b40160e 100644 --- a/src/Umbraco.Core/Cache/DeepCloneAppCache.cs +++ b/src/Umbraco.Core/Cache/DeepCloneAppCache.cs @@ -73,7 +73,7 @@ namespace Umbraco.Core.Cache var result = SafeLazy.GetSafeLazy(factory); var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache // do not store null values (backward compat), clone / reset to go into the cache - return value == null ? null : CheckCloneableAndTracksChanges(value); + return value == null ? null : CheckCloneableAndTracksChanges(value); // clone / reset to go into the cache }, timeout, isSliding, dependentFiles); @@ -107,9 +107,9 @@ namespace Umbraco.Core.Cache } /// - public void ClearOfType(string typeName) + public void ClearOfType(Type type) { - InnerCache.ClearOfType(typeName); + InnerCache.ClearOfType(type); } /// diff --git a/src/Umbraco.Core/Cache/DictionaryAppCache.cs b/src/Umbraco.Core/Cache/DictionaryAppCache.cs index d372916240..04ee3e0afa 100644 --- a/src/Umbraco.Core/Cache/DictionaryAppCache.cs +++ b/src/Umbraco.Core/Cache/DictionaryAppCache.cs @@ -71,16 +71,16 @@ namespace Umbraco.Core.Cache } /// - public virtual void ClearOfType(string typeName) + public virtual void ClearOfType(Type type) { - _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType().ToString().InvariantEquals(typeName)); + _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == type); } /// public virtual void ClearOfType() { var typeOfT = typeof(T); - _items.RemoveAll(kvp => kvp.Value != null && kvp.Value.GetType() == typeOfT); + ClearOfType(typeOfT); } /// diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs index 159f9cd7cb..54009af465 100644 --- a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs +++ b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs @@ -12,12 +12,6 @@ namespace Umbraco.Core.Cache /// public class FastDictionaryAppCache : IAppCache { - private readonly ITypeFinder _typeFinder; - - public FastDictionaryAppCache(ITypeFinder typeFinder) - { - _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder)); - } /// /// Gets the internal items dictionary, for tests only! @@ -83,9 +77,8 @@ namespace Umbraco.Core.Cache } /// - public void ClearOfType(string typeName) + public void ClearOfType(Type type) { - var type = _typeFinder.GetTypeByName(typeName); if (type == null) return; var isInterface = type.IsInterface; diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs index f417c5ffd0..bb55762826 100644 --- a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs +++ b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs @@ -12,13 +12,6 @@ namespace Umbraco.Core.Cache /// public abstract class FastDictionaryAppCacheBase : IAppCache { - private readonly ITypeFinder _typeFinder; - - protected FastDictionaryAppCacheBase(ITypeFinder typeFinder) - { - _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder)); - } - // prefix cache keys so we know which one are ours protected const string CacheItemPrefix = "umbrtmche"; @@ -121,9 +114,8 @@ namespace Umbraco.Core.Cache } /// - public virtual void ClearOfType(string typeName) + public virtual void ClearOfType(Type type) { - var type = _typeFinder.GetTypeByName(typeName); if (type == null) return; var isInterface = type.IsInterface; try diff --git a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs index e698d93ebe..6ce43a7bc9 100644 --- a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs +++ b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Cache /// /// Initializes a new instance of the class with a context, for unit tests! /// - public HttpRequestAppCache(Func requestItems, ITypeFinder typeFinder) : base(typeFinder) + public HttpRequestAppCache(Func requestItems) : base() { ContextItems = requestItems; } diff --git a/src/Umbraco.Core/Cache/IAppCache.cs b/src/Umbraco.Core/Cache/IAppCache.cs index 674781f6d6..c84ec1135c 100644 --- a/src/Umbraco.Core/Cache/IAppCache.cs +++ b/src/Umbraco.Core/Cache/IAppCache.cs @@ -51,14 +51,14 @@ namespace Umbraco.Core.Cache /// /// Removes items of a specified type from the cache. /// - /// The name of the type to remove. + /// The type to remove. /// /// If the type is an interface, then all items of a type implementing that interface are /// removed. Otherwise, only items of that exact type are removed (items of type inheriting from /// the specified type are not removed). /// Performs a case-sensitive search. /// - void ClearOfType(string typeName); + void ClearOfType(Type type); /// /// Removes items of a specified type from the cache. diff --git a/src/Umbraco.Core/Cache/NoAppCache.cs b/src/Umbraco.Core/Cache/NoAppCache.cs index 60bc6fb8b8..cae3a7381e 100644 --- a/src/Umbraco.Core/Cache/NoAppCache.cs +++ b/src/Umbraco.Core/Cache/NoAppCache.cs @@ -67,7 +67,7 @@ namespace Umbraco.Core.Cache { } /// - public virtual void ClearOfType(string typeName) + public virtual void ClearOfType(Type type) { } /// diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs index 208390276a..dc9163affb 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs @@ -13,15 +13,13 @@ namespace Umbraco.Core.Cache /// public class ObjectCacheAppCache : IAppPolicyCache { - private readonly ITypeFinder _typeFinder; private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); /// /// Initializes a new instance of the . /// - public ObjectCacheAppCache(ITypeFinder typeFinder) + public ObjectCacheAppCache() { - _typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder)); // the MemoryCache is created with name "in-memory". That name is // used to retrieve configuration options. It does not identify the memory cache, i.e. // each instance of this class has its own, independent, memory cache. @@ -178,9 +176,8 @@ namespace Umbraco.Core.Cache } /// - public virtual void ClearOfType(string typeName) + public virtual void ClearOfType(Type type) { - var type = _typeFinder.GetTypeByName(typeName); if (type == null) return; var isInterface = type.IsInterface; try diff --git a/src/Umbraco.Core/Composing/Composition.cs b/src/Umbraco.Core/Composing/Composition.cs index a186a1f00a..05c7554eab 100644 --- a/src/Umbraco.Core/Composing/Composition.cs +++ b/src/Umbraco.Core/Composing/Composition.cs @@ -33,13 +33,13 @@ namespace Umbraco.Core.Composing /// An IOHelper public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs, IIOHelper ioHelper, AppCaches appCaches) { - _register = register; - TypeLoader = typeLoader; - Logger = logger; - RuntimeState = runtimeState; - Configs = configs; - IOHelper = ioHelper; - AppCaches = appCaches; + _register = register ?? throw new ArgumentNullException(nameof(register)); + TypeLoader = typeLoader ?? throw new ArgumentNullException(nameof(typeLoader)); + Logger = logger ?? throw new ArgumentNullException(nameof(logger)); + RuntimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); + Configs = configs ?? throw new ArgumentNullException(nameof(configs)); + IOHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); + AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); } #region Services @@ -135,7 +135,7 @@ namespace Umbraco.Core.Composing IFactory factory = null; - Configs.RegisterWith(_register, () => factory); + Configs.RegisterWith(_register); // ReSharper disable once AccessToModifiedClosure -- on purpose _register.Register(_ => factory, Lifetime.Singleton); diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs new file mode 100644 index 0000000000..f7c81d6d7e --- /dev/null +++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Umbraco.Core.Composing +{ + /// + /// Returns a list of scannable assemblies based on an entry point assembly and it's references + /// + /// + /// This will recursively search through the entry point's assemblies and Umbraco's core assemblies and their references + /// to create a list of scannable assemblies based on whether they themselves or their transitive dependencies reference Umbraco core assemblies. + /// + public class DefaultUmbracoAssemblyProvider : IAssemblyProvider + { + private readonly Assembly _entryPointAssembly; + private static readonly string[] UmbracoCoreAssemblyNames = new[] + { + "Umbraco.Core", + "Umbraco.Web", + "Umbraco.Web.BackOffice", + "Umbraco.Infrastructure", + "Umbraco.PublishedCache.NuCache", + "Umbraco.ModelsBuilder.Embedded", + "Umbraco.Examine.Lucene", + }; + + public DefaultUmbracoAssemblyProvider(Assembly entryPointAssembly) + { + _entryPointAssembly = entryPointAssembly ?? throw new ArgumentNullException(nameof(entryPointAssembly)); + } + + // TODO: It would be worth investigating a netcore3 version of this which would use + // var allAssemblies = System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies); + // that will still only resolve Assemblies that are already loaded but it would also make it possible to + // query dynamically generated assemblies once they are added. It would also provide the ability to probe + // assembly locations that are not in the same place as the entry point assemblies. + + public IEnumerable Assemblies + { + get + { + var finder = new FindAssembliesWithReferencesTo(new[] { _entryPointAssembly }, UmbracoCoreAssemblyNames, true); + return finder.Find(); + } + } + } +} diff --git a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs new file mode 100644 index 0000000000..9378941166 --- /dev/null +++ b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Umbraco.Core.Composing +{ + /// + /// Finds Assemblies from the entry point assemblies, it's dependencies and it's transitive dependencies that reference that targetAssemblyNames + /// + /// + /// borrowed and modified from here https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/FindAssembliesWithReferencesTo.cs + /// + internal class FindAssembliesWithReferencesTo + { + private readonly Assembly[] _referenceAssemblies; + private readonly string[] _targetAssemblies; + private readonly bool _includeTargets; + + /// + /// Constructor + /// + /// Entry point assemblies + /// Used to check if the entry point or it's transitive assemblies reference these assembly names + /// If true will also use the target assembly names as entry point assemblies + public FindAssembliesWithReferencesTo(Assembly[] referenceAssemblies, string[] targetAssemblyNames, bool includeTargets) + { + _referenceAssemblies = referenceAssemblies; + _targetAssemblies = targetAssemblyNames; + _includeTargets = includeTargets; + } + + public IEnumerable Find() + { + var referenceItems = new List(); + foreach (var assembly in _referenceAssemblies) + { + referenceItems.Add(assembly); + } + + if (_includeTargets) + { + foreach(var target in _targetAssemblies) + { + try + { + referenceItems.Add(Assembly.Load(target)); + } + catch (FileNotFoundException) + { + // occurs if we cannot load this ... for example in a test project where we aren't currently referencing Umbraco.Web, etc... + } + } + } + + var provider = new ReferenceResolver(_targetAssemblies, referenceItems); + var assemblyNames = provider.ResolveAssemblies(); + return assemblyNames.ToList(); + } + + } +} diff --git a/src/Umbraco.Core/Composing/IAssemblyProvider.cs b/src/Umbraco.Core/Composing/IAssemblyProvider.cs new file mode 100644 index 0000000000..bde97a9556 --- /dev/null +++ b/src/Umbraco.Core/Composing/IAssemblyProvider.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace Umbraco.Core.Composing +{ + /// + /// Provides a list of assemblies that can be scanned + /// + public interface IAssemblyProvider + { + IEnumerable Assemblies { get; } + } +} diff --git a/src/Umbraco.Core/Composing/ReferenceResolver.cs b/src/Umbraco.Core/Composing/ReferenceResolver.cs new file mode 100644 index 0000000000..65dba8bf23 --- /dev/null +++ b/src/Umbraco.Core/Composing/ReferenceResolver.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Umbraco.Core.Composing +{ + /// + /// Resolves assemblies that reference one of the specified "targetAssemblies" either directly or transitively. + /// + /// + /// Borrowed and modified from https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/ReferenceResolver.cs + /// + internal class ReferenceResolver + { + private readonly HashSet _umbracoAssemblies; + private readonly IReadOnlyList _assemblies; + private readonly Dictionary _classifications; + private readonly List _lookup = new List(); + + public ReferenceResolver(IReadOnlyList targetAssemblies, IReadOnlyList entryPointAssemblies) + { + _umbracoAssemblies = new HashSet(targetAssemblies, StringComparer.Ordinal); + _assemblies = entryPointAssemblies; + _classifications = new Dictionary(); + + foreach (var item in entryPointAssemblies) + { + _lookup.Add(item); + } + } + + /// + /// Returns a list of assemblies that directly reference or transitively reference the targetAssemblies + /// + /// + /// + /// This includes all assemblies in the same location as the entry point assemblies + /// + public IEnumerable ResolveAssemblies() + { + var applicationParts = new List(); + + var assemblies = new HashSet(_assemblies); + + // Get the unique directories of the assemblies + var assemblyLocations = GetAssemblyFolders(assemblies).ToList(); + + // Load in each assembly in the directory of the entry assembly to be included in the search + // for Umbraco dependencies/transitive dependencies + foreach(var dir in assemblyLocations) + { + foreach(var dll in Directory.EnumerateFiles(dir, "*.dll")) + { + var assemblyName = AssemblyName.GetAssemblyName(dll); + + // don't include if this is excluded + if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => assemblyName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase))) + continue; + + // don't include this item if it's Umbraco + // TODO: We should maybe pass an explicit list of these names in? + if (assemblyName.FullName.StartsWith("Umbraco.")) + continue; + + var assembly = Assembly.Load(assemblyName); + assemblies.Add(assembly); + } + } + + foreach (var item in assemblies) + { + var classification = Resolve(item); + if (classification == Classification.ReferencesUmbraco || classification == Classification.IsUmbraco) + { + applicationParts.Add(item); + } + } + + return applicationParts; + } + + + private IEnumerable GetAssemblyFolders(IEnumerable assemblies) + { + return assemblies.Select(x => Path.GetDirectoryName(GetAssemblyLocation(x)).ToLowerInvariant()).Distinct(); + } + + // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs + private string GetAssemblyLocation(Assembly assembly) + { + if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out var result) && + result.IsFile && string.IsNullOrWhiteSpace(result.Fragment)) + { + return result.LocalPath; + } + + return assembly.Location; + } + + private Classification Resolve(Assembly assembly) + { + if (_classifications.TryGetValue(assembly, out var classification)) + { + return classification; + } + + // Initialize the dictionary with a value to short-circuit recursive references. + classification = Classification.Unknown; + _classifications[assembly] = classification; + + if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => assembly.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase))) + { + // if its part of the filter it doesn't reference umbraco + classification = Classification.DoesNotReferenceUmbraco; + } + else if (_umbracoAssemblies.Contains(assembly.GetName().Name)) + { + classification = Classification.IsUmbraco; + } + else + { + classification = Classification.DoesNotReferenceUmbraco; + foreach (var reference in GetReferences(assembly)) + { + // recurse + var referenceClassification = Resolve(reference); + + if (referenceClassification == Classification.IsUmbraco || referenceClassification == Classification.ReferencesUmbraco) + { + classification = Classification.ReferencesUmbraco; + break; + } + } + } + + Debug.Assert(classification != Classification.Unknown); + _classifications[assembly] = classification; + return classification; + } + + protected virtual IEnumerable GetReferences(Assembly assembly) + { + foreach (var referenceName in assembly.GetReferencedAssemblies()) + { + // don't include if this is excluded + if (TypeFinder.KnownAssemblyExclusionFilter.Any(f => referenceName.FullName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase))) + continue; + + var reference = Assembly.Load(referenceName); + + if (!_lookup.Contains(reference)) + { + // A dependency references an item that isn't referenced by this project. + // We'll add this reference so that we can calculate the classification. + + _lookup.Add(reference); + } + yield return reference; + } + } + + protected enum Classification + { + Unknown, + DoesNotReferenceUmbraco, + ReferencesUmbraco, + IsUmbraco, + } + } +} diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs index 9d88153b0a..79fddad1ca 100644 --- a/src/Umbraco.Core/Composing/TypeFinder.cs +++ b/src/Umbraco.Core/Composing/TypeFinder.cs @@ -1,106 +1,35 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Configuration; -using System.IO; using System.Linq; using System.Reflection; using System.Security; using System.Text; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Exceptions; -using Umbraco.Core.IO; using Umbraco.Core.Logging; namespace Umbraco.Core.Composing { + /// public class TypeFinder : ITypeFinder { private readonly ILogger _logger; - - public TypeFinder(ILogger logger, ITypeFinderConfig typeFinderConfig = null) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty(); - _allAssemblies = new Lazy>(() => - { - HashSet assemblies = null; - try - { - //NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have - // already been loaded in to the app domain, instead we will look directly into the bin folder and load each one. - var binFolder = GetRootDirectorySafe(); - var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList(); - //var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory; - //var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList(); - assemblies = new HashSet(); - foreach (var a in binAssemblyFiles) - { - try - { - var assName = AssemblyName.GetAssemblyName(a); - var ass = Assembly.Load(assName); - assemblies.Add(ass); - } - catch (Exception e) - { - if (e is SecurityException || e is BadImageFormatException) - { - //swallow these exceptions - } - else - { - throw; - } - } - } - - //Since we are only loading in the /bin assemblies above, we will also load in anything that's already loaded (which will include gac items) - foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) - { - assemblies.Add(a); - } - } - catch (InvalidOperationException e) - { - if (e.InnerException is SecurityException == false) - throw; - } - - return assemblies; - }); - } - - //Lazy access to the all assemblies list - private readonly Lazy> _allAssemblies; + private readonly IAssemblyProvider _assemblyProvider; private volatile HashSet _localFilteredAssemblyCache; private readonly object _localFilteredAssemblyCacheLocker = new object(); private readonly List _notifiedLoadExceptionAssemblies = new List(); - private static readonly ConcurrentDictionary TypeNamesCache= new ConcurrentDictionary(); - private string _rootDir = ""; + private static readonly ConcurrentDictionary TypeNamesCache = new ConcurrentDictionary(); private readonly string[] _assembliesAcceptingLoadExceptions; - // FIXME - this is only an interim change, once the IIOHelper stuff is merged we should use IIOHelper here - private string GetRootDirectorySafe() + // used for benchmark tests + internal bool QueryWithReferencingAssemblies = true; + + public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, ITypeFinderConfig typeFinderConfig = null) { - if (string.IsNullOrEmpty(_rootDir) == false) - { - return _rootDir; - } - - var codeBase = Assembly.GetExecutingAssembly().CodeBase; - var uri = new Uri(codeBase); - var path = uri.LocalPath; - var baseDirectory = Path.GetDirectoryName(path); - if (string.IsNullOrEmpty(baseDirectory)) - throw new PanicException("No root directory could be resolved."); - - _rootDir = baseDirectory.Contains("bin") - ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1) - : baseDirectory; - - return _rootDir; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _assemblyProvider = assemblyProvider; + _assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty(); } private bool AcceptsLoadExceptions(Assembly a) @@ -119,22 +48,8 @@ namespace Umbraco.Core.Composing }); } - /// - /// lazily load a reference to all assemblies and only local assemblies. - /// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder - /// - /// - /// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been - /// loaded in the CLR, not all assemblies. - /// See these threads: - /// http://issues.umbraco.org/issue/U5-198 - /// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app - /// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl - /// - private IEnumerable GetAllAssemblies() - { - return _allAssemblies.Value; - } + + private IEnumerable GetAllAssemblies() => _assemblyProvider.Assemblies; /// public IEnumerable AssembliesToScan @@ -181,7 +96,10 @@ namespace Umbraco.Core.Composing /// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match /// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll" /// - private static readonly string[] KnownAssemblyExclusionFilter = { + internal static readonly string[] KnownAssemblyExclusionFilter = { + "mscorlib,", + "netstandard,", + "System,", "Antlr3.", "AutoMapper,", "AutoMapper.", @@ -228,7 +146,14 @@ namespace Umbraco.Core.Composing "WebDriver,", "itextsharp,", "mscorlib,", - "nunit.framework,", + "NUnit,", + "NUnit.", + "NUnit3.", + "Selenium.", + "ImageProcessor", + "MiniProfiler.", + "Owin,", + "SQLite", }; /// @@ -290,6 +215,11 @@ namespace Umbraco.Core.Composing /// public virtual Type GetTypeByName(string name) { + + //NOTE: This will not find types in dynamic assemblies unless those assemblies are already loaded + //into the appdomain. + + // This is exactly what the BuildManager does, if the type is an assembly qualified type // name it will find it. if (TypeNameContainsAssembly(name)) @@ -340,18 +270,24 @@ namespace Umbraco.Core.Composing var stack = new Stack(); stack.Push(attributeType.Assembly); + if (!QueryWithReferencingAssemblies) + { + foreach (var a in candidateAssemblies) + stack.Push(a); + } + while (stack.Count > 0) { var assembly = stack.Pop(); - Type[] assemblyTypes = null; + IReadOnlyList assemblyTypes = null; if (assembly != attributeType.Assembly || attributeAssemblyIsCandidate) { // get all assembly types that can be assigned to baseType try { assemblyTypes = GetTypesWithFormattedException(assembly) - .ToArray(); // in try block + .ToList(); // in try block } catch (TypeLoadException ex) { @@ -371,10 +307,13 @@ namespace Umbraco.Core.Composing if (assembly != attributeType.Assembly && assemblyTypes.Where(attributeType.IsAssignableFrom).Any() == false) continue; - foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies)) + if (QueryWithReferencingAssemblies) { - candidateAssemblies.Remove(referencing); - stack.Push(referencing); + foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies)) + { + candidateAssemblies.Remove(referencing); + stack.Push(referencing); + } } } @@ -405,19 +344,25 @@ namespace Umbraco.Core.Composing var stack = new Stack(); stack.Push(baseType.Assembly); + if (!QueryWithReferencingAssemblies) + { + foreach (var a in candidateAssemblies) + stack.Push(a); + } + while (stack.Count > 0) { var assembly = stack.Pop(); // get all assembly types that can be assigned to baseType - Type[] assemblyTypes = null; + IReadOnlyList assemblyTypes = null; if (assembly != baseType.Assembly || baseTypeAssemblyIsCandidate) { try { assemblyTypes = GetTypesWithFormattedException(assembly) .Where(baseType.IsAssignableFrom) - .ToArray(); // in try block + .ToList(); // in try block } catch (TypeLoadException ex) { @@ -437,10 +382,13 @@ namespace Umbraco.Core.Composing if (assembly != baseType.Assembly && assemblyTypes.All(x => x.IsSealed)) continue; - foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies)) + if (QueryWithReferencingAssemblies) { - candidateAssemblies.Remove(referencing); - stack.Push(referencing); + foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies)) + { + candidateAssemblies.Remove(referencing); + stack.Push(referencing); + } } } @@ -522,6 +470,5 @@ namespace Umbraco.Core.Composing #endregion - } } diff --git a/src/Umbraco.Core/Composing/TypeFinderConfig.cs b/src/Umbraco.Core/Composing/TypeFinderConfig.cs new file mode 100644 index 0000000000..3dc672b27c --- /dev/null +++ b/src/Umbraco.Core/Composing/TypeFinderConfig.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Core.Composing +{ + /// + /// TypeFinder config via appSettings + /// + internal class TypeFinderConfig : ITypeFinderConfig + { + private readonly ITypeFinderSettings _settings; + private IEnumerable _assembliesAcceptingLoadExceptions; + + public TypeFinderConfig(ITypeFinderSettings settings) + { + _settings = settings; + } + + public IEnumerable AssembliesAcceptingLoadExceptions + { + get + { + if (_assembliesAcceptingLoadExceptions != null) + return _assembliesAcceptingLoadExceptions; + + var s = _settings.AssembliesAcceptingLoadExceptions; + return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s) + ? Array.Empty() + : s.Split(',').Select(x => x.Trim()).ToArray(); + } + } + } +} diff --git a/src/Umbraco.Core/Composing/TypeHelper.cs b/src/Umbraco.Core/Composing/TypeHelper.cs index 28eab6a5ec..1987a4059c 100644 --- a/src/Umbraco.Core/Composing/TypeHelper.cs +++ b/src/Umbraco.Core/Composing/TypeHelper.cs @@ -82,9 +82,9 @@ namespace Umbraco.Core.Composing /// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot /// reference that assembly, same with the global.asax assembly. /// - public static Assembly[] GetReferencingAssemblies(Assembly assembly, IEnumerable assemblies) + public static IReadOnlyList GetReferencingAssemblies(Assembly assembly, IEnumerable assemblies) { - if (assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly()) + if (assembly.IsDynamic || assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly()) return EmptyAssemblies; @@ -92,7 +92,7 @@ namespace Umbraco.Core.Composing // should only be scanning those assemblies because any other assembly will definitely not // contain sub type's of the one we're currently looking for var name = assembly.GetName().Name; - return assemblies.Where(x => x == assembly || HasReference(x, name)).ToArray(); + return assemblies.Where(x => x == assembly || HasReference(x, name)).ToList(); } /// diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 76d00c472d..4d8b5c984c 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -516,29 +516,29 @@ namespace Umbraco.Core.Composing #region Get Assembly Attributes - /// - /// Gets the assembly attributes of the specified type . - /// - /// The attribute type. - /// - /// The assembly attributes of the specified type . - /// - public IEnumerable GetAssemblyAttributes() - where T : Attribute - { - return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList(); - } + ///// + ///// Gets the assembly attributes of the specified type . + ///// + ///// The attribute type. + ///// + ///// The assembly attributes of the specified type . + ///// + //public IEnumerable GetAssemblyAttributes() + // where T : Attribute + //{ + // return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList(); + //} - /// - /// Gets all the assembly attributes. - /// - /// - /// All assembly attributes. - /// - public IEnumerable GetAssemblyAttributes() - { - return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList(); - } + ///// + ///// Gets all the assembly attributes. + ///// + ///// + ///// All assembly attributes. + ///// + //public IEnumerable GetAssemblyAttributes() + //{ + // return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList(); + //} /// /// Gets the assembly attributes of the specified . diff --git a/src/Umbraco.Core/Configuration/Configs.cs b/src/Umbraco.Core/Configuration/Configs.cs index abb06d525f..821ee308f0 100644 --- a/src/Umbraco.Core/Configuration/Configs.cs +++ b/src/Umbraco.Core/Configuration/Configs.cs @@ -13,16 +13,8 @@ namespace Umbraco.Core.Configuration /// public class Configs { - private readonly Func _configSectionResolver; - - public Configs(Func configSectionResolver) - { - _configSectionResolver = configSectionResolver ?? throw new ArgumentNullException(nameof(configSectionResolver)); - } - private readonly Dictionary> _configs = new Dictionary>(); private Dictionary> _registerings = new Dictionary>(); - private Lazy _factory; /// /// Gets a configuration. @@ -52,61 +44,15 @@ namespace Umbraco.Core.Configuration _registerings[typeOfConfig] = register => register.Register(_ => (TConfig) lazyConfigFactory.Value, Lifetime.Singleton); } - /// - /// Adds a configuration, provided by a factory. - /// - public void Add(Func configFactory) - where TConfig : class - { - // make sure it is not too late - if (_registerings == null) - throw new InvalidOperationException("Configurations have already been registered."); - - var typeOfConfig = typeof(TConfig); - - _configs[typeOfConfig] = new Lazy(() => - { - if (!(_factory is null)) return _factory.Value.GetInstance(); - throw new InvalidOperationException($"Cannot get configuration of type {typeOfConfig} during composition."); - }); - _registerings[typeOfConfig] = register => register.Register(configFactory, Lifetime.Singleton); - } - - /// - /// Adds a configuration, provided by a configuration section. - /// - public void Add(string sectionName) - where TConfig : class - { - Add(() => GetConfig(sectionName)); - } - - private TConfig GetConfig(string sectionName) - where TConfig : class - { - // note: need to use SafeCallContext here because ConfigurationManager.GetSection ends up getting AppDomain.Evidence - // which will want to serialize the call context including anything that is in there - what a mess! - - using (new SafeCallContext()) - { - if ((_configSectionResolver(sectionName) is TConfig config)) - return config; - var ex = new InvalidOperationException($"Could not get configuration section \"{sectionName}\" from config files."); - throw ex; - } - } - /// /// Registers configurations in a register. /// - public void RegisterWith(IRegister register, Func factory) + public void RegisterWith(IRegister register) { // do it only once if (_registerings == null) throw new InvalidOperationException("Configurations have already been registered."); - _factory = new Lazy(factory); - register.Register(this); foreach (var registering in _registerings.Values) diff --git a/src/Umbraco.Core/Configuration/ConfigsExtensions.cs b/src/Umbraco.Core/Configuration/ConfigsExtensions.cs index 1723785069..f9ea352399 100644 --- a/src/Umbraco.Core/Configuration/ConfigsExtensions.cs +++ b/src/Umbraco.Core/Configuration/ConfigsExtensions.cs @@ -1,13 +1,7 @@ -using System.IO; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Grid; using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Manifest; namespace Umbraco.Core { @@ -16,6 +10,9 @@ namespace Umbraco.Core /// public static class ConfigsExtensions { + + public static IImagingSettings Imaging(this Configs configs) + => configs.GetConfig(); public static IGlobalSettings Global(this Configs configs) => configs.GetConfig(); @@ -25,47 +22,28 @@ namespace Umbraco.Core public static IConnectionStrings ConnectionStrings(this Configs configs) => configs.GetConfig(); - public static IUmbracoSettingsSection Settings(this Configs configs) - => configs.GetConfig(); + public static IContentSettings Content(this Configs configs) + => configs.GetConfig(); - public static IHealthChecks HealthChecks(this Configs configs) - => configs.GetConfig(); + public static ISecuritySettings Security(this Configs configs) + => configs.GetConfig(); - public static IGridConfig Grids(this Configs configs) - => configs.GetConfig(); - - public static ICoreDebug CoreDebug(this Configs configs) - => configs.GetConfig(); public static IUserPasswordConfiguration UserPasswordConfiguration(this Configs configs) => configs.GetConfig(); - public static IMemberPasswordConfiguration MemberPasswordConfiguration(this Configs configs) => configs.GetConfig(); - public static void AddPasswordConfigurations(this Configs configs) - { - configs.Add(() => - { - return new UserPasswordConfiguration(configs.Settings().Security.UserPasswordConfiguration); - }); - configs.Add(() => - { - return new MemberPasswordConfiguration(configs.Settings().Security.MemberPasswordConfiguration); - }); - } + public static IRequestHandlerSettings RequestHandler(this Configs configs) + => configs.GetConfig(); - public static void AddCoreConfigs(this Configs configs, IIOHelper ioHelper) - { - var configDir = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config)); + public static IWebRoutingSettings WebRouting(this Configs configs) + => configs.GetConfig(); + + public static IHealthChecksSettings HealthChecks(this Configs configs) + => configs.GetConfig(); + public static ICoreDebugSettings CoreDebug(this Configs configs) + => configs.GetConfig(); - // GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition - configs.Add(factory => new GridConfig( - factory.GetInstance(), - factory.GetInstance(), - configDir, - factory.GetInstance(), - factory.GetInstance().Debug)); - } } } diff --git a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs deleted file mode 100644 index 4d8039dfbb..0000000000 --- a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using Umbraco.Core.IO; - -namespace Umbraco.Core.Configuration -{ - public static class GlobalSettingsExtensions - { - private static string _mvcArea; - - - /// - /// This returns the string of the MVC Area route. - /// - /// - /// This will return the MVC area that we will route all custom routes through like surface controllers, etc... - /// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin - /// we will convert the '/' to '-' and use that as the path. its a bit lame but will work. - /// - /// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something - /// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco". - /// - public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings, IIOHelper ioHelper) - { - if (_mvcArea != null) return _mvcArea; - - _mvcArea = GetUmbracoMvcAreaNoCache(globalSettings, ioHelper); - - return _mvcArea; - } - - internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IIOHelper ioHelper) - { - if (globalSettings.Path.IsNullOrWhiteSpace()) - { - throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified"); - } - - var path = globalSettings.Path; - if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518 - path = path.Substring(ioHelper.Root.Length); - return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower(); - } - - } -} diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs index de4f7ccd5a..72c720e3d6 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -1,15 +1,18 @@ using System.IO; using Umbraco.Core.Cache; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Configuration.Grid { public class GridConfig : IGridConfig { - public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug) + public GridConfig(AppCaches appCaches, IIOHelper ioHelper, IManifestParser manifestParser, IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment) { - EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, manifestParser, isDebug); + EditorsConfig = new GridEditorsConfig(appCaches, ioHelper, manifestParser, jsonSerializer, hostingEnvironment.IsDebugMode); } public IGridEditorsConfig EditorsConfig { get; } diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs index a1ebf008fc..410c83ff1a 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -1,27 +1,30 @@ using System; using System.Collections.Generic; using System.IO; +using Umbraco.Composing; using Umbraco.Core.Cache; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Configuration.Grid { internal class GridEditorsConfig : IGridEditorsConfig { - private readonly ILogger _logger; private readonly AppCaches _appCaches; - private readonly DirectoryInfo _configFolder; + private readonly IIOHelper _ioHelper; private readonly IManifestParser _manifestParser; private readonly bool _isDebug; + private readonly IJsonSerializer _jsonSerializer; - public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug) + public GridEditorsConfig(AppCaches appCaches, IIOHelper ioHelper, IManifestParser manifestParser,IJsonSerializer jsonSerializer, bool isDebug) { - _logger = logger; _appCaches = appCaches; - _configFolder = configFolder; + _ioHelper = ioHelper; _manifestParser = manifestParser; + _jsonSerializer = jsonSerializer; _isDebug = isDebug; } @@ -31,19 +34,20 @@ namespace Umbraco.Core.Configuration.Grid { List GetResult() { + var configFolder = new DirectoryInfo(_ioHelper.MapPath(Constants.SystemDirectories.Config)); var editors = new List(); - var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js"); + var gridConfig = Path.Combine(configFolder.FullName, "grid.editors.config.js"); if (File.Exists(gridConfig)) { var sourceString = File.ReadAllText(gridConfig); try { - editors.AddRange(_manifestParser.ParseGridEditors(sourceString)); + editors.AddRange(_jsonSerializer.Deserialize>(sourceString)); } catch (Exception ex) { - _logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString); + Current.Logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString); } } @@ -63,7 +67,6 @@ namespace Umbraco.Core.Configuration.Grid return result; } - } } } diff --git a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs similarity index 84% rename from src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs rename to src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs index fa98e3b054..785e8d5651 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecks.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.HealthChecks { - public interface IHealthChecks + public interface IHealthChecksSettings { IEnumerable DisabledChecks { get; } IHealthCheckNotificationSettings NotificationSettings { get; } diff --git a/src/Umbraco.Core/Configuration/IConfigManipulator.cs b/src/Umbraco.Core/Configuration/IConfigManipulator.cs new file mode 100644 index 0000000000..83ab2c0631 --- /dev/null +++ b/src/Umbraco.Core/Configuration/IConfigManipulator.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.IO; + +namespace Umbraco.Core.Configuration +{ + public interface IConfigManipulator + { + void RemoveConnectionString(); + void SaveConnectionString(string connectionString, string providerName); + } +} diff --git a/src/Umbraco.Core/Configuration/IConfigsFactory.cs b/src/Umbraco.Core/Configuration/IConfigsFactory.cs index 98a24ca37f..dd2459b88c 100644 --- a/src/Umbraco.Core/Configuration/IConfigsFactory.cs +++ b/src/Umbraco.Core/Configuration/IConfigsFactory.cs @@ -1,9 +1,10 @@ using Umbraco.Core.IO; +using Umbraco.Core.Logging; namespace Umbraco.Core.Configuration { public interface IConfigsFactory { - Configs Create(IIOHelper ioHelper); + Configs Create(); } } diff --git a/src/Umbraco.Core/Configuration/IConnectionStrings.cs b/src/Umbraco.Core/Configuration/IConnectionStrings.cs index acd2281a1e..0d33378669 100644 --- a/src/Umbraco.Core/Configuration/IConnectionStrings.cs +++ b/src/Umbraco.Core/Configuration/IConnectionStrings.cs @@ -6,7 +6,5 @@ namespace Umbraco.Core.Configuration { get; } - - void RemoveConnectionString(string umbracoConnectionName); } } diff --git a/src/Umbraco.Core/Configuration/ICoreDebug.cs b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs similarity index 93% rename from src/Umbraco.Core/Configuration/ICoreDebug.cs rename to src/Umbraco.Core/Configuration/ICoreDebugSettings.cs index 4ff2a1a300..586e4bc3e4 100644 --- a/src/Umbraco.Core/Configuration/ICoreDebug.cs +++ b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration { - public interface ICoreDebug + public interface ICoreDebugSettings { /// /// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed. diff --git a/src/Umbraco.Core/Configuration/IGlobalSettings.cs b/src/Umbraco.Core/Configuration/IGlobalSettings.cs index ffc52130cc..3cb211a7a7 100644 --- a/src/Umbraco.Core/Configuration/IGlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/IGlobalSettings.cs @@ -21,7 +21,7 @@ string ReservedPaths { get; } /// - /// Gets the path to umbraco's root directory (/umbraco by default). + /// Gets the path to umbraco's root directory. /// string Path { get; } @@ -96,5 +96,10 @@ string RegisterType { get; } string DatabaseFactoryServerVersion { get; } string MainDomLock { get; } + + /// + /// Gets the path to the razor file used when no published content is available. + /// + string NoNodesViewPath { get; } } } diff --git a/src/Umbraco.Core/Configuration/IImagingSettings.cs b/src/Umbraco.Core/Configuration/IImagingSettings.cs new file mode 100644 index 0000000000..13e1b30389 --- /dev/null +++ b/src/Umbraco.Core/Configuration/IImagingSettings.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Configuration +{ + public interface IImagingSettings + { + int MaxBrowserCacheDays { get;} + int MaxCacheDays { get; } + uint CachedNameLength { get; } + int MaxResizeWidth { get; } + int MaxResizeHeight { get; } + string CacheFolder { get; } + } +} diff --git a/src/Umbraco.Core/Configuration/IMachineKeyConfig.cs b/src/Umbraco.Core/Configuration/IMachineKeyConfig.cs deleted file mode 100644 index 35969e668a..0000000000 --- a/src/Umbraco.Core/Configuration/IMachineKeyConfig.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IMachineKeyConfig - { - bool HasMachineKey { get;} - } -} diff --git a/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs index 6a071ac277..990bde9843 100644 --- a/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs +++ b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs @@ -7,7 +7,6 @@ int DebugLevel { get; } bool EnableFactory { get; } bool FlagOutOfDateModels { get; } - bool IsDebug { get; } string ModelsDirectory { get; } ModelsMode ModelsMode { get; } string ModelsNamespace { get; } diff --git a/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs index 98cd1010c0..6a5fd8e73f 100644 --- a/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs +++ b/src/Umbraco.Core/Configuration/IPasswordConfiguration.cs @@ -6,13 +6,11 @@ /// public interface IPasswordConfiguration { - int RequiredLength { get; } + int RequiredLength { get; } bool RequireNonLetterOrDigit { get; } bool RequireDigit { get; } bool RequireLowercase { get; } bool RequireUppercase { get; } - - bool UseLegacyEncoding { get; } string HashAlgorithmType { get; } // TODO: This doesn't really belong here diff --git a/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs index 58c907c31f..8e7cd97f35 100644 --- a/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs +++ b/src/Umbraco.Core/Configuration/MemberPasswordConfiguration.cs @@ -7,9 +7,9 @@ namespace Umbraco.Core.Configuration /// public class MemberPasswordConfiguration : PasswordConfiguration, IMemberPasswordConfiguration { - public MemberPasswordConfiguration(IMemberPasswordConfigurationSection configSection) - : base(configSection) - { + public MemberPasswordConfiguration(IMemberPasswordConfiguration configSettings) + : base(configSettings) + { } } } diff --git a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs new file mode 100644 index 0000000000..3e3b116395 --- /dev/null +++ b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs @@ -0,0 +1,57 @@ +using System.Configuration; +using System.IO; +using Umbraco.Core.IO; + +namespace Umbraco.Core.Configuration +{ + public static class ModelsBuilderConfigExtensions + { + private static string _modelsDirectoryAbsolute = null; + + public static string ModelsDirectoryAbsolute(this IModelsBuilderConfig modelsBuilderConfig, IIOHelper ioHelper) + { + + if (_modelsDirectoryAbsolute is null) + { + var modelsDirectory = modelsBuilderConfig.ModelsDirectory; + var root = ioHelper.MapPath("~/"); + + _modelsDirectoryAbsolute = GetModelsDirectory(root, modelsDirectory, + modelsBuilderConfig.AcceptUnsafeModelsDirectory); + } + + return _modelsDirectoryAbsolute; + } + + // internal for tests + internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe) + { + // making sure it is safe, ie under the website root, + // unless AcceptUnsafeModelsDirectory and then everything is OK. + + if (!Path.IsPathRooted(root)) + throw new ConfigurationErrorsException($"Root is not rooted \"{root}\"."); + + if (config.StartsWith("~/")) + { + var dir = Path.Combine(root, config.TrimStart("~/")); + + // sanitize - GetFullPath will take care of any relative + // segments in path, eg '../../foo.tmp' - it may throw a SecurityException + // if the combined path reaches illegal parts of the filesystem + dir = Path.GetFullPath(dir); + root = Path.GetFullPath(root); + + if (!dir.StartsWith(root) && !acceptUnsafe) + throw new ConfigurationErrorsException($"Invalid models directory \"{config}\"."); + + return dir; + } + + if (acceptUnsafe) + return Path.GetFullPath(config); + + throw new ConfigurationErrorsException($"Invalid models directory \"{config}\"."); + } + } +} diff --git a/src/Umbraco.Core/Configuration/PasswordConfiguration.cs b/src/Umbraco.Core/Configuration/PasswordConfiguration.cs index 9edf1a462e..0c5ed9adb0 100644 --- a/src/Umbraco.Core/Configuration/PasswordConfiguration.cs +++ b/src/Umbraco.Core/Configuration/PasswordConfiguration.cs @@ -5,21 +5,20 @@ namespace Umbraco.Core.Configuration { public abstract class PasswordConfiguration : IPasswordConfiguration { - protected PasswordConfiguration(IPasswordConfigurationSection configSection) + protected PasswordConfiguration(IPasswordConfiguration configSettings) { - if (configSection == null) + if (configSettings == null) { - throw new ArgumentNullException(nameof(configSection)); + throw new ArgumentNullException(nameof(configSettings)); } - RequiredLength = configSection.RequiredLength; - RequireNonLetterOrDigit = configSection.RequireNonLetterOrDigit; - RequireDigit = configSection.RequireDigit; - RequireLowercase = configSection.RequireLowercase; - RequireUppercase = configSection.RequireUppercase; - UseLegacyEncoding = configSection.UseLegacyEncoding; - HashAlgorithmType = configSection.HashAlgorithmType; - MaxFailedAccessAttemptsBeforeLockout = configSection.MaxFailedAccessAttemptsBeforeLockout; + RequiredLength = configSettings.RequiredLength; + RequireNonLetterOrDigit = configSettings.RequireNonLetterOrDigit; + RequireDigit = configSettings.RequireDigit; + RequireLowercase = configSettings.RequireLowercase; + RequireUppercase = configSettings.RequireUppercase; + HashAlgorithmType = configSettings.HashAlgorithmType; + MaxFailedAccessAttemptsBeforeLockout = configSettings.MaxFailedAccessAttemptsBeforeLockout; } public int RequiredLength { get; } @@ -32,8 +31,6 @@ namespace Umbraco.Core.Configuration public bool RequireUppercase { get; } - public bool UseLegacyEncoding { get; } - public string HashAlgorithmType { get; } public int MaxFailedAccessAttemptsBeforeLockout { get; } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs index 82cc5928cf..d100eb0a74 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings /// The file extension. /// /// A value indicating whether the file extension corresponds to an image. - public static bool IsImageFile(this IContentSection contentConfig, string extension) + public static bool IsImageFile(this IContentSettings contentConfig, string extension) { if (contentConfig == null) throw new ArgumentNullException(nameof(contentConfig)); if (extension == null) return false; @@ -24,22 +24,22 @@ namespace Umbraco.Core.Configuration.UmbracoSettings /// held in settings. /// Allow upload if extension is whitelisted OR if there is no whitelist and extension is NOT blacklisted. /// - public static bool IsFileAllowedForUpload(this IContentSection contentSection, string extension) + public static bool IsFileAllowedForUpload(this IContentSettings contentSettings, string extension) { - return contentSection.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) || - (contentSection.AllowedUploadFiles.Any() == false && - contentSection.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false); + return contentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) || + (contentSettings.AllowedUploadFiles.Any() == false && + contentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false); } /// /// Gets the auto-fill configuration for a specified property alias. /// - /// + /// /// The property type alias. /// The auto-fill configuration for the specified property alias, or null. - public static IImagingAutoFillUploadField GetConfig(this IContentSection contentSection, string propertyTypeAlias) + public static IImagingAutoFillUploadField GetConfig(this IContentSettings contentSettings, string propertyTypeAlias) { - var autoFillConfigs = contentSection.ImageAutoFillProperties; + var autoFillConfigs = contentSettings.ImageAutoFillProperties; return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias); } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs index 36dd6a22ed..85df4540c0 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs @@ -2,6 +2,6 @@ { public interface IBackOfficeSection { - ITourSection Tours { get; } + ITourSettings Tours { get; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs similarity index 93% rename from src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs index 228b0923dc..08f6231309 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs @@ -3,7 +3,7 @@ using Umbraco.Core.Macros; namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface IContentSection : IUmbracoConfigurationSection + public interface IContentSettings : IUmbracoConfigurationSection { string NotificationEmailAddress { get; } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs similarity index 68% rename from src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs index 3a0ad258c5..58a8151474 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface IKeepAliveSection : IUmbracoConfigurationSection + public interface IKeepAliveSettings : IUmbracoConfigurationSection { bool DisableKeepAliveTask { get; } string KeepAlivePingUrl { get; } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs similarity index 66% rename from src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs index 6c1be8ade5..ee5647ee27 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface ILoggingSection : IUmbracoConfigurationSection + public interface ILoggingSettings : IUmbracoConfigurationSection { int MaxLogAge { get; } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IMemberPasswordConfigurationSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IMemberPasswordConfigurationSection.cs deleted file mode 100644 index cbbb933857..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IMemberPasswordConfigurationSection.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IMemberPasswordConfigurationSection : IPasswordConfigurationSection - { - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs similarity index 78% rename from src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs index 2393c5af63..11fdaa8310 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface IRequestHandlerSection : IUmbracoConfigurationSection + public interface IRequestHandlerSettings : IUmbracoConfigurationSection { bool AddTrailingSlash { get; } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs similarity index 78% rename from src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs index a6ed188713..6ab520fefd 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs @@ -1,9 +1,9 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface ISecuritySection : IUmbracoConfigurationSection + public interface ISecuritySettings : IUmbracoConfigurationSection { bool KeepUserLoggedIn { get; } - + bool HideDisabledUsersInBackoffice { get; } /// @@ -23,9 +23,5 @@ /// When this is false, the username and email fields will be shown in the user section. /// bool UsernameIsEmail { get; } - - IUserPasswordConfigurationSection UserPasswordConfiguration { get; } - - IMemberPasswordConfigurationSection MemberPasswordConfiguration { get; } } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs similarity index 75% rename from src/Umbraco.Core/Configuration/UmbracoSettings/ITourSection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs index 938642521e..d3d8293140 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface ITourSection + public interface ITourSettings { bool EnableTours { get; } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs deleted file mode 100644 index acd9c92588..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IUmbracoSettingsSection.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IUmbracoSettingsSection : IUmbracoConfigurationSection - { - IBackOfficeSection BackOffice { get; } - - IContentSection Content { get; } - - ISecuritySection Security { get; } - - IRequestHandlerSection RequestHandler { get; } - - ILoggingSection Logging { get; } - - IWebRoutingSection WebRouting { get; } - - IKeepAliveSection KeepAlive { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IUserPasswordConfigurationSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IUserPasswordConfigurationSection.cs deleted file mode 100644 index d80dd2b7e5..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IUserPasswordConfigurationSection.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IUserPasswordConfigurationSection : IPasswordConfigurationSection - { - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs similarity index 86% rename from src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs rename to src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs index f0a986efe2..f7f6a94d30 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { - public interface IWebRoutingSection : IUmbracoConfigurationSection + public interface IWebRoutingSettings : IUmbracoConfigurationSection { bool TrySkipIisCustomErrors { get; } diff --git a/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs b/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs index 4cfee5280b..07e6603cee 100644 --- a/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs +++ b/src/Umbraco.Core/Configuration/UserPasswordConfiguration.cs @@ -7,9 +7,9 @@ namespace Umbraco.Core.Configuration /// public class UserPasswordConfiguration : PasswordConfiguration, IUserPasswordConfiguration { - public UserPasswordConfiguration(IUserPasswordConfigurationSection configSection) - : base(configSection) - { + public UserPasswordConfiguration(IUserPasswordConfiguration configSettings) + : base(configSettings) + { } } } diff --git a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs new file mode 100644 index 0000000000..333f9dc6f9 --- /dev/null +++ b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs @@ -0,0 +1,118 @@ +using System; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Umbraco.Composing; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; + +namespace Umbraco.Core.Configuration +{ + public class XmlConfigManipulator : IConfigManipulator + { + private readonly IIOHelper _ioHelper; + private readonly ILogger _logger; + + public XmlConfigManipulator(IIOHelper ioHelper, ILogger logger) + { + _ioHelper = ioHelper; + _logger = logger; + } + + public void RemoveConnectionString() + { + var key = Constants.System.UmbracoConnectionName; + var fileName = _ioHelper.MapPath(string.Format("{0}/web.config", _ioHelper.Root)); + var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); + + var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single(); + var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key); + + if (setting != null) + { + setting.Remove(); + xml.Save(fileName, SaveOptions.DisableFormatting); + ConfigurationManager.RefreshSection("appSettings"); + } + + var settings = ConfigurationManager.ConnectionStrings[key]; + } + + /// + /// Saves the connection string as a proper .net connection string in web.config. + /// + /// Saves the ConnectionString in the very nasty 'medium trust'-supportive way. + /// The connection string. + /// The provider name. + public void SaveConnectionString(string connectionString, string providerName) + { + if (connectionString == null) throw new ArgumentNullException(nameof(connectionString)); + if (string.IsNullOrWhiteSpace(connectionString)) + throw new ArgumentException("Value can't be empty or consist only of white-space characters.", + nameof(connectionString)); + if (providerName == null) throw new ArgumentNullException(nameof(providerName)); + if (string.IsNullOrWhiteSpace(providerName)) + throw new ArgumentException("Value can't be empty or consist only of white-space characters.", + nameof(providerName)); + + + var fileSource = "web.config"; + var fileName = _ioHelper.MapPath(_ioHelper.Root + "/" + fileSource); + + var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); + if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root)."); + + var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); + if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings)."); + + // handle configSource + var configSourceAttribute = connectionStrings.Attribute("configSource"); + if (configSourceAttribute != null) + { + fileSource = configSourceAttribute.Value; + fileName = _ioHelper.MapPath(_ioHelper.Root + "/" + fileSource); + + if (!File.Exists(fileName)) + throw new Exception($"Invalid configSource \"{fileSource}\" (no such file)."); + + xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); + if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root)."); + + connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); + if (connectionStrings == null) + throw new Exception($"Invalid {fileSource} file (no connection strings)."); + } + + // create or update connection string + var setting = connectionStrings.Descendants("add").FirstOrDefault(s => + s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName); + if (setting == null) + { + connectionStrings.Add(new XElement("add", + new XAttribute("name", Constants.System.UmbracoConnectionName), + new XAttribute("connectionString", connectionString), + new XAttribute("providerName", providerName))); + } + else + { + AddOrUpdateAttribute(setting, "connectionString", connectionString); + AddOrUpdateAttribute(setting, "providerName", providerName); + } + + // save + _logger.Info("Saving connection string to {ConfigFile}.", fileSource); + xml.Save(fileName, SaveOptions.DisableFormatting); + _logger.Info("Saved connection string to {ConfigFile}.", fileSource); + } + + private static void AddOrUpdateAttribute(XElement element, string name, string value) + { + var attribute = element.Attribute(name); + if (attribute == null) + element.Add(new XAttribute(name, value)); + else + attribute.Value = value; + } + } +} diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs index 4c47f12ba0..c55b4b0314 100644 --- a/src/Umbraco.Core/Constants-AppSettings.cs +++ b/src/Umbraco.Core/Constants-AppSettings.cs @@ -115,6 +115,11 @@ namespace Umbraco.Core /// public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer"; + /// + /// Gets the path to the razor file used when no published content is available. + /// + public const string NoNodesViewPath = "Umbraco.Core.NoNodesViewPath"; + /// /// Debug specific web.config AppSetting keys for Umbraco /// diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs new file mode 100644 index 0000000000..c45229d918 --- /dev/null +++ b/src/Umbraco.Core/Constants-Configuration.cs @@ -0,0 +1,18 @@ +namespace Umbraco.Core +{ + public static partial class Constants + { + public static class Configuration + { + /// + /// Case insensitive prefix for all configurations + /// + /// + /// ":" is used as marker for nested objects in json. E.g. "Umbraco:CMS:" = {"Umbraco":{"CMS":{....}} + /// + public const string ConfigPrefix = "Umbraco:CMS:"; + public const string ConfigSecurityPrefix = ConfigPrefix+"Security:"; + public const string ConfigModelsBuilderPrefix = ConfigPrefix+"ModelsBuilder:"; + } + } +} diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs index abb92298f4..837db01b63 100644 --- a/src/Umbraco.Core/Constants-System.cs +++ b/src/Umbraco.Core/Constants-System.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core + namespace Umbraco.Core { public static partial class Constants { diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs index 5b64319fb0..b1efd782fa 100644 --- a/src/Umbraco.Core/Constants-Web.cs +++ b/src/Umbraco.Core/Constants-Web.cs @@ -34,7 +34,11 @@ /// The header name that angular uses to pass in the token to validate the cookie /// public const string AngularHeadername = "X-UMB-XSRF-TOKEN"; - + + /// + /// The route name of the page shown when Umbraco has no published content. + /// + public const string NoContentRouteName = "umbraco-no-content"; } } } diff --git a/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs b/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs new file mode 100644 index 0000000000..93441f1a47 --- /dev/null +++ b/src/Umbraco.Core/Hosting/IApplicationShutdownRegistry.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Hosting +{ + public interface IApplicationShutdownRegistry + { + void RegisterObject(IRegisteredObject registeredObject); + void UnregisterObject(IRegisteredObject registeredObject); + } +} diff --git a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs index 5b97d8e4f3..b12ffbc138 100644 --- a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs +++ b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs @@ -19,8 +19,5 @@ namespace Umbraco.Core.Hosting Version IISVersion { get; } string MapPath(string path); string ToAbsolute(string virtualPath, string root); - - void RegisterObject(IRegisteredObject registeredObject); - void UnregisterObject(IRegisteredObject registeredObject); } } diff --git a/src/Umbraco.Core/IO/IIOHelper.cs b/src/Umbraco.Core/IO/IIOHelper.cs index 11f5c6c565..f478b49de6 100644 --- a/src/Umbraco.Core/IO/IIOHelper.cs +++ b/src/Umbraco.Core/IO/IIOHelper.cs @@ -4,6 +4,9 @@ namespace Umbraco.Core.IO { public interface IIOHelper { + + string BackOfficePath { get; } + bool ForceNotHosted { get; set; } char DirSepChar { get; } diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index d5e1335f35..9eddea6477 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Reflection; using System.IO; using System.Linq; +using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.Strings; @@ -12,10 +13,22 @@ namespace Umbraco.Core.IO public class IOHelper : IIOHelper { private readonly IHostingEnvironment _hostingEnvironment; + private readonly IGlobalSettings _globalSettings; - public IOHelper(IHostingEnvironment hostingEnvironment) + public IOHelper(IHostingEnvironment hostingEnvironment, IGlobalSettings globalSettings) { - _hostingEnvironment = hostingEnvironment; + _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); + _globalSettings = globalSettings; + } + + public string BackOfficePath + { + get + { + var path = _globalSettings.Path; + + return string.IsNullOrEmpty(path) ? string.Empty : ResolveUrl(path); + } } /// diff --git a/src/Umbraco.Core/IO/IOHelperExtensions.cs b/src/Umbraco.Core/IO/IOHelperExtensions.cs index 64b57e7dc1..39bd5e6cc9 100644 --- a/src/Umbraco.Core/IO/IOHelperExtensions.cs +++ b/src/Umbraco.Core/IO/IOHelperExtensions.cs @@ -5,6 +5,8 @@ namespace Umbraco.Core.IO { public static class IOHelperExtensions { + private static string _mvcArea; + /// /// Tries to create a directory. /// @@ -35,5 +37,38 @@ namespace Umbraco.Core.IO { return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8); } + + /// + /// This returns the string of the MVC Area route. + /// + /// + /// This will return the MVC area that we will route all custom routes through like surface controllers, etc... + /// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin + /// we will convert the '/' to '-' and use that as the path. its a bit lame but will work. + /// + /// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something + /// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco". + /// + public static string GetUmbracoMvcArea(this IIOHelper ioHelper) + { + if (_mvcArea != null) return _mvcArea; + + _mvcArea = GetUmbracoMvcAreaNoCache(ioHelper); + + return _mvcArea; + } + + internal static string GetUmbracoMvcAreaNoCache(this IIOHelper ioHelper) + { + if (ioHelper.BackOfficePath.IsNullOrWhiteSpace()) + { + throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified"); + } + + var path = ioHelper.BackOfficePath; + if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518 + path = path.Substring(ioHelper.Root.Length); + return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower(); + } } } diff --git a/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs b/src/Umbraco.Core/Logging/ConsoleLogger.cs similarity index 98% rename from src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs rename to src/Umbraco.Core/Logging/ConsoleLogger.cs index 53d6078e4b..275b8d988b 100644 --- a/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs +++ b/src/Umbraco.Core/Logging/ConsoleLogger.cs @@ -1,7 +1,6 @@ using System; -using Umbraco.Core.Logging; -namespace Umbraco.Tests.TestHelpers +namespace Umbraco.Core.Logging { public class ConsoleLogger : ILogger { diff --git a/src/Umbraco.Core/Logging/ILogger.cs b/src/Umbraco.Core/Logging/ILogger.cs index 4f49d0b3b4..fe7d798ebf 100644 --- a/src/Umbraco.Core/Logging/ILogger.cs +++ b/src/Umbraco.Core/Logging/ILogger.cs @@ -2,6 +2,7 @@ namespace Umbraco.Core.Logging { + /// /// Defines the logging service. /// diff --git a/src/Umbraco.Core/Manifest/IManifestParser.cs b/src/Umbraco.Core/Manifest/IManifestParser.cs index eeb0c756f6..3eec7007b3 100644 --- a/src/Umbraco.Core/Manifest/IManifestParser.cs +++ b/src/Umbraco.Core/Manifest/IManifestParser.cs @@ -17,7 +17,5 @@ namespace Umbraco.Core.Manifest /// Parses a manifest. /// PackageManifest ParseManifest(string text); - - IEnumerable ParseGridEditors(string text); } } diff --git a/src/Umbraco.Core/Models/DeepCloneHelper.cs b/src/Umbraco.Core/Models/DeepCloneHelper.cs index 6470de912b..453b455d4b 100644 --- a/src/Umbraco.Core/Models/DeepCloneHelper.cs +++ b/src/Umbraco.Core/Models/DeepCloneHelper.cs @@ -81,9 +81,10 @@ namespace Umbraco.Core.Models if (propertyInfo.PropertyType.IsGenericType && (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>) || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) - || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>))) + || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>) + || propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>))) { - //if it is a IEnumerable<>, IList or ICollection<> we'll use a List<> + //if it is a IEnumerable<>, IReadOnlyCollection, IList or ICollection<> we'll use a List<> since it implements them all var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments()); return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType }; } diff --git a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs b/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs index 10d5b10955..3e5361a1c1 100644 --- a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs @@ -1,5 +1,6 @@ namespace Umbraco.Net { + // TODO: This shouldn't be in this namespace? public interface IUmbracoApplicationLifetime { /// diff --git a/src/Umbraco.Core/PublishedContentExtensions.cs b/src/Umbraco.Core/PublishedContentExtensions.cs index 84ee8c314b..03ce0c066a 100644 --- a/src/Umbraco.Core/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/PublishedContentExtensions.cs @@ -149,11 +149,11 @@ namespace Umbraco.Core } public static bool IsAllowedTemplate(this IPublishedContent content, IContentTypeService contentTypeService, - IUmbracoSettingsSection umbracoSettingsSection, int templateId) + IWebRoutingSettings webRoutingSettings, int templateId) { return content.IsAllowedTemplate(contentTypeService, - umbracoSettingsSection.WebRouting.DisableAlternativeTemplates, - umbracoSettingsSection.WebRouting.ValidateAlternativeTemplates, templateId); + webRoutingSettings.DisableAlternativeTemplates, + webRoutingSettings.ValidateAlternativeTemplates, templateId); } public static bool IsAllowedTemplate(this IPublishedContent content, IContentTypeService contentTypeService, bool disableAlternativeTemplates, bool validateAlternativeTemplates, int templateId) diff --git a/src/Umbraco.Core/Routing/AliasUrlProvider.cs b/src/Umbraco.Core/Routing/AliasUrlProvider.cs index c9cc3d5156..e71de2f6c6 100644 --- a/src/Umbraco.Core/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Core/Routing/AliasUrlProvider.cs @@ -14,13 +14,13 @@ namespace Umbraco.Web.Routing public class AliasUrlProvider : IUrlProvider { private readonly IGlobalSettings _globalSettings; - private readonly IRequestHandlerSection _requestConfig; + private readonly IRequestHandlerSettings _requestConfig; private readonly ISiteDomainHelper _siteDomainHelper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly UriUtility _uriUtility; private readonly IPublishedValueFallback _publishedValueFallback; - public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSection requestConfig, ISiteDomainHelper siteDomainHelper, UriUtility uriUtility, IPublishedValueFallback publishedValueFallback, IUmbracoContextAccessor umbracoContextAccessor) + public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSettings requestConfig, ISiteDomainHelper siteDomainHelper, UriUtility uriUtility, IPublishedValueFallback publishedValueFallback, IUmbracoContextAccessor umbracoContextAccessor) { _globalSettings = globalSettings; _requestConfig = requestConfig; diff --git a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs index c4bfd5a697..49a6ff6bfe 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs @@ -18,11 +18,11 @@ namespace Umbraco.Web.Routing { private readonly ILogger _logger; private readonly IRequestAccessor _requestAccessor; - private readonly IWebRoutingSection _webRoutingSection; + private readonly IWebRoutingSettings _webRoutingSettings; - public ContentFinderByIdPath(IWebRoutingSection webRoutingSection, ILogger logger, IRequestAccessor requestAccessor) + public ContentFinderByIdPath(IWebRoutingSettings webRoutingSettings, ILogger logger, IRequestAccessor requestAccessor) { - _webRoutingSection = webRoutingSection ?? throw new System.ArgumentNullException(nameof(webRoutingSection)); + _webRoutingSettings = webRoutingSettings ?? throw new System.ArgumentNullException(nameof(webRoutingSettings)); _logger = logger ?? throw new System.ArgumentNullException(nameof(logger)); _requestAccessor = requestAccessor; } @@ -36,7 +36,7 @@ namespace Umbraco.Web.Routing { if (frequest.UmbracoContext != null && frequest.UmbracoContext.InPreviewMode == false - && _webRoutingSection.DisableFindContentByIdPath) + && _webRoutingSettings.DisableFindContentByIdPath) return false; IPublishedContent node = null; diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs index 933ab47150..7bcea4681e 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs @@ -17,15 +17,16 @@ namespace Umbraco.Web.Routing public class ContentFinderByUrlAndTemplate : ContentFinderByUrl { private readonly IFileService _fileService; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; - private readonly IContentTypeService _contentTypeService; - public ContentFinderByUrlAndTemplate(ILogger logger, IFileService fileService, IUmbracoSettingsSection umbracoSettingsSection, IContentTypeService contentTypeService) + private readonly IContentTypeService _contentTypeService; + private readonly IWebRoutingSettings _webRoutingSettings; + + public ContentFinderByUrlAndTemplate(ILogger logger, IFileService fileService, IContentTypeService contentTypeService, IWebRoutingSettings webRoutingSettings) : base(logger) { _fileService = fileService; - _umbracoSettingsSection = umbracoSettingsSection; _contentTypeService = contentTypeService; + _webRoutingSettings = webRoutingSettings; } /// @@ -75,7 +76,7 @@ namespace Umbraco.Web.Routing } // IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings - if (!node.IsAllowedTemplate(_contentTypeService, _umbracoSettingsSection, template.Id)) + if (!node.IsAllowedTemplate(_contentTypeService, _webRoutingSettings, template.Id)) { Logger.Warn("Alternative template '{TemplateAlias}' is not allowed on node {NodeId}.", template.Alias, node.Id); frequest.PublishedContent = null; // clear diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index 81102810e8..f56d96b6b3 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -12,14 +12,14 @@ namespace Umbraco.Web.Routing /// public class DefaultUrlProvider : IUrlProvider { - private readonly IRequestHandlerSection _requestSettings; + private readonly IRequestHandlerSettings _requestSettings; private readonly ILogger _logger; private readonly IGlobalSettings _globalSettings; private readonly ISiteDomainHelper _siteDomainHelper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly UriUtility _uriUtility; - public DefaultUrlProvider(IRequestHandlerSection requestSettings, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility) + public DefaultUrlProvider(IRequestHandlerSettings requestSettings, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility) { _requestSettings = requestSettings; _logger = logger; diff --git a/src/Umbraco.Core/Routing/PublishedRequest.cs b/src/Umbraco.Core/Routing/PublishedRequest.cs index 9b00e59deb..6e4d0008a9 100644 --- a/src/Umbraco.Core/Routing/PublishedRequest.cs +++ b/src/Umbraco.Core/Routing/PublishedRequest.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.Routing public class PublishedRequest : IPublishedRequest { private readonly IPublishedRouter _publishedRouter; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IWebRoutingSettings _webRoutingSettings; private bool _readonly; // after prepared private bool _readonlyUri; // after preparing @@ -33,11 +33,11 @@ namespace Umbraco.Web.Routing /// The published router. /// The Umbraco context. /// The request Uri. - internal PublishedRequest(IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IUmbracoSettingsSection umbracoSettingsSection, Uri uri = null) + internal PublishedRequest(IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IWebRoutingSettings webRoutingSettings, Uri uri = null) { UmbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); _publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _webRoutingSettings = webRoutingSettings; Uri = uri ?? umbracoContext.CleanedUmbracoUrl; } @@ -178,7 +178,7 @@ namespace Umbraco.Web.Routing IsInternalRedirectPublishedContent = isInternalRedirect; // must restore the template if it's an internal redirect & the config option is set - if (isInternalRedirect && _umbracoSettingsSection.WebRouting.InternalRedirectPreservesTemplate) + if (isInternalRedirect && _webRoutingSettings.InternalRedirectPreservesTemplate) { // restore TemplateModel = template; diff --git a/src/Umbraco.Core/Routing/PublishedRouter.cs b/src/Umbraco.Core/Routing/PublishedRouter.cs index f521c3a95a..af4ec60e4d 100644 --- a/src/Umbraco.Core/Routing/PublishedRouter.cs +++ b/src/Umbraco.Core/Routing/PublishedRouter.cs @@ -19,13 +19,12 @@ namespace Umbraco.Web.Routing /// public class PublishedRouter : IPublishedRouter { - private readonly IWebRoutingSection _webRoutingSection; + private readonly IWebRoutingSettings _webRoutingSettings; private readonly ContentFinderCollection _contentFinders; private readonly IContentLastChanceFinder _contentLastChanceFinder; private readonly IProfilingLogger _profilingLogger; private readonly IVariationContextAccessor _variationContextAccessor; private readonly ILogger _logger; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IRequestAccessor _requestAccessor; private readonly IPublishedValueFallback _publishedValueFallback; @@ -38,12 +37,11 @@ namespace Umbraco.Web.Routing /// Initializes a new instance of the class. /// public PublishedRouter( - IWebRoutingSection webRoutingSection, + IWebRoutingSettings webRoutingSettings, ContentFinderCollection contentFinders, IContentLastChanceFinder contentLastChanceFinder, IVariationContextAccessor variationContextAccessor, IProfilingLogger proflog, - IUmbracoSettingsSection umbracoSettingsSection, IPublishedUrlProvider publishedUrlProvider, IRequestAccessor requestAccessor, IPublishedValueFallback publishedValueFallback, @@ -52,13 +50,12 @@ namespace Umbraco.Web.Routing IContentTypeService contentTypeService, IPublicAccessService publicAccessService) { - _webRoutingSection = webRoutingSection ?? throw new ArgumentNullException(nameof(webRoutingSection)); + _webRoutingSettings = webRoutingSettings ?? throw new ArgumentNullException(nameof(webRoutingSettings)); _contentFinders = contentFinders ?? throw new ArgumentNullException(nameof(contentFinders)); _contentLastChanceFinder = contentLastChanceFinder ?? throw new ArgumentNullException(nameof(contentLastChanceFinder)); _profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog)); _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _logger = proflog; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); _publishedUrlProvider = publishedUrlProvider; _requestAccessor = requestAccessor; _publishedValueFallback = publishedValueFallback; @@ -71,7 +68,7 @@ namespace Umbraco.Web.Routing /// public IPublishedRequest CreateRequest(IUmbracoContext umbracoContext, Uri uri = null) { - return new PublishedRequest(this, umbracoContext, _umbracoSettingsSection, uri ?? umbracoContext.CleanedUmbracoUrl); + return new PublishedRequest(this, umbracoContext, _webRoutingSettings, uri ?? umbracoContext.CleanedUmbracoUrl); } #region Request @@ -628,7 +625,7 @@ namespace Umbraco.Web.Routing // does not apply // + optionally, apply the alternate template on internal redirects var useAltTemplate = request.IsInitialPublishedContent - || (_webRoutingSection.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent); + || (_webRoutingSettings.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent); var altTemplate = useAltTemplate ? _requestAccessor.GetRequestValue(Constants.Conventions.Url.AltTemplate) : null; @@ -670,8 +667,8 @@ namespace Umbraco.Web.Routing if (request.PublishedContent.IsAllowedTemplate( _fileService, _contentTypeService, - _umbracoSettingsSection.WebRouting.DisableAlternativeTemplates, - _umbracoSettingsSection.WebRouting.ValidateAlternativeTemplates, + _webRoutingSettings.DisableAlternativeTemplates, + _webRoutingSettings.ValidateAlternativeTemplates, altTemplate)) { // allowed, use diff --git a/src/Umbraco.Core/Routing/UriUtility.cs b/src/Umbraco.Core/Routing/UriUtility.cs index 11bb1dabfb..0c68580204 100644 --- a/src/Umbraco.Core/Routing/UriUtility.cs +++ b/src/Umbraco.Core/Routing/UriUtility.cs @@ -15,6 +15,7 @@ namespace Umbraco.Web public UriUtility(IHostingEnvironment hostingEnvironment) { + if (hostingEnvironment is null) throw new ArgumentNullException(nameof(hostingEnvironment)); ResetAppDomainAppVirtualPath(hostingEnvironment); } @@ -61,7 +62,7 @@ namespace Umbraco.Web // maps an internal umbraco uri to a public uri // ie with virtual directory, .aspx if required... - public Uri UriFromUmbraco(Uri uri, IGlobalSettings globalSettings, IRequestHandlerSection requestConfig) + public Uri UriFromUmbraco(Uri uri, IGlobalSettings globalSettings, IRequestHandlerSettings requestConfig) { var path = uri.GetSafeAbsolutePath(); diff --git a/src/Umbraco.Core/Routing/UrlProvider.cs b/src/Umbraco.Core/Routing/UrlProvider.cs index 80169e54e2..fa764cf7ff 100644 --- a/src/Umbraco.Core/Routing/UrlProvider.cs +++ b/src/Umbraco.Core/Routing/UrlProvider.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Routing /// The list of media url providers. /// The current variation accessor. /// - public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IWebRoutingSection routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor) + public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IWebRoutingSettings routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor) { if (routingSettings == null) throw new ArgumentNullException(nameof(routingSettings)); diff --git a/src/Umbraco.Core/Runtime/IMainDom.cs b/src/Umbraco.Core/Runtime/IMainDom.cs index 444fc1c7d0..93a560ff7d 100644 --- a/src/Umbraco.Core/Runtime/IMainDom.cs +++ b/src/Umbraco.Core/Runtime/IMainDom.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core.Hosting; // TODO: Can't change namespace due to breaking changes, change in netcore namespace Umbraco.Core @@ -16,10 +17,17 @@ namespace Umbraco.Core /// Gets a value indicating whether the current domain is the main domain. /// /// - /// When the first call is made to this there will generally be some logic executed to acquire a distributed lock lease. + /// Acquire must be called first else this will always return false /// bool IsMainDom { get; } + /// + /// Tries to acquire the MainDom, returns true if successful else false + /// + /// + /// + bool Acquire(IApplicationShutdownRegistry hostingEnvironment); + /// /// Registers a resource that requires the current AppDomain to be the main domain to function. /// diff --git a/src/Umbraco.Core/Runtime/MainDom.cs b/src/Umbraco.Core/Runtime/MainDom.cs index 2c56852095..81db1b700d 100644 --- a/src/Umbraco.Core/Runtime/MainDom.cs +++ b/src/Umbraco.Core/Runtime/MainDom.cs @@ -21,7 +21,7 @@ namespace Umbraco.Core.Runtime #region Vars private readonly ILogger _logger; - private readonly IHostingEnvironment _hostingEnvironment; + private IApplicationShutdownRegistry _hostingEnvironment; private readonly IMainDomLock _mainDomLock; // our own lock for local consistency @@ -42,17 +42,25 @@ namespace Umbraco.Core.Runtime #region Ctor // initializes a new instance of MainDom - public MainDom(ILogger logger, IHostingEnvironment hostingEnvironment, IMainDomLock systemLock) + public MainDom(ILogger logger, IMainDomLock systemLock) { - hostingEnvironment.RegisterObject(this); - _logger = logger; - _hostingEnvironment = hostingEnvironment; _mainDomLock = systemLock; } #endregion + public bool Acquire(IApplicationShutdownRegistry hostingEnvironment) + { + _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); + + return LazyInitializer.EnsureInitialized(ref _isMainDom, ref _isInitialized, ref _locko, () => + { + hostingEnvironment.RegisterObject(this); + return Acquire(); + }); + } + /// /// Registers a resource that requires the current AppDomain to be the main domain to function. /// @@ -180,10 +188,9 @@ namespace Umbraco.Core.Runtime /// Gets a value indicating whether the current domain is the main domain. /// /// - /// The lazy initializer call will only call the Acquire callback when it's not been initialized, else it will just return - /// the value from _isMainDom which means when we set _isMainDom to false again after being signaled, this will return false; + /// Acquire must be called first else this will always return false /// - public bool IsMainDom => LazyInitializer.EnsureInitialized(ref _isMainDom, ref _isInitialized, ref _locko, () => Acquire()); + public bool IsMainDom => _isMainDom; // IRegisteredObject void IRegisteredObject.Stop(bool immediate) @@ -193,7 +200,7 @@ namespace Umbraco.Core.Runtime // The web app is stopping, need to wind down Dispose(true); - _hostingEnvironment.UnregisterObject(this); + _hostingEnvironment?.UnregisterObject(this); } #region IDisposable Support diff --git a/src/Umbraco.Core/Scheduling/KeepAlive.cs b/src/Umbraco.Core/Scheduling/KeepAlive.cs index c677c66b83..1c4ef075ae 100644 --- a/src/Umbraco.Core/Scheduling/KeepAlive.cs +++ b/src/Umbraco.Core/Scheduling/KeepAlive.cs @@ -11,18 +11,22 @@ namespace Umbraco.Web.Scheduling { public class KeepAlive : RecurringTaskBase { - private readonly IRuntimeState _runtime; - private readonly IKeepAliveSection _keepAliveSection; + private readonly IRuntimeState _runtimeState; + private readonly IMainDom _mainDom; + private readonly IKeepAliveSettings _keepAliveSettings; private readonly IProfilingLogger _logger; + private readonly IServerRegistrar _serverRegistrar; private static HttpClient _httpClient; public KeepAlive(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, - IRuntimeState runtime, IKeepAliveSection keepAliveSection, IProfilingLogger logger) + IRuntimeState runtimeState, IMainDom mainDom, IKeepAliveSettings keepAliveSettings, IProfilingLogger logger, IServerRegistrar serverRegistrar) : base(runner, delayMilliseconds, periodMilliseconds) { - _runtime = runtime; - _keepAliveSection = keepAliveSection; + _runtimeState = runtimeState; + _mainDom = mainDom; + _keepAliveSettings = keepAliveSettings; _logger = logger; + _serverRegistrar = serverRegistrar; if (_httpClient == null) _httpClient = new HttpClient(); } @@ -30,7 +34,7 @@ namespace Umbraco.Web.Scheduling public override async Task PerformRunAsync(CancellationToken token) { // not on replicas nor unknown role servers - switch (_runtime.ServerRole) + switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: _logger.Debug("Does not run on replica servers."); @@ -41,7 +45,7 @@ namespace Umbraco.Web.Scheduling } // ensure we do not run if not main domain, but do NOT lock it - if (_runtime.IsMainDom == false) + if (_mainDom.IsMainDom == false) { _logger.Debug("Does not run if not MainDom."); return false; // do NOT repeat, going down @@ -49,12 +53,12 @@ namespace Umbraco.Web.Scheduling using (_logger.DebugDuration("Keep alive executing", "Keep alive complete")) { - var keepAlivePingUrl = _keepAliveSection.KeepAlivePingUrl; + var keepAlivePingUrl = _keepAliveSettings.KeepAlivePingUrl; try { if (keepAlivePingUrl.Contains("{umbracoApplicationUrl}")) { - var umbracoAppUrl = _runtime.ApplicationUrl.ToString(); + var umbracoAppUrl = _runtimeState.ApplicationUrl.ToString(); if (umbracoAppUrl.IsNullOrWhiteSpace()) { _logger.Warn("No umbracoApplicationUrl for service (yet), skip."); diff --git a/src/Umbraco.Core/Scheduling/TempFileCleanup.cs b/src/Umbraco.Core/Scheduling/TempFileCleanup.cs index aefaf605db..90bf4ee9eb 100644 --- a/src/Umbraco.Core/Scheduling/TempFileCleanup.cs +++ b/src/Umbraco.Core/Scheduling/TempFileCleanup.cs @@ -14,26 +14,26 @@ namespace Umbraco.Web.Scheduling { private readonly DirectoryInfo[] _tempFolders; private readonly TimeSpan _age; - private readonly IRuntimeState _runtime; + private readonly IMainDom _mainDom; private readonly IProfilingLogger _logger; public TempFileCleanup(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, IEnumerable tempFolders, TimeSpan age, - IRuntimeState runtime, IProfilingLogger logger) + IMainDom mainDom, IProfilingLogger logger) : base(runner, delayMilliseconds, periodMilliseconds) { //SystemDirectories.TempFileUploads _tempFolders = tempFolders.ToArray(); _age = age; - _runtime = runtime; + _mainDom = mainDom; _logger = logger; } public override bool PerformRun() { // ensure we do not run if not main domain - if (_runtime.IsMainDom == false) + if (_mainDom.IsMainDom == false) { _logger.Debug("Does not run if not MainDom."); return false; // do NOT repeat, going down diff --git a/src/Umbraco.Core/Services/IRuntime.cs b/src/Umbraco.Core/Services/IRuntime.cs index e846342dbc..4715068073 100644 --- a/src/Umbraco.Core/Services/IRuntime.cs +++ b/src/Umbraco.Core/Services/IRuntime.cs @@ -13,13 +13,15 @@ namespace Umbraco.Core /// /// The application register. /// The application factory. - IFactory Boot(IRegister register); + IFactory Configure(IRegister register); /// /// Gets the runtime state. /// IRuntimeState State { get; } + void Start(); + /// /// Terminates the runtime. /// diff --git a/src/Umbraco.Core/Services/IRuntimeState.cs b/src/Umbraco.Core/Services/IRuntimeState.cs index 38da246cc1..4b5e26651b 100644 --- a/src/Umbraco.Core/Services/IRuntimeState.cs +++ b/src/Umbraco.Core/Services/IRuntimeState.cs @@ -25,33 +25,12 @@ namespace Umbraco.Core /// SemVersion SemanticVersion { get; } - /// - /// Gets a value indicating whether the application is running in debug mode. - /// - bool Debug { get; } - - /// - /// Gets a value indicating whether the runtime is the current main domain. - /// - bool IsMainDom { get; } - - /// - /// Get the server's current role. - /// - ServerRole ServerRole { get; } - /// /// Gets the Umbraco application url. /// /// This is eg "http://www.example.com". Uri ApplicationUrl { get; } - /// - /// Gets the Umbraco application virtual path. - /// - /// This is either "/" or eg "/virtual". - string ApplicationVirtualPath { get; } - /// /// Gets the runtime level of execution. /// @@ -77,6 +56,5 @@ namespace Umbraco.Core /// BootFailedException BootFailedException { get; } - IMainDom MainDom { get; } } } diff --git a/src/Umbraco.Core/SimpleMainDom.cs b/src/Umbraco.Core/SimpleMainDom.cs index 87cc7bcff1..e6bdda67d7 100644 --- a/src/Umbraco.Core/SimpleMainDom.cs +++ b/src/Umbraco.Core/SimpleMainDom.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Hosting; namespace Umbraco.Core { @@ -16,6 +17,9 @@ namespace Umbraco.Core /// public bool IsMainDom { get; private set; } = true; + // always acquire + public bool Acquire(IApplicationShutdownRegistry hostingEnvironment) => true; + /// public bool Register(Action release, int weight = 100) => Register(null, release, weight); diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs index 6361186604..c3e7fa85c3 100644 --- a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs +++ b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Strings { #region Ctor, consts and vars - public DefaultShortStringHelper(IUmbracoSettingsSection settings) + public DefaultShortStringHelper(IRequestHandlerSettings settings) { _config = new DefaultShortStringHelperConfig().WithDefault(settings); } @@ -619,6 +619,6 @@ namespace Umbraco.Core.Strings return new string(output, 0, opos); } - #endregion + #endregion } } diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs index e75e00defb..25ee781ae9 100644 --- a/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs +++ b/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Strings public string DefaultCulture { get; set; } = ""; // invariant public Dictionary UrlReplaceCharacters { get; set; } - + public DefaultShortStringHelperConfig WithConfig(Config config) { return WithConfig(DefaultCulture, CleanStringType.RoleMask, config); @@ -57,16 +57,16 @@ namespace Umbraco.Core.Strings /// Sets the default configuration. /// /// The short string helper. - public DefaultShortStringHelperConfig WithDefault(IUmbracoSettingsSection umbracoSettings) + public DefaultShortStringHelperConfig WithDefault(IRequestHandlerSettings requestHandlerSettings) { - UrlReplaceCharacters = umbracoSettings.RequestHandler.CharCollection + UrlReplaceCharacters = requestHandlerSettings.CharCollection .Where(x => string.IsNullOrEmpty(x.Char) == false) .ToDictionary(x => x.Char, x => x.Replacement); var urlSegmentConvertTo = CleanStringType.Utf8; - if (umbracoSettings.RequestHandler.ConvertUrlsToAscii) + if (requestHandlerSettings.ConvertUrlsToAscii) urlSegmentConvertTo = CleanStringType.Ascii; - if (umbracoSettings.RequestHandler.TryConvertUrlsToAscii) + if (requestHandlerSettings.TryConvertUrlsToAscii) urlSegmentConvertTo = CleanStringType.TryAscii; return WithConfig(CleanStringType.UrlSegment, new Config diff --git a/src/Umbraco.Core/Templates/HtmlUrlParser.cs b/src/Umbraco.Core/Templates/HtmlUrlParser.cs index a2fdb93292..566fce8b87 100644 --- a/src/Umbraco.Core/Templates/HtmlUrlParser.cs +++ b/src/Umbraco.Core/Templates/HtmlUrlParser.cs @@ -7,16 +7,16 @@ namespace Umbraco.Web.Templates { public sealed class HtmlUrlParser { - private readonly IContentSection _contentSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; private readonly IProfilingLogger _logger; private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - public HtmlUrlParser(IContentSection contentSection, IProfilingLogger logger, IIOHelper ioHelper) + public HtmlUrlParser(IContentSettings contentSettings, IProfilingLogger logger, IIOHelper ioHelper) { - _contentSection = contentSection; + _contentSettings = contentSettings; _ioHelper = ioHelper; _logger = logger; } @@ -32,7 +32,7 @@ namespace Umbraco.Web.Templates /// public string EnsureUrls(string text) { - if (_contentSection.ResolveUrlsFromTextString == false) return text; + if (_contentSettings.ResolveUrlsFromTextString == false) return text; using (var timer = _logger.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete")) { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7a15e7fbed..c083cccf8f 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index cf84d7914d..4321aefd7f 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -40,7 +40,7 @@ namespace Umbraco.Core /// But if we've got this far we'll just have to assume it's front-end anyways. /// /// - internal static bool IsBackOfficeRequest(this Uri url, string applicationPath, IGlobalSettings globalSettings, IIOHelper ioHelper) + internal static bool IsBackOfficeRequest(this Uri url, string applicationPath, IIOHelper ioHelper) { applicationPath = applicationPath ?? string.Empty; @@ -49,11 +49,11 @@ namespace Umbraco.Core var urlPath = fullUrlPath.TrimStart(appPath).EnsureStartsWith('/'); //check if this is in the umbraco back office - var isUmbracoPath = urlPath.InvariantStartsWith(globalSettings.Path.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/')); + var isUmbracoPath = urlPath.InvariantStartsWith(ioHelper.BackOfficePath.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/')); //if not, then def not back office if (isUmbracoPath == false) return false; - var mvcArea = globalSettings.GetUmbracoMvcArea(ioHelper); + var mvcArea = ioHelper.GetUmbracoMvcArea(); //if its the normal /umbraco path if (urlPath.InvariantEquals("/" + mvcArea) || urlPath.InvariantEquals("/" + mvcArea + "/")) @@ -127,12 +127,12 @@ namespace Umbraco.Core /// /// /// - internal static bool IsDefaultBackOfficeRequest(this Uri url, IGlobalSettings globalSettings) + internal static bool IsDefaultBackOfficeRequest(this Uri url, IIOHelper ioHelper) { - if (url.AbsolutePath.InvariantEquals(globalSettings.Path.TrimEnd("/")) - || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/')) - || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/') + "Default") - || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/') + "Default/")) + if (url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.TrimEnd("/")) + || url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.EnsureEndsWith('/')) + || url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.EnsureEndsWith('/') + "Default") + || url.AbsolutePath.InvariantEquals(ioHelper.BackOfficePath.EnsureEndsWith('/') + "Default/")) { return true; } diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs index d73dc89948..c4e7f264fb 100644 --- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs +++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs @@ -6,8 +6,6 @@ using System.Text.RegularExpressions; using Examine; using Umbraco.Core; using Umbraco.Core.Models; -using Umbraco.Core.Models.Identity; -using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web; using Umbraco.Web.Models.ContentEditing; diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs index 78b9589a2e..70b79fbeb0 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs @@ -28,17 +28,18 @@ namespace Umbraco.Web private readonly IRequestAccessor _requestAccessor; public BatchedDatabaseServerMessenger( - IRuntimeState runtime, + IMainDom mainDom, IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, + IServerRegistrar serverRegistrar, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IRequestCache requestCache, IRequestAccessor requestAccessor) - : base(runtime, scopeProvider, sqlContext, proflog, true, options, hostingEnvironment, cacheRefreshers) + : base(mainDom, scopeProvider, sqlContext, proflog, serverRegistrar, true, options, hostingEnvironment, cacheRefreshers) { _databaseFactory = databaseFactory; _requestCache = requestCache; diff --git a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs index 2a24e6f318..6c745f3877 100644 --- a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs @@ -91,7 +91,6 @@ namespace Umbraco.Web.Compose private readonly BackgroundTaskRunner _processTaskRunner; private bool _started; private IBackgroundTask[] _tasks; - private IndexRebuilder _indexRebuilder; private readonly IRequestAccessor _requestAccessor; public DatabaseServerRegistrarAndMessengerComponent( @@ -100,14 +99,12 @@ namespace Umbraco.Web.Compose IServerMessenger serverMessenger, IServerRegistrationService registrationService, ILogger logger, - IHostingEnvironment hostingEnvironment, - IndexRebuilder indexRebuilder, + IApplicationShutdownRegistry hostingEnvironment, IRequestAccessor requestAccessor) { _runtime = runtime; _logger = logger; _registrationService = registrationService; - _indexRebuilder = indexRebuilder; _requestAccessor = requestAccessor; // create task runner for DatabaseServerRegistrar diff --git a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs index d4e22bbfde..a2ee650595 100644 --- a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs @@ -10,7 +10,7 @@ namespace Umbraco.Core.Compose { public sealed class ManifestWatcherComponent : IComponent { - private readonly IRuntimeState _runtimeState; + private readonly IHostingEnvironment _hosting; private readonly ILogger _logger; private readonly IIOHelper _ioHelper; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; @@ -19,9 +19,9 @@ namespace Umbraco.Core.Compose // package.manifest chances and restarts the application on any change private ManifestWatcher _mw; - public ManifestWatcherComponent(IRuntimeState runtimeState, ILogger logger, IIOHelper ioHelper, IUmbracoApplicationLifetime umbracoApplicationLifetime) + public ManifestWatcherComponent(IHostingEnvironment hosting, ILogger logger, IIOHelper ioHelper, IUmbracoApplicationLifetime umbracoApplicationLifetime) { - _runtimeState = runtimeState; + _hosting = hosting; _logger = logger; _ioHelper = ioHelper; _umbracoApplicationLifetime = umbracoApplicationLifetime; @@ -29,7 +29,7 @@ namespace Umbraco.Core.Compose public void Initialize() { - if (_runtimeState.Debug == false) return; + if (_hosting.IsDebugMode == false) return; //if (ApplicationContext.Current.IsConfigured == false || GlobalSettings.DebugMode == false) // return; diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Configuration.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Configuration.cs deleted file mode 100644 index 5c931a225b..0000000000 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Configuration.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Core.Composing.CompositionExtensions -{ - /// - /// Compose configurations. - /// - internal static class Configuration - { - public static Composition ComposeConfiguration(this Composition composition) - { - // common configurations are already registered - // register others - - composition.RegisterUnique(factory => factory.GetInstance().Content); - composition.RegisterUnique(factory => factory.GetInstance().RequestHandler); - composition.RegisterUnique(factory => factory.GetInstance().Security); - - return composition; - } - } -} diff --git a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs new file mode 100644 index 0000000000..2099778185 --- /dev/null +++ b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.Hosting; + +namespace Umbraco.Core.Composing +{ + /// + /// Extends the to enable Umbraco to be used as the service container. + /// + public static class HostBuilderExtensions + { + /// + /// Assigns a custom service provider factory to use Umbraco's container + /// + /// + /// + public static IHostBuilder UseUmbraco(this IHostBuilder builder) + => builder.UseUmbraco(new UmbracoServiceProviderFactory()); + + public static IHostBuilder UseUmbraco(this IHostBuilder builder, UmbracoServiceProviderFactory umbracoServiceProviderFactory) + => builder.UseServiceProviderFactory(umbracoServiceProviderFactory); + } +} diff --git a/src/Umbraco.Infrastructure/Composing/LightInject/LightInjectContainer.cs b/src/Umbraco.Infrastructure/Composing/LightInject/LightInjectContainer.cs index 5200dced90..a6db0b7b2b 100644 --- a/src/Umbraco.Infrastructure/Composing/LightInject/LightInjectContainer.cs +++ b/src/Umbraco.Infrastructure/Composing/LightInject/LightInjectContainer.cs @@ -16,11 +16,13 @@ namespace Umbraco.Core.Composing.LightInject /// /// Initializes a new instance of the with a LightInject container. /// - protected LightInjectContainer(ServiceContainer container) + public LightInjectContainer(ServiceContainer container) { - Container = container; + Container = ConfigureContainer(container); } + //TODO: The Create methods can die when net framework is gone + /// /// Creates a new instance of the class. /// @@ -33,7 +35,12 @@ namespace Umbraco.Core.Composing.LightInject protected static ServiceContainer CreateServiceContainer() { var container = new ServiceContainer(new ContainerOptions { EnablePropertyInjection = false }); + ConfigureContainer(container); + return container; + } + private static ServiceContainer ConfigureContainer(ServiceContainer container) + { // note: the block below is disabled, as it is too LightInject-specific // // supports annotated constructor injections @@ -84,7 +91,7 @@ namespace Umbraco.Core.Composing.LightInject /// /// Gets the LightInject container. /// - protected ServiceContainer Container { get; } + public ServiceContainer Container { get; } /// /// diff --git a/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs b/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs index 8f842e14fe..835bd0b9a8 100644 --- a/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs +++ b/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs @@ -1,14 +1,22 @@ -using System; +using LightInject; +using LightInject.Microsoft.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; using System.Reflection; +using Umbraco.Core.Composing.LightInject; using Umbraco.Core.Configuration; namespace Umbraco.Core.Composing { + /// /// Creates the container. /// public static class RegisterFactory { + //TODO: This can die when net framework is gone + // cannot use typeof().AssemblyQualifiedName on the web container - we don't reference it // a normal Umbraco site should run on the web container, but an app may run on the core one private const string CoreLightInjectContainerTypeName = "Umbraco.Core.Composing.LightInject.LightInjectContainer,Umbraco.Core"; diff --git a/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs new file mode 100644 index 0000000000..6fd0bda61e --- /dev/null +++ b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs @@ -0,0 +1,78 @@ +using LightInject; +using LightInject.Microsoft.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using Umbraco.Core.Composing.LightInject; + +namespace Umbraco.Core.Composing +{ + /// + /// Used to create Umbraco's container and cross-wire it up before the applicaton starts + /// + public class UmbracoServiceProviderFactory : IServiceProviderFactory + { + public UmbracoServiceProviderFactory(ServiceContainer container) + { + _container = new LightInjectContainer(container); + } + + /// + /// Creates an ASP.NET Core compatible service container + /// + /// + public static ServiceContainer CreateServiceContainer() => new ServiceContainer(ContainerOptions.Default.Clone().WithMicrosoftSettings().WithAspNetCoreSettings()); + + /// + /// Default ctor for use in Host Builder configuration + /// + public UmbracoServiceProviderFactory() + { + var container = CreateServiceContainer(); + UmbracoContainer = _container = new LightInjectContainer(container); + IsActive = true; + } + + // see here for orig lightinject version https://github.com/seesharper/LightInject.Microsoft.DependencyInjection/blob/412566e3f70625e6b96471db5e1f7cd9e3e1eb18/src/LightInject.Microsoft.DependencyInjection/LightInject.Microsoft.DependencyInjection.cs#L263 + // we don't really need all that, we're manually creating our container with the correct options and that + // is what we'll return in CreateBuilder + + IServiceCollection _services; + readonly LightInjectContainer _container; + + internal LightInjectContainer GetContainer() => _container; + + /// + /// When the empty ctor is used this returns if this factory is active + /// + public static bool IsActive { get; private set; } + + /// + /// When the empty ctor is used this returns the created IRegister + /// + public static IRegister UmbracoContainer { get; private set; } + + /// + /// Create the container with the required settings for aspnetcore3 + /// + /// + /// + public IServiceContainer CreateBuilder(IServiceCollection services) + { + _services = services; + return _container.Container; + } + + /// + /// This cross-wires the container just before the application calls "Configure" + /// + /// + /// + public IServiceProvider CreateServiceProvider(IServiceContainer containerBuilder) + { + var provider = containerBuilder.CreateServiceProvider(_services); + return provider; + } + + } +} diff --git a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs index eb74d37590..02e5a6f5ee 100644 --- a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs +++ b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs @@ -1,6 +1,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -15,6 +16,9 @@ namespace Umbraco.Core /// /// Registers essential services. /// + /// + /// These services are all either created by the runtime or used to construct the runtime + /// public static void RegisterEssentials(this Composition composition, ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger, IMainDom mainDom, @@ -25,8 +29,10 @@ namespace Umbraco.Core ITypeFinder typeFinder, IIOHelper ioHelper, IUmbracoVersion umbracoVersion, - IDbProviderFactoryCreator dbProviderFactoryCreator) - { + IDbProviderFactoryCreator dbProviderFactoryCreator, + IHostingEnvironment hostingEnvironment, + IBackOfficeInfo backOfficeInfo) + { composition.RegisterUnique(logger); composition.RegisterUnique(profiler); composition.RegisterUnique(profilingLogger); @@ -42,6 +48,8 @@ namespace Umbraco.Core composition.RegisterUnique(umbracoVersion); composition.RegisterUnique(dbProviderFactoryCreator); composition.RegisterUnique(factory => factory.GetInstance().BulkSqlInsertProvider); + composition.RegisterUnique(hostingEnvironment); + composition.RegisterUnique(backOfficeInfo); } } } diff --git a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs new file mode 100644 index 0000000000..3c78faea37 --- /dev/null +++ b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using Microsoft.Extensions.FileProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core.IO; +using Umbraco.Core.Serialization; + +namespace Umbraco.Core.Configuration +{ + public class JsonConfigManipulator : IConfigManipulator + { + private readonly IConfiguration _configuration; + + public JsonConfigManipulator(IConfiguration configuration) + { + _configuration = configuration; + } + + public string UmbracoConnectionPath { get; } = $"ConnectionStrings:{ Constants.System.UmbracoConnectionName}"; + public void RemoveConnectionString() + { + var provider = GetJsonConfigurationProvider(UmbracoConnectionPath); + + var json = GetJson(provider); + + RemoveJsonKey(json, UmbracoConnectionPath); + + SaveJson(provider, json); + } + + public void SaveConnectionString(string connectionString, string providerName) + { + var provider = GetJsonConfigurationProvider(); + + var json = GetJson(provider); + + var item = GetConnectionItem(connectionString, providerName); + + json.Merge(item, new JsonMergeSettings()); + + SaveJson(provider, json); + } + + + private JToken GetConnectionItem(string connectionString, string providerName) + { + JTokenWriter writer = new JTokenWriter(); + + writer.WriteStartObject(); + writer.WritePropertyName("ConnectionStrings"); + writer.WriteStartObject(); + writer.WritePropertyName(Constants.System.UmbracoConnectionName); + writer.WriteValue(connectionString); + writer.WriteEndObject(); + writer.WriteEndObject(); + + return writer.Token; + } + + private static void RemoveJsonKey(JObject json, string key) + { + JToken token = json; + foreach (var propertyName in key.Split(new[] { ':' })) + { + token = CaseSelectPropertyValues(token, propertyName); + } + + token?.Parent?.Remove(); + } + + private static void SaveJson(JsonConfigurationProvider provider, JObject json) + { + if (provider.Source.FileProvider is PhysicalFileProvider physicalFileProvider) + { + var jsonFilePath = Path.Combine(physicalFileProvider.Root, provider.Source.Path); + + using (var sw = new StreamWriter(jsonFilePath, false)) + using (var jsonTextWriter = new JsonTextWriter(sw) + { + Formatting = Formatting.Indented, + }) + { + json?.WriteTo(jsonTextWriter); + } + } + + } + + private static JObject GetJson(JsonConfigurationProvider provider) + { + if (provider.Source.FileProvider is PhysicalFileProvider physicalFileProvider) + { + var jsonFilePath = Path.Combine(physicalFileProvider.Root, provider.Source.Path); + + var serializer = new JsonSerializer(); + using (var sr = new StreamReader(jsonFilePath)) + using (var jsonTextReader = new JsonTextReader(sr)) + { + return serializer.Deserialize(jsonTextReader); + } + } + + return null; + } + + + + + private JsonConfigurationProvider GetJsonConfigurationProvider(string requiredKey = null) + { + if (_configuration is IConfigurationRoot configurationRoot) + { + foreach (var provider in configurationRoot.Providers) + { + if(provider is JsonConfigurationProvider jsonConfigurationProvider) + { + if (requiredKey is null || provider.TryGet(requiredKey, out _)) + { + return jsonConfigurationProvider; + } + } + } + } + throw new InvalidOperationException("Could not find a writable json config source"); + } + + /// + /// Returns the property value when case insensative + /// + /// + /// This method is required because keys are case insensative in IConfiguration. + /// JObject[..] do not support case insensative and JObject.Property(...) do not return a new JObject. + /// + private static JToken CaseSelectPropertyValues(JToken token, string name) + { + if (token is JObject obj) + { + + foreach (var property in obj.Properties()) + { + if (name is null) + return property.Value; + if (string.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase)) + return property.Value; + } + } + return null; + } + + } +} diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs index b27113a0f1..9d36b60d83 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs @@ -18,9 +18,9 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods private readonly IRuntimeState _runtimeState; private readonly ILogger _logger; private readonly IGlobalSettings _globalSettings; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; - public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings, IHealthChecks healthChecks, IUmbracoSettingsSection umbracoSettingsSection) : base(healthChecks) + public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings, IHealthChecksSettings healthChecksSettings, IContentSettings contentSettings) : base(healthChecksSettings) { var recipientEmail = Settings["recipientEmail"]?.Value; if (string.IsNullOrWhiteSpace(recipientEmail)) @@ -35,7 +35,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods _runtimeState = runtimeState; _logger = logger; _globalSettings = globalSettings; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } public string RecipientEmail { get; } @@ -74,7 +74,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods private MailMessage CreateMailMessage(string subject, string message) { - var to = _umbracoSettingsSection.Content.NotificationEmailAddress; + var to = _contentSettings.NotificationEmailAddress; if (string.IsNullOrWhiteSpace(subject)) subject = "Umbraco Health Check Status"; diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs index ff6fbe2371..9c3516e712 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs @@ -8,7 +8,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods { public abstract class NotificationMethodBase : IHealthCheckNotificationMethod { - protected NotificationMethodBase(IHealthChecks healthCheckConfig) + protected NotificationMethodBase(IHealthChecksSettings healthCheckSettingsConfig) { var type = GetType(); var attribute = type.GetCustomAttribute(); @@ -18,7 +18,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods return; } - var notificationMethods = healthCheckConfig.NotificationSettings.NotificationMethods; + var notificationMethods = healthCheckSettingsConfig.NotificationSettings.NotificationMethods; var notificationMethod = notificationMethods[attribute.Alias]; if (notificationMethod == null) { diff --git a/src/Umbraco.Infrastructure/Intall/InstallHelper.cs b/src/Umbraco.Infrastructure/Intall/InstallHelper.cs index a5b4f71d8e..cf4b174cde 100644 --- a/src/Umbraco.Infrastructure/Intall/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Intall/InstallHelper.cs @@ -9,10 +9,10 @@ using Umbraco.Core.Cookie; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Models; +using Umbraco.Net; using Umbraco.Core.Persistence; using Umbraco.Core.Serialization; using Umbraco.Core.Services; -using Umbraco.Net; using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/ConfigureMachineKey.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/ConfigureMachineKey.cs deleted file mode 100644 index fb8201600c..0000000000 --- a/src/Umbraco.Infrastructure/Intall/InstallSteps/ConfigureMachineKey.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using System.Xml.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Security; -using Umbraco.Web.Install.Models; - -namespace Umbraco.Web.Install.InstallSteps -{ - [InstallSetupStep(InstallationType.NewInstall, - "ConfigureMachineKey", "machinekey", 2, - "Updating some security settings...", - PerformsAppRestart = true)] - public class ConfigureMachineKey : InstallSetupStep - { - private readonly IIOHelper _ioHelper; - private readonly IMachineKeyConfig _machineKeyConfig; - - public ConfigureMachineKey(IIOHelper ioHelper, IMachineKeyConfig machineKeyConfig) - { - _ioHelper = ioHelper; - _machineKeyConfig = machineKeyConfig; - } - - public override string View => HasMachineKey() == false ? base.View : ""; - - /// - /// Don't display the view or execute if a machine key already exists - /// - /// - private bool HasMachineKey() - { - return _machineKeyConfig.HasMachineKey; - } - - /// - /// The step execution method - /// - /// - /// - public override Task ExecuteAsync(bool? model) - { - if (model.HasValue && model.Value == false) return Task.FromResult(null); - - //install the machine key - var fileName = _ioHelper.MapPath($"{_ioHelper.Root}/web.config"); - var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - - // we only want to get the element that is under the root, (there may be more under tags we don't want them) - var systemWeb = xml.Root.Element("system.web"); - - // Update appSetting if it exists, or else create a new appSetting for the given key and value - var machineKey = systemWeb.Descendants("machineKey").FirstOrDefault(); - if (machineKey != null) return Task.FromResult(null); - - var generator = new MachineKeyGenerator(); - var generatedSection = generator.GenerateConfigurationBlock(); - systemWeb.Add(XElement.Parse(generatedSection)); - - xml.Save(fileName, SaveOptions.DisableFormatting); - - return Task.FromResult(null); - } - - public override bool RequiresExecution(bool? model) - { - return HasMachineKey() == false; - } - } -} diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs index a7b3dcc218..865df4bc02 100644 --- a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseInstallStep.cs @@ -19,14 +19,16 @@ namespace Umbraco.Web.Install.InstallSteps private readonly ILogger _logger; private readonly IIOHelper _ioHelper; private readonly IConnectionStrings _connectionStrings; + private readonly IConfigManipulator _configManipulator; - public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings) + public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings, IConfigManipulator configManipulator) { _databaseBuilder = databaseBuilder; _runtime = runtime; _logger = logger; _ioHelper = ioHelper; _connectionStrings = connectionStrings; + _configManipulator = configManipulator; } public override Task ExecuteAsync(object model) @@ -43,7 +45,7 @@ namespace Umbraco.Web.Install.InstallSteps if (result.RequiresUpgrade == false) { - HandleConnectionStrings(_logger, _ioHelper, _connectionStrings); + HandleConnectionStrings(_logger, _ioHelper, _connectionStrings, _configManipulator); return Task.FromResult(null); } @@ -54,7 +56,7 @@ namespace Umbraco.Web.Install.InstallSteps })); } - internal static void HandleConnectionStrings(ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings) + internal static void HandleConnectionStrings(ILogger logger, IIOHelper ioHelper, IConnectionStrings connectionStrings, IConfigManipulator configManipulator) { @@ -65,7 +67,7 @@ namespace Umbraco.Web.Install.InstallSteps // Remove legacy umbracoDbDsn configuration setting if it exists and connectionstring also exists if (databaseSettings != null) { - connectionStrings.RemoveConnectionString(Constants.System.UmbracoConnectionName); + configManipulator.RemoveConnectionString(); } else { diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs index 3cd3c1ca56..91a718d0f4 100644 --- a/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Infrastructure/Intall/InstallSteps/DatabaseUpgradeStep.cs @@ -23,8 +23,17 @@ namespace Umbraco.Web.Install.InstallSteps private readonly IGlobalSettings _globalSettings; private readonly IConnectionStrings _connectionStrings; private readonly IIOHelper _ioHelper; + private readonly IConfigManipulator _configManipulator; - public DatabaseUpgradeStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IUmbracoVersion umbracoVersion, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, IIOHelper ioHelper) + public DatabaseUpgradeStep( + DatabaseBuilder databaseBuilder, + IRuntimeState runtime, + ILogger logger, + IUmbracoVersion umbracoVersion, + IGlobalSettings globalSettings, + IConnectionStrings connectionStrings, + IIOHelper ioHelper, + IConfigManipulator configManipulator) { _databaseBuilder = databaseBuilder; _runtime = runtime; @@ -33,6 +42,7 @@ namespace Umbraco.Web.Install.InstallSteps _globalSettings = globalSettings; _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); _ioHelper = ioHelper; + _configManipulator = configManipulator; } public override Task ExecuteAsync(object model) @@ -55,7 +65,7 @@ namespace Umbraco.Web.Install.InstallSteps throw new InstallException("The database failed to upgrade. ERROR: " + result.Message); } - DatabaseInstallStep.HandleConnectionStrings(_logger, _ioHelper, _connectionStrings); + DatabaseInstallStep.HandleConnectionStrings(_logger, _ioHelper, _connectionStrings, _configManipulator); } return Task.FromResult(null); diff --git a/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs index cc269408f4..4e14da30b7 100644 --- a/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Infrastructure/Intall/InstallSteps/StarterKitInstallStep.cs @@ -2,8 +2,8 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Umbraco.Core.Services; using Umbraco.Net; +using Umbraco.Core.Services; using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs index 9dde28e95a..bb77869e28 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Logging.Serilog /// public class SerilogLogger : ILogger, IDisposable { - private readonly ICoreDebug _coreDebug; + private readonly ICoreDebugSettings _coreDebugSettings; private readonly IIOHelper _ioHelper; private readonly IMarchal _marchal; @@ -26,9 +26,9 @@ namespace Umbraco.Core.Logging.Serilog /// Initialize a new instance of the class with a configuration file. /// /// - public SerilogLogger(ICoreDebug coreDebug, IIOHelper ioHelper, IMarchal marchal, FileInfo logConfigFile) + public SerilogLogger(ICoreDebugSettings coreDebugSettings, IIOHelper ioHelper, IMarchal marchal, FileInfo logConfigFile) { - _coreDebug = coreDebug; + _coreDebugSettings = coreDebugSettings; _ioHelper = ioHelper; _marchal = marchal; @@ -37,9 +37,9 @@ namespace Umbraco.Core.Logging.Serilog .CreateLogger(); } - public SerilogLogger(ICoreDebug coreDebug, IIOHelper ioHelper, IMarchal marchal, LoggerConfiguration logConfig) + public SerilogLogger(ICoreDebugSettings coreDebugSettings, IIOHelper ioHelper, IMarchal marchal, LoggerConfiguration logConfig) { - _coreDebug = coreDebug; + _coreDebugSettings = coreDebugSettings; _ioHelper = ioHelper; _marchal = marchal; @@ -51,7 +51,7 @@ namespace Umbraco.Core.Logging.Serilog /// Creates a logger with some pre-defined configuration and remainder from config file /// /// Used by UmbracoApplicationBase to get its logger. - public static SerilogLogger CreateWithDefaultConfiguration(IHostingEnvironment hostingEnvironment, ISessionIdResolver sessionIdResolver, Func requestCacheGetter, ICoreDebug coreDebug, IIOHelper ioHelper, IMarchal marchal) + public static SerilogLogger CreateWithDefaultConfiguration(IHostingEnvironment hostingEnvironment, ISessionIdResolver sessionIdResolver, Func requestCacheGetter, ICoreDebugSettings coreDebugSettings, IIOHelper ioHelper, IMarchal marchal) { var loggerConfig = new LoggerConfiguration(); loggerConfig @@ -59,7 +59,7 @@ namespace Umbraco.Core.Logging.Serilog .ReadFromConfigFile() .ReadFromUserConfigFile(); - return new SerilogLogger(coreDebug, ioHelper, marchal, loggerConfig); + return new SerilogLogger(coreDebugSettings, ioHelper, marchal, loggerConfig); } /// @@ -179,7 +179,7 @@ namespace Umbraco.Core.Logging.Serilog messageTemplate += "\r\nThe thread has been aborted, because the request has timed out."; // dump if configured, or if stacktrace contains Monitor.ReliableEnter - dump = _coreDebug.DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception); + dump = _coreDebugSettings.DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception); // dump if it is ok to dump (might have a cap on number of dump...) dump &= MiniDump.OkToDump(_ioHelper); diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs index 2074409ec8..987d3a98fb 100644 --- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs +++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs @@ -220,11 +220,5 @@ namespace Umbraco.Core.Manifest return manifest; } - - // purely for tests - public IEnumerable ParseGridEditors(string text) - { - return _jsonSerializer.Deserialize>(text); - } } } diff --git a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs index 4c02111ccd..665693d91f 100644 --- a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs @@ -17,13 +17,13 @@ namespace Umbraco.Web.Media { private readonly IMediaFileSystem _mediaFileSystem; private readonly ILogger _logger; - private readonly IContentSection _contentSection; + private readonly IContentSettings _contentSettings; - public UploadAutoFillProperties(IMediaFileSystem mediaFileSystem, ILogger logger, IContentSection contentSection) + public UploadAutoFillProperties(IMediaFileSystem mediaFileSystem, ILogger logger, IContentSettings contentSettings) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _contentSection = contentSection ?? throw new ArgumentNullException(nameof(contentSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } /// @@ -68,7 +68,7 @@ namespace Umbraco.Web.Media using (var filestream = _mediaFileSystem.OpenFile(filepath)) { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); - var size = _contentSection.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; + var size = _contentSettings.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); } } @@ -102,7 +102,7 @@ namespace Umbraco.Web.Media else { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); - var size = _contentSection.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; + var size = _contentSettings.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 8b1e6d741b..8d5922028c 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -28,6 +28,7 @@ namespace Umbraco.Core.Migrations.Install private readonly IIOHelper _ioHelper; private readonly IUmbracoVersion _umbracoVersion; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; + private readonly IConfigManipulator _configManipulator; private DatabaseSchemaResult _databaseSchemaValidationResult; @@ -44,7 +45,8 @@ namespace Umbraco.Core.Migrations.Install IKeyValueService keyValueService, IIOHelper ioHelper, IUmbracoVersion umbracoVersion, - IDbProviderFactoryCreator dbProviderFactoryCreator) + IDbProviderFactoryCreator dbProviderFactoryCreator, + IConfigManipulator configManipulator) { _scopeProvider = scopeProvider; _globalSettings = globalSettings; @@ -56,6 +58,7 @@ namespace Umbraco.Core.Migrations.Install _ioHelper = ioHelper; _umbracoVersion = umbracoVersion; _dbProviderFactoryCreator = dbProviderFactoryCreator; + _configManipulator = configManipulator; } #region Status @@ -138,12 +141,12 @@ namespace Umbraco.Core.Migrations.Install /// public void ConfigureEmbeddedDatabaseConnection() { - ConfigureEmbeddedDatabaseConnection(_databaseFactory, _ioHelper, _logger); + ConfigureEmbeddedDatabaseConnection(_databaseFactory, _ioHelper); } - private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory, IIOHelper ioHelper, ILogger logger) + private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory, IIOHelper ioHelper) { - SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe, ioHelper, logger); + _configManipulator.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe); var path = Path.Combine(ioHelper.GetRootDirectorySafe(), "App_Data", "Umbraco.sdf"); if (File.Exists(path) == false) @@ -166,7 +169,7 @@ namespace Umbraco.Core.Migrations.Install { const string providerName = Constants.DbProviderNames.SqlServer; - SaveConnectionString(connectionString, providerName, _ioHelper, _logger); + _configManipulator.SaveConnectionString(connectionString, providerName); _databaseFactory.Configure(connectionString, providerName); } @@ -182,7 +185,7 @@ namespace Umbraco.Core.Migrations.Install { var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out var providerName); - SaveConnectionString(connectionString, providerName, _ioHelper, _logger); + _configManipulator.SaveConnectionString(connectionString, providerName); _databaseFactory.Configure(connectionString, providerName); } @@ -213,7 +216,7 @@ namespace Umbraco.Core.Migrations.Install public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName) { var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName); - SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer, _ioHelper, _logger); + _configManipulator.SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer); _databaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlServer); } @@ -282,75 +285,8 @@ namespace Umbraco.Core.Migrations.Install return server.ToLower().StartsWith("tcp:".ToLower()); } - /// - /// Saves the connection string as a proper .net connection string in web.config. - /// - /// Saves the ConnectionString in the very nasty 'medium trust'-supportive way. - /// The connection string. - /// The provider name. - /// A logger. - private static void SaveConnectionString(string connectionString, string providerName, IIOHelper ioHelper, ILogger logger) - { - if (connectionString == null) throw new ArgumentNullException(nameof(connectionString)); - if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(connectionString)); - if (providerName == null) throw new ArgumentNullException(nameof(providerName)); - if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(providerName)); - var fileSource = "web.config"; - var fileName = ioHelper.MapPath(ioHelper.Root +"/" + fileSource); - var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root)."); - - var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); - if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings)."); - - // handle configSource - var configSourceAttribute = connectionStrings.Attribute("configSource"); - if (configSourceAttribute != null) - { - fileSource = configSourceAttribute.Value; - fileName = ioHelper.MapPath(ioHelper.Root + "/" + fileSource); - - if (!File.Exists(fileName)) - throw new Exception($"Invalid configSource \"{fileSource}\" (no such file)."); - - xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root)."); - - connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); - if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings)."); - } - - // create or update connection string - var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName); - if (setting == null) - { - connectionStrings.Add(new XElement("add", - new XAttribute("name", Constants.System.UmbracoConnectionName), - new XAttribute("connectionString", connectionString), - new XAttribute("providerName", providerName))); - } - else - { - AddOrUpdateAttribute(setting, "connectionString", connectionString); - AddOrUpdateAttribute(setting, "providerName", providerName); - } - - // save - logger.Info("Saving connection string to {ConfigFile}.", fileSource); - xml.Save(fileName, SaveOptions.DisableFormatting); - logger.Info("Saved connection string to {ConfigFile}.", fileSource); - } - - private static void AddOrUpdateAttribute(XElement element, string name, string value) - { - var attribute = element.Attribute(name); - if (attribute == null) - element.Add(new XAttribute(name, value)); - else - attribute.Value = value; - } #endregion diff --git a/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs b/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs index f1c6cf6c04..06e4d0748c 100644 --- a/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs +++ b/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.Models.ContentEditing if (UserGroups.Any() == false) yield return new ValidationResult("A user must be assigned to at least one group", new[] { nameof(UserGroups) }); - if (Current.Configs.Settings().Security.UsernameIsEmail == false && Username.IsNullOrWhiteSpace()) + if (Current.Configs.Security().UsernameIsEmail == false && Username.IsNullOrWhiteSpace()) yield return new ValidationResult("A username cannot be empty", new[] { nameof(Username) }); } } diff --git a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs index f7a2d6376b..59f63f4f15 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs @@ -191,7 +191,7 @@ namespace Umbraco.Web.Models.Mapping target.Icon = source.Icon; target.IconFilePath = target.IconIsClass ? string.Empty - : $"{_globalSettings.Path.EnsureEndsWith("/")}images/umbraco/{source.Icon}"; + : $"{_ioHelper.BackOfficePath.EnsureEndsWith("/")}images/umbraco/{source.Icon}"; target.Trashed = source.Trashed; target.Id = source.Id; @@ -497,7 +497,7 @@ namespace Umbraco.Web.Models.Mapping target.Icon = source.Icon; target.IconFilePath = target.IconIsClass ? string.Empty - : $"{_globalSettings.Path.EnsureEndsWith("/")}images/umbraco/{source.Icon}"; + : $"{_ioHelper.BackOfficePath.EnsureEndsWith("/")}images/umbraco/{source.Icon}"; target.Id = source.Id; target.IsContainer = source.IsContainer; target.IsElement = source.IsElement; @@ -540,7 +540,7 @@ namespace Umbraco.Web.Models.Mapping target.Icon = source.Icon; target.IconFilePath = target.IconIsClass ? string.Empty - : $"{_globalSettings.Path.EnsureEndsWith("/")}images/umbraco/{source.Icon}"; + : $"{_ioHelper.BackOfficePath.EnsureEndsWith("/")}images/umbraco/{source.Icon}"; target.Id = source.Id; target.IsContainer = source.IsContainer; target.IsElement = source.IsElement; diff --git a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs index d57809c844..0bd6d54c08 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs @@ -15,13 +15,13 @@ namespace Umbraco.Web.Models.Mapping { private readonly PropertyEditorCollection _propertyEditors; private readonly ILogger _logger; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; - public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IUmbracoSettingsSection umbracoSettingsSection) + public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IContentSettings contentSettings) { _propertyEditors = propertyEditors; _logger = logger; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } private static readonly int[] SystemIds = @@ -128,9 +128,8 @@ namespace Umbraco.Web.Models.Mapping private IEnumerable MapAvailableEditors(IDataType source, MapperContext context) { - var contentSection = _umbracoSettingsSection.Content; var properties = _propertyEditors - .Where(x => !x.IsDeprecated || contentSection.ShowDeprecatedPropertyEditors || source.EditorAlias == x.Alias) + .Where(x => !x.IsDeprecated || _contentSettings.ShowDeprecatedPropertyEditors || source.EditorAlias == x.Alias) .OrderBy(x => x.Name); return context.MapEnumerable(properties); } diff --git a/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs index f2faaf275d..ba7b5cddf2 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs @@ -175,6 +175,12 @@ namespace Umbraco.Web.Models.Mapping target.Name = source.Values.ContainsKey(UmbracoExamineFieldNames.NodeNameFieldName) ? source.Values[UmbracoExamineFieldNames.NodeNameFieldName] : "[no name]"; + var culture = context.GetCulture(); + if(culture.IsNullOrWhiteSpace() == false) + { + target.Name = source.Values.ContainsKey($"nodeName_{culture}") ? source.Values[$"nodeName_{culture}"] : target.Name; + } + if (source.Values.TryGetValue(UmbracoExamineFieldNames.UmbracoFileFieldName, out var umbracoFile)) { if (umbracoFile != null) diff --git a/src/Umbraco.Infrastructure/Models/MediaExtensions.cs b/src/Umbraco.Infrastructure/Models/MediaExtensions.cs index 41bcfdbc88..ffcc2c2a92 100644 --- a/src/Umbraco.Infrastructure/Models/MediaExtensions.cs +++ b/src/Umbraco.Infrastructure/Models/MediaExtensions.cs @@ -27,9 +27,9 @@ namespace Umbraco.Core.Models /// /// Gets the urls of a media item. /// - public static string[] GetUrls(this IMedia media, IContentSection contentSection, MediaUrlGeneratorCollection mediaUrlGenerators) + public static string[] GetUrls(this IMedia media, IContentSettings contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators) { - return contentSection.ImageAutoFillProperties + return contentSettings.ImageAutoFillProperties .Select(field => media.GetUrl(field.Alias, mediaUrlGenerators)) .Where(link => string.IsNullOrWhiteSpace(link) == false) .ToArray(); diff --git a/src/Umbraco.Infrastructure/Models/Property.cs b/src/Umbraco.Infrastructure/Models/Property.cs index 36efbad404..798f84cf6f 100644 --- a/src/Umbraco.Infrastructure/Models/Property.cs +++ b/src/Umbraco.Infrastructure/Models/Property.cs @@ -98,7 +98,7 @@ namespace Umbraco.Core.Models /// /// Represents a property value. /// - public class PropertyValue : IPropertyValue + public class PropertyValue : IPropertyValue, IDeepCloneable, IEquatable { // TODO: Either we allow change tracking at this class level, or we add some special change tracking collections to the Property // class to deal with change tracking which variants have changed @@ -143,6 +143,32 @@ namespace Umbraco.Core.Models /// public IPropertyValue Clone() => new PropertyValue { _culture = _culture, _segment = _segment, PublishedValue = PublishedValue, EditedValue = EditedValue }; + + public object DeepClone() => Clone(); + + public override bool Equals(object obj) + { + return Equals(obj as PropertyValue); + } + + public bool Equals(PropertyValue other) + { + return other != null && + _culture == other._culture && + _segment == other._segment && + EqualityComparer.Default.Equals(EditedValue, other.EditedValue) && + EqualityComparer.Default.Equals(PublishedValue, other.PublishedValue); + } + + public override int GetHashCode() + { + var hashCode = 1885328050; + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(_culture); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(_segment); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(EditedValue); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(PublishedValue); + return hashCode; + } } private static readonly DelegateEqualityComparer PropertyValueComparer = new DelegateEqualityComparer( diff --git a/src/Umbraco.Infrastructure/Models/PropertyType.cs b/src/Umbraco.Infrastructure/Models/PropertyType.cs index a7ac63f70f..8b15fdfac4 100644 --- a/src/Umbraco.Infrastructure/Models/PropertyType.cs +++ b/src/Umbraco.Infrastructure/Models/PropertyType.cs @@ -168,6 +168,7 @@ namespace Umbraco.Core.Models /// [DataMember] + [DoNotClone] public Lazy PropertyGroupId { get => _propertyGroupId; diff --git a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs index 23ef0bfda5..5806bb90ec 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs @@ -1,9 +1,9 @@ using System.Data.Common; -using StackExchange.Profiling.Internal; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence { + public interface IDbProviderFactoryCreator { DbProviderFactory CreateFactory(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs index c3f9f03ec0..3d006914a2 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs @@ -653,10 +653,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var entity = new MediaEntitySlim(); BuildContentEntity(entity, dto); - if (dto is MediaEntityDto contentDto) + // fill in the media info + if (dto is MediaEntityDto mediaEntityDto) { - // fill in the media info - entity.MediaPath = contentDto.MediaPath; + entity.MediaPath = mediaEntityDto.MediaPath; + } + else if (dto is GenericContentEntityDto genericContentEntityDto) + { + entity.MediaPath = genericContentEntityDto.MediaPath; } return entity; diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs new file mode 100644 index 0000000000..9c2c6273c2 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs @@ -0,0 +1,55 @@ +using System; +using System.Data.Common; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence +{ + public class SqlServerDbProviderFactoryCreator : IDbProviderFactoryCreator + { + private readonly string _defaultProviderName; + private readonly Func _getFactory; + + public SqlServerDbProviderFactoryCreator(string defaultProviderName, Func getFactory) + { + _defaultProviderName = defaultProviderName; + _getFactory = getFactory; + } + + public DbProviderFactory CreateFactory() => CreateFactory(_defaultProviderName); + + public DbProviderFactory CreateFactory(string providerName) + { + if (string.IsNullOrEmpty(providerName)) return null; + return _getFactory(providerName); + } + + // gets the sql syntax provider that corresponds, from attribute + public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName) + { + return providerName switch + { + Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), + Constants.DbProviderNames.SqlServer => new SqlServerSyntaxProvider(), + _ => throw new InvalidOperationException($"Unknown provider name \"{providerName}\""), + }; + } + + public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName) + { + switch (providerName) + { + case Constants.DbProviderNames.SqlCe: + throw new NotSupportedException("SqlCe is not supported"); + case Constants.DbProviderNames.SqlServer: + return new SqlServerBulkSqlInsertProvider(); + default: + return new BasicBulkSqlInsertProvider(); + } + } + + public void CreateDatabase() + { + throw new NotSupportedException("Embedded databases are not supported"); + } + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 9474e02d38..a93c8db409 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -27,8 +27,9 @@ namespace Umbraco.Core.Persistence // TODO: this class needs not be disposable! internal class UmbracoDatabaseFactory : DisposableObjectSlim, IUmbracoDatabaseFactory { - private readonly Configs _configs; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; + private readonly IGlobalSettings _globalSettings; + private readonly IConnectionStrings _connectionStrings; private readonly Lazy _mappers; private readonly ILogger _logger; @@ -71,27 +72,28 @@ namespace Umbraco.Core.Persistence /// Initializes a new instance of the . /// /// Used by core runtime. - public UmbracoDatabaseFactory(ILogger logger, Lazy mappers, Configs configs, IDbProviderFactoryCreator dbProviderFactoryCreator) - : this(Constants.System.UmbracoConnectionName, logger, mappers, configs, dbProviderFactoryCreator) + public UmbracoDatabaseFactory(ILogger logger, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, Lazy mappers,IDbProviderFactoryCreator dbProviderFactoryCreator) + : this(Constants.System.UmbracoConnectionName, globalSettings, connectionStrings, logger, mappers, dbProviderFactoryCreator) { - _configs = configs; + } /// /// Initializes a new instance of the . /// /// Used by the other ctor and in tests. - public UmbracoDatabaseFactory(string connectionStringName, ILogger logger, Lazy mappers, Configs configs, IDbProviderFactoryCreator dbProviderFactoryCreator) + public UmbracoDatabaseFactory(string connectionStringName, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, ILogger logger, Lazy mappers, IDbProviderFactoryCreator dbProviderFactoryCreator) { if (connectionStringName == null) throw new ArgumentNullException(nameof(connectionStringName)); if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(connectionStringName)); + _globalSettings = globalSettings; + _connectionStrings = connectionStrings; _mappers = mappers ?? throw new ArgumentNullException(nameof(mappers)); - _configs = configs; _dbProviderFactoryCreator = dbProviderFactoryCreator ?? throw new ArgumentNullException(nameof(dbProviderFactoryCreator)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - var settings = configs.ConnectionStrings()[connectionStringName]; + var settings = connectionStrings[connectionStringName]; if (settings == null) { @@ -161,7 +163,7 @@ namespace Umbraco.Core.Persistence { // replace NPoco database type by a more efficient one - var setting = _configs.Global().DatabaseFactoryServerVersion; + var setting = _globalSettings.DatabaseFactoryServerVersion; var fromSettings = false; if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.") diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs index afdcd65ad1..95bc898ea6 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs @@ -119,7 +119,7 @@ namespace Umbraco.Core.PropertyEditors /// Technically, it could be cached by datatype but let's keep things /// simple enough for now. /// - public IDataValueEditor GetValueEditor(object configuration) + public virtual IDataValueEditor GetValueEditor(object configuration) { // if an explicit value editor has been set (by the manifest parser) // then return it, and ignore the configuration, which is going to be diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index 8c820c497c..698fcb10b3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -22,23 +22,21 @@ namespace Umbraco.Web.PropertyEditors public class FileUploadPropertyEditor : DataEditor, IMediaUrlGenerator { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSection _contentSection; + private readonly IContentSettings _contentSettings; private readonly UploadAutoFillProperties _uploadAutoFillProperties; private readonly IDataTypeService _dataTypeService; private readonly ILocalizationService _localizationService; private readonly ILocalizedTextService _localizedTextService; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; - public FileUploadPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSection contentSection, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection) + public FileUploadPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _contentSection = contentSection; + _contentSettings = contentSettings; _dataTypeService = dataTypeService; _localizationService = localizationService; _localizedTextService = localizedTextService; - _uploadAutoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, contentSection); - _umbracoSettingsSection = umbracoSettingsSection; + _uploadAutoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, contentSettings); } /// @@ -47,8 +45,8 @@ namespace Umbraco.Web.PropertyEditors /// The corresponding property value editor. protected override IDataValueEditor CreateValueEditor() { - var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, _umbracoSettingsSection); - editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, _umbracoSettingsSection)); + var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, _contentSettings); + editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, _contentSettings)); return editor; } @@ -179,7 +177,7 @@ namespace Umbraco.Web.PropertyEditors foreach (var property in properties) { - var autoFillConfig = _contentSection.GetConfig(property.Alias); + var autoFillConfig = _contentSettings.GetConfig(property.Alias); if (autoFillConfig == null) continue; foreach (var pvalue in property.Values) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index 97b5ef20f5..e45896551c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -16,13 +16,13 @@ namespace Umbraco.Web.PropertyEditors internal class FileUploadPropertyValueEditor : DataValueEditor { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; - public FileUploadPropertyValueEditor(DataEditorAttribute attribute, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection) + public FileUploadPropertyValueEditor(DataEditorAttribute attribute, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IContentSettings contentSettings) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } /// @@ -101,7 +101,7 @@ namespace Umbraco.Web.PropertyEditors { // process the file // no file, invalid file, reject change - if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _umbracoSettingsSection) == false) + if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _contentSettings) == false) return null; // get the filepath diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index 045a0fb3d2..586a120609 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -29,17 +29,16 @@ namespace Umbraco.Web.PropertyEditors public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSection _contentSettings; + private readonly IContentSettings _contentSettings; private readonly IDataTypeService _dataTypeService; private readonly ILocalizationService _localizationService; private readonly IIOHelper _ioHelper; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; private readonly UploadAutoFillProperties _autoFillProperties; /// /// Initializes a new instance of the class. /// - public ImageCropperPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSection contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService, IUmbracoSettingsSection umbracoSettingsSection) + public ImageCropperPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) : base(logger, dataTypeService, localizationService, localizedTextService,shortStringHelper) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); @@ -47,7 +46,6 @@ namespace Umbraco.Web.PropertyEditors _dataTypeService = dataTypeService; _localizationService = localizationService; _ioHelper = ioHelper; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); // TODO: inject? _autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, _contentSettings); @@ -68,7 +66,7 @@ namespace Umbraco.Web.PropertyEditors /// Creates the corresponding property value editor. /// /// The corresponding property value editor. - protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, Logger, _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _umbracoSettingsSection); + protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, Logger, _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings); /// /// Creates the corresponding preValue editor. diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 9919dda47d..1c7c8b922a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -22,14 +22,14 @@ namespace Umbraco.Web.PropertyEditors { private readonly ILogger _logger; private readonly IMediaFileSystem _mediaFileSystem; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; - public ImageCropperPropertyValueEditor(DataEditorAttribute attribute, ILogger logger, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection) + public ImageCropperPropertyValueEditor(DataEditorAttribute attribute, ILogger logger, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IContentSettings contentSettings) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } /// @@ -146,7 +146,7 @@ namespace Umbraco.Web.PropertyEditors { // process the file // no file, invalid file, reject change - if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _umbracoSettingsSection) == false) + if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _contentSettings) == false) return null; // get the filepath diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs index 7168ce194a..b833a60c2d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs @@ -16,12 +16,12 @@ namespace Umbraco.Web.PropertyEditors internal class UploadFileTypeValidator : IValueValidator { private readonly ILocalizedTextService _localizedTextService; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; - public UploadFileTypeValidator(ILocalizedTextService localizedTextService, IUmbracoSettingsSection umbracoSettingsSection) + public UploadFileTypeValidator(ILocalizedTextService localizedTextService, IContentSettings contentSettings) { _localizedTextService = localizedTextService; - _umbracoSettingsSection = umbracoSettingsSection; + _contentSettings = contentSettings; } public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) @@ -46,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors foreach (string filename in fileNames) { - if (IsValidFileExtension(filename, _umbracoSettingsSection) == false) + if (IsValidFileExtension(filename, _contentSettings) == false) { //we only store a single value for this editor so the 'member' or 'field' // we'll associate this error with will simply be called 'value' @@ -55,11 +55,11 @@ namespace Umbraco.Web.PropertyEditors } } - internal static bool IsValidFileExtension(string fileName, IUmbracoSettingsSection umbracoSettingsSection) + internal static bool IsValidFileExtension(string fileName, IContentSettings contentSettings) { if (fileName.IndexOf('.') <= 0) return false; var extension = new FileInfo(fileName).Extension.TrimStart("."); - return umbracoSettingsSection.Content.IsFileAllowedForUpload(extension); + return contentSettings.IsFileAllowedForUpload(extension); } } } diff --git a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs index f8e21982e0..ac8d0980c4 100644 --- a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs +++ b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs @@ -16,14 +16,14 @@ namespace Umbraco.Web.Routing { private readonly ILogger _logger; private readonly IEntityService _entityService; - private readonly IContentSection _contentConfigSection; + private readonly IContentSettings _contentConfigSettings; private readonly IExamineManager _examineManager; - public ContentFinderByConfigured404(ILogger logger, IEntityService entityService, IContentSection contentConfigSection, IExamineManager examineManager) + public ContentFinderByConfigured404(ILogger logger, IEntityService entityService, IContentSettings contentConfigSettings, IExamineManager examineManager) { _logger = logger; _entityService = entityService; - _contentConfigSection = contentConfigSection; + _contentConfigSettings = contentConfigSettings; _examineManager = examineManager; } @@ -63,7 +63,7 @@ namespace Umbraco.Web.Routing } var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId( - _contentConfigSection.Error404Collection.ToArray(), + _contentConfigSettings.Error404Collection.ToArray(), _entityService, new PublishedContentQuery(frequest.UmbracoContext.PublishedSnapshot, frequest.UmbracoContext.VariationContextAccessor, _examineManager), errorCulture); diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs index 0eae54bf7d..f9256b3692 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs @@ -24,14 +24,15 @@ namespace Umbraco.Web.Routing { private const string _eventStateKey = "Umbraco.Web.Redirects.RedirectTrackingEventHandler"; - private readonly IUmbracoSettingsSection _umbracoSettings; + + private readonly IWebRoutingSettings _webRoutingSettings; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly IRedirectUrlService _redirectUrlService; private readonly IVariationContextAccessor _variationContextAccessor; - public RedirectTrackingComponent(IUmbracoSettingsSection umbracoSettings, IPublishedSnapshotAccessor publishedSnapshotAccessor, IRedirectUrlService redirectUrlService, IVariationContextAccessor variationContextAccessor) + public RedirectTrackingComponent(IWebRoutingSettings webRoutingSettings, IPublishedSnapshotAccessor publishedSnapshotAccessor, IRedirectUrlService redirectUrlService, IVariationContextAccessor variationContextAccessor) { - _umbracoSettings = umbracoSettings; + _webRoutingSettings = webRoutingSettings; _publishedSnapshotAccessor = publishedSnapshotAccessor; _redirectUrlService = redirectUrlService; _variationContextAccessor = variationContextAccessor; @@ -40,7 +41,7 @@ namespace Umbraco.Web.Routing public void Initialize() { // don't let the event handlers kick in if Redirect Tracking is turned off in the config - if (_umbracoSettings.WebRouting.DisableRedirectUrlTracking) return; + if (_webRoutingSettings.DisableRedirectUrlTracking) return; ContentService.Publishing += ContentService_Publishing; ContentService.Published += ContentService_Published; diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs index 6ea873cab5..f1f96a9f4a 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -1,12 +1,15 @@ using System; +using System.IO; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Grid; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Dashboards; using Umbraco.Core.Hosting; using Umbraco.Core.Dictionary; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Migrations; @@ -42,10 +45,9 @@ namespace Umbraco.Core.Runtime public override void Compose(Composition composition) { base.Compose(composition); - + // composers composition - .ComposeConfiguration() .ComposeRepositories() .ComposeServices() .ComposeCoreMappingProfiles() @@ -119,10 +121,11 @@ namespace Umbraco.Core.Runtime // project composition.RegisterUnique(factory => new DatabaseServerMessenger( - factory.GetInstance(), + factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), + factory.GetInstance(), true, new DatabaseServerMessengerOptions(), factory.GetInstance(), factory.GetInstance() @@ -140,7 +143,7 @@ namespace Umbraco.Core.Runtime composition.RegisterUnique(); composition.RegisterUnique(factory - => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance()))); + => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance()))); composition.UrlSegmentProviders() .Append(); @@ -172,6 +175,12 @@ namespace Umbraco.Core.Runtime // will be injected in controllers when needed to invoke rest endpoints on Our composition.RegisterUnique(); composition.RegisterUnique(); + + // Grid config is not a real config file as we know them + composition.RegisterUnique(); + + // Config manipulator + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 8e4401495d..139e9e9b67 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -11,7 +11,6 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.Sync; namespace Umbraco.Core.Runtime { @@ -24,9 +23,10 @@ namespace Umbraco.Core.Runtime { private ComponentCollection _components; private IFactory _factory; - private RuntimeState _state; + private readonly RuntimeState _state; private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker; - + private readonly IGlobalSettings _globalSettings; + private readonly IConnectionStrings _connectionStrings; public CoreRuntime( Configs configs, @@ -38,7 +38,8 @@ namespace Umbraco.Core.Runtime IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom) + IMainDom mainDom, + ITypeFinder typeFinder) { IOHelper = ioHelper; Configs = configs; @@ -52,15 +53,16 @@ namespace Umbraco.Core.Runtime Logger = logger; MainDom = mainDom; + TypeFinder = typeFinder; + + _globalSettings = Configs.Global(); + _connectionStrings = configs.ConnectionStrings(); + // runtime state // beware! must use '() => _factory.GetInstance()' and NOT '_factory.GetInstance' // as the second one captures the current value (null) and therefore fails - _state = new RuntimeState(Logger, - Configs.Settings(), Configs.Global(), - new Lazy(() => mainDom), - new Lazy(() => _factory.GetInstance()), - UmbracoVersion,HostingEnvironment, BackOfficeInfo) + _state = new RuntimeState(Logger, Configs.Global(), UmbracoVersion, BackOfficeInfo) { Level = RuntimeLevel.Boot }; @@ -72,13 +74,13 @@ namespace Umbraco.Core.Runtime protected ILogger Logger { get; } protected IBackOfficeInfo BackOfficeInfo { get; } + public IDbProviderFactoryCreator DbProviderFactoryCreator { get; } - //public IBulkSqlInsertProvider BulkSqlInsertProvider { get; } /// /// Gets the profiler. /// - protected IProfiler Profiler { get; set; } + protected IProfiler Profiler { get; } /// /// Gets the profiling logger. @@ -88,7 +90,7 @@ namespace Umbraco.Core.Runtime /// /// Gets the /// - protected ITypeFinder TypeFinder { get; private set; } + protected ITypeFinder TypeFinder { get; } /// /// Gets the @@ -101,19 +103,16 @@ namespace Umbraco.Core.Runtime /// public IRuntimeState State => _state; - public IMainDom MainDom { get; private set; } + public IMainDom MainDom { get; } /// - public virtual IFactory Boot(IRegister register) + public virtual IFactory Configure(IRegister register) { + if (register is null) throw new ArgumentNullException(nameof(register)); + // create and register the essential services // ie the bare minimum required to boot - - TypeFinder = GetTypeFinder(); - if (TypeFinder == null) - throw new InvalidOperationException($"The object returned from {nameof(GetTypeFinder)} cannot be null"); - // the boot loader boots using a container scope, so anything that is PerScope will // be disposed after the boot loader has booted, and anything else will remain. // note that this REQUIRES that perWebRequestScope has NOT been enabled yet, else @@ -135,25 +134,24 @@ namespace Umbraco.Core.Runtime // application environment ConfigureUnhandledException(); - ConfigureApplicationRootPath(); - - Boot(register, timer); + return _factory = Configure(register, timer); } - - return _factory; } /// - /// Boots the runtime within a timer. + /// Configure the runtime within a timer. /// - protected virtual IFactory Boot(IRegister register, DisposableTimer timer) + private IFactory Configure(IRegister register, DisposableTimer timer) { + if (register is null) throw new ArgumentNullException(nameof(register)); + if (timer is null) throw new ArgumentNullException(nameof(timer)); + Composition composition = null; + IFactory factory = null; try { - // throws if not full-trust - _umbracoBootPermissionChecker.ThrowIfNotPermissions(); + // run handlers RuntimeOptions.DoRuntimeBoot(ProfilingLogger); @@ -167,31 +165,12 @@ namespace Umbraco.Core.Runtime // type finder/loader var typeLoader = new TypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, new DirectoryInfo(HostingEnvironment.LocalTempPath), ProfilingLogger); - // runtime state - // beware! must use '() => _factory.GetInstance()' and NOT '_factory.GetInstance' - // as the second one captures the current value (null) and therefore fails - _state = new RuntimeState(Logger, - Configs.Settings(), Configs.Global(), - new Lazy(() => _factory.GetInstance()), - new Lazy(() => _factory.GetInstance()), - UmbracoVersion, HostingEnvironment, BackOfficeInfo) - { - Level = RuntimeLevel.Boot - }; - // create the composition composition = new Composition(register, typeLoader, ProfilingLogger, _state, Configs, IOHelper, appCaches); - composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator); + composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator, HostingEnvironment, BackOfficeInfo); - // run handlers - RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory); - - // register runtime-level services - // there should be none, really - this is here "just in case" - Compose(composition); - - // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate - AcquireMainDom(MainDom); + // register ourselves (TODO: Should we put this in RegisterEssentials?) + composition.Register(_ => this, Lifetime.Singleton); // determine our runtime level DetermineRuntimeLevel(databaseFactory, ProfilingLogger); @@ -209,13 +188,7 @@ namespace Umbraco.Core.Runtime composers.Compose(); // create the factory - _factory = composition.CreateFactory(); - - // create & initialize the components - _components = _factory.GetInstance(); - _components.Initialize(); - - + factory = composition.CreateFactory(); } catch (Exception e) { @@ -232,11 +205,11 @@ namespace Umbraco.Core.Runtime // if something goes wrong above, we may end up with no factory // meaning nothing can get the runtime state, etc - so let's try // to make sure we have a factory - if (_factory == null) + if (factory == null) { try { - _factory = composition?.CreateFactory(); + factory = composition?.CreateFactory(); } catch { /* yea */ } } @@ -250,12 +223,29 @@ namespace Umbraco.Core.Runtime // throw a BootFailedException for every requests. } - return _factory; + return factory; } - private IUmbracoVersion GetUmbracoVersion(IGlobalSettings globalSettings) + public void Start() { - return new UmbracoVersion(globalSettings); + // throws if not full-trust + _umbracoBootPermissionChecker.ThrowIfNotPermissions(); + + ConfigureApplicationRootPath(); + + // run handlers + RuntimeOptions.DoRuntimeEssentials(_factory); + + var hostingEnvironmentLifetime = _factory.TryGetInstance(); + if (hostingEnvironmentLifetime == null) + 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(Start)}"); + + // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate + AcquireMainDom(MainDom, _factory.GetInstance()); + + // create & initialize the components + _components = _factory.GetInstance(); + _components.Initialize(); } protected virtual void ConfigureUnhandledException() @@ -282,13 +272,13 @@ namespace Umbraco.Core.Runtime IOHelper.SetRootDirectory(path); } - private bool AcquireMainDom(IMainDom mainDom) + private bool AcquireMainDom(IMainDom mainDom, IApplicationShutdownRegistry applicationShutdownRegistry) { using (var timer = ProfilingLogger.DebugDuration("Acquiring MainDom.", "Acquired.")) { try { - return mainDom.IsMainDom; + return mainDom.Acquire(applicationShutdownRegistry); } catch { @@ -347,12 +337,6 @@ namespace Umbraco.Core.Runtime _components?.Terminate(); } - /// - /// Composes the runtime. - /// - public virtual void Compose(Composition composition) - { - } #region Getters @@ -364,14 +348,6 @@ namespace Umbraco.Core.Runtime protected virtual IEnumerable GetComposerTypes(TypeLoader typeLoader) => typeLoader.GetTypes(); - /// - /// Gets a - /// - /// - protected virtual ITypeFinder GetTypeFinder() - => new TypeFinder(Logger); - - /// /// Gets the application caches. /// @@ -382,9 +358,9 @@ namespace Umbraco.Core.Runtime // is overridden by the web runtime return new AppCaches( - new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)), + new DeepCloneAppCache(new ObjectCacheAppCache()), NoAppCache.Instance, - new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)))); + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } // by default, returns null, meaning that Umbraco should auto-detect the application root path. @@ -397,9 +373,10 @@ namespace Umbraco.Core.Runtime /// /// This is strictly internal, for tests only. protected internal virtual IUmbracoDatabaseFactory GetDatabaseFactory() - => new UmbracoDatabaseFactory(Logger, new Lazy(() => _factory.GetInstance()), Configs, DbProviderFactoryCreator); + => new UmbracoDatabaseFactory(Logger, _globalSettings, _connectionStrings, new Lazy(() => _factory.GetInstance()), DbProviderFactoryCreator); #endregion + } } diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index d8a66b4198..ec9a7d21db 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -28,16 +28,18 @@ namespace Umbraco.Core.Runtime private bool _hasError; private object _locker = new object(); - public SqlMainDomLock(ILogger logger, Configs configs, IDbProviderFactoryCreator dbProviderFactoryCreator) + public SqlMainDomLock(ILogger logger, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, IDbProviderFactoryCreator dbProviderFactoryCreator) { // unique id for our appdomain, this is more unique than the appdomain id which is just an INT counter to its safer _lockId = Guid.NewGuid().ToString(); _logger = logger; _dbFactory = new UmbracoDatabaseFactory( Constants.System.UmbracoConnectionName, + globalSettings, + connectionStrings, _logger, new Lazy(() => new MapperCollection(Enumerable.Empty())), - configs, dbProviderFactoryCreator + dbProviderFactoryCreator ); } diff --git a/src/Umbraco.Web/Runtime/WebRuntime.cs b/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs similarity index 67% rename from src/Umbraco.Web/Runtime/WebRuntime.cs rename to src/Umbraco.Infrastructure/Runtime/WebRuntime.cs index 582f35db70..fc2a019023 100644 --- a/src/Umbraco.Web/Runtime/WebRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs @@ -1,6 +1,4 @@ -using System.Web; -using Umbraco.Configuration; -using Umbraco.Core; +using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; @@ -9,9 +7,6 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Runtime; -using Umbraco.Web.Composing; -using Umbraco.Web.Logging; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Web.Runtime { @@ -21,7 +16,7 @@ namespace Umbraco.Web.Runtime /// On top of CoreRuntime, handles all of the web-related runtime aspects of Umbraco. public class WebRuntime : CoreRuntime { - private BuildManagerTypeFinder _typeFinder; + private readonly IRequestCache _requestCache; /// /// Initializes a new instance of the class. @@ -35,31 +30,17 @@ namespace Umbraco.Web.Runtime IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom): - base(configs, umbracoVersion, ioHelper, logger, profiler ,new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom) + IMainDom mainDom, + ITypeFinder typeFinder, + IRequestCache requestCache, + IUmbracoBootPermissionChecker umbracoBootPermissionChecker): + base(configs, umbracoVersion, ioHelper, logger, profiler ,umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder) { - - Profiler = GetWebProfiler(); - } - - private IProfiler GetWebProfiler() - { - // create and start asap to profile boot - if (!State.Debug) - { - // should let it be null, that's how MiniProfiler is meant to work, - // but our own IProfiler expects an instance so let's get one - return new VoidProfiler(); - } - - var webProfiler = new WebProfiler(); - webProfiler.Start(); - - return webProfiler; + _requestCache = requestCache; } /// - public override IFactory Boot(IRegister register) + public override IFactory Configure(IRegister register) { var profilingLogger = new ProfilingLogger(Logger, Profiler); @@ -76,7 +57,7 @@ namespace Umbraco.Web.Runtime NetworkHelper.MachineName); Logger.Debug("Runtime: {Runtime}", GetType().FullName); - var factory = Current.Factory = base.Boot(register); + var factory = base.Configure(register); // now (and only now) is the time to switch over to perWebRequest scopes. // up until that point we may not have a request, and scoped services would @@ -92,18 +73,16 @@ namespace Umbraco.Web.Runtime #region Getters - protected override ITypeFinder GetTypeFinder() => _typeFinder ?? (_typeFinder = new BuildManagerTypeFinder(IOHelper, HostingEnvironment, Logger, new BuildManagerTypeFinder.TypeFinderConfig(new TypeFinderSettings()))); - protected override AppCaches GetAppCaches() => new AppCaches( // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) - new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)), + new DeepCloneAppCache(new ObjectCacheAppCache()), // we need request based cache when running in web-based context - new HttpRequestAppCache(() => HttpContext.Current?.Items, TypeFinder), + _requestCache, new IsolatedCaches(type => // we need to have the dep clone runtime cache provider to ensure // all entities are cached properly (cloned in and cloned out) - new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)))); + new DeepCloneAppCache(new ObjectCacheAppCache()))); #endregion } diff --git a/src/Umbraco.Infrastructure/RuntimeOptions.cs b/src/Umbraco.Infrastructure/RuntimeOptions.cs index 23abd474a4..562a7e3c5c 100644 --- a/src/Umbraco.Infrastructure/RuntimeOptions.cs +++ b/src/Umbraco.Infrastructure/RuntimeOptions.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core public static class RuntimeOptions { private static List> _onBoot; - private static List> _onEssentials; + private static List> _onEssentials; /// /// Executes the RuntimeBoot handlers. @@ -33,13 +33,13 @@ namespace Umbraco.Core /// /// Executes the RuntimeEssentials handlers. /// - internal static void DoRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) + internal static void DoRuntimeEssentials(IFactory factory) { if (_onEssentials== null) return; foreach (var action in _onEssentials) - action(composition, appCaches, typeLoader, databaseFactory); + action(factory); } /// @@ -64,10 +64,10 @@ namespace Umbraco.Core /// essential things (AppCaches, a TypeLoader, and a database factory) but /// before anything else. /// - public static void OnRuntimeEssentials(Action action) + public static void OnRuntimeEssentials(Action action) { if (_onEssentials == null) - _onEssentials = new List>(); + _onEssentials = new List>(); _onEssentials.Add(action); } } diff --git a/src/Umbraco.Infrastructure/RuntimeState.cs b/src/Umbraco.Infrastructure/RuntimeState.cs index b6ffecbb0d..9e5cf96906 100644 --- a/src/Umbraco.Infrastructure/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/RuntimeState.cs @@ -20,50 +20,24 @@ namespace Umbraco.Core public class RuntimeState : IRuntimeState { private readonly ILogger _logger; - private readonly IUmbracoSettingsSection _settings; private readonly IGlobalSettings _globalSettings; private readonly ConcurrentHashSet _applicationUrls = new ConcurrentHashSet(); - private readonly Lazy _mainDom; - private readonly Lazy _serverRegistrar; private readonly IUmbracoVersion _umbracoVersion; - private readonly IHostingEnvironment _hostingEnvironment; private readonly IBackOfficeInfo _backOfficeInfo; /// /// Initializes a new instance of the class. /// - public RuntimeState(ILogger logger, IUmbracoSettingsSection settings, IGlobalSettings globalSettings, - Lazy mainDom, Lazy serverRegistrar, IUmbracoVersion umbracoVersion, - IHostingEnvironment hostingEnvironment, + public RuntimeState(ILogger logger, IGlobalSettings globalSettings, + IUmbracoVersion umbracoVersion, IBackOfficeInfo backOfficeInfo) { _logger = logger; - _settings = settings; _globalSettings = globalSettings; - _mainDom = mainDom; - _serverRegistrar = serverRegistrar; _umbracoVersion = umbracoVersion; - _hostingEnvironment = hostingEnvironment; _backOfficeInfo = backOfficeInfo; - - ApplicationVirtualPath = _hostingEnvironment.ApplicationVirtualPath; } - /// - /// Gets the server registrar. - /// - /// - /// This is NOT exposed in the interface. - /// - private IServerRegistrar ServerRegistrar => _serverRegistrar.Value; - - /// - /// Gets the application MainDom. - /// - /// - /// This is NOT exposed in the interface as MainDom is internal. - /// - public IMainDom MainDom => _mainDom.Value; /// public Version Version => _umbracoVersion.Current; @@ -74,26 +48,14 @@ namespace Umbraco.Core /// public SemVersion SemanticVersion => _umbracoVersion.SemanticVersion; - /// - public bool Debug => _hostingEnvironment.IsDebugMode; - - /// - public bool IsMainDom => MainDom.IsMainDom; - - /// - public ServerRole ServerRole => ServerRegistrar.GetCurrentServerRole(); - /// public Uri ApplicationUrl { get; private set; } /// - public string ApplicationVirtualPath { get; } + public string CurrentMigrationState { get; private set; } /// - public string CurrentMigrationState { get; internal set; } - - /// - public string FinalMigrationState { get; internal set; } + public string FinalMigrationState { get; private set; } /// public RuntimeLevel Level { get; internal set; } = RuntimeLevel.Unknown; @@ -255,7 +217,7 @@ namespace Umbraco.Core Reason = RuntimeLevelReason.UpgradeMigrations; } - protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) + private bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) { var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion, _globalSettings)); var stateValueKey = upgrader.StateValueKey; diff --git a/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs index 0b5b81319f..2cda289591 100644 --- a/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs +++ b/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs @@ -81,7 +81,7 @@ namespace Umbraco.Web.Scheduling private readonly string _logPrefix; private readonly BackgroundTaskRunnerOptions _options; private readonly ILogger _logger; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationShutdownRegistry _hostingEnvironment; private readonly object _locker = new object(); private readonly BufferBlock _tasks = new BufferBlock(new DataflowBlockOptions()); @@ -105,7 +105,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The hosting environment /// An optional main domain hook. - public BackgroundTaskRunner(ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null) + public BackgroundTaskRunner(ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null) : this(typeof(T).FullName, new BackgroundTaskRunnerOptions(), logger, hostingEnvironment, hook) { } @@ -116,7 +116,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The hosting environment /// An optional main domain hook. - public BackgroundTaskRunner(string name, ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null) + public BackgroundTaskRunner(string name, ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null) : this(name, new BackgroundTaskRunnerOptions(), logger, hostingEnvironment, hook) { } @@ -127,7 +127,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The hosting environment /// An optional main domain hook. - public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null) + public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null) : this(typeof(T).FullName, options, logger, hostingEnvironment, hook) { } @@ -139,7 +139,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The hosting environment /// An optional main domain hook. - public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger, IHostingEnvironment hostingEnvironment, MainDomHook hook = null) + public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger, IApplicationShutdownRegistry hostingEnvironment, MainDomHook hook = null) { _options = options ?? throw new ArgumentNullException(nameof(options)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); diff --git a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs index 00bbba8bb8..e7692b851a 100644 --- a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs @@ -11,22 +11,27 @@ namespace Umbraco.Web.Scheduling { public class HealthCheckNotifier : RecurringTaskBase { - private readonly IRuntimeState _runtimeState; + private readonly IMainDom _mainDom; private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IProfilingLogger _logger; - private readonly IHealthChecks _healthChecksConfig; + private readonly IHealthChecksSettings _healthChecksSettingsConfig; + private readonly IServerRegistrar _serverRegistrar; + private readonly IRuntimeState _runtimeState; public HealthCheckNotifier(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, - IRuntimeState runtimeState, IProfilingLogger logger, IHealthChecks healthChecksConfig) + IMainDom mainDom, IProfilingLogger logger, IHealthChecksSettings healthChecksSettingsConfig, IServerRegistrar serverRegistrar, + IRuntimeState runtimeState) : base(runner, delayMilliseconds, periodMilliseconds) { _healthChecks = healthChecks; _notifications = notifications; - _runtimeState = runtimeState; + _mainDom = mainDom; _logger = logger; - _healthChecksConfig = healthChecksConfig; + _healthChecksSettingsConfig = healthChecksSettingsConfig; + _serverRegistrar = serverRegistrar; + _runtimeState = runtimeState; } public override async Task PerformRunAsync(CancellationToken token) @@ -34,7 +39,7 @@ namespace Umbraco.Web.Scheduling if (_runtimeState.Level != RuntimeLevel.Run) return true; // repeat... - switch (_runtimeState.ServerRole) + switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: _logger.Debug("Does not run on replica servers."); @@ -45,7 +50,7 @@ namespace Umbraco.Web.Scheduling } // ensure we do not run if not main domain, but do NOT lock it - if (_runtimeState.IsMainDom == false) + if (_mainDom.IsMainDom == false) { _logger.Debug("Does not run if not MainDom."); return false; // do NOT repeat, going down @@ -53,7 +58,7 @@ namespace Umbraco.Web.Scheduling using (_logger.DebugDuration("Health checks executing", "Health checks complete")) { - var healthCheckConfig = _healthChecksConfig; + var healthCheckConfig = _healthChecksSettingsConfig; // Don't notify for any checks that are disabled, nor for any disabled // just for notifications diff --git a/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs b/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs index e624c4e591..aaf09dbe8f 100644 --- a/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs @@ -11,17 +11,19 @@ namespace Umbraco.Web.Scheduling public class LogScrubber : RecurringTaskBase { - private readonly IRuntimeState _runtime; + private readonly IMainDom _mainDom; + private readonly IServerRegistrar _serverRegistrar; private readonly IAuditService _auditService; - private readonly IUmbracoSettingsSection _settings; + private readonly ILoggingSettings _settings; private readonly IProfilingLogger _logger; private readonly IScopeProvider _scopeProvider; public LogScrubber(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, - IRuntimeState runtime, IAuditService auditService, IUmbracoSettingsSection settings, IScopeProvider scopeProvider, IProfilingLogger logger) + IMainDom mainDom, IServerRegistrar serverRegistrar, IAuditService auditService, ILoggingSettings settings, IScopeProvider scopeProvider, IProfilingLogger logger) : base(runner, delayMilliseconds, periodMilliseconds) { - _runtime = runtime; + _mainDom = mainDom; + _serverRegistrar = serverRegistrar; _auditService = auditService; _settings = settings; _scopeProvider = scopeProvider; @@ -29,13 +31,13 @@ namespace Umbraco.Web.Scheduling } // maximum age, in minutes - private int GetLogScrubbingMaximumAge(IUmbracoSettingsSection settings) + private int GetLogScrubbingMaximumAge(ILoggingSettings settings) { var maximumAge = 24 * 60; // 24 hours, in minutes try { - if (settings.Logging.MaxLogAge > -1) - maximumAge = settings.Logging.MaxLogAge; + if (settings.MaxLogAge > -1) + maximumAge = settings.MaxLogAge; } catch (Exception ex) { @@ -45,7 +47,7 @@ namespace Umbraco.Web.Scheduling } - public static int GetLogScrubbingInterval(IUmbracoSettingsSection settings, ILogger logger) + public static int GetLogScrubbingInterval() { const int interval = 4 * 60 * 60 * 1000; // 4 hours, in milliseconds return interval; @@ -53,7 +55,7 @@ namespace Umbraco.Web.Scheduling public override bool PerformRun() { - switch (_runtime.ServerRole) + switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: _logger.Debug("Does not run on replica servers."); @@ -64,7 +66,7 @@ namespace Umbraco.Web.Scheduling } // ensure we do not run if not main domain, but do NOT lock it - if (_runtime.IsMainDom == false) + if (_mainDom.IsMainDom == false) { _logger.Debug("Does not run if not MainDom."); return false; // do NOT repeat, going down diff --git a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs index b074704033..fea16999fd 100644 --- a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs @@ -10,16 +10,20 @@ namespace Umbraco.Web.Scheduling public class ScheduledPublishing : RecurringTaskBase { private readonly IRuntimeState _runtime; + private readonly IMainDom _mainDom; + private readonly IServerRegistrar _serverRegistrar; private readonly IContentService _contentService; private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly ILogger _logger; private readonly IServerMessenger _serverMessenger; public ScheduledPublishing(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, - IRuntimeState runtime, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger) + IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger) : base(runner, delayMilliseconds, periodMilliseconds) { _runtime = runtime; + _mainDom = mainDom; + _serverRegistrar = serverRegistrar; _contentService = contentService; _umbracoContextFactory = umbracoContextFactory; _logger = logger; @@ -31,7 +35,7 @@ namespace Umbraco.Web.Scheduling if (Suspendable.ScheduledPublishing.CanRun == false) return true; // repeat, later - switch (_runtime.ServerRole) + switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: _logger.Debug("Does not run on replica servers."); @@ -42,7 +46,7 @@ namespace Umbraco.Web.Scheduling } // ensure we do not run if not main domain, but do NOT lock it - if (_runtime.IsMainDom == false) + if (_mainDom.IsMainDom == false) { _logger.Debug("Does not run if not MainDom."); return false; // do NOT repeat, going down diff --git a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs index 6e5d0ee81e..30d0bc7e4a 100644 --- a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs @@ -26,23 +26,25 @@ namespace Umbraco.Web.Scheduling private const int OneHourMilliseconds = 3600000; private readonly IRuntimeState _runtime; + private readonly IMainDom _mainDom; + private readonly IServerRegistrar _serverRegistrar; private readonly IContentService _contentService; private readonly IAuditService _auditService; private readonly IProfilingLogger _logger; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationShutdownRegistry _hostingEnvironment; private readonly IScopeProvider _scopeProvider; private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IUmbracoContextFactory _umbracoContextFactory; - private readonly IHealthChecks _healthChecksConfig; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IHealthChecksSettings _healthChecksSettingsConfig; private readonly IIOHelper _ioHelper; private readonly IServerMessenger _serverMessenger; private readonly IRequestAccessor _requestAccessor; + private readonly ILoggingSettings _loggingSettings; + private readonly IKeepAliveSettings _keepAliveSettings; private BackgroundTaskRunner _keepAliveRunner; private BackgroundTaskRunner _publishingRunner; - private BackgroundTaskRunner _tasksRunner; private BackgroundTaskRunner _scrubberRunner; private BackgroundTaskRunner _fileCleanupRunner; private BackgroundTaskRunner _healthCheckRunner; @@ -51,14 +53,17 @@ namespace Umbraco.Web.Scheduling private object _locker = new object(); private IBackgroundTask[] _tasks; - public SchedulerComponent(IRuntimeState runtime, + public SchedulerComponent(IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService, IAuditService auditService, HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger, - IHostingEnvironment hostingEnvironment, IHealthChecks healthChecksConfig, - IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, IServerMessenger serverMessenger, IRequestAccessor requestAccessor) + IApplicationShutdownRegistry hostingEnvironment, IHealthChecksSettings healthChecksSettingsConfig, + IIOHelper ioHelper, IServerMessenger serverMessenger, IRequestAccessor requestAccessor, + ILoggingSettings loggingSettings, IKeepAliveSettings keepAliveSettings) { _runtime = runtime; + _mainDom = mainDom; + _serverRegistrar = serverRegistrar; _contentService = contentService; _auditService = auditService; _scopeProvider = scopeProvider; @@ -68,11 +73,12 @@ namespace Umbraco.Web.Scheduling _healthChecks = healthChecks; _notifications = notifications; - _healthChecksConfig = healthChecksConfig ?? throw new ArgumentNullException(nameof(healthChecksConfig)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _healthChecksSettingsConfig = healthChecksSettingsConfig ?? throw new ArgumentNullException(nameof(healthChecksSettingsConfig)); _ioHelper = ioHelper; _serverMessenger = serverMessenger; _requestAccessor = requestAccessor; + _loggingSettings = loggingSettings; + _keepAliveSettings = keepAliveSettings; } public void Initialize() @@ -80,7 +86,6 @@ namespace Umbraco.Web.Scheduling // backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly _keepAliveRunner = new BackgroundTaskRunner("KeepAlive", _logger, _hostingEnvironment); _publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", _logger, _hostingEnvironment); - _tasksRunner = new BackgroundTaskRunner("ScheduledTasks", _logger, _hostingEnvironment); _scrubberRunner = new BackgroundTaskRunner("LogScrubber", _logger, _hostingEnvironment); _fileCleanupRunner = new BackgroundTaskRunner("TempFileCleanup", _logger, _hostingEnvironment); _healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", _logger, _hostingEnvironment); @@ -111,20 +116,19 @@ namespace Umbraco.Web.Scheduling LazyInitializer.EnsureInitialized(ref _tasks, ref _started, ref _locker, () => { _logger.Debug("Initializing the scheduler"); - var settings = _umbracoSettingsSection; var tasks = new List(); - if (settings.KeepAlive.DisableKeepAliveTask == false) + if (_keepAliveSettings.DisableKeepAliveTask == false) { - tasks.Add(RegisterKeepAlive(settings.KeepAlive)); + tasks.Add(RegisterKeepAlive(_keepAliveSettings)); } tasks.Add(RegisterScheduledPublishing()); - tasks.Add(RegisterLogScrubber(settings)); + tasks.Add(RegisterLogScrubber(_loggingSettings)); tasks.Add(RegisterTempFileCleanup()); - var healthCheckConfig = _healthChecksConfig; + var healthCheckConfig = _healthChecksSettingsConfig; if (healthCheckConfig.NotificationSettings.Enabled) tasks.Add(RegisterHealthCheckNotifier(healthCheckConfig, _healthChecks, _notifications, _logger)); @@ -132,11 +136,11 @@ namespace Umbraco.Web.Scheduling }); } - private IBackgroundTask RegisterKeepAlive(IKeepAliveSection keepAliveSection) + private IBackgroundTask RegisterKeepAlive(IKeepAliveSettings keepAliveSettings) { // ping/keepalive // on all servers - var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _runtime, keepAliveSection, _logger); + var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _runtime, _mainDom, keepAliveSettings, _logger, _serverRegistrar); _keepAliveRunner.TryAdd(task); return task; } @@ -145,42 +149,42 @@ namespace Umbraco.Web.Scheduling { // scheduled publishing/unpublishing // install on all, will only run on non-replica servers - var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _contentService, _umbracoContextFactory, _logger, _serverMessenger); + var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _logger, _serverMessenger); _publishingRunner.TryAdd(task); return task; } - private IBackgroundTask RegisterHealthCheckNotifier(IHealthChecks healthCheckConfig, + private IBackgroundTask RegisterHealthCheckNotifier(IHealthChecksSettings healthCheckSettingsConfig, HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IProfilingLogger logger) { // If first run time not set, start with just small delay after application start int delayInMilliseconds; - if (string.IsNullOrEmpty(healthCheckConfig.NotificationSettings.FirstRunTime)) + if (string.IsNullOrEmpty(healthCheckSettingsConfig.NotificationSettings.FirstRunTime)) { delayInMilliseconds = DefaultDelayMilliseconds; } else { // Otherwise start at scheduled time - delayInMilliseconds = DateTime.Now.PeriodicMinutesFrom(healthCheckConfig.NotificationSettings.FirstRunTime) * 60 * 1000; + delayInMilliseconds = DateTime.Now.PeriodicMinutesFrom(healthCheckSettingsConfig.NotificationSettings.FirstRunTime) * 60 * 1000; if (delayInMilliseconds < DefaultDelayMilliseconds) { delayInMilliseconds = DefaultDelayMilliseconds; } } - var periodInMilliseconds = healthCheckConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000; - var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _runtime, logger, _healthChecksConfig); + var periodInMilliseconds = healthCheckSettingsConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000; + var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _mainDom, logger, _healthChecksSettingsConfig, _serverRegistrar, _runtime); _healthCheckRunner.TryAdd(task); return task; } - private IBackgroundTask RegisterLogScrubber(IUmbracoSettingsSection settings) + private IBackgroundTask RegisterLogScrubber(ILoggingSettings settings) { // log scrubbing // install on all, will only run on non-replica servers - var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(settings, _logger), _runtime, _auditService, settings, _scopeProvider, _logger); + var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _mainDom, _serverRegistrar, _auditService, settings, _scopeProvider, _logger); _scrubberRunner.TryAdd(task); return task; } @@ -192,7 +196,7 @@ namespace Umbraco.Web.Scheduling var task = new TempFileCleanup(_fileCleanupRunner, DefaultDelayMilliseconds, OneHourMilliseconds, new[] { new DirectoryInfo(_ioHelper.MapPath(Constants.SystemDirectories.TempFileUploads)) }, TimeSpan.FromDays(1), //files that are over a day old - _runtime, _logger); + _mainDom, _logger); _scrubberRunner.TryAdd(task); return task; } diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 8f7a0bf958..3b17ae876d 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Scoping internal class Scope : IScope { private readonly ScopeProvider _scopeProvider; - private readonly ICoreDebug _coreDebug; + private readonly ICoreDebugSettings _coreDebugSettings; private readonly IMediaFileSystem _mediaFileSystem; private readonly ILogger _logger; private readonly ITypeFinder _typeFinder; @@ -39,7 +39,7 @@ namespace Umbraco.Core.Scoping // initializes a new scope private Scope(ScopeProvider scopeProvider, - ICoreDebug coreDebug, + ICoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IScopeContext scopeContext, bool detachable, IsolationLevel isolationLevel = IsolationLevel.Unspecified, @@ -50,7 +50,7 @@ namespace Umbraco.Core.Scoping bool autoComplete = false) { _scopeProvider = scopeProvider; - _coreDebug = coreDebug; + _coreDebugSettings = coreDebugSettings; _mediaFileSystem = mediaFileSystem; _logger = logger; _typeFinder = typeFinder; @@ -118,7 +118,7 @@ namespace Umbraco.Core.Scoping // initializes a new scope public Scope(ScopeProvider scopeProvider, - ICoreDebug coreDebug, + ICoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, bool detachable, IScopeContext scopeContext, IsolationLevel isolationLevel = IsolationLevel.Unspecified, @@ -127,12 +127,12 @@ namespace Umbraco.Core.Scoping bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) - : this(scopeProvider, coreDebug, mediaFileSystem, logger, typeFinder, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) + : this(scopeProvider, coreDebugSettings, mediaFileSystem, logger, typeFinder, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } // initializes a new scope in a nested scopes chain, with its parent public Scope(ScopeProvider scopeProvider, - ICoreDebug coreDebug, + ICoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IsolationLevel isolationLevel = IsolationLevel.Unspecified, @@ -141,7 +141,7 @@ namespace Umbraco.Core.Scoping bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) - : this(scopeProvider, coreDebug, mediaFileSystem, logger, typeFinder, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) + : this(scopeProvider, coreDebugSettings, mediaFileSystem, logger, typeFinder, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } public Guid InstanceId { get; } = Guid.NewGuid(); @@ -188,7 +188,7 @@ namespace Umbraco.Core.Scoping if (ParentScope != null) return ParentScope.IsolatedCaches; return _isolatedCaches ?? (_isolatedCaches - = new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache(_typeFinder)))); + = new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } } @@ -494,9 +494,9 @@ namespace Umbraco.Core.Scoping private static bool? _logUncompletedScopes; // caching config - // true if Umbraco.CoreDebug.LogUncompletedScope appSetting is set to "true" + // true if Umbraco.CoreDebugSettings.LogUncompletedScope appSetting is set to "true" private bool LogUncompletedScopes => (_logUncompletedScopes - ?? (_logUncompletedScopes = _coreDebug.LogUncompletedScopes)).Value; + ?? (_logUncompletedScopes = _coreDebugSettings.LogUncompletedScopes)).Value; /// public void ReadLock(params int[] lockIds) => Database.SqlContext.SqlSyntax.ReadLock(Database, lockIds); diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 0dba73b55b..610f308b96 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -26,14 +26,14 @@ namespace Umbraco.Core.Scoping private readonly ITypeFinder _typeFinder; private readonly IRequestCache _requestCache; private readonly FileSystems _fileSystems; - private readonly ICoreDebug _coreDebug; + private readonly ICoreDebugSettings _coreDebugSettings; private readonly IMediaFileSystem _mediaFileSystem; - public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, ICoreDebug coreDebug, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, IRequestCache requestCache) + public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, ICoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, IRequestCache requestCache) { DatabaseFactory = databaseFactory; _fileSystems = fileSystems; - _coreDebug = coreDebug; + _coreDebugSettings = coreDebugSettings; _mediaFileSystem = mediaFileSystem; _logger = logger; _typeFinder = typeFinder; @@ -255,7 +255,7 @@ namespace Umbraco.Core.Scoping IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null) { - return new Scope(this, _coreDebug, _mediaFileSystem, _logger, _typeFinder, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); + return new Scope(this, _coreDebugSettings, _mediaFileSystem, _logger, _typeFinder, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); } /// @@ -311,13 +311,13 @@ namespace Umbraco.Core.Scoping { var ambientContext = AmbientContext; var newContext = ambientContext == null ? new ScopeContext() : null; - var scope = new Scope(this, _coreDebug, _mediaFileSystem, _logger, _typeFinder, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var scope = new Scope(this, _coreDebugSettings, _mediaFileSystem, _logger, _typeFinder, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); // assign only if scope creation did not throw! SetAmbient(scope, newContext ?? ambientContext); return scope; } - var nested = new Scope(this, _coreDebug, _mediaFileSystem, _logger, _typeFinder, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var nested = new Scope(this, _coreDebugSettings, _mediaFileSystem, _logger, _typeFinder, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); SetAmbient(nested, AmbientContext); return nested; } diff --git a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs index 2c964a2723..1946e2041b 100644 --- a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs +++ b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs @@ -18,10 +18,10 @@ namespace Umbraco.Web.Search private readonly IndexRebuilder _indexRebuilder; private readonly IMainDom _mainDom; private readonly IProfilingLogger _logger; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationShutdownRegistry _hostingEnvironment; private static BackgroundTaskRunner _rebuildOnStartupRunner; - public BackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger logger, IHostingEnvironment hostingEnvironment, IndexRebuilder indexRebuilder) + public BackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger logger, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) { _mainDom = mainDom; _logger = logger; @@ -32,8 +32,6 @@ namespace Umbraco.Web.Search /// /// Called to rebuild empty indexes on startup /// - /// - /// /// /// public void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0) diff --git a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs index 11b91ffc90..ecaf7354ca 100644 --- a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Examine; using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Mapping; using Umbraco.Web.Routing; using Umbraco.Web.Trees; @@ -50,6 +51,7 @@ namespace Umbraco.Web.Search /// /// /// + /// /// /// /// A starting point for the search, generally a node id, but for members this is a member type alias @@ -62,7 +64,7 @@ namespace Umbraco.Web.Search string query, UmbracoEntityTypes entityType, int pageSize, - long pageIndex, out long totalFound, string searchFrom = null, bool ignoreUserStartNodes = false) + long pageIndex, out long totalFound, string culture = null, string searchFrom = null, bool ignoreUserStartNodes = false) { var pagedResult = _backOfficeExamineSearcher.Search(query, entityType, pageSize, pageIndex, out totalFound, searchFrom, ignoreUserStartNodes); @@ -73,7 +75,7 @@ namespace Umbraco.Web.Search case UmbracoEntityTypes.Media: return MediaFromSearchResults(pagedResult); case UmbracoEntityTypes.Document: - return ContentFromSearchResults(pagedResult); + return ContentFromSearchResults(pagedResult, culture); default: throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType); } @@ -145,14 +147,20 @@ namespace Umbraco.Web.Search /// Returns a collection of entities for content based on search results /// /// + /// /// - private IEnumerable ContentFromSearchResults(IEnumerable results) + private IEnumerable ContentFromSearchResults(IEnumerable results, string culture = null) { var defaultLang = _languageService.GetDefaultLanguageIsoCode(); foreach (var result in results) { - var entity = _mapper.Map(result); + var entity = _mapper.Map(result, context => { + if(culture != null) { + context.SetCulture(culture); + } + } + ); var intId = entity.Id.TryConvertTo(); if (intId.Success) @@ -160,7 +168,7 @@ namespace Umbraco.Web.Search //if it varies by culture, return the default language URL if (result.Values.TryGetValue(UmbracoExamineFieldNames.VariesByCultureFieldName, out var varies) && varies == "y") { - entity.AdditionalData["Url"] = _publishedUrlProvider.GetUrl(intId.Result, culture: defaultLang); + entity.AdditionalData["Url"] = _publishedUrlProvider.GetUrl(intId.Result, culture: culture ?? defaultLang); } else { diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index c8b8e617c9..d6c30b24c6 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -28,16 +28,16 @@ namespace Umbraco.Core.Services.Implement private readonly ILocalizationService _localizationService; private readonly INotificationsRepository _notificationsRepository; private readonly IGlobalSettings _globalSettings; - private readonly IContentSection _contentSection; + private readonly IContentSettings _contentSettings; private readonly ILogger _logger; private readonly IIOHelper _ioHelper; public NotificationService(IScopeProvider provider, IUserService userService, IContentService contentService, ILocalizationService localizationService, - ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IGlobalSettings globalSettings, IContentSection contentSection) + ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IGlobalSettings globalSettings, IContentSettings contentSettings) { _notificationsRepository = notificationsRepository; _globalSettings = globalSettings; - _contentSection = contentSection; + _contentSettings = contentSettings; _uowProvider = provider ?? throw new ArgumentNullException(nameof(provider)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -302,7 +302,7 @@ namespace Umbraco.Core.Services.Implement if (content.ContentType.VariesByNothing()) { - if (!_contentSection.DisableHtmlEmail) + if (!_contentSettings.DisableHtmlEmail) { //create the HTML summary for invariant content @@ -344,7 +344,7 @@ namespace Umbraco.Core.Services.Implement { //it's variant, so detect what cultures have changed - if (!_contentSection.DisableHtmlEmail) + if (!_contentSettings.DisableHtmlEmail) { //Create the HTML based summary (ul of culture names) @@ -406,13 +406,13 @@ namespace Umbraco.Core.Services.Implement summary.ToString()); // create the mail message - var mail = new MailMessage(_contentSection.NotificationEmailAddress, mailingUser.Email); + var mail = new MailMessage(_contentSettings.NotificationEmailAddress, mailingUser.Email); // populate the message mail.Subject = createSubject((mailingUser, subjectVars)); - if (_contentSection.DisableHtmlEmail) + if (_contentSettings.DisableHtmlEmail) { mail.IsBodyHtml = false; mail.Body = createBody((user: mailingUser, body: bodyVars, false)); diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index c6cf6c01c3..e23f7539c2 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -1177,7 +1177,7 @@ namespace Umbraco.Core.Services.Implement /// /// Occurs before Save /// - internal static event TypedEventHandler> SavingUserGroup; + public static event TypedEventHandler> SavingUserGroup; /// /// Occurs after Save diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 5a46a37d43..c915013162 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -28,10 +28,11 @@ namespace Umbraco.Core.Sync // public class DatabaseServerMessenger : ServerMessengerBase, IDatabaseServerMessenger { - private readonly IRuntimeState _runtime; + private readonly IMainDom _mainDom; private readonly ManualResetEvent _syncIdle; private readonly object _locko = new object(); private readonly IProfilingLogger _profilingLogger; + private readonly IServerRegistrar _serverRegistrar; private readonly IHostingEnvironment _hostingEnvironment; private readonly CacheRefresherCollection _cacheRefreshers; private readonly ISqlContext _sqlContext; @@ -46,14 +47,15 @@ namespace Umbraco.Core.Sync public DatabaseServerMessengerOptions Options { get; } public DatabaseServerMessenger( - IRuntimeState runtime, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, + IMainDom mainDom, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, IServerRegistrar serverRegistrar, bool distributedEnabled, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers) : base(distributedEnabled) { ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider)); _sqlContext = sqlContext; - _runtime = runtime; + _mainDom = mainDom; _profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog)); + _serverRegistrar = serverRegistrar; _hostingEnvironment = hostingEnvironment; _cacheRefreshers = cacheRefreshers; Logger = proflog; @@ -126,7 +128,7 @@ namespace Umbraco.Core.Sync const int weight = 10; - var registered = _runtime.MainDom.Register( + var registered = _mainDom.Register( () => { lock (_locko) @@ -262,7 +264,7 @@ namespace Umbraco.Core.Sync _lastPruned = _lastSync; - switch (_runtime.ServerRole) + switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Single: case ServerRole.Master: diff --git a/src/Umbraco.Infrastructure/Trees/TreeNode.cs b/src/Umbraco.Infrastructure/Trees/TreeNode.cs index cc130b1b97..7d3c657207 100644 --- a/src/Umbraco.Infrastructure/Trees/TreeNode.cs +++ b/src/Umbraco.Infrastructure/Trees/TreeNode.cs @@ -112,7 +112,7 @@ namespace Umbraco.Web.Models.Trees return Current.IOHelper.ResolveUrl("~" + Icon.TrimStart('~')); //legacy icon path - return string.Format("{0}images/umbraco/{1}", Current.Configs.Global().Path.EnsureEndsWith("/"), Icon); + return string.Format("{0}images/umbraco/{1}", Current.IOHelper.BackOfficePath.EnsureEndsWith("/"), Icon); } } diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index 1db36a9c09..3d99c4918f 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -7,10 +7,15 @@ - + + + + + + @@ -55,6 +60,9 @@ <_Parameter1>Umbraco.Tests.Benchmarks + + <_Parameter1>Umbraco.Tests.Integration + diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs index 192f049930..648a2e76fa 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs @@ -1,6 +1,7 @@ using System.IO; using System.Text; using Umbraco.Core.Configuration; +using Umbraco.Core.IO; namespace Umbraco.ModelsBuilder.Embedded.Building { @@ -9,20 +10,23 @@ namespace Umbraco.ModelsBuilder.Embedded.Building private readonly UmbracoServices _umbracoService; private readonly IModelsBuilderConfig _config; private readonly OutOfDateModelsStatus _outOfDateModels; + private readonly IIOHelper _ioHelper; - public ModelsGenerator(UmbracoServices umbracoService, IModelsBuilderConfig config, OutOfDateModelsStatus outOfDateModels) + public ModelsGenerator(UmbracoServices umbracoService, IModelsBuilderConfig config, OutOfDateModelsStatus outOfDateModels, IIOHelper ioHelper) { _umbracoService = umbracoService; _config = config; _outOfDateModels = outOfDateModels; + _ioHelper = ioHelper; } internal void GenerateModels() { - if (!Directory.Exists(_config.ModelsDirectory)) - Directory.CreateDirectory(_config.ModelsDirectory); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + if (!Directory.Exists(modelsDirectory)) + Directory.CreateDirectory(modelsDirectory); - foreach (var file in Directory.GetFiles(_config.ModelsDirectory, "*.generated.cs")) + foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs")) File.Delete(file); var typeModels = _umbracoService.GetAllTypes(); @@ -33,7 +37,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building { var sb = new StringBuilder(); builder.Generate(sb, typeModel); - var filename = Path.Combine(_config.ModelsDirectory, typeModel.ClrName + ".generated.cs"); + var filename = Path.Combine(modelsDirectory, typeModel.ClrName + ".generated.cs"); File.WriteAllText(filename, sb.ToString()); } diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs index 4c796f3c7b..723ee10f35 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs @@ -94,7 +94,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building // private static void WriteGeneratedCodeAttribute(StringBuilder sb, string tabs) { - sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder\", \"{1}\")]\n", tabs, ApiVersion.Current.Version); + sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder.Embedded\", \"{1}\")]\n", tabs, ApiVersion.Current.Version); } private void WriteContentType(StringBuilder sb, TypeModel type) diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/TextHeaderWriter.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/TextHeaderWriter.cs index a93df97806..0ffad1c5bc 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/TextHeaderWriter.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/TextHeaderWriter.cs @@ -14,7 +14,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building sb.Append("// \n"); sb.Append("// This code was generated by a tool.\n"); sb.Append("//\n"); - sb.AppendFormat("// Umbraco.ModelsBuilder v{0}\n", ApiVersion.Current.Version); + sb.AppendFormat("// Umbraco.ModelsBuilder.Embedded v{0}\n", ApiVersion.Current.Version); sb.Append("//\n"); sb.Append("// Changes to this file will be lost if the code is regenerated.\n"); sb.Append("// \n"); diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index 2914fe1b12..e582301740 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -31,7 +31,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); - + if (composition.Configs.ModelsBuilder().ModelsMode == ModelsMode.PureLive) ComposeForLiveModels(composition); else if (composition.Configs.ModelsBuilder().EnableFactory) diff --git a/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs b/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs index 5b498fd5f3..f8f6e8c7bc 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs @@ -2,16 +2,19 @@ using System.IO; using System.Text; using Umbraco.Core.Configuration; +using Umbraco.Core.IO; namespace Umbraco.ModelsBuilder.Embedded { public sealed class ModelsGenerationError { private readonly IModelsBuilderConfig _config; + private readonly IIOHelper _ioHelper; - public ModelsGenerationError(IModelsBuilderConfig config) + public ModelsGenerationError(IModelsBuilderConfig config, IIOHelper ioHelper) { _config = config; + _ioHelper = ioHelper; } public void Clear() @@ -56,7 +59,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GetErrFile() { - var modelsDirectory = _config.ModelsDirectory; + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); if (!Directory.Exists(modelsDirectory)) return null; diff --git a/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs b/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs index 0e93030438..b8105eeef2 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs @@ -1,5 +1,6 @@ using System.IO; using Umbraco.Core.Configuration; +using Umbraco.Core.IO; using Umbraco.Web.Cache; namespace Umbraco.ModelsBuilder.Embedded @@ -7,10 +8,12 @@ namespace Umbraco.ModelsBuilder.Embedded public sealed class OutOfDateModelsStatus { private readonly IModelsBuilderConfig _config; + private readonly IIOHelper _ioHelper; - public OutOfDateModelsStatus(IModelsBuilderConfig config) + public OutOfDateModelsStatus(IModelsBuilderConfig config, IIOHelper ioHelper) { _config = config; + _ioHelper = ioHelper; } internal void Install() @@ -25,7 +28,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GetFlagPath() { - var modelsDirectory = _config.ModelsDirectory; + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); return Path.Combine(modelsDirectory, "ood.flag"); diff --git a/src/Umbraco.ModelsBuilder.Embedded/Properties/AssemblyInfo.cs b/src/Umbraco.ModelsBuilder.Embedded/Properties/AssemblyInfo.cs index 68c149adde..5fa17d3c77 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Properties/AssemblyInfo.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -[assembly: AssemblyTitle("Umbraco.ModelsBuilder")] +[assembly: AssemblyTitle("Umbraco.ModelsBuilder.Embedded")] [assembly: AssemblyDescription("Umbraco ModelsBuilder")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyProduct("Umbraco CMS")] diff --git a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs index bef2fa8414..3cfefa77ce 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs @@ -14,6 +14,7 @@ using System.Web.WebPages.Razor; using Umbraco.Core.Configuration; using Umbraco.Core; using Umbraco.Core.Hosting; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded.Building; @@ -41,31 +42,39 @@ namespace Umbraco.ModelsBuilder.Embedded private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err" }; private readonly IModelsBuilderConfig _config; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationShutdownRegistry _hostingLifetime; + private readonly IIOHelper _ioHelper; private readonly ModelsGenerationError _errors; - public PureLiveModelFactory(Lazy umbracoServices, IProfilingLogger logger, IModelsBuilderConfig config, IHostingEnvironment hostingEnvironment) + public PureLiveModelFactory( + Lazy umbracoServices, + IProfilingLogger logger, + IModelsBuilderConfig config, + IHostingEnvironment hostingEnvironment, + IApplicationShutdownRegistry hostingLifetime, + IIOHelper ioHelper) { _umbracoServices = umbracoServices; _logger = logger; _config = config; - _hostingEnvironment = hostingEnvironment; - _errors = new ModelsGenerationError(config); + _hostingLifetime = hostingLifetime; + _ioHelper = ioHelper; + _errors = new ModelsGenerationError(config, ioHelper); _ver = 1; // zero is for when we had no version _skipver = -1; // nothing to skip RazorBuildProvider.CodeGenerationStarted += RazorBuildProvider_CodeGenerationStarted; - if (!_hostingEnvironment.IsHosted) return; + if (!hostingEnvironment.IsHosted) return; - var modelsDirectory = _config.ModelsDirectory; + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); // BEWARE! if the watcher is not properly released then for some reason the // BuildManager will start confusing types - using a 'registered object' here // though we should probably plug into Umbraco's MainDom - which is internal - _hostingEnvironment.RegisterObject(this); + _hostingLifetime.RegisterObject(this); _watcher = new FileSystemWatcher(modelsDirectory); _watcher.Changed += WatcherOnChanged; _watcher.EnableRaisingEvents = true; @@ -208,7 +217,7 @@ namespace Umbraco.ModelsBuilder.Embedded _hasModels = false; _pendingRebuild = true; - var modelsDirectory = _config.ModelsDirectory; + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -330,7 +339,7 @@ namespace Umbraco.ModelsBuilder.Embedded private Assembly GetModelsAssembly(bool forceRebuild) { - var modelsDirectory = _config.ModelsDirectory; + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -552,7 +561,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GenerateModelsCode(IList typeModels) { - var modelsDirectory = _config.ModelsDirectory; + var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -669,7 +678,7 @@ namespace Umbraco.ModelsBuilder.Embedded { _watcher.EnableRaisingEvents = false; _watcher.Dispose(); - _hostingEnvironment.UnregisterObject(this); + _hostingLifetime.UnregisterObject(this); } #endregion diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 74295b7182..09f486b5d9 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -49,7 +49,6 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IPublishedModelFactory _publishedModelFactory; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly UrlSegmentProviderCollection _urlSegmentProviders; - private readonly ITypeFinder _typeFinder; private readonly IHostingEnvironment _hostingEnvironment; private readonly IShortStringHelper _shortStringHelper; private readonly IIOHelper _ioHelper; @@ -88,7 +87,6 @@ namespace Umbraco.Web.PublishedCache.NuCache IEntityXmlSerializer entitySerializer, IPublishedModelFactory publishedModelFactory, UrlSegmentProviderCollection urlSegmentProviders, - ITypeFinder typeFinder, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper, IIOHelper ioHelper, @@ -109,7 +107,6 @@ namespace Umbraco.Web.PublishedCache.NuCache _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings; _urlSegmentProviders = urlSegmentProviders; - _typeFinder = typeFinder; _hostingEnvironment = hostingEnvironment; _shortStringHelper = shortStringHelper; _ioHelper = ioHelper; @@ -1207,7 +1204,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _contentGen = contentSnap.Gen; _mediaGen = mediaSnap.Gen; _domainGen = domainSnap.Gen; - elementsCache = _elementsCache = new FastDictionaryAppCache(_typeFinder); + elementsCache = _elementsCache = new FastDictionaryAppCache(); } } diff --git a/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs new file mode 100644 index 0000000000..7b4322bfac --- /dev/null +++ b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs @@ -0,0 +1,30 @@ +using BenchmarkDotNet.Attributes; +using System; +using System.Linq; +using Umbraco.Core.Composing; +using Umbraco.Core.Logging; +using Umbraco.Tests.Benchmarks.Config; + +namespace Umbraco.Tests.Benchmarks +{ + [MediumRunJob] + [MemoryDiagnoser] + public class TypeFinderBenchmarks + { + + [Benchmark(Baseline = true)] + public void WithGetReferencingAssembliesCheck() + { + var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly)); + var found = typeFinder1.FindClassesOfType().Count(); + } + + [Benchmark] + public void WithoutGetReferencingAssembliesCheck() + { + var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly)); + typeFinder2.QueryWithReferencingAssemblies = false; + var found = typeFinder2.FindClassesOfType().Count(); + } + } +} diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 7566d8ab85..84ec535b9d 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -61,6 +61,7 @@ + diff --git a/src/Umbraco.Tests.Common/Assertions.cs b/src/Umbraco.Tests.Common/Assertions.cs new file mode 100644 index 0000000000..0f99a6a091 --- /dev/null +++ b/src/Umbraco.Tests.Common/Assertions.cs @@ -0,0 +1,35 @@ +using LightInject; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Umbraco.Tests.Common.Composing; + +namespace Umbraco.Tests.Common +{ + public class Assertions + { + public static void AssertContainer(ServiceContainer container, bool reportOnly = false) + { + var results = container.Validate().ToList(); + foreach (var resultGroup in results.GroupBy(x => x.Severity).OrderBy(x => x.Key)) + { + Console.WriteLine($"{resultGroup.Key}: {resultGroup.Count()}"); + } + + foreach (var resultGroup in results.GroupBy(x => x.Severity).OrderBy(x => x.Key)) + { + foreach (var result in resultGroup) + { + Console.WriteLine(); + Console.Write(result.ToText()); + } + } + + if (!reportOnly) + Assert.AreEqual(0, results.Count); + } + + } +} diff --git a/src/Umbraco.Tests.Common/Builders/BuilderBase.cs b/src/Umbraco.Tests.Common/Builders/BuilderBase.cs new file mode 100644 index 0000000000..d8fc048d1b --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/BuilderBase.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Tests.Common.Builders +{ + public abstract class BuilderBase + { + public abstract T Build(); + } +} diff --git a/src/Umbraco.Tests.Common/Builders/ChildBuilderBase.cs b/src/Umbraco.Tests.Common/Builders/ChildBuilderBase.cs new file mode 100644 index 0000000000..e1436ac1fe --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/ChildBuilderBase.cs @@ -0,0 +1,19 @@ +namespace Umbraco.Tests.Common.Builders +{ + public abstract class ChildBuilderBase : BuilderBase + { + private readonly TParent _parentBuilder; + + protected ChildBuilderBase(TParent parentBuilder) + { + _parentBuilder = parentBuilder; + } + + + public TParent Done() + { + return _parentBuilder; + } + + } +} diff --git a/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs new file mode 100644 index 0000000000..7789090d16 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Tests.Common.Builders +{ + public class ConfigurationEditorBuilder : ChildBuilderBase + { + private IDictionary _defaultConfiguration; + + + public ConfigurationEditorBuilder(TParent parentBuilder) : base(parentBuilder) + { + } + + + public ConfigurationEditorBuilder WithDefaultConfiguration(IDictionary defaultConfiguration) + { + _defaultConfiguration = defaultConfiguration; + return this; + } + + public override IConfigurationEditor Build() + { + var defaultConfiguration = _defaultConfiguration ?? new Dictionary(); + + return new ConfigurationEditor() + { + DefaultConfiguration = defaultConfiguration, + }; + } + + } +} diff --git a/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs new file mode 100644 index 0000000000..b3c3ff1b7e --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Moq; +using Umbraco.Core.Logging; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; + +namespace Umbraco.Tests.Common.Builders +{ + public class DataEditorBuilder : ChildBuilderBase + { + private readonly ConfigurationEditorBuilder> _explicitConfigurationEditorBuilder; + private readonly DataValueEditorBuilder> _explicitValueEditorBuilder; + private IDictionary _defaultConfiguration; + + public DataEditorBuilder(TParent parentBuilder) : base(parentBuilder) + { + _explicitConfigurationEditorBuilder = new ConfigurationEditorBuilder>(this); + _explicitValueEditorBuilder = new DataValueEditorBuilder>(this); + } + + public DataEditorBuilder WithDefaultConfiguration(IDictionary defaultConfiguration) + { + _defaultConfiguration = defaultConfiguration; + return this; + } + + public ConfigurationEditorBuilder> AddExplicitConfigurationEditorBuilder() => + _explicitConfigurationEditorBuilder; + + public DataValueEditorBuilder> AddExplicitValueEditorBuilder() => + _explicitValueEditorBuilder; + + public override IDataEditor Build() + { + var defaultConfiguration = _defaultConfiguration ?? new Dictionary(); + var explicitConfigurationEditor = _explicitConfigurationEditorBuilder.Build(); + var explicitValueEditor = _explicitValueEditorBuilder.Build(); + + return new DataEditor( + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of() + ) + { + DefaultConfiguration = defaultConfiguration, + ExplicitConfigurationEditor = explicitConfigurationEditor, + ExplicitValueEditor = explicitValueEditor + }; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs new file mode 100644 index 0000000000..20dc1bab81 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs @@ -0,0 +1,160 @@ +using System; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders.Interfaces; + +namespace Umbraco.Tests.Common.Builders +{ + public class DataTypeBuilder + : BuilderBase, + IWithIdBuilder, + IWithKeyBuilder, + IWithCreateDateBuilder, + IWithUpdateDateBuilder, + IWithDeleteDateBuilder, + IWithNameBuilder + { + private readonly DataEditorBuilder _dataEditorBuilder; + private int? _id; + private int? _parentId; + private Guid? _key; + private DateTime? _createDate; + private DateTime? _updateDate; + private DateTime? _deleteDate; + private string _name; + private bool? _trashed; + // private object _configuration; + private int? _level; + private string _path; + private int? _creatorId; + private ValueStorageType? _databaseType; + private int? _sortOrder; + + public DataTypeBuilder() + { + _dataEditorBuilder = new DataEditorBuilder(this); + } + + public DataTypeBuilder WithParentId(int parentId) + { + _parentId = parentId; + return this; + } + + public DataTypeBuilder WithTrashed(bool trashed) + { + _trashed = trashed; + return this; + } + + // public DataTypeBuilder WithConfiguration(object configuration) + // { + // _configuration = configuration; + // return this; + // } + + public DataTypeBuilder WithLevel(int level) + { + _level = level; + return this; + } + + public DataTypeBuilder WithPath(string path) + { + _path = path; + return this; + } + + public DataTypeBuilder WithCreatorId(int creatorId) + { + _creatorId = creatorId; + return this; + } + + public DataTypeBuilder WithDatabaseType(ValueStorageType databaseType) + { + _databaseType = databaseType; + return this; + } + + public DataTypeBuilder WithSortOrder(int sortOrder) + { + _sortOrder = sortOrder; + return this; + } + + public DataEditorBuilder AddEditor() + { + return _dataEditorBuilder; + } + + public override DataType Build() + { + var editor = _dataEditorBuilder.Build(); + var parentId = _parentId ?? -1; + var id = _id ?? 1; + var key = _key ?? Guid.NewGuid(); + var createDate = _createDate ?? DateTime.Now; + var updateDate = _updateDate ?? DateTime.Now; + var deleteDate = _deleteDate ?? null; + var name = _name ?? Guid.NewGuid().ToString(); + // var configuration = _configuration ?? editor.GetConfigurationEditor().DefaultConfigurationObject; + var level = _level ?? 0; + var path = _path ?? string.Empty; + var creatorId = _creatorId ?? 1; + var databaseType = _databaseType ?? ValueStorageType.Ntext; + var sortOrder = _sortOrder ?? 0; + + return new DataType(editor, parentId) + { + Id = id, + Key = key, + CreateDate = createDate, + UpdateDate = updateDate, + DeleteDate = deleteDate, + Name = name, + Trashed = _trashed ?? false, + Level = level, + Path = path, + CreatorId = creatorId, + DatabaseType = databaseType, + SortOrder = sortOrder, + }; + } + + int? IWithIdBuilder.Id + { + get => _id; + set => _id = value; + } + + Guid? IWithKeyBuilder.Key + { + get => _key; + set => _key = value; + } + + DateTime? IWithCreateDateBuilder.CreateDate + { + get => _createDate; + set => _createDate = value; + } + + DateTime? IWithUpdateDateBuilder.UpdateDate + { + get => _updateDate; + set => _updateDate = value; + } + + DateTime? IWithDeleteDateBuilder.DeleteDate + { + get => _deleteDate; + set => _deleteDate = value; + } + + string IWithNameBuilder.Name + { + get => _name; + set => _name = value; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs new file mode 100644 index 0000000000..3d0b518ee7 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs @@ -0,0 +1,66 @@ +using System; +using Moq; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; + +namespace Umbraco.Tests.Common.Builders +{ + public class DataValueEditorBuilder : ChildBuilderBase + { + private string _configuration; + private string _view; + private bool? _hideLabel; + private string _valueType; + + + public DataValueEditorBuilder(TParent parentBuilder) : base(parentBuilder) + { + } + + public DataValueEditorBuilder WithConfiguration(string configuration) + { + _configuration = configuration; + return this; + } + + public DataValueEditorBuilder WithView(string view) + { + _view = view; + return this; + } + + public DataValueEditorBuilder WithHideLabel(bool hideLabel) + { + _hideLabel = hideLabel; + return this; + } + + public DataValueEditorBuilder WithValueType(string valueType) + { + _valueType = valueType; + return this; + } + + public override IDataValueEditor Build() + { + var configuration = _configuration ?? null; + var view = _view ?? null; + var hideLabel = _hideLabel ?? false; + var valueType = _valueType ?? Guid.NewGuid().ToString(); + + return new DataValueEditor( + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of() + ) + { + Configuration = configuration, + View = view, + HideLabel = hideLabel, + ValueType = valueType, + }; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/DictionaryItemBuilder.cs b/src/Umbraco.Tests.Common/Builders/DictionaryItemBuilder.cs new file mode 100644 index 0000000000..206bccba80 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/DictionaryItemBuilder.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders.Interfaces; + +namespace Umbraco.Tests.Common.Builders +{ + public class DictionaryItemBuilder + : BuilderBase, + IWithIdBuilder, + IWithCreateDateBuilder, + IWithUpdateDateBuilder, + IWithDeleteDateBuilder, + IWithKeyBuilder + { + private readonly List _translationBuilders = + new List(); + + private DateTime? _createDate; + private DateTime? _deleteDate; + private int? _id; + private string _itemKey; + private Guid? _key; + private Guid? _parentId; + private DateTime? _updateDate; + + DateTime? IWithCreateDateBuilder.CreateDate + { + get => _createDate; + set => _createDate = value; + } + + DateTime? IWithDeleteDateBuilder.DeleteDate + { + get => _deleteDate; + set => _deleteDate = value; + } + + int? IWithIdBuilder.Id + { + get => _id; + set => _id = value; + } + + Guid? IWithKeyBuilder.Key + { + get => _key; + set => _key = value; + } + + DateTime? IWithUpdateDateBuilder.UpdateDate + { + get => _updateDate; + set => _updateDate = value; + } + + public override DictionaryItem Build() + { + var createDate = _createDate ?? DateTime.Now; + var updateDate = _updateDate ?? DateTime.Now; + var deleteDate = _deleteDate ?? null; + var id = _id ?? 1; + var key = _key ?? Guid.NewGuid(); + var parentId = _parentId ?? null; + var itemKey = _itemKey ?? Guid.NewGuid().ToString(); + + var result = new DictionaryItem(itemKey) + { + Translations = _translationBuilders.Select(x => x.Build()), + CreateDate = createDate, + UpdateDate = updateDate, + DeleteDate = deleteDate, + Id = id, + ParentId = parentId, + Key = key, + }; + return result; + } + + public DictionaryItemBuilder WithParentId(Guid parentId) + { + _parentId = parentId; + return this; + } + + public DictionaryItemBuilder WithItemKey(string itemKey) + { + _itemKey = itemKey; + return this; + } + + public DictionaryTranslationBuilder AddTranslation() + { + var builder = new DictionaryTranslationBuilder(this); + + _translationBuilders.Add(builder); + + return builder; + } + + public DictionaryItemBuilder WithRandomTranslations(int count) + { + for (var i = 0; i < count; i++) + { + AddTranslation().Done(); + } + + return this; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/DictionaryTranslationBuilder.cs b/src/Umbraco.Tests.Common/Builders/DictionaryTranslationBuilder.cs new file mode 100644 index 0000000000..37fb7c5b07 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/DictionaryTranslationBuilder.cs @@ -0,0 +1,90 @@ +using System; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders.Interfaces; + +namespace Umbraco.Tests.Common.Builders +{ + public class DictionaryTranslationBuilder + : ChildBuilderBase, + IWithIdBuilder, + IWithCreateDateBuilder, + IWithUpdateDateBuilder, + IWithDeleteDateBuilder, + IWithKeyBuilder + { + private readonly LanguageBuilder _languageBuilder; + private readonly Guid? _uniqueId = null; + private DateTime? _createDate; + private DateTime? _deleteDate; + private int? _id; + private Guid? _key; + private DateTime? _updateDate; + private string _value; + + + public DictionaryTranslationBuilder(DictionaryItemBuilder parentBuilder) : base(parentBuilder) + { + _languageBuilder = new LanguageBuilder(this); + } + + DateTime? IWithCreateDateBuilder.CreateDate + { + get => _createDate; + set => _createDate = value; + } + + DateTime? IWithDeleteDateBuilder.DeleteDate + { + get => _deleteDate; + set => _deleteDate = value; + } + + int? IWithIdBuilder.Id + { + get => _id; + set => _id = value; + } + + Guid? IWithKeyBuilder.Key + { + get => _key; + set => _key = value; + } + + DateTime? IWithUpdateDateBuilder.UpdateDate + { + get => _updateDate; + set => _updateDate = value; + } + + public override IDictionaryTranslation Build() + { + var createDate = _createDate ?? DateTime.Now; + var updateDate = _updateDate ?? DateTime.Now; + var deleteDate = _deleteDate ?? null; + var id = _id ?? 1; + var key = _key ?? Guid.NewGuid(); + + var result = new DictionaryTranslation( + _languageBuilder.Build(), + _value ?? Guid.NewGuid().ToString(), + _uniqueId ?? key) + { + CreateDate = createDate, + UpdateDate = updateDate, + DeleteDate = deleteDate, + Id = id + }; + + return result; + } + + public LanguageBuilder AddLanguage() => _languageBuilder; + + public DictionaryTranslationBuilder WithValue(string value) + { + _value = value; + return this; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs b/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs new file mode 100644 index 0000000000..c8f3f80bf1 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs @@ -0,0 +1,50 @@ +using System; +using Umbraco.Tests.Common.Builders.Interfaces; + +namespace Umbraco.Tests.Common.Builders.Extensions +{ + public static class BuilderExtensions + { + public static T WithId(this T builder, int id) + where T : IWithIdBuilder + { + builder.Id = id; + return builder; + } + + public static T WithCreateDate(this T builder, DateTime createDate) + where T : IWithCreateDateBuilder + { + builder.CreateDate = createDate; + return builder; + } + + public static T WithUpdateDate(this T builder, DateTime updateDate) + where T : IWithUpdateDateBuilder + { + builder.UpdateDate = updateDate; + return builder; + } + + public static T WithAlias(this T builder, string alias) + where T : IWithAliasBuilder + { + builder.Alias = alias; + return builder; + } + + public static T WithName(this T builder, string name) + where T : IWithNameBuilder + { + builder.Name = name; + return builder; + } + + public static T WithKey(this T builder, Guid key) + where T : IWithKeyBuilder + { + builder.Key = key; + return builder; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs new file mode 100644 index 0000000000..56e242146c --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs @@ -0,0 +1,249 @@ +using Umbraco.Core.Configuration; + +namespace Umbraco.Tests.Common.Builders +{ + public class GlobalSettingsBuilder : GlobalSettingsBuilder + { + public GlobalSettingsBuilder() : base(null) + { + } + } + + public class GlobalSettingsBuilder : ChildBuilderBase + { + private string _configurationStatus; + private string _databaseFactoryServerVersion; + private string _defaultUiLanguage; + private bool? _disableElectionForSingleServer; + private bool? _hideTopLevelNodeFromPath; + private bool? _installEmptyDatabase; + private bool? _installMissingDatabase; + private bool? _isSmtpServerConfigured; + private string _path; + private string _registerType; + private string _reservedPaths; + private string _reservedUrls; + private int? _timeOutInMinutes; + private string _umbracoCssPath; + private string _umbracoMediaPath; + private string _umbracoPath; + private string _umbracoScriptsPath; + private string _mainDomLock; + private string _noNodesViewPath; + private bool? _useHttps; + private int? _versionCheckPeriod; + private readonly SmtpSettingsBuilder> _smtpSettingsBuilder; + + + public GlobalSettingsBuilder(TParent parentBuilder) : base(parentBuilder) + { + _smtpSettingsBuilder = new SmtpSettingsBuilder>(this); + } + + public SmtpSettingsBuilder> AddSmtpSettings() => _smtpSettingsBuilder; + + public GlobalSettingsBuilder WithConfigurationStatus(string configurationStatus) + { + _configurationStatus = configurationStatus; + return this; + } + + public GlobalSettingsBuilder WithDatabaseFactoryServerVersion(string databaseFactoryServerVersion) + { + _databaseFactoryServerVersion = databaseFactoryServerVersion; + return this; + } + + public GlobalSettingsBuilder WithDefaultUiLanguage(string defaultUiLanguage) + { + _defaultUiLanguage = defaultUiLanguage; + return this; + } + + public GlobalSettingsBuilder WithDisableElectionForSingleServer(bool disableElectionForSingleServer) + { + _disableElectionForSingleServer = disableElectionForSingleServer; + return this; + } + + public GlobalSettingsBuilder WithHideTopLevelNodeFromPath(bool hideTopLevelNodeFromPath) + { + _hideTopLevelNodeFromPath = hideTopLevelNodeFromPath; + return this; + } + + public GlobalSettingsBuilder WithInstallEmptyDatabase(bool installEmptyDatabase) + { + _installEmptyDatabase = installEmptyDatabase; + return this; + } + + public GlobalSettingsBuilder WithInstallMissingDatabase(bool installMissingDatabase) + { + _installMissingDatabase = installMissingDatabase; + return this; + } + + public GlobalSettingsBuilder WithIsSmtpServerConfigured(bool isSmtpServerConfigured) + { + _isSmtpServerConfigured = isSmtpServerConfigured; + return this; + } + + public GlobalSettingsBuilder WithPath(string path) + { + _path = path; + return this; + } + + public GlobalSettingsBuilder WithRegisterType(string registerType) + { + _registerType = registerType; + return this; + } + + public GlobalSettingsBuilder WithReservedPaths(string reservedPaths) + { + _reservedPaths = reservedPaths; + return this; + } + + public GlobalSettingsBuilder WithReservedUrls(string reservedUrls) + { + _reservedUrls = reservedUrls; + return this; + } + + public GlobalSettingsBuilder WithUmbracoPath(string umbracoPath) + { + _umbracoPath = umbracoPath; + return this; + } + + public GlobalSettingsBuilder WithUseHttps(bool useHttps) + { + _useHttps = useHttps; + return this; + } + + public GlobalSettingsBuilder WithUmbracoCssPath(string umbracoCssPath) + { + _umbracoCssPath = umbracoCssPath; + return this; + } + + public GlobalSettingsBuilder WithUmbracoMediaPath(string umbracoMediaPath) + { + _umbracoMediaPath = umbracoMediaPath; + return this; + } + + public GlobalSettingsBuilder WithUmbracoScriptsPath(string umbracoScriptsPath) + { + _umbracoScriptsPath = umbracoScriptsPath; + return this; + } + + public GlobalSettingsBuilder WithMainDomLock(string mainDomLock) + { + _mainDomLock = mainDomLock; + return this; + } + + public GlobalSettingsBuilder WithNoNodesViewPath(string noNodesViewPath) + { + _noNodesViewPath = noNodesViewPath; + return this; + } + public GlobalSettingsBuilder WithVersionCheckPeriod(int versionCheckPeriod) + { + _versionCheckPeriod = versionCheckPeriod; + return this; + } + + public GlobalSettingsBuilder WithTimeOutInMinutes(int timeOutInMinutes) + { + _timeOutInMinutes = timeOutInMinutes; + return this; + } + + public override IGlobalSettings Build() + { + var configurationStatus = _configurationStatus ?? "9.0.0"; + var databaseFactoryServerVersion = _databaseFactoryServerVersion ?? null; + var defaultUiLanguage = _defaultUiLanguage ?? "en"; + var disableElectionForSingleServer = _disableElectionForSingleServer ?? false; + var hideTopLevelNodeFromPath = _hideTopLevelNodeFromPath ?? false; + var installEmptyDatabase = _installEmptyDatabase ?? false; + var installMissingDatabase = _installMissingDatabase ?? false; + var isSmtpServerConfigured = _isSmtpServerConfigured ?? false; + var path = _path ?? "/umbraco"; + var registerType = _registerType ?? null; + var reservedPaths = _reservedPaths ?? "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; + var reservedUrls = _reservedUrls ?? "~/config/splashes/noNodes.aspx,~/.well-known,"; + var umbracoPath = _umbracoPath ?? "~/umbraco"; + var useHttps = _useHttps ?? false; + var umbracoCssPath = _umbracoCssPath ?? "~/css"; + var umbracoMediaPath = _umbracoMediaPath ?? "~/media"; + var umbracoScriptsPath = _umbracoScriptsPath ?? "~/scripts"; + var versionCheckPeriod = _versionCheckPeriod ?? 0; + var timeOutInMinutes = _timeOutInMinutes ?? 20; + var smtpSettings = _smtpSettingsBuilder.Build(); + var mainDomLock = _mainDomLock ?? string.Empty; + var noNodesViewPath = _noNodesViewPath ?? "~/config/splashes/NoNodes.cshtml"; + + + return new TestGlobalSettings + { + ConfigurationStatus = configurationStatus, + DatabaseFactoryServerVersion = databaseFactoryServerVersion, + DefaultUILanguage = defaultUiLanguage, + DisableElectionForSingleServer = disableElectionForSingleServer, + HideTopLevelNodeFromPath = hideTopLevelNodeFromPath, + InstallEmptyDatabase = installEmptyDatabase, + InstallMissingDatabase = installMissingDatabase, + IsSmtpServerConfigured = isSmtpServerConfigured, + Path = path, + RegisterType = registerType, + ReservedPaths = reservedPaths, + ReservedUrls = reservedUrls, + UmbracoPath = umbracoPath, + UseHttps = useHttps, + UmbracoCssPath = umbracoCssPath, + UmbracoMediaPath = umbracoMediaPath, + UmbracoScriptsPath = umbracoScriptsPath, + VersionCheckPeriod = versionCheckPeriod, + TimeOutInMinutes = timeOutInMinutes, + SmtpSettings = smtpSettings, + MainDomLock = mainDomLock, + NoNodesViewPath = noNodesViewPath, + }; + } + + private class TestGlobalSettings : IGlobalSettings + { + public string ReservedUrls { get; set; } + public string ReservedPaths { get; set; } + public string Path { get; set; } + public string ConfigurationStatus { get; set; } + public int TimeOutInMinutes { get; set; } + public string DefaultUILanguage { get; set; } + public bool HideTopLevelNodeFromPath { get; set; } + public bool UseHttps { get; set; } + public int VersionCheckPeriod { get; set; } + public string UmbracoPath { get; set; } + public string UmbracoCssPath { get; set; } + public string UmbracoScriptsPath { get; set; } + public string UmbracoMediaPath { get; set; } + public bool IsSmtpServerConfigured { get; set; } + public ISmtpSettings SmtpSettings { get; set; } + public bool InstallMissingDatabase { get; set; } + public bool InstallEmptyDatabase { get; set; } + public bool DisableElectionForSingleServer { get; set; } + public string RegisterType { get; set; } + public string DatabaseFactoryServerVersion { get; set; } + public string MainDomLock { get; set; } + public string NoNodesViewPath { get; set; } + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithAliasBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithAliasBuilder.cs new file mode 100644 index 0000000000..78bbbddec9 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithAliasBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithAliasBuilder + { + string Alias { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithCreateDateBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithCreateDateBuilder.cs new file mode 100644 index 0000000000..47acaa9a52 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithCreateDateBuilder.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithCreateDateBuilder + { + DateTime? CreateDate { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithCultureInfoBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithCultureInfoBuilder.cs new file mode 100644 index 0000000000..a60fe3c23c --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithCultureInfoBuilder.cs @@ -0,0 +1,9 @@ +using System.Globalization; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithCultureInfoBuilder + { + CultureInfo CultureInfo { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithDeleteDateBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithDeleteDateBuilder.cs new file mode 100644 index 0000000000..0fdeb6d69d --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithDeleteDateBuilder.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithDeleteDateBuilder + { + DateTime? DeleteDate { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithIdBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithIdBuilder.cs new file mode 100644 index 0000000000..c13343df15 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithIdBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithIdBuilder + { + int? Id { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithKeyBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithKeyBuilder.cs new file mode 100644 index 0000000000..a71bd2d114 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithKeyBuilder.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithKeyBuilder + { + Guid? Key { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithNameBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithNameBuilder.cs new file mode 100644 index 0000000000..d2ccb8dbbc --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithNameBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithNameBuilder + { + string Name { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithUpdateDateBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithUpdateDateBuilder.cs new file mode 100644 index 0000000000..80a5aa4f61 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithUpdateDateBuilder.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithUpdateDateBuilder + { + DateTime? UpdateDate { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs b/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs new file mode 100644 index 0000000000..ae60920c9c --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs @@ -0,0 +1,120 @@ +using System; +using System.Globalization; +using Moq; +using Umbraco.Core.Configuration; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders.Interfaces; + +namespace Umbraco.Tests.Common.Builders +{ + public class LanguageBuilder : LanguageBuilder + { + public LanguageBuilder() : base(null) + { + } + } + + public class LanguageBuilder + : ChildBuilderBase, + IWithIdBuilder, + IWithKeyBuilder, + IWithCreateDateBuilder, + IWithUpdateDateBuilder, + IWithDeleteDateBuilder, + IWithCultureInfoBuilder + { + private DateTime? _createDate; + private CultureInfo _cultureInfo; + private DateTime? _deleteDate; + private int? _fallbackLanguageId; + private int? _id; + private bool? _isDefault; + private bool? _isMandatory; + private Guid? _key; + private DateTime? _updateDate; + + public LanguageBuilder(TParent parentBuilder) : base(parentBuilder) + { + } + + DateTime? IWithCreateDateBuilder.CreateDate + { + get => _createDate; + set => _createDate = value; + } + + CultureInfo IWithCultureInfoBuilder.CultureInfo + { + get => _cultureInfo; + set => _cultureInfo = value; + } + + DateTime? IWithDeleteDateBuilder.DeleteDate + { + get => _deleteDate; + set => _deleteDate = value; + } + + int? IWithIdBuilder.Id + { + get => _id; + set => _id = value; + } + + Guid? IWithKeyBuilder.Key + { + get => _key; + set => _key = value; + } + + DateTime? IWithUpdateDateBuilder.UpdateDate + { + get => _updateDate; + set => _updateDate = value; + } + + public override ILanguage Build() + { + var cultureInfo = _cultureInfo ?? CultureInfo.GetCultureInfo("en-US"); + var key = _key ?? Guid.NewGuid(); + var createDate = _createDate ?? DateTime.Now; + var updateDate = _updateDate ?? DateTime.Now; + var deleteDate = _deleteDate ?? null; + var fallbackLanguageId = _fallbackLanguageId ?? null; + var isDefault = _isDefault ?? false; + var isMandatory = _isMandatory ?? false; + + return new Language(Mock.Of(), cultureInfo.Name) + { + Id = _id ?? 1, + CultureName = cultureInfo.TwoLetterISOLanguageName, + IsoCode = new RegionInfo(cultureInfo.LCID).Name, + Key = key, + CreateDate = createDate, + UpdateDate = updateDate, + DeleteDate = deleteDate, + IsDefault = isDefault, + IsMandatory = isMandatory, + FallbackLanguageId = fallbackLanguageId + }; + } + + public LanguageBuilder WithIsDefault(bool isDefault) + { + _isDefault = isDefault; + return this; + } + + public LanguageBuilder WithIsMandatory(bool isMandatory) + { + _isMandatory = isMandatory; + return this; + } + + public LanguageBuilder WithFallbackLanguageId(int fallbackLanguageId) + { + _fallbackLanguageId = fallbackLanguageId; + return this; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs new file mode 100644 index 0000000000..4ad39c6641 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs @@ -0,0 +1,123 @@ +using System; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders.Interfaces; + +namespace Umbraco.Tests.Common.Builders +{ + public class RelationTypeBuilder : RelationTypeBuilder + { + public RelationTypeBuilder() : base(null) + { + } + } + + public class RelationTypeBuilder + : ChildBuilderBase, + IWithIdBuilder, + IWithAliasBuilder, + IWithNameBuilder, + IWithKeyBuilder, + IWithCreateDateBuilder, + IWithUpdateDateBuilder, + IWithDeleteDateBuilder + { + private string _alias; + private Guid? _childObjectType; + private DateTime? _createDate; + private DateTime? _deleteDate; + private int? _id; + private bool? _isBidirectional; + private Guid? _key; + private string _name; + private Guid? _parentObjectType; + private DateTime? _updateDate; + + public RelationTypeBuilder(TParent parentBuilder) : base(parentBuilder) + { + } + + string IWithAliasBuilder.Alias + { + get => _alias; + set => _alias = value; + } + + DateTime? IWithCreateDateBuilder.CreateDate + { + get => _createDate; + set => _createDate = value; + } + + DateTime? IWithDeleteDateBuilder.DeleteDate + { + get => _deleteDate; + set => _deleteDate = value; + } + + int? IWithIdBuilder.Id + { + get => _id; + set => _id = value; + } + + Guid? IWithKeyBuilder.Key + { + get => _key; + set => _key = value; + } + + string IWithNameBuilder.Name + { + get => _name; + set => _name = value; + } + + DateTime? IWithUpdateDateBuilder.UpdateDate + { + get => _updateDate; + set => _updateDate = value; + } + + public override IRelationType Build() + { + var alias = _alias ?? Guid.NewGuid().ToString(); + var name = _name ?? Guid.NewGuid().ToString(); + var parentObjectType = _parentObjectType ?? null; + var childObjectType = _childObjectType ?? null; + var id = _id ?? 1; + var key = _key ?? Guid.NewGuid(); + var isBidirectional = _isBidirectional ?? false; + var createDate = _createDate ?? DateTime.Now; + var updateDate = _updateDate ?? DateTime.Now; + var deleteDate = _deleteDate ?? null; + + return new RelationType(name, alias, isBidirectional, parentObjectType, + childObjectType) + { + Id = id, + Key = key, + CreateDate = createDate, + UpdateDate = updateDate, + DeleteDate = deleteDate + }; + } + + public RelationTypeBuilder WithIsBidirectional(bool isBidirectional) + { + _isBidirectional = isBidirectional; + return this; + } + + public RelationTypeBuilder WithChildObjectType(Guid childObjectType) + { + _childObjectType = childObjectType; + return this; + } + + public RelationTypeBuilder WithParentObjectType(Guid parentObjectType) + { + _parentObjectType = parentObjectType; + return this; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs new file mode 100644 index 0000000000..3120cc95f6 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs @@ -0,0 +1,73 @@ +using Umbraco.Core.Configuration; + +namespace Umbraco.Tests.Common.Builders +{ + public class SmtpSettingsBuilder : SmtpSettingsBuilder + { + public SmtpSettingsBuilder() : base(null) + { + } + } + + public class SmtpSettingsBuilder + : ChildBuilderBase + { + private string _from; + private string _host; + private int? _port; + private string _pickupDirectoryLocation; + + public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder) + { + } + + public SmtpSettingsBuilder WithFrom(string from) + { + _from = from; + return this; + } + + public SmtpSettingsBuilder WithHost(string host) + { + _host = host; + return this; + } + + public SmtpSettingsBuilder WithPost(int port) + { + _port = port; + return this; + } + + public SmtpSettingsBuilder WithPickupDirectoryLocation(string pickupDirectoryLocation) + { + _pickupDirectoryLocation = pickupDirectoryLocation; + return this; + } + + + public override ISmtpSettings Build() + { + var from = _from ?? null; + var host = _host ?? null; + var port = _port ?? 25; + var pickupDirectoryLocation = _pickupDirectoryLocation ?? null; + + return new TestSmtpSettings() + { + From = from, + Host = host, + Port = port, + PickupDirectoryLocation = pickupDirectoryLocation, + }; + } + + private class TestSmtpSettings : ISmtpSettings + { + public string From { get; set; } + public string Host { get; set; } + public int Port { get; set; } + public string PickupDirectoryLocation { get; set; } + } + } +} diff --git a/src/Umbraco.Tests/Composing/LightInjectValidation.cs b/src/Umbraco.Tests.Common/Composing/LightInjectValidation.cs similarity index 92% rename from src/Umbraco.Tests/Composing/LightInjectValidation.cs rename to src/Umbraco.Tests.Common/Composing/LightInjectValidation.cs index 75062e613c..4925074b9e 100644 --- a/src/Umbraco.Tests/Composing/LightInjectValidation.cs +++ b/src/Umbraco.Tests.Common/Composing/LightInjectValidation.cs @@ -35,7 +35,7 @@ using ServiceMap = System.Collections.Generic.Dictionary 1; } } diff --git a/src/Umbraco.Tests.Common/Composing/ValidationResultExtensions.cs b/src/Umbraco.Tests.Common/Composing/ValidationResultExtensions.cs new file mode 100644 index 0000000000..cfd136b63c --- /dev/null +++ b/src/Umbraco.Tests.Common/Composing/ValidationResultExtensions.cs @@ -0,0 +1,107 @@ +using System; +using System.Text; +using Umbraco.Core; + +namespace Umbraco.Tests.Common.Composing +{ + // These are used for Light Inject container validation + public static class ValidationResultExtensions + { + public static string ToText(this ValidationResult result) + { + var text = new StringBuilder(); + + text.AppendLine($"{result.Severity}: {WordWrap(result.Message, 120)}"); + var target = result.ValidationTarget; + text.Append("\tsvce: "); + text.Append(target.ServiceName); + text.Append(target.DeclaringService.ServiceType); + if (!target.DeclaringService.ServiceName.IsNullOrWhiteSpace()) + { + text.Append(" '"); + text.Append(target.DeclaringService.ServiceName); + text.Append("'"); + } + + text.Append(" ("); + if (target.DeclaringService.Lifetime == null) + text.Append("Transient"); + else + text.Append(target.DeclaringService.Lifetime.ToString().TrimStart("LightInject.").TrimEnd("Lifetime")); + text.AppendLine(")"); + text.Append("\timpl: "); + text.Append(target.DeclaringService.ImplementingType); + text.AppendLine(); + text.Append("\tparm: "); + text.Append(target.Parameter); + text.AppendLine(); + + return text.ToString(); + } + + private static string WordWrap(string text, int width) + { + int pos, next; + var sb = new StringBuilder(); + var nl = Environment.NewLine; + + // Lucidity check + if (width < 1) + return text; + + // Parse each line of text + for (pos = 0; pos < text.Length; pos = next) + { + // Find end of line + var eol = text.IndexOf(nl, pos, StringComparison.Ordinal); + + if (eol == -1) + next = eol = text.Length; + else + next = eol + nl.Length; + + // Copy this line of text, breaking into smaller lines as needed + if (eol > pos) + { + do + { + var len = eol - pos; + + if (len > width) + len = BreakLine(text, pos, width); + + if (pos > 0) + sb.Append("\t\t"); + sb.Append(text, pos, len); + sb.Append(nl); + + // Trim whitespace following break + pos += len; + + while (pos < eol && char.IsWhiteSpace(text[pos])) + pos++; + + } while (eol > pos); + } + else sb.Append(nl); // Empty line + } + + return sb.ToString(); + } + + private static int BreakLine(string text, int pos, int max) + { + // Find last whitespace in line + var i = max - 1; + while (i >= 0 && !char.IsWhiteSpace(text[pos + i])) + i--; + if (i < 0) + return max; // No whitespace found; break at maximum length + // Find start of whitespace + while (i >= 0 && char.IsWhiteSpace(text[pos + i])) + i--; + // Return length of text before whitespace + return i + 1; + } + } +} diff --git a/src/Umbraco.Tests.Common/SettingsForTests.cs b/src/Umbraco.Tests.Common/SettingsForTests.cs new file mode 100644 index 0000000000..f7427009ba --- /dev/null +++ b/src/Umbraco.Tests.Common/SettingsForTests.cs @@ -0,0 +1,182 @@ +using Moq; +using Semver; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Legacy; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Tests.Common +{ + public class SettingsForTests + { + public SettingsForTests() + { + } + + public IGlobalSettings GenerateMockGlobalSettings(IUmbracoVersion umbVersion = null) + { + var semanticVersion = umbVersion?.SemanticVersion ?? new SemVersion(9); + + var config = Mock.Of( + settings => + settings.ConfigurationStatus == semanticVersion.ToSemanticString() && + settings.UseHttps == false && + settings.HideTopLevelNodeFromPath == false && + settings.Path == "~/umbraco" && + settings.TimeOutInMinutes == 20 && + settings.DefaultUILanguage == "en" && + settings.ReservedPaths == (GlobalSettings.StaticReservedPaths + "~/umbraco") && + settings.ReservedUrls == GlobalSettings.StaticReservedUrls && + settings.UmbracoPath == "~/umbraco" && + settings.UmbracoMediaPath == "~/media" && + settings.UmbracoCssPath == "~/css" && + settings.UmbracoScriptsPath == "~/scripts" + ); + + + + return config; + } + + /// + /// Returns generated settings which can be stubbed to return whatever values necessary + /// + /// + public IContentSettings GenerateMockContentSettings() + { + + var content = new Mock(); + + //Now configure some defaults - the defaults in the config section classes do NOT pertain to the mocked data!! + content.Setup(x => x.ImageAutoFillProperties).Returns(ContentImagingElement.GetDefaultImageAutoFillProperties()); + content.Setup(x => x.ImageFileTypes).Returns(ContentImagingElement.GetDefaultImageFileTypes()); + return content.Object; + } + + //// from appSettings + + //private readonly IDictionary SavedAppSettings = new Dictionary(); + + //static void SaveSetting(string key) + //{ + // SavedAppSettings[key] = ConfigurationManager.AppSettings[key]; + //} + + //static void SaveSettings() + //{ + // SaveSetting("umbracoHideTopLevelNodeFromPath"); + // SaveSetting("umbracoUseDirectoryUrls"); + // SaveSetting("umbracoPath"); + // SaveSetting("umbracoReservedPaths"); + // SaveSetting("umbracoReservedUrls"); + // SaveSetting("umbracoConfigurationStatus"); + //} + + + + // reset & defaults + + //static SettingsForTests() + //{ + // //SaveSettings(); + //} + + public void Reset() + { + ResetSettings(); + GlobalSettings.Reset(); + + //foreach (var kvp in SavedAppSettings) + // ConfigurationManager.AppSettings.Set(kvp.Key, kvp.Value); + + //// set some defaults that are wrong in the config file?! + //// this is annoying, really + //HideTopLevelNodeFromPath = false; + } + + /// + /// This sets all settings back to default settings + /// + private void ResetSettings() + { + _defaultGlobalSettings = null; + } + + private IGlobalSettings _defaultGlobalSettings; + private IHostingSettings _defaultHostingSettings; + + public IGlobalSettings GetDefaultGlobalSettings(IUmbracoVersion umbVersion) + { + if (_defaultGlobalSettings == null) + { + _defaultGlobalSettings = GenerateMockGlobalSettings(umbVersion); + } + return _defaultGlobalSettings; + } + + public IHostingSettings GetDefaultHostingSettings() + { + if (_defaultHostingSettings == null) + { + _defaultHostingSettings = GenerateMockHostingSettings(); + } + return _defaultHostingSettings; + } + + private IHostingSettings GenerateMockHostingSettings() + { + var config = Mock.Of( + settings => + settings.LocalTempStorageLocation == LocalTempStorage.EnvironmentTemp && + settings.DebugMode == false + ); + return config; + } + + public IWebRoutingSettings GenerateMockWebRoutingSettings() + { + var mock = new Mock(); + + mock.Setup(x => x.DisableRedirectUrlTracking).Returns(false); + mock.Setup(x => x.InternalRedirectPreservesTemplate).Returns(false); + mock.Setup(x => x.UrlProviderMode).Returns(UrlMode.Auto.ToString()); + + return mock.Object; + } + + public IRequestHandlerSettings GenerateMockRequestHandlerSettings() + { + var mock = new Mock(); + + mock.Setup(x => x.AddTrailingSlash).Returns(true); + mock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + mock.Setup(x => x.TryConvertUrlsToAscii).Returns(false); + mock.Setup(x => x.CharCollection).Returns(RequestHandlerElement.GetDefaultCharReplacements); + + return mock.Object; + } + + public ISecuritySettings GenerateMockSecuritySettings() + { + var security = new Mock(); + + return security.Object; + } + + public IUserPasswordConfiguration GenerateMockUserPasswordConfiguration() + { + var mock = new Mock(); + + return mock.Object; + } + + public IMemberPasswordConfiguration GenerateMockMemberPasswordConfiguration() + { + var mock = new Mock(); + + return mock.Object; + } + } +} diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestDefaultCultureAccessor.cs b/src/Umbraco.Tests.Common/TestDefaultCultureAccessor.cs similarity index 86% rename from src/Umbraco.Tests/Testing/Objects/Accessors/TestDefaultCultureAccessor.cs rename to src/Umbraco.Tests.Common/TestDefaultCultureAccessor.cs index 41bd70626c..e1bec33c94 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestDefaultCultureAccessor.cs +++ b/src/Umbraco.Tests.Common/TestDefaultCultureAccessor.cs @@ -1,6 +1,6 @@ using Umbraco.Web.PublishedCache; -namespace Umbraco.Tests.Testing.Objects.Accessors +namespace Umbraco.Tests.Common { public class TestDefaultCultureAccessor : IDefaultCultureAccessor { diff --git a/src/Umbraco.Tests.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs new file mode 100644 index 0000000000..67108833c3 --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelperBase.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; +using System.Reflection; +using Moq; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Net; +using Umbraco.Core.Persistence; +using Umbraco.Core.Serialization; +using Umbraco.Core.Strings; +using Umbraco.Core.Sync; +using Umbraco.Web; +using Umbraco.Web.Routing; + +namespace Umbraco.Tests.Common +{ + /// + /// Common helper properties and methods useful to testing + /// + public abstract class TestHelperBase + { + private readonly ITypeFinder _typeFinder; + private UriUtility _uriUtility; + private IIOHelper _ioHelper; + + protected TestHelperBase(Assembly entryAssembly) + { + SettingsForTests = new SettingsForTests(); + MainDom = new SimpleMainDom(); + _typeFinder = new TypeFinder(Mock.Of(), new DefaultUmbracoAssemblyProvider(entryAssembly)); + } + + public ITypeFinder GetTypeFinder() => _typeFinder; + + public TypeLoader GetMockedTypeLoader() + { + return new TypeLoader(IOHelper, Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of()); + } + + public Configs GetConfigs() => GetConfigsFactory().Create(); + + public IRuntimeState GetRuntimeState() + { + return new RuntimeState( + Mock.Of(), + Mock.Of(), + GetUmbracoVersion(), + GetBackOfficeInfo()); + } + + public abstract IBackOfficeInfo GetBackOfficeInfo(); + + public IConfigsFactory GetConfigsFactory() => new ConfigsFactory(); + + /// + /// Gets the current assembly directory. + /// + /// The assembly directory. + public string CurrentAssemblyDirectory + { + get + { + var codeBase = typeof(TestHelperBase).Assembly.CodeBase; + var uri = new Uri(codeBase); + var path = uri.LocalPath; + return Path.GetDirectoryName(path); + } + } + + public IShortStringHelper ShortStringHelper { get; } = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); + public IJsonSerializer JsonSerializer { get; } = new JsonNetSerializer(); + public IVariationContextAccessor VariationContextAccessor { get; } = new TestVariationContextAccessor(); + public abstract IDbProviderFactoryCreator DbProviderFactoryCreator { get; } + public abstract IBulkSqlInsertProvider BulkSqlInsertProvider { get; } + public abstract IMarchal Marchal { get; } + public ICoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings(); + + public IIOHelper IOHelper + { + get + { + if (_ioHelper == null) + _ioHelper = new IOHelper(GetHostingEnvironment(), SettingsForTests.GenerateMockGlobalSettings()); + return _ioHelper; + } + } + + public IMainDom MainDom { get; } + public UriUtility UriUtility + { + get + { + if (_uriUtility == null) + _uriUtility = new UriUtility(GetHostingEnvironment()); + return _uriUtility; + } + } + + public SettingsForTests SettingsForTests { get; } + public IWebRoutingSettings WebRoutingSettings => SettingsForTests.GenerateMockWebRoutingSettings(); + + /// + /// Maps the given making it rooted on . must start with ~/ + /// + /// The relative path. + /// + public string MapPathForTest(string relativePath) + { + if (!relativePath.StartsWith("~/")) + throw new ArgumentException("relativePath must start with '~/'", "relativePath"); + + return relativePath.Replace("~/", CurrentAssemblyDirectory + "/"); + } + + public IUmbracoVersion GetUmbracoVersion() => new UmbracoVersion(GetConfigs().Global()); + + public IRegister GetRegister() + { + return RegisterFactory.Create(GetConfigs().Global()); + } + + public abstract IHostingEnvironment GetHostingEnvironment(); + public abstract IApplicationShutdownRegistry GetHostingEnvironmentLifetime(); + + public abstract IIpResolver GetIpResolver(); + + public IRequestCache GetRequestCache() + { + return new DictionaryAppCache(); + } + + public IPublishedUrlProvider GetPublishedUrlProvider() + { + var mock = new Mock(); + + return mock.Object; + } + } +} diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedSnapshotAccessor.cs b/src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs similarity index 79% rename from src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedSnapshotAccessor.cs rename to src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs index c46915e3a0..ed1ba0b5b9 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestPublishedSnapshotAccessor.cs +++ b/src/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs @@ -1,6 +1,6 @@ using Umbraco.Web.PublishedCache; -namespace Umbraco.Tests.Testing.Objects.Accessors +namespace Umbraco.Tests.Common { public class TestPublishedSnapshotAccessor : IPublishedSnapshotAccessor { diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestUmbracoContextAccessor.cs b/src/Umbraco.Tests.Common/TestUmbracoContextAccessor.cs similarity index 88% rename from src/Umbraco.Tests/Testing/Objects/Accessors/TestUmbracoContextAccessor.cs rename to src/Umbraco.Tests.Common/TestUmbracoContextAccessor.cs index f9862701ea..feaf8eafa5 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestUmbracoContextAccessor.cs +++ b/src/Umbraco.Tests.Common/TestUmbracoContextAccessor.cs @@ -1,6 +1,6 @@ using Umbraco.Web; -namespace Umbraco.Tests.Testing.Objects.Accessors +namespace Umbraco.Tests.Common { public class TestUmbracoContextAccessor : IUmbracoContextAccessor { diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs b/src/Umbraco.Tests.Common/TestVariationContextAccessor.cs similarity index 87% rename from src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs rename to src/Umbraco.Tests.Common/TestVariationContextAccessor.cs index 134b709447..b2a07b74f2 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/TestVariationContextAccessor.cs +++ b/src/Umbraco.Tests.Common/TestVariationContextAccessor.cs @@ -1,6 +1,6 @@ using Umbraco.Core.Models.PublishedContent; -namespace Umbraco.Tests.Testing.Objects.Accessors +namespace Umbraco.Tests.Common { /// /// Provides an implementation of for tests. diff --git a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj new file mode 100644 index 0000000000..e6963bc8aa --- /dev/null +++ b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + diff --git a/src/Umbraco.Tests.Integration/ContainerTests.cs b/src/Umbraco.Tests.Integration/ContainerTests.cs new file mode 100644 index 0000000000..945eeda2f0 --- /dev/null +++ b/src/Umbraco.Tests.Integration/ContainerTests.cs @@ -0,0 +1,119 @@ +using System.Threading.Tasks; +using LightInject; +using LightInject.Microsoft.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Composing.LightInject; +using Umbraco.Core.Configuration; +using Umbraco.Core.Persistence; +using Umbraco.Tests.Common; +using Umbraco.Tests.Integration.Implementations; + +namespace Umbraco.Tests.Integration +{ + + [TestFixture] + public class ContainerTests + { + [Test] + public void CrossWire() + { + // MSDI + var services = new ServiceCollection(); + services.AddSingleton(); + var msdiServiceProvider = services.BuildServiceProvider(); + + // LightInject / Umbraco + var container = UmbracoServiceProviderFactory.CreateServiceContainer(); + var serviceProviderFactory = new UmbracoServiceProviderFactory(container); + var umbracoContainer = serviceProviderFactory.GetContainer(); + serviceProviderFactory.CreateBuilder(services); // called during Host Builder, needed to capture services + + // Dependencies needed for creating composition/register essentials + var testHelper = new TestHelper(); + var runtimeState = Mock.Of(); + var umbracoDatabaseFactory = Mock.Of(); + var dbProviderFactoryCreator = Mock.Of(); + var typeLoader = testHelper.GetMockedTypeLoader(); + + // Register in the container + var composition = new Composition(umbracoContainer, typeLoader, + testHelper.Logger, runtimeState, testHelper.GetConfigs(), testHelper.IOHelper, testHelper.AppCaches); + composition.RegisterEssentials(testHelper.Logger, testHelper.Profiler, testHelper.Logger, testHelper.MainDom, + testHelper.AppCaches, umbracoDatabaseFactory, typeLoader, runtimeState, testHelper.GetTypeFinder(), + testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator, + testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo()); + + // Cross wire - this would be called by the Host Builder at the very end of ConfigureServices + var lightInjectServiceProvider = serviceProviderFactory.CreateServiceProvider(umbracoContainer.Container); + + // From MSDI + var foo1 = msdiServiceProvider.GetService(); + var foo2 = lightInjectServiceProvider.GetService(); + var foo3 = umbracoContainer.GetInstance(); + + Assert.IsNotNull(foo1); + Assert.IsNotNull(foo2); + Assert.IsNotNull(foo3); + + // These are not the same because cross wiring means copying the container, not falling back to a container + Assert.AreNotSame(foo1, foo2); + // These are the same because the umbraco container wraps the light inject container + Assert.AreSame(foo2, foo3); + + Assertions.AssertContainer(umbracoContainer.Container); + } + + [Explicit("This test just shows that resolving services from the container before the host is done resolves 2 different instances")] + [Test] + public async Task BuildServiceProvider_Before_Host_Is_Configured() + { + // This is a test to show an anti-pattern used in netcore. This should be avoided in all cases if possible. + // There's a thread about this here: https://github.com/dotnet/aspnetcore/issues/14587 + // For some reason we are not being warned about this with our code analysis since we are using it + // in a couple of places but we should really try to see if we can avoid it. + // The test below shows how it could be possible to resolve an instance and then re-register it as a factory + // so that only one singleton instance is every created, but it's hacky and like Fowler says in that article + // it means the container won't be disposed, and maybe other services? not sure. + // In cases where we use it can we use IConfigureOptions? https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/ + + var umbracoContainer = RuntimeTests.GetUmbracoContainer(out var serviceProviderFactory); + + IHostApplicationLifetime lifetime1 = null; + + var hostBuilder = new HostBuilder() + .UseUmbraco(serviceProviderFactory) + .ConfigureServices((hostContext, services) => + { + // Resolve a service from the netcore container before the host has finished the ConfigureServices sequence + lifetime1 = services.BuildServiceProvider().GetRequiredService(); + + // Re-add as a callback, ensures its the same instance all the way through (hack) + services.AddSingleton(x => lifetime1); + }); + + var host = await hostBuilder.StartAsync(); + + var lifetime2 = host.Services.GetRequiredService(); + var lifetime3 = umbracoContainer.GetInstance(); + + lifetime1.StopApplication(); + Assert.IsTrue(lifetime1.ApplicationStopping.IsCancellationRequested); + Assert.AreEqual(lifetime1.ApplicationStopping.IsCancellationRequested, lifetime2.ApplicationStopping.IsCancellationRequested); + Assert.AreEqual(lifetime1.ApplicationStopping.IsCancellationRequested, lifetime3.ApplicationStopping.IsCancellationRequested); + + } + + private class Foo + { + public Foo() + { + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Implementations/HostBuilderExtensions.cs b/src/Umbraco.Tests.Integration/Implementations/HostBuilderExtensions.cs new file mode 100644 index 0000000000..60cac26349 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Implementations/HostBuilderExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data.SqlClient; +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Umbraco.Core; +using Umbraco.Tests.Integration.Testing; + +namespace Umbraco.Tests.Integration.Implementations +{ + public static class HostBuilderExtensions + { + + public static IHostBuilder UseLocalDb(this IHostBuilder hostBuilder, string dbFilePath) + { + // Need to register SqlClient manually + // TODO: Move this to someplace central + DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); + + hostBuilder.ConfigureAppConfiguration(x => + { + if (!Directory.Exists(dbFilePath)) + Directory.CreateDirectory(dbFilePath); + + var dbName = Guid.NewGuid().ToString("N"); + var instance = TestLocalDb.EnsureLocalDbInstanceAndDatabase(dbName, dbFilePath); + + x.AddInMemoryCollection(new[] + { + new KeyValuePair($"ConnectionStrings:{Constants.System.UmbracoConnectionName}", instance.GetConnectionString(dbName)) + }); + }); + return hostBuilder; + } + + + } + + +} diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs new file mode 100644 index 0000000000..4a986fa35a --- /dev/null +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -0,0 +1,85 @@ + +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Hosting; +using Moq; +using System.Data.Common; +using System.Net; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Hosting; +using Umbraco.Core.Logging; +using Umbraco.Net; +using Umbraco.Core.Persistence; +using Umbraco.Core.Runtime; +using Umbraco.Tests.Common; +using Umbraco.Web.BackOffice; +using Umbraco.Web.BackOffice.AspNetCore; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; + +namespace Umbraco.Tests.Integration.Implementations +{ + public class TestHelper : TestHelperBase + { + private IBackOfficeInfo _backOfficeInfo; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationShutdownRegistry _hostingLifetime; + private readonly IIpResolver _ipResolver; + private readonly IWebHostEnvironment _hostEnvironment; + private readonly IHttpContextAccessor _httpContextAccessor; + + public TestHelper() : base(typeof(TestHelper).Assembly) + { + var httpContext = new DefaultHttpContext(); + httpContext.Connection.RemoteIpAddress = IPAddress.Parse("127.0.0.1"); + _httpContextAccessor = Mock.Of(x => x.HttpContext == httpContext); + _ipResolver = new AspNetIpResolver(_httpContextAccessor); + + _hostEnvironment = Mock.Of(x => + x.ApplicationName == "UmbracoIntegrationTests" + && x.ContentRootPath == CurrentAssemblyDirectory + && x.WebRootPath == CurrentAssemblyDirectory); // same folder for now? + + _hostingEnvironment = new TestHostingEnvironment( + SettingsForTests.GetDefaultHostingSettings(), + _hostEnvironment, + _httpContextAccessor); + + _hostingLifetime = new AspNetCoreApplicationShutdownRegistry(Mock.Of()); + + Logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), Profiler); + } + + public IUmbracoBootPermissionChecker UmbracoBootPermissionChecker { get; } = new TestUmbracoBootPermissionChecker(); + + public AppCaches AppCaches { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(type => NoAppCache.Instance)); + + public IProfilingLogger Logger { get; private set; } + + public IProfiler Profiler { get; } = new VoidProfiler(); + + public IHttpContextAccessor GetHttpContextAccessor() => _httpContextAccessor; + + public IWebHostEnvironment GetWebHostEnvironment() => _hostEnvironment; + + public override IDbProviderFactoryCreator DbProviderFactoryCreator => new SqlServerDbProviderFactoryCreator(Constants.DbProviderNames.SqlServer, DbProviderFactories.GetFactory); + + public override IBulkSqlInsertProvider BulkSqlInsertProvider => new SqlServerBulkSqlInsertProvider(); + + public override IMarchal Marchal { get; } = new AspNetCoreMarchal(); + + public override IBackOfficeInfo GetBackOfficeInfo() + { + if (_backOfficeInfo == null) + _backOfficeInfo = new AspNetCoreBackOfficeInfo(SettingsForTests.GetDefaultGlobalSettings(GetUmbracoVersion())); + return _backOfficeInfo; + } + + public override IHostingEnvironment GetHostingEnvironment() => _hostingEnvironment; + public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _hostingLifetime; + + public override IIpResolver GetIpResolver() => _ipResolver; + + } +} diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs new file mode 100644 index 0000000000..491b7e5480 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Umbraco.Core.Configuration; +using Umbraco.Web.BackOffice.AspNetCore; + +namespace Umbraco.Tests.Integration.Implementations +{ + + public class TestHostingEnvironment : AspNetCoreHostingEnvironment, Umbraco.Core.Hosting.IHostingEnvironment + { + public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor) : base(hostingSettings, webHostEnvironment, httpContextAccessor) + { + } + + /// + /// Override for tests since we are not hosted + /// + /// + /// This is specifically used by IOHelper and we want this to return false so that the root path is manually calcualted which is what we want for tests. + /// + bool Umbraco.Core.Hosting.IHostingEnvironment.IsHosted { get; } = false; + } +} diff --git a/src/Umbraco.Tests.Integration/Implementations/TestLifetime.cs b/src/Umbraco.Tests.Integration/Implementations/TestLifetime.cs new file mode 100644 index 0000000000..a18360eff9 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Implementations/TestLifetime.cs @@ -0,0 +1,18 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; + +namespace Umbraco.Tests.Integration.Implementations +{ + /// + /// Ensures the host lifetime ends as soon as code execution is done + /// + public class TestLifetime : IHostLifetime + { + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + public Task WaitForStartAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } + + +} diff --git a/src/Umbraco.Tests.Integration/Implementations/TestUmbracoBootPermissionChecker.cs b/src/Umbraco.Tests.Integration/Implementations/TestUmbracoBootPermissionChecker.cs new file mode 100644 index 0000000000..b4f876fc66 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Implementations/TestUmbracoBootPermissionChecker.cs @@ -0,0 +1,11 @@ +using Umbraco.Core.Runtime; + +namespace Umbraco.Tests.Integration.Implementations +{ + public class TestUmbracoBootPermissionChecker : IUmbracoBootPermissionChecker + { + public void ThrowIfNotPermissions() + { + } + } +} diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs new file mode 100644 index 0000000000..0e11a29b95 --- /dev/null +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -0,0 +1,284 @@ +using LightInject; +using LightInject.Microsoft.DependencyInjection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Moq; +using NUnit.Framework; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Composing.LightInject; +using Umbraco.Core.Logging; +using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Persistence; +using Umbraco.Core.Runtime; +using Umbraco.Tests.Common; +using Umbraco.Tests.Integration.Implementations; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Web.BackOffice.AspNetCore; +using static Umbraco.Core.Migrations.Install.DatabaseBuilder; + +namespace Umbraco.Tests.Integration +{ + + [TestFixture] + public class RuntimeTests + { + [TearDown] + public void TearDown() + { + MyComponent.Reset(); + MyComposer.Reset(); + } + + [OneTimeTearDown] + public void FixtureTearDown() + { + TestLocalDb.Cleanup(); + } + + /// + /// Manually configure the containers/dependencies and call Boot on Core runtime + /// + [Test] + public void Boot_Core_Runtime() + { + // LightInject / Umbraco + var container = UmbracoServiceProviderFactory.CreateServiceContainer(); + var serviceProviderFactory = new UmbracoServiceProviderFactory(container); + var umbracoContainer = serviceProviderFactory.GetContainer(); + + // Special case since we are not using the Generic Host, we need to manually add an AspNetCore service to the container + umbracoContainer.Register(x => Mock.Of()); + + var testHelper = new TestHelper(); + + // Create the core runtime + var coreRuntime = new CoreRuntime(testHelper.GetConfigs(), testHelper.GetUmbracoVersion(), + testHelper.IOHelper, testHelper.Logger, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker, + testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator, + testHelper.MainDom, testHelper.GetTypeFinder()); + + // boot it! + var factory = coreRuntime.Configure(umbracoContainer); + + Assert.IsTrue(coreRuntime.MainDom.IsMainDom); + Assert.IsNull(coreRuntime.State.BootFailedException); + Assert.AreEqual(RuntimeLevel.Install, coreRuntime.State.Level); + Assert.IsTrue(MyComposer.IsComposed); + Assert.IsFalse(MyComponent.IsInit); + Assert.IsFalse(MyComponent.IsTerminated); + + coreRuntime.Start(); + + Assert.IsTrue(MyComponent.IsInit); + Assert.IsFalse(MyComponent.IsTerminated); + + Assertions.AssertContainer(umbracoContainer.Container, reportOnly: true); // TODO Change that to false eventually when we clean up the container + + coreRuntime.Terminate(); + + Assert.IsTrue(MyComponent.IsTerminated); + } + + /// + /// Calling AddUmbracoCore to configure the container + /// + [Test] + public async Task AddUmbracoCore() + { + var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory); + var testHelper = new TestHelper(); + + var hostBuilder = new HostBuilder() + .UseUmbraco(serviceProviderFactory) + .ConfigureServices((hostContext, services) => + { + var webHostEnvironment = testHelper.GetWebHostEnvironment(); + AddRequiredNetCoreServices(services, testHelper, webHostEnvironment); + + // Add it! + services.AddUmbracoConfiguration(hostContext.Configuration); + services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly); + }); + + var host = await hostBuilder.StartAsync(); + var app = new ApplicationBuilder(host.Services); + + // assert results + var runtimeState = app.ApplicationServices.GetRequiredService(); + var mainDom = app.ApplicationServices.GetRequiredService(); + + Assert.IsFalse(mainDom.IsMainDom); // We haven't "Started" the runtime yet + Assert.IsNull(runtimeState.BootFailedException); + Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); + Assert.IsFalse(MyComponent.IsInit); // We haven't "Started" the runtime yet + + await host.StopAsync(); + + Assert.IsFalse(MyComponent.IsTerminated); // we didn't "Start" the runtime so nothing was registered for shutdown + } + + /// + /// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime + /// + /// + [Test] + public async Task UseUmbracoCore() + { + var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory); + var testHelper = new TestHelper(); + + var hostBuilder = new HostBuilder() + .UseUmbraco(serviceProviderFactory) + .ConfigureServices((hostContext, services) => + { + var webHostEnvironment = testHelper.GetWebHostEnvironment(); + AddRequiredNetCoreServices(services, testHelper, webHostEnvironment); + + // Add it! + services.AddUmbracoConfiguration(hostContext.Configuration); + services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly); + }); + + var host = await hostBuilder.StartAsync(); + var app = new ApplicationBuilder(host.Services); + + app.UseUmbracoCore(); + + + // assert results + var runtimeState = app.ApplicationServices.GetRequiredService(); + var mainDom = app.ApplicationServices.GetRequiredService(); + + Assert.IsTrue(mainDom.IsMainDom); + Assert.IsNull(runtimeState.BootFailedException); + Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); + Assert.IsTrue(MyComponent.IsInit); + + await host.StopAsync(); + + Assert.IsTrue(MyComponent.IsTerminated); + } + + [Test] + public async Task Install_Database() + { + var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory); + var testHelper = new TestHelper(); + + var hostBuilder = new HostBuilder() + //TODO: Need to have a configured umb version for the runtime state + .UseLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb")) + .UseUmbraco(serviceProviderFactory) + .ConfigureServices((hostContext, services) => + { + var webHostEnvironment = testHelper.GetWebHostEnvironment(); + AddRequiredNetCoreServices(services, testHelper, webHostEnvironment); + + // Add it! + services.AddUmbracoConfiguration(hostContext.Configuration); + services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly); + }); + + var host = await hostBuilder.StartAsync(); + var app = new ApplicationBuilder(host.Services); + + app.UseUmbracoCore(); + + + var runtimeState = (RuntimeState)app.ApplicationServices.GetRequiredService(); + Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); + + var dbBuilder = app.ApplicationServices.GetRequiredService(); + Assert.IsNotNull(dbBuilder); + + var canConnect = dbBuilder.CanConnectToDatabase; + Assert.IsTrue(canConnect); + + var dbResult = dbBuilder.CreateSchemaAndData(); + Assert.IsTrue(dbResult.Success); + + // TODO: Get this to work ... but to do that we need to mock or pass in a current umbraco version + //var dbFactory = app.ApplicationServices.GetRequiredService(); + //var profilingLogger = app.ApplicationServices.GetRequiredService(); + //runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger); + //Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level); + } + + internal static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory) + { + var container = UmbracoServiceProviderFactory.CreateServiceContainer(); + serviceProviderFactory = new UmbracoServiceProviderFactory(container); + var umbracoContainer = serviceProviderFactory.GetContainer(); + return umbracoContainer; + } + + /// + /// These services need to be manually added because they do not get added by the generic host + /// + /// + /// + /// + private void AddRequiredNetCoreServices(IServiceCollection services, TestHelper testHelper, IWebHostEnvironment webHostEnvironment) + { + services.AddSingleton(x => testHelper.GetHttpContextAccessor()); + // the generic host does add IHostEnvironment but not this one because we are not actually in a web context + services.AddSingleton(x => webHostEnvironment); + } + + [RuntimeLevel(MinLevel = RuntimeLevel.Install)] + public class MyComposer : IUserComposer + { + public void Compose(Composition composition) + { + composition.Components().Append(); + IsComposed = true; + } + + public static void Reset() + { + IsComposed = false; + } + + public static bool IsComposed { get; private set; } + } + + public class MyComponent : IComponent + { + public static bool IsInit { get; private set; } + public static bool IsTerminated { get; private set; } + + private readonly ILogger _logger; + + public MyComponent(ILogger logger) + { + _logger = logger; + } + + public void Initialize() + { + IsInit = true; + } + + public void Terminate() + { + IsTerminated = true; + } + + public static void Reset() + { + IsTerminated = false; + IsInit = false; + } + } + } + + +} diff --git a/src/Umbraco.Tests.Integration/Testing/TestLocalDb.cs b/src/Umbraco.Tests.Integration/Testing/TestLocalDb.cs new file mode 100644 index 0000000000..8ee326783b --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/TestLocalDb.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Umbraco.Core.Persistence; + +namespace Umbraco.Tests.Integration.Testing +{ + public static class TestLocalDb + { + private const string LocalDbInstanceName = "UmbTests"; + + private static LocalDb LocalDb { get; } = new LocalDb(); + + // TODO: We need to borrow logic from this old branch, this is the latest commit at the old branch where we had LocalDb + // working for tests. There's a lot of hoops to jump through to make it work 'fast'. Turns out it didn't actually run as + // fast as SqlCe due to the dropping/creating of DB instances since that is faster in SqlCe but this code was all heavily + // optimized to go as fast as possible. + // see https://github.com/umbraco/Umbraco-CMS/blob/3a8716ac7b1c48b51258724337086cd0712625a1/src/Umbraco.Tests/TestHelpers/LocalDbTestDatabase.cs + internal static LocalDb.Instance EnsureLocalDbInstanceAndDatabase(string dbName, string dbFilePath) + { + if (!LocalDb.InstanceExists(LocalDbInstanceName) && !LocalDb.CreateInstance(LocalDbInstanceName)) + { + throw new InvalidOperationException( + $"Failed to create LocalDb instance {LocalDbInstanceName}, assuming LocalDb is not really available."); + } + + var instance = LocalDb.GetInstance(LocalDbInstanceName); + + if (instance == null) + { + throw new InvalidOperationException( + $"Failed to get LocalDb instance {LocalDbInstanceName}, assuming LocalDb is not really available."); + } + + instance.CreateDatabase(dbName, dbFilePath); + + return instance; + } + + public static void Cleanup() + { + var instance = LocalDb.GetInstance(LocalDbInstanceName); + if (instance != null) + { + instance.DropDatabases(); + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj new file mode 100644 index 0000000000..320db33568 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -0,0 +1,28 @@ + + + + Exe + netcoreapp3.1 + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/Umbraco.Tests.Shared/Umbraco.Tests.Shared.csproj b/src/Umbraco.Tests.Shared/Umbraco.Tests.Shared.csproj new file mode 100644 index 0000000000..43cd79bd6e --- /dev/null +++ b/src/Umbraco.Tests.Shared/Umbraco.Tests.Shared.csproj @@ -0,0 +1,30 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs new file mode 100644 index 0000000000..c5acba362b --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs @@ -0,0 +1,39 @@ +using Microsoft.Extensions.Configuration; +using Moq; +using NUnit.Framework; +using Umbraco.Configuration.Models; +using Umbraco.Core; + +namespace Umbraco.Tests.UnitTests.Umbraco.Configuration.Models +{ + public class ConnectionStringsTests + { + [Test] + [TestCase("", ExpectedResult = null)] + [TestCase(null, ExpectedResult = null)] + [TestCase(@"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;", ExpectedResult = Constants.DbProviderNames.SqlCe)] + [TestCase(@"Server=(LocalDb)\Umbraco;Database=NetCore;Integrated Security=true", ExpectedResult = Constants.DbProviderNames.SqlServer)] + public string ParseProviderName(string connectionString) + { + var key = Constants.System.UmbracoConnectionName; + var configuration = new Mock(); + + + //This is the underlying method that is called by Configuration.GetConnectionString(string) + if (connectionString != null) + { + configuration.Setup(x => x.GetSection("ConnectionStrings")[key]).Returns(connectionString); + } + + + var connectionStrings = new ConnectionStrings(configuration.Object); + + var actual = connectionStrings[key]; + + Assert.AreEqual(connectionString, actual.ConnectionString); + Assert.AreEqual(key, actual.Name); + + return connectionStrings[key].ProviderName; + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs new file mode 100644 index 0000000000..a097661a93 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; + + +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +{ + [TestFixture] + public class DataTypeTests + { + + private readonly DataTypeBuilder _builder = new DataTypeBuilder(); + [Test] + public void Can_Deep_Clone() + { + var dtd = _builder + .WithId(3123) + .Build(); + + var clone = (DataType) dtd.DeepClone(); + + Assert.AreNotSame(clone, dtd); + Assert.AreEqual(clone, dtd); + Assert.AreEqual(clone.CreateDate, dtd.CreateDate); + Assert.AreEqual(clone.CreatorId, dtd.CreatorId); + Assert.AreEqual(clone.DatabaseType, dtd.DatabaseType); + Assert.AreEqual(clone.Id, dtd.Id); + Assert.AreEqual(clone.Key, dtd.Key); + Assert.AreEqual(clone.Level, dtd.Level); + Assert.AreEqual(clone.Name, dtd.Name); + Assert.AreEqual(clone.ParentId, dtd.ParentId); + Assert.AreEqual(clone.Path, dtd.Path); + Assert.AreEqual(clone.SortOrder, dtd.SortOrder); + Assert.AreEqual(clone.Trashed, dtd.Trashed); + Assert.AreEqual(clone.UpdateDate, dtd.UpdateDate); + + //This double verifies by reflection + var allProps = clone.GetType().GetProperties(); + foreach (var propertyInfo in allProps) + { + Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(dtd, null)); + } + } + + [Test] + public void Can_Serialize_Without_Error() + { + var item = _builder.Build(); + + Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); + } + + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryItemTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryItemTests.cs new file mode 100644 index 0000000000..28878a2463 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryItemTests.cs @@ -0,0 +1,57 @@ +using System.Linq; +using Newtonsoft.Json; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +{ + [TestFixture] + public class DictionaryItemTests + { + private readonly DictionaryItemBuilder _builder = new DictionaryItemBuilder(); + + [Test] + public void Can_Deep_Clone() + { + var item = _builder + .WithRandomTranslations(2) + .Build(); + + var clone = (DictionaryItem)item.DeepClone(); + + Assert.AreNotSame(clone, item); + Assert.AreEqual(clone, item); + Assert.AreEqual(clone.CreateDate, item.CreateDate); + Assert.AreEqual(clone.Id, item.Id); + Assert.AreEqual(clone.ItemKey, item.ItemKey); + Assert.AreEqual(clone.Key, item.Key); + Assert.AreEqual(clone.ParentId, item.ParentId); + Assert.AreEqual(clone.UpdateDate, item.UpdateDate); + Assert.AreEqual(clone.Translations.Count(), item.Translations.Count()); + for (var i = 0; i < item.Translations.Count(); i++) + { + Assert.AreNotSame(clone.Translations.ElementAt(i), item.Translations.ElementAt(i)); + Assert.AreEqual(clone.Translations.ElementAt(i), item.Translations.ElementAt(i)); + } + + //This double verifies by reflection + var allProps = clone.GetType().GetProperties(); + foreach (var propertyInfo in allProps) + { + Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); + } + + } + + [Test] + public void Can_Serialize_Without_Error() + { + var item = _builder + .WithRandomTranslations(2) + .Build(); + + Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); + } + } +} diff --git a/src/Umbraco.Tests/Models/LanguageTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/LanguageTests.cs similarity index 50% rename from src/Umbraco.Tests/Models/LanguageTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/LanguageTests.cs index 36986d68ae..bb82e69fa6 100644 --- a/src/Umbraco.Tests/Models/LanguageTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/LanguageTests.cs @@ -1,32 +1,19 @@ -using System; -using System.Diagnostics; -using Newtonsoft.Json; +using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core.Configuration; using Umbraco.Core.Models; -using Umbraco.Core.Serialization; -using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Common.Builders; -namespace Umbraco.Tests.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models { [TestFixture] public class LanguageTests { - private IGlobalSettings GlobalSettings { get; } = SettingsForTests.GenerateMockGlobalSettings(); + private readonly LanguageBuilder _builder = new LanguageBuilder(); [Test] public void Can_Deep_Clone() { - var item = new Language(GlobalSettings, "en-AU") - { - CreateDate = DateTime.Now, - CultureName = "AU", - Id = 11, - IsoCode = "en", - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }; + var item = _builder.Build(); var clone = (Language) item.DeepClone(); Assert.AreNotSame(clone, item); @@ -49,18 +36,9 @@ namespace Umbraco.Tests.Models [Test] public void Can_Serialize_Without_Error() { - var item = new Language(GlobalSettings, "en-AU") - { - CreateDate = DateTime.Now, - CultureName = "AU", - Id = 11, - IsoCode = "en", - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }; + var item = _builder.Build(); - var json = JsonConvert.SerializeObject(item); - Debug.Print(json); + Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); } } } diff --git a/src/Umbraco.Tests/Models/RelationTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs similarity index 56% rename from src/Umbraco.Tests/Models/RelationTypeTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs index bc5572d563..29ad8251cc 100644 --- a/src/Umbraco.Tests/Models/RelationTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs @@ -1,39 +1,37 @@ using System; -using System.Diagnostics; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; -using Umbraco.Core.Serialization; +using Umbraco.Tests.Common.Builders; -namespace Umbraco.Tests.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models { [TestFixture] public class RelationTypeTests { + private readonly RelationTypeBuilder _builder = new RelationTypeBuilder(); + [Test] public void Can_Deep_Clone() { - var item = new RelationType("test", "test", false, Guid.NewGuid(), Guid.NewGuid()) - { - Id = 66, - CreateDate = DateTime.Now, - IsBidirectional = true, - Key = Guid.NewGuid(), - Name = "Test", - UpdateDate = DateTime.Now - }; + var item = _builder + .WithParentObjectType(Guid.NewGuid()) + .WithChildObjectType(Guid.NewGuid()) + .Build(); - var clone = (RelationType)item.DeepClone(); + var clone = (RelationType) item.DeepClone(); Assert.AreNotSame(clone, item); Assert.AreEqual(clone, item); Assert.AreEqual(clone.Alias, item.Alias); Assert.AreEqual(clone.ChildObjectType, item.ChildObjectType); + Assert.AreEqual(clone.ParentObjectType, item.ParentObjectType); Assert.AreEqual(clone.IsBidirectional, item.IsBidirectional); Assert.AreEqual(clone.Id, item.Id); Assert.AreEqual(clone.Key, item.Key); Assert.AreEqual(clone.Name, item.Name); Assert.AreNotSame(clone.ParentObjectType, item.ParentObjectType); + Assert.AreNotSame(clone.ChildObjectType, item.ChildObjectType); Assert.AreEqual(clone.UpdateDate, item.UpdateDate); //This double verifies by reflection @@ -47,18 +45,9 @@ namespace Umbraco.Tests.Models [Test] public void Can_Serialize_Without_Error() { - var item = new RelationType("test", "test", false, Guid.NewGuid(), Guid.NewGuid()) - { - Id = 66, - CreateDate = DateTime.Now, - IsBidirectional = true, - Key = Guid.NewGuid(), - Name = "Test", - UpdateDate = DateTime.Now - }; + var item = _builder.Build(); - var json = JsonConvert.SerializeObject(item); - Debug.Print(json); + Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj new file mode 100644 index 0000000000..f60b400f3f --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj @@ -0,0 +1,31 @@ + + + + Exe + netcoreapp3.1 + false + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Tests/Cache/AppCacheTests.cs b/src/Umbraco.Tests/Cache/AppCacheTests.cs index 3a86feb90a..bb283064c7 100644 --- a/src/Umbraco.Tests/Cache/AppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/AppCacheTests.cs @@ -229,7 +229,7 @@ namespace Umbraco.Tests.Cache Assert.AreEqual(4, GetTotalItemCount); //Provider.ClearCacheObjectTypes("umbraco.MacroCacheContent"); - AppCache.ClearOfType(typeof(MacroCacheContent).ToString()); + AppCache.ClearOfType(); Assert.AreEqual(1, GetTotalItemCount); } diff --git a/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs index 3a504ad4e2..63e481e9a5 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneAppCacheTests.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Tests.Collections; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Cache; namespace Umbraco.Tests.Cache @@ -28,8 +29,7 @@ namespace Umbraco.Tests.Cache public override void Setup() { base.Setup(); - var typeFinder = new TypeFinder(Mock.Of()); - _memberCache = new ObjectCacheAppCache(typeFinder); + _memberCache = new ObjectCacheAppCache(); _provider = new DeepCloneAppCache(_memberCache); } diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index 5fb4b19168..eedcc498c5 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -10,9 +10,9 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Serialization; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache; diff --git a/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs index b9c948c1de..2eea382bd3 100644 --- a/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/HttpRequestAppCacheTests.cs @@ -16,9 +16,8 @@ namespace Umbraco.Tests.Cache public override void Setup() { base.Setup(); - var typeFinder = new TypeFinder(Mock.Of()); _ctx = new FakeHttpContextFactory("http://localhost/test"); - _appCache = new HttpRequestAppCache(() => _ctx.HttpContext.Items, typeFinder); + _appCache = new HttpRequestAppCache(() => _ctx.HttpContext.Items); } internal override IAppCache AppCache diff --git a/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs b/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs index 772e92cabe..3172738bf7 100644 --- a/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs +++ b/src/Umbraco.Tests/Cache/ObjectAppCacheTests.cs @@ -1,10 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using Moq; +using System.Linq; using NUnit.Framework; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Cache { @@ -21,8 +18,7 @@ namespace Umbraco.Tests.Cache public override void Setup() { base.Setup(); - var typeFinder = new TypeFinder(Mock.Of()); - _provider = new ObjectCacheAppCache(typeFinder); + _provider = new ObjectCacheAppCache(); } internal override IAppCache AppCache diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index b096235708..af4c660112 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -57,7 +58,6 @@ namespace Umbraco.Tests.Cache.PublishedCache _httpContextFactory = new FakeHttpContextFactory("~/Home"); - var umbracoSettings = Factory.GetInstance(); var globalSettings = Factory.GetInstance(); var umbracoContextAccessor = Factory.GetInstance(); diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs index bef72e5fb7..cb8da6e23d 100644 --- a/src/Umbraco.Tests/Components/ComponentTests.cs +++ b/src/Umbraco.Tests/Components/ComponentTests.cs @@ -32,10 +32,10 @@ namespace Umbraco.Tests.Components var mock = new Mock(); var logger = Mock.Of(); - var typeFinder = new TypeFinder(logger); - var f = new UmbracoDatabaseFactory(logger, new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator); + var typeFinder = TestHelper.GetTypeFinder(); + var f = new UmbracoDatabaseFactory(logger, SettingsForTests.GetDefaultGlobalSettings(), Mock.Of(), new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.DbProviderFactoryCreator); var fs = new FileSystems(mock.Object, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings()); - var coreDebug = Mock.Of(); + var coreDebug = Mock.Of(); var mediaFileSystem = Mock.Of(); var p = new ScopeProvider(f, fs, coreDebug, mediaFileSystem, logger, typeFinder, NoAppCache.Instance); @@ -371,14 +371,15 @@ namespace Umbraco.Tests.Components public void AllComposers() { var ioHelper = TestHelper.IOHelper; - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var typeLoader = new TypeLoader(ioHelper, typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of()); var register = MockRegister(); var composition = new Composition(register, typeLoader, Mock.Of(), MockRuntimeState(RuntimeLevel.Run), Configs, TestHelper.IOHelper, AppCaches.NoCache); - var types = typeLoader.GetTypes().Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")); + var allComposers = typeLoader.GetTypes().ToList(); + var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); var requirements = composers.GetRequirements(); var report = Composers.GetComposersReport(requirements); diff --git a/src/Umbraco.Tests/Composing/ComposingTestBase.cs b/src/Umbraco.Tests/Composing/ComposingTestBase.cs index ac7dd8be2a..6c5ccd5510 100644 --- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests/Composing/ComposingTestBase.cs @@ -22,7 +22,7 @@ namespace Umbraco.Tests.Composing { ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of()); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; TypeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), ProfilingLogger, false, AssembliesToScan); } diff --git a/src/Umbraco.Tests/Composing/CompositionTests.cs b/src/Umbraco.Tests/Composing/CompositionTests.cs index 4dfaf6871d..ce3cdfac17 100644 --- a/src/Umbraco.Tests/Composing/CompositionTests.cs +++ b/src/Umbraco.Tests/Composing/CompositionTests.cs @@ -38,7 +38,7 @@ namespace Umbraco.Tests.Composing .Returns(() => factoryFactory?.Invoke(mockedFactory)); var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; var typeLoader = new TypeLoader(ioHelper, typeFinder, Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), logger); var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of(), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); diff --git a/src/Umbraco.Tests/Composing/TypeFinderTests.cs b/src/Umbraco.Tests/Composing/TypeFinderTests.cs index 5fe4c241d6..3bdfd09752 100644 --- a/src/Umbraco.Tests/Composing/TypeFinderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeFinderTests.cs @@ -57,7 +57,7 @@ namespace Umbraco.Tests.Composing [Test] public void Find_Class_Of_Type_With_Attribute() { - var typeFinder = new TypeFinder(GetTestProfilingLogger()); + var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly)); var typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies); Assert.AreEqual(2, typesFound.Count()); } @@ -65,12 +65,15 @@ namespace Umbraco.Tests.Composing [Test] public void Find_Classes_With_Attribute() { - var typeFinder = new TypeFinder(GetTestProfilingLogger()); + var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly)); var typesFound = typeFinder.FindClassesWithAttribute(_assemblies); Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree] typesFound = typeFinder.FindClassesWithAttribute(new[] { typeof (UmbracoContext).Assembly }); Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] + + typesFound = typeFinder.FindClassesWithAttribute(); + Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] } private static IProfilingLogger GetTestProfilingLogger() diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 6658c689e1..d0181563a8 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Composing public void Initialize() { // this ensures it's reset - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); _typeLoader = new TypeLoader(TestHelper.IOHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(TestHelper.IOHelper.MapPath("~/App_Data/TEMP")), new ProfilingLogger(Mock.Of(), Mock.Of()), false, diff --git a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs index 37e2636bf4..b171199e25 100644 --- a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs +++ b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs @@ -1,6 +1,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Configuration; +using Umbraco.Core.IO; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Configurations @@ -30,13 +31,15 @@ namespace Umbraco.Tests.Configurations [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir/NestedVDir/", "some-wacky-nestedpath")] public void Umbraco_Mvc_Area(string path, string rootPath, string outcome) { + var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + var ioHelper = new IOHelper(TestHelper.GetHostingEnvironment(), globalSettings); var globalSettingsMock = Mock.Get(globalSettings); - globalSettingsMock.Setup(x => x.Path).Returns(() => TestHelper.IOHelper.ResolveUrl(path)); + globalSettingsMock.Setup(x => x.Path).Returns(() => path); - TestHelper.IOHelper.Root = rootPath; - Assert.AreEqual(outcome, globalSettings.GetUmbracoMvcAreaNoCache(IOHelper)); + ioHelper.Root = rootPath; + Assert.AreEqual(outcome, ioHelper.GetUmbracoMvcAreaNoCache()); } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementDefaultTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementDefaultTests.cs index 5fb896abb2..b14319b1b7 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementDefaultTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementDefaultTests.cs @@ -14,27 +14,27 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public override void DisableHtmlEmail() { - Assert.IsTrue(SettingsSection.Content.DisableHtmlEmail == false); + Assert.IsTrue(ContentSettings.DisableHtmlEmail == false); } [Test] public override void Can_Set_Multiple() { - Assert.IsTrue(SettingsSection.Content.Error404Collection.Count() == 1); - Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).Culture == null); - Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId == 1); + Assert.IsTrue(ContentSettings.Error404Collection.Count() == 1); + Assert.IsTrue(ContentSettings.Error404Collection.ElementAt(0).Culture == null); + Assert.IsTrue(ContentSettings.Error404Collection.ElementAt(0).ContentId == 1); } [Test] public override void ImageAutoFillProperties() { - Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.Count() == 1); - Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).Alias == "umbracoFile"); - Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias == "umbracoWidth"); - Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias == "umbracoHeight"); - Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias == "umbracoBytes"); - Assert.IsTrue(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias == "umbracoExtension"); + Assert.IsTrue(ContentSettings.ImageAutoFillProperties.Count() == 1); + Assert.IsTrue(ContentSettings.ImageAutoFillProperties.ElementAt(0).Alias == "umbracoFile"); + Assert.IsTrue(ContentSettings.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias == "umbracoWidth"); + Assert.IsTrue(ContentSettings.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias == "umbracoHeight"); + Assert.IsTrue(ContentSettings.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias == "umbracoBytes"); + Assert.IsTrue(ContentSettings.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias == "umbracoExtension"); } - + } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs index 0245159c6e..9657091859 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs @@ -16,80 +16,80 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public void EmailAddress() { - Assert.AreEqual(SettingsSection.Content.NotificationEmailAddress, "robot@umbraco.dk"); + Assert.AreEqual(ContentSettings.NotificationEmailAddress, "robot@umbraco.dk"); } [Test] public virtual void DisableHtmlEmail() { - Assert.IsTrue(SettingsSection.Content.DisableHtmlEmail); + Assert.IsTrue(ContentSettings.DisableHtmlEmail); } [Test] public virtual void Can_Set_Multiple() { - Assert.AreEqual(SettingsSection.Content.Error404Collection.Count(), 3); - Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(0).Culture, "default"); - Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId, 1047); - Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentId); - Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentKey); - Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(1).Culture, "en-US"); - Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath, "$site/error [@name = 'error']"); - Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentId); - Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentKey); - Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(2).Culture, "en-UK"); - Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey, new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC")); - Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentKey); - Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentId); + Assert.AreEqual(ContentSettings.Error404Collection.Count(), 3); + Assert.AreEqual(ContentSettings.Error404Collection.ElementAt(0).Culture, "default"); + Assert.AreEqual(ContentSettings.Error404Collection.ElementAt(0).ContentId, 1047); + Assert.IsTrue(ContentSettings.Error404Collection.ElementAt(0).HasContentId); + Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(0).HasContentKey); + Assert.AreEqual(ContentSettings.Error404Collection.ElementAt(1).Culture, "en-US"); + Assert.AreEqual(ContentSettings.Error404Collection.ElementAt(1).ContentXPath, "$site/error [@name = 'error']"); + Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(1).HasContentId); + Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(1).HasContentKey); + Assert.AreEqual(ContentSettings.Error404Collection.ElementAt(2).Culture, "en-UK"); + Assert.AreEqual(ContentSettings.Error404Collection.ElementAt(2).ContentKey, new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC")); + Assert.IsTrue(ContentSettings.Error404Collection.ElementAt(2).HasContentKey); + Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(2).HasContentId); } [Test] public void ImageFileTypes() { - Assert.IsTrue(SettingsSection.Content.ImageFileTypes.All(x => "jpeg,jpg,gif,bmp,png,tiff,tif".Split(',').Contains(x))); + Assert.IsTrue(ContentSettings.ImageFileTypes.All(x => "jpeg,jpg,gif,bmp,png,tiff,tif".Split(',').Contains(x))); } - + [Test] public virtual void ImageAutoFillProperties() { - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.Count(), 2); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).Alias, "umbracoFile"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias, "umbracoWidth"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias, "umbracoHeight"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias, "umbracoBytes"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias, "umbracoExtension"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).Alias, "umbracoFile2"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias, "umbracoWidth2"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias, "umbracoHeight2"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias, "umbracoBytes2"); - Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias, "umbracoExtension2"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.Count(), 2); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(0).Alias, "umbracoFile"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias, "umbracoWidth"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias, "umbracoHeight"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias, "umbracoBytes"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias, "umbracoExtension"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(1).Alias, "umbracoFile2"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias, "umbracoWidth2"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias, "umbracoHeight2"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias, "umbracoBytes2"); + Assert.AreEqual(ContentSettings.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias, "umbracoExtension2"); } - + [Test] public void PreviewBadge() { - Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"
Preview modeClick to end
"); + Assert.AreEqual(ContentSettings.PreviewBadge, @"
Preview modeClick to end
"); } [Test] public void ResolveUrlsFromTextString() { - Assert.IsFalse(SettingsSection.Content.ResolveUrlsFromTextString); + Assert.IsFalse(ContentSettings.ResolveUrlsFromTextString); } [Test] public void MacroErrors() { - Assert.AreEqual(SettingsSection.Content.MacroErrorBehaviour, MacroErrorBehaviour.Inline); + Assert.AreEqual(ContentSettings.MacroErrorBehaviour, MacroErrorBehaviour.Inline); } [Test] public void DisallowedUploadFiles() { - Assert.IsTrue(SettingsSection.Content.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x))); + Assert.IsTrue(ContentSettings.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x))); } [Test] public void AllowedUploadFiles() { - Assert.IsTrue(SettingsSection.Content.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x))); + Assert.IsTrue(ContentSettings.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x))); } [Test] @@ -107,16 +107,16 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings TestingDefaults = false; Debug.WriteLine("Extension being tested", extension); - Debug.WriteLine("AllowedUploadFiles: {0}", SettingsSection.Content.AllowedUploadFiles); - Debug.WriteLine("DisallowedUploadFiles: {0}", SettingsSection.Content.DisallowedUploadFiles); + Debug.WriteLine("AllowedUploadFiles: {0}", ContentSettings.AllowedUploadFiles); + Debug.WriteLine("DisallowedUploadFiles: {0}", ContentSettings.DisallowedUploadFiles); - var allowedContainsExtension = SettingsSection.Content.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)); - var disallowedContainsExtension = SettingsSection.Content.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)); + var allowedContainsExtension = ContentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)); + var disallowedContainsExtension = ContentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)); Debug.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension); Debug.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension); - Assert.AreEqual(SettingsSection.Content.IsFileAllowedForUpload(extension), expected); + Assert.AreEqual(ContentSettings.IsFileAllowedForUpload(extension), expected); } } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementDefaultTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementDefaultTests.cs index c0819ad828..cdd5855730 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementDefaultTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementDefaultTests.cs @@ -14,7 +14,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public override void MaxLogAge() { - Assert.IsTrue(SettingsSection.Logging.MaxLogAge == -1); + Assert.IsTrue(LoggingSettings.MaxLogAge == -1); } } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementTests.cs index 31edc87a7c..be495ad9d0 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/LoggingElementTests.cs @@ -6,11 +6,11 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [TestFixture] public class LoggingElementTests : UmbracoSettingsTests { - + [Test] public virtual void MaxLogAge() { - Assert.IsTrue(SettingsSection.Logging.MaxLogAge == 1440); + Assert.IsTrue(LoggingSettings.MaxLogAge == 1440); } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/RequestHandlerElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/RequestHandlerElementTests.cs index b085c4104c..bb4d1efd1e 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/RequestHandlerElementTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/RequestHandlerElementTests.cs @@ -10,7 +10,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public void AddTrailingSlash() { - Assert.IsTrue(SettingsSection.RequestHandler.AddTrailingSlash == true); + Assert.IsTrue(RequestHandlerSettings.AddTrailingSlash == true); } [Test] @@ -18,14 +18,14 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings { var chars = @" ,"",',%,.,;,/,\,:,#,+,*,&,?,æ,ø,å,ä,ö,ü,ß,Ä,Ö,|,<,>"; var items = chars.Split(','); - Assert.AreEqual(items.Length, SettingsSection.RequestHandler.CharCollection.Count()); - Assert.IsTrue(SettingsSection.RequestHandler.CharCollection + Assert.AreEqual(items.Length, RequestHandlerSettings.CharCollection.Count()); + Assert.IsTrue(RequestHandlerSettings.CharCollection .All(x => items.Contains(x.Char))); var vals = @"-,plus,star,ae,oe,aa,ae,oe,ue,ss,ae,oe,-"; var splitVals = vals.Split(','); - Assert.AreEqual(splitVals.Length, SettingsSection.RequestHandler.CharCollection.Count(x => x.Replacement.IsNullOrWhiteSpace() == false)); - Assert.IsTrue(SettingsSection.RequestHandler.CharCollection + Assert.AreEqual(splitVals.Length, RequestHandlerSettings.CharCollection.Count(x => x.Replacement.IsNullOrWhiteSpace() == false)); + Assert.IsTrue(RequestHandlerSettings.CharCollection .All(x => string.IsNullOrEmpty(x.Replacement) || vals.Split(',').Contains(x.Replacement))); } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/SecurityElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/SecurityElementTests.cs index 9300c88a67..2eccd50295 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/SecurityElementTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/SecurityElementTests.cs @@ -9,127 +9,115 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public void KeepUserLoggedIn() { - Assert.IsTrue(SettingsSection.Security.KeepUserLoggedIn == true); + Assert.IsTrue(SecuritySettings.KeepUserLoggedIn == true); } [Test] public void HideDisabledUsersInBackoffice() { - Assert.IsTrue(SettingsSection.Security.HideDisabledUsersInBackoffice == false); + Assert.IsTrue(SecuritySettings.HideDisabledUsersInBackoffice == false); } [Test] public void AllowPasswordReset() { - Assert.IsTrue(SettingsSection.Security.AllowPasswordReset == true); + Assert.IsTrue(SecuritySettings.AllowPasswordReset == true); } [Test] public void AuthCookieDomain() { - Assert.IsTrue(SettingsSection.Security.AuthCookieDomain == null); + Assert.IsTrue(SecuritySettings.AuthCookieDomain == null); } [Test] public void AuthCookieName() { - Assert.IsTrue(SettingsSection.Security.AuthCookieName == "UMB_UCONTEXT"); + Assert.IsTrue(SecuritySettings.AuthCookieName == "UMB_UCONTEXT"); } [Test] public void UserPasswordConfiguration_RequiredLength() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.RequiredLength == 12); + Assert.IsTrue(UserPasswordConfiguration.RequiredLength == 12); } [Test] public void UserPasswordConfiguration_RequireNonLetterOrDigit() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit == false); + Assert.IsTrue(UserPasswordConfiguration.RequireNonLetterOrDigit == false); } [Test] public void UserPasswordConfiguration_RequireDigit() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.RequireDigit == false); + Assert.IsTrue(UserPasswordConfiguration.RequireDigit == false); } [Test] public void UserPasswordConfiguration_RequireLowercase() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.RequireLowercase == false); + Assert.IsTrue(UserPasswordConfiguration.RequireLowercase == false); } [Test] public void UserPasswordConfiguration_RequireUppercase() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.RequireUppercase == false); - } - - [Test] - public void UserPasswordConfiguration_UseLegacyEncoding() - { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding == false); + Assert.IsTrue(UserPasswordConfiguration.RequireUppercase == false); } [Test] public void UserPasswordConfiguration_HashAlgorithmType() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType == "HMACSHA256"); + Assert.IsTrue(UserPasswordConfiguration.HashAlgorithmType == "HMACSHA256"); } [Test] public void UserPasswordConfiguration_MaxFailedAccessAttemptsBeforeLockout() { - Assert.IsTrue(SettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout == 5); + Assert.IsTrue(UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout == 5); } [Test] public void MemberPasswordConfiguration_RequiredLength() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.RequiredLength == 12); + Assert.IsTrue(MemberPasswordConfiguration.RequiredLength == 12); } [Test] public void MemberPasswordConfiguration_RequireNonLetterOrDigit() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.RequireNonLetterOrDigit == false); + Assert.IsTrue(MemberPasswordConfiguration.RequireNonLetterOrDigit == false); } [Test] public void MemberPasswordConfiguration_RequireDigit() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.RequireDigit == false); + Assert.IsTrue(MemberPasswordConfiguration.RequireDigit == false); } [Test] public void MemberPasswordConfiguration_RequireLowercase() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.RequireLowercase == false); + Assert.IsTrue(MemberPasswordConfiguration.RequireLowercase == false); } [Test] public void MemberPasswordConfiguration_RequireUppercase() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.RequireUppercase == false); - } - - [Test] - public void MemberPasswordConfiguration_UseLegacyEncoding() - { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.UseLegacyEncoding == false); + Assert.IsTrue(MemberPasswordConfiguration.RequireUppercase == false); } [Test] public void MemberPasswordConfiguration_HashAlgorithmType() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.HashAlgorithmType == "HMACSHA256"); + Assert.IsTrue(MemberPasswordConfiguration.HashAlgorithmType == "HMACSHA256"); } [Test] public void MemberPasswordConfiguration_MaxFailedAccessAttemptsBeforeLockout() { - Assert.IsTrue(SettingsSection.Security.MemberPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout == 5); + Assert.IsTrue(MemberPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout == 5); } } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs index e537bad504..7a82f3c070 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using NUnit.Framework; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Tests.TestHelpers; @@ -22,16 +23,23 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings Debug.WriteLine("Testing defaults? {0}", TestingDefaults); if (TestingDefaults) { - SettingsSection = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection; + Settings = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection; } else { - SettingsSection = configuration.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection; + Settings = configuration.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection; } - Assert.IsNotNull(SettingsSection); + Assert.IsNotNull(Settings); } + private UmbracoSettingsSection Settings { get; set; } - protected IUmbracoSettingsSection SettingsSection { get; private set; } + protected ILoggingSettings LoggingSettings => Settings.Logging; + protected IWebRoutingSettings WebRoutingSettings => Settings.WebRouting; + protected IRequestHandlerSettings RequestHandlerSettings => Settings.RequestHandler; + protected ISecuritySettings SecuritySettings => Settings.Security; + protected IUserPasswordConfiguration UserPasswordConfiguration => Settings.Security.UserPasswordConfiguration; + protected IMemberPasswordConfiguration MemberPasswordConfiguration => Settings.Security.MemberPasswordConfiguration; + protected IContentSettings ContentSettings => Settings.Content; } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementDefaultTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementDefaultTests.cs index b593e9082e..73483ee8d2 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementDefaultTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementDefaultTests.cs @@ -14,31 +14,31 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public override void UrlProviderMode() { - Assert.IsTrue(SettingsSection.WebRouting.UrlProviderMode == "Auto"); + Assert.IsTrue(WebRoutingSettings.UrlProviderMode == "Auto"); } [Test] public void DisableAlternativeTemplates() { - Assert.IsTrue(SettingsSection.WebRouting.DisableAlternativeTemplates == false); + Assert.IsTrue(WebRoutingSettings.DisableAlternativeTemplates == false); } [Test] public void ValidateAlternativeTemplates() { - Assert.IsTrue(SettingsSection.WebRouting.ValidateAlternativeTemplates == false); + Assert.IsTrue(WebRoutingSettings.ValidateAlternativeTemplates == false); } [Test] public void DisableFindContentByIdPath() { - Assert.IsTrue(SettingsSection.WebRouting.DisableFindContentByIdPath == false); + Assert.IsTrue(WebRoutingSettings.DisableFindContentByIdPath == false); } [Test] public void DisableRedirectUrlTracking() { - Assert.IsTrue(SettingsSection.WebRouting.DisableRedirectUrlTracking == false); + Assert.IsTrue(WebRoutingSettings.DisableRedirectUrlTracking == false); } } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementTests.cs index 0fa1fb6681..8068c1605f 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/WebRoutingElementTests.cs @@ -8,19 +8,19 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public void TrySkipIisCustomErrors() { - Assert.IsTrue(SettingsSection.WebRouting.TrySkipIisCustomErrors == false); + Assert.IsTrue(WebRoutingSettings.TrySkipIisCustomErrors == false); } [Test] public void InternalRedirectPreservesTemplate() { - Assert.IsTrue(SettingsSection.WebRouting.InternalRedirectPreservesTemplate == false); + Assert.IsTrue(WebRoutingSettings.InternalRedirectPreservesTemplate == false); } [Test] public virtual void UrlProviderMode() { - Assert.IsTrue(SettingsSection.WebRouting.UrlProviderMode == "Auto"); + Assert.IsTrue(WebRoutingSettings.UrlProviderMode == "Auto"); } } } diff --git a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs index 5723b51bab..fbb89b1c5d 100644 --- a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs @@ -14,7 +14,7 @@ namespace Umbraco.Tests.CoreThings { base.Compose(); - Composition.RegisterUnique(f => new DefaultShortStringHelper(f.GetInstance())); + Composition.RegisterUnique(f => new DefaultShortStringHelper(f.GetInstance())); } [Test] diff --git a/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs b/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs index 5c0ca7a582..2fda471b70 100644 --- a/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs +++ b/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs @@ -47,9 +47,8 @@ namespace Umbraco.Tests.CoreThings { var ioHelper = TestHelper.IOHelper; ioHelper.Root = virtualPath; - var globalConfig = SettingsForTests.GenerateMockGlobalSettings(); var source = new Uri(input); - Assert.AreEqual(expected, source.IsBackOfficeRequest(virtualPath, globalConfig, ioHelper)); + Assert.AreEqual(expected, source.IsBackOfficeRequest(virtualPath, ioHelper)); } [TestCase("http://www.domain.com/install", true)] diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index 8b8b71304a..bf726c6fd8 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -34,18 +34,18 @@ namespace Umbraco.Tests.IO composition.Register(_ => Mock.Of()); composition.Register(_ => Mock.Of()); - composition.Register(_ => Mock.Of()); + composition.Register(_ => Mock.Of()); composition.Register(_ => TestHelper.ShortStringHelper); composition.Register(_ => TestHelper.IOHelper); composition.RegisterUnique(); composition.RegisterUnique(TestHelper.IOHelper); composition.Configs.Add(SettingsForTests.GetDefaultGlobalSettings); - composition.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings); + composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); composition.ComposeFileSystems(); - composition.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings); + composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); _factory = composition.CreateFactory(); diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs index 609dcd98b8..bf7cbe40c4 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs @@ -41,6 +41,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache private readonly IEntityXmlSerializer _entitySerializer; private readonly IVariationContextAccessor _variationContextAccessor; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IApplicationShutdownRegistry _hostingLifetime; private readonly IHostingEnvironment _hostingEnvironment; #region Constructors @@ -57,6 +58,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache ILogger logger, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, + IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper, ISiteDomainHelper siteDomainHelper, IEntityXmlSerializer entitySerializer, @@ -67,7 +69,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor, documentRepository, mediaRepository, memberRepository, defaultCultureAccessor, - logger, globalSettings, hostingEnvironment, shortStringHelper, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) + logger, globalSettings, hostingEnvironment, hostingLifetime, shortStringHelper, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) { _umbracoContextAccessor = umbracoContextAccessor; } @@ -84,6 +86,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache ILogger logger, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, + IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper, ISiteDomainHelper siteDomainHelper, IEntityXmlSerializer entitySerializer, @@ -99,7 +102,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _xmlStore = new XmlStore(serviceContext.ContentTypeService, serviceContext.ContentService, scopeProvider, _routesCache, _contentTypeCache, publishedSnapshotAccessor, mainDom, testing, enableRepositoryEvents, - documentRepository, mediaRepository, memberRepository, globalSettings, entitySerializer, hostingEnvironment, shortStringHelper); + documentRepository, mediaRepository, memberRepository, entitySerializer, hostingEnvironment, hostingLifetime, shortStringHelper); _domainService = serviceContext.DomainService; _memberService = serviceContext.MemberService; @@ -113,6 +116,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _siteDomainHelper = siteDomainHelper; _entitySerializer = entitySerializer; _hostingEnvironment = hostingEnvironment; + _hostingLifetime = hostingLifetime; } public override void Dispose() diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs index 238da68370..dadf8b6824 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs @@ -45,9 +45,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache private readonly IDocumentRepository _documentRepository; private readonly IMediaRepository _mediaRepository; private readonly IMemberRepository _memberRepository; - private readonly IGlobalSettings _globalSettings; private readonly IEntityXmlSerializer _entitySerializer; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationShutdownRegistry _hostingLifetime; private readonly IShortStringHelper _shortStringHelper; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly PublishedContentTypeCache _contentTypeCache; @@ -58,7 +57,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache private XmlStoreFilePersister _persisterTask; private volatile bool _released; - private bool _withRepositoryEvents; #region Constructors @@ -67,8 +65,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache ///
/// The default constructor will boot the cache, load data from file or database, /// wire events in order to manage changes, etc. public XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper) - : this(contentTypeService, contentService, scopeProvider, routesCache, contentTypeCache, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, globalSettings, entitySerializer, hostingEnvironment, shortStringHelper) + IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper) + : this(contentTypeService, contentService, scopeProvider, routesCache, contentTypeCache, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, entitySerializer, hostingEnvironment, hostingLifetime, shortStringHelper) { } // internal for unit tests @@ -76,7 +74,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // TODO: er, we DO have a DB? internal XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, - bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper) + bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper) { if (testing == false) EnsureConfigurationIsValid(); @@ -90,12 +88,11 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _documentRepository = documentRepository; _mediaRepository = mediaRepository; _memberRepository = memberRepository; - _globalSettings = globalSettings; _entitySerializer = entitySerializer; - _hostingEnvironment = hostingEnvironment; + _hostingLifetime = hostingLifetime; _shortStringHelper = shortStringHelper; - _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(_hostingEnvironment)); + _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); if (testing) { @@ -150,7 +147,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache LongRunning = true, KeepAlive = true, Hosted = false // main domain will take care of stopping the runner (see below) - }, logger, _hostingEnvironment); + }, logger, _hostingLifetime); // create (and add to runner) _persisterTask = new XmlStoreFilePersister(runner, this, logger); @@ -207,7 +204,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache MediaTypeService.ScopedRefreshedEntity += OnMediaTypeRefreshedEntity; MemberTypeService.ScopedRefreshedEntity += OnMemberTypeRefreshedEntity; - _withRepositoryEvents = true; } private void ClearEvents() @@ -226,7 +222,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache MediaTypeService.ScopedRefreshedEntity -= OnMediaTypeRefreshedEntity; MemberTypeService.ScopedRefreshedEntity -= OnMemberTypeRefreshedEntity; - _withRepositoryEvents = false; } private void LazyInitializeContent() diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 66adfc4a97..6f1358e9a2 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -17,12 +17,11 @@ namespace Umbraco.Tests.Macros [SetUp] public void Setup() { - var typeFinder = new TypeFinder(Mock.Of()); //we DO want cache enabled for these tests var cacheHelper = new AppCaches( - new ObjectCacheAppCache(typeFinder), + new ObjectCacheAppCache(), NoAppCache.Instance, - new IsolatedCaches(type => new ObjectCacheAppCache(typeFinder))); + new IsolatedCaches(type => new ObjectCacheAppCache())); } [TestCase("anything", true)] diff --git a/src/Umbraco.Tests/Misc/UriUtilityTests.cs b/src/Umbraco.Tests/Misc/UriUtilityTests.cs index 0d0f6db61e..a10d6e2179 100644 --- a/src/Umbraco.Tests/Misc/UriUtilityTests.cs +++ b/src/Umbraco.Tests/Misc/UriUtilityTests.cs @@ -77,15 +77,15 @@ namespace Umbraco.Tests.Misc { var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); - var settings = SettingsForTests.GenerateMockUmbracoSettings(); - var requestMock = Mock.Get(settings.RequestHandler); + var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestMock = Mock.Get(settings); requestMock.Setup(x => x.AddTrailingSlash).Returns(trailingSlash); UriUtility.SetAppDomainAppVirtualPath("/"); var expectedUri = NewUri(expectedUrl); var sourceUri = NewUri(sourceUrl); - var resultUri = UriUtility.UriFromUmbraco(sourceUri, globalConfig.Object, settings.RequestHandler); + var resultUri = UriUtility.UriFromUmbraco(sourceUri, globalConfig.Object, settings); Assert.AreEqual(expectedUri.ToString(), resultUri.ToString()); } diff --git a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs index 87bd661015..bab3a540be 100644 --- a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs +++ b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Models Composition.ComposeFileSystems(); Composition.Register(_ => Mock.Of()); - Composition.Register(_ => Mock.Of()); + Composition.Register(_ => Mock.Of()); // all this is required so we can validate properties... var editor = new TextboxPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), IOHelper, ShortStringHelper, LocalizedTextService) { Alias = "test" }; diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 7dec69e3be..31e928159b 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -22,10 +22,10 @@ using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Models { - [TestFixture] public class ContentTests : UmbracoTestBase { @@ -39,7 +39,7 @@ namespace Umbraco.Tests.Models Composition.ComposeFileSystems(); Composition.Register(_ => Mock.Of()); - Composition.Register(_ => Mock.Of()); + Composition.Register(_ => Mock.Of()); // all this is required so we can validate properties... var editor = new TextboxPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), IOHelper, ShortStringHelper, LocalizedTextService) { Alias = "test" }; @@ -269,7 +269,7 @@ namespace Umbraco.Tests.Models content.UpdateDate = DateTime.Now; content.WriterId = 23; - var runtimeCache = new ObjectCacheAppCache(new TypeFinder(Mock.Of())); + var runtimeCache = new ObjectCacheAppCache(); runtimeCache.Insert(content.Id.ToString(CultureInfo.InvariantCulture), () => content); var proflog = GetTestProfilingLogger(); @@ -459,7 +459,7 @@ namespace Umbraco.Tests.Models Assert.IsTrue(prop.WasPropertyDirty("Id")); } Assert.IsTrue(content.WasPropertyDirty("CultureInfos")); - foreach(var culture in content.CultureInfos) + foreach (var culture in content.CultureInfos) { Assert.IsTrue(culture.WasDirty()); Assert.IsTrue(culture.WasPropertyDirty("Name")); @@ -537,7 +537,7 @@ namespace Umbraco.Tests.Models var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act - content.PropertyValues(new { title = "This is the new title"}); + content.PropertyValues(new { title = "This is the new title" }); // Assert Assert.That(content.Properties.Any(), Is.True); @@ -601,13 +601,13 @@ namespace Umbraco.Tests.Models // Act contentType.PropertyGroups["Content"].PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }); + { + Name = "Subtitle", + Description = "Optional subtitle", + Mandatory = false, + SortOrder = 3, + DataTypeId = -88 + }); // Assert Assert.That(contentType.PropertyGroups["Content"].PropertyTypes.Count, Is.EqualTo(3)); @@ -624,9 +624,13 @@ namespace Umbraco.Tests.Models // Act var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", Description = "Optional subtitle", Mandatory = false, SortOrder = 3, DataTypeId = -88 - }; + { + Name = "Subtitle", + Description = "Optional subtitle", + Mandatory = false, + SortOrder = 3, + DataTypeId = -88 + }; contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType); var newProperty = new Property(propertyType); newProperty.SetValue("This is a subtitle Test"); @@ -648,14 +652,14 @@ namespace Umbraco.Tests.Models // Act var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }; - var propertyGroup = new PropertyGroup(true) { Name = "Test Group", SortOrder = 3}; + { + Name = "Subtitle", + Description = "Optional subtitle", + Mandatory = false, + SortOrder = 3, + DataTypeId = -88 + }; + var propertyGroup = new PropertyGroup(true) { Name = "Test Group", SortOrder = 3 }; propertyGroup.PropertyTypes.Add(propertyType); contentType.PropertyGroups.Add(propertyGroup); var newProperty = new Property(propertyType); @@ -679,9 +683,13 @@ namespace Umbraco.Tests.Models // Act - note that the PropertyType's properties like SortOrder is not updated through the Content object var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "title") - { - Name = "Title", Description = "Title description added", Mandatory = false, SortOrder = 10, DataTypeId = -88 - }; + { + Name = "Title", + Description = "Title description added", + Mandatory = false, + SortOrder = 10, + DataTypeId = -88 + }; content.Properties.Add(new Property(propertyType)); // Assert @@ -909,13 +917,13 @@ namespace Umbraco.Tests.Models // Act var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }; + { + Name = "Subtitle", + Description = "Optional subtitle", + Mandatory = false, + SortOrder = 3, + DataTypeId = -88 + }; contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType); // Assert diff --git a/src/Umbraco.Tests/Models/DataTypeTests.cs b/src/Umbraco.Tests/Models/DataTypeTests.cs deleted file mode 100644 index fe8a26e431..0000000000 --- a/src/Umbraco.Tests/Models/DataTypeTests.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Diagnostics; -using Moq; -using Newtonsoft.Json; -using NUnit.Framework; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Serialization; -using Umbraco.Core.Services; -using Umbraco.Core.Strings; - -namespace Umbraco.Tests.Models -{ - [TestFixture] - public class DataTypeTests - { - [Test] - public void Can_Deep_Clone() - { - var dtd = new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of()), 9) - { - CreateDate = DateTime.Now, - CreatorId = 5, - DatabaseType = ValueStorageType.Nvarchar, - Id = 4, - Key = Guid.NewGuid(), - Level = 7, - Name = "Test", - ParentId = 9, - Path = "-1,2", - SortOrder = 8, - Trashed = true, - UpdateDate = DateTime.Now - }; - var clone = (DataType) dtd.DeepClone(); - - Assert.AreNotSame(clone, dtd); - Assert.AreEqual(clone, dtd); - Assert.AreEqual(clone.CreateDate, dtd.CreateDate); - Assert.AreEqual(clone.CreatorId, dtd.CreatorId); - Assert.AreEqual(clone.DatabaseType, dtd.DatabaseType); - Assert.AreEqual(clone.Id, dtd.Id); - Assert.AreEqual(clone.Key, dtd.Key); - Assert.AreEqual(clone.Level, dtd.Level); - Assert.AreEqual(clone.Name, dtd.Name); - Assert.AreEqual(clone.ParentId, dtd.ParentId); - Assert.AreEqual(clone.Path, dtd.Path); - Assert.AreEqual(clone.SortOrder, dtd.SortOrder); - Assert.AreEqual(clone.Trashed, dtd.Trashed); - Assert.AreEqual(clone.UpdateDate, dtd.UpdateDate); - - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) - { - Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(dtd, null)); - } - } - - [Test] - public void Can_Serialize_Without_Error() - { - var dtd = new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of()), 9) - { - CreateDate = DateTime.Now, - CreatorId = 5, - DatabaseType = ValueStorageType.Nvarchar, - Id = 4, - Key = Guid.NewGuid(), - Level = 7, - Name = "Test", - ParentId = 9, - Path = "-1,2", - SortOrder = 8, - Trashed = true, - UpdateDate = DateTime.Now - }; - - var json = JsonConvert.SerializeObject(dtd); - Debug.Print(json); - } - - } -} diff --git a/src/Umbraco.Tests/Models/DictionaryItemTests.cs b/src/Umbraco.Tests/Models/DictionaryItemTests.cs deleted file mode 100644 index 835cfd96f1..0000000000 --- a/src/Umbraco.Tests/Models/DictionaryItemTests.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using Newtonsoft.Json; -using NUnit.Framework; -using Umbraco.Core.Models; -using Umbraco.Core.Serialization; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Models -{ - [TestFixture] - public class DictionaryItemTests - { - [Test] - public void Can_Deep_Clone() - { - var item = new DictionaryItem("blah") - { - CreateDate = DateTime.Now, - Id = 8, - ItemKey = "blah", - Key = Guid.NewGuid(), - ParentId = Guid.NewGuid(), - UpdateDate = DateTime.Now, - Translations = new[] - { - new DictionaryTranslation(new Language(SettingsForTests.GenerateMockGlobalSettings(),"en-AU") - { - CreateDate = DateTime.Now, - CultureName = "en", - Id = 11, - IsoCode = "AU", - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, "colour") - { - CreateDate = DateTime.Now, - Id = 88, - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, - new DictionaryTranslation(new Language(SettingsForTests.GenerateMockGlobalSettings(),"en-US") - { - CreateDate = DateTime.Now, - CultureName = "en", - Id = 12, - IsoCode = "US", - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, "color") - { - CreateDate = DateTime.Now, - Id = 89, - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, - } - }; - - var clone = (DictionaryItem)item.DeepClone(); - - Assert.AreNotSame(clone, item); - Assert.AreEqual(clone, item); - Assert.AreEqual(clone.CreateDate, item.CreateDate); - Assert.AreEqual(clone.Id, item.Id); - Assert.AreEqual(clone.ItemKey, item.ItemKey); - Assert.AreEqual(clone.Key, item.Key); - Assert.AreEqual(clone.ParentId, item.ParentId); - Assert.AreEqual(clone.UpdateDate, item.UpdateDate); - Assert.AreEqual(clone.Translations.Count(), item.Translations.Count()); - for (var i = 0; i < item.Translations.Count(); i++) - { - Assert.AreNotSame(clone.Translations.ElementAt(i), item.Translations.ElementAt(i)); - Assert.AreEqual(clone.Translations.ElementAt(i), item.Translations.ElementAt(i)); - } - - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) - { - Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); - } - } - - [Test] - public void Can_Serialize_Without_Error() - { - var item = new DictionaryItem("blah") - { - CreateDate = DateTime.Now, - Id = 8, - ItemKey = "blah", - Key = Guid.NewGuid(), - ParentId = Guid.NewGuid(), - UpdateDate = DateTime.Now, - Translations = new[] - { - new DictionaryTranslation(new Language(SettingsForTests.GenerateMockGlobalSettings(),"en-AU") - { - CreateDate = DateTime.Now, - CultureName = "en", - Id = 11, - IsoCode = "AU", - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, "colour") - { - CreateDate = DateTime.Now, - Id = 88, - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, - new DictionaryTranslation(new Language(SettingsForTests.GenerateMockGlobalSettings(),"en-US") - { - CreateDate = DateTime.Now, - CultureName = "en", - Id = 12, - IsoCode = "US", - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, "color") - { - CreateDate = DateTime.Now, - Id = 89, - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now - }, - } - }; - - - var json = JsonConvert.SerializeObject(item); - Debug.Print(json); - } - } -} diff --git a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs index 5c6d5c6947..cc923df4b4 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Models.Mapping Composition.ComposeFileSystems(); Composition.Register(_ => Mock.Of()); - Composition.Register(_ => Mock.Of()); + Composition.Register(_ => Mock.Of()); // all this is required so we can validate properties... var editor = new TextboxPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), IOHelper, ShortStringHelper, LocalizedTextService) { Alias = "test" }; diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 2b9c4a32e2..632f433c5b 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -31,13 +31,10 @@ namespace Umbraco.Tests.Models // and then, this will reset the width, height... because the file does not exist, of course ;-( var logger = Mock.Of(); var scheme = Mock.Of(); - var config = Mock.Of(); - var dataTypeService = Mock.Of(); - var localizationService = Mock.Of(); - var umbracoSettingsSection = TestObjects.GetUmbracoSettings(); + var config = Mock.Of(); var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, ShortStringHelper); - var ignored = new FileUploadPropertyEditor(Mock.Of(), mediaFileSystem, config, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, umbracoSettingsSection); + var ignored = new FileUploadPropertyEditor(Mock.Of(), mediaFileSystem, config, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper); var media = MockedMedia.CreateMediaImage(mediaType, -1); media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests diff --git a/src/Umbraco.Tests/Models/PropertyTests.cs b/src/Umbraco.Tests/Models/PropertyTests.cs new file mode 100644 index 0000000000..b9462db0db --- /dev/null +++ b/src/Umbraco.Tests/Models/PropertyTests.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Models +{ + [TestFixture] + public class PropertyTests : UmbracoTestBase + { + [Test] + public void Can_Deep_Clone() + { + // needs to be within collection to support publishing + var ptCollection = new PropertyTypeCollection(true, new[] {new PropertyType(ShortStringHelper,"TestPropertyEditor", ValueStorageType.Nvarchar, "test") + { + Id = 3, + CreateDate = DateTime.Now, + DataTypeId = 5, + PropertyEditorAlias = "propTest", + Description = "testing", + Key = Guid.NewGuid(), + Mandatory = true, + Name = "Test", + PropertyGroupId = new Lazy(() => 11), + SortOrder = 9, + UpdateDate = DateTime.Now, + ValidationRegExp = "xxxx", + ValueStorageType = ValueStorageType.Nvarchar + }}); + + var property = new Property(123, ptCollection[0]) + { + CreateDate = DateTime.Now, + Id = 4, + Key = Guid.NewGuid(), + UpdateDate = DateTime.Now + }; + + property.SetValue("hello"); + property.PublishValues(); + + var clone = (Property)property.DeepClone(); + + Assert.AreNotSame(clone, property); + Assert.AreNotSame(clone.Values, property.Values); + Assert.AreNotSame(property.PropertyType, clone.PropertyType); + for (int i = 0; i < property.Values.Count; i++) + { + Assert.AreNotSame(property.Values.ElementAt(i), clone.Values.ElementAt(i)); + } + + + //This double verifies by reflection + var allProps = clone.GetType().GetProperties(); + foreach (var propertyInfo in allProps) + { + Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(property, null)); + } + } + } +} diff --git a/src/Umbraco.Tests/Models/PropertyTypeTests.cs b/src/Umbraco.Tests/Models/PropertyTypeTests.cs index 0df1470169..73fba856be 100644 --- a/src/Umbraco.Tests/Models/PropertyTypeTests.cs +++ b/src/Umbraco.Tests/Models/PropertyTypeTests.cs @@ -1,9 +1,10 @@ using System; using System.Diagnostics; using Newtonsoft.Json; +using System.Linq; +using System.Reflection; using NUnit.Framework; using Umbraco.Core.Models; -using Umbraco.Core.Serialization; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Models @@ -50,9 +51,9 @@ namespace Umbraco.Tests.Models Assert.AreEqual(clone.ValidationRegExp, pt.ValidationRegExp); Assert.AreEqual(clone.ValueStorageType, pt.ValueStorageType); - //This double verifies by reflection + //This double verifies by reflection (don't test properties marked with [DoNotClone] var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + foreach (var propertyInfo in allProps.Where(p => p.GetCustomAttribute(false) == null)) { var expected = propertyInfo.GetValue(pt, null); var actual = propertyInfo.GetValue(clone, null); diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs index d322926783..f353ee3c8a 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -35,7 +35,7 @@ namespace Umbraco.Tests.Models var configs = TestHelper.GetConfigs(); configs.Add(SettingsForTests.GetDefaultGlobalSettings); - configs.Add(SettingsForTests.GetDefaultUmbracoSettings); + configs.Add(SettingsForTests.GenerateMockContentSettings); _factory = Mock.Of(); diff --git a/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs b/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs index b3f644ae43..6065570b13 100644 --- a/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs +++ b/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs @@ -54,7 +54,7 @@ namespace Umbraco.Tests.ModelsBuilder // // This code was generated by a tool. // -// Umbraco.ModelsBuilder v" + version + @" +// Umbraco.ModelsBuilder.Embedded v" + version + @" // // Changes to this file will be lost if the code is regenerated. // @@ -76,14 +76,14 @@ namespace Umbraco.Web.PublishedModels { // helpers #pragma warning disable 0109 // new is redundant - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const string ModelTypeAlias = ""type1""; - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const PublishedItemType ModelItemType = PublishedItemType.Content; - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new static IPublishedContentType GetModelContentType() => PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias); - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public static IPublishedPropertyType GetModelPropertyType(Expression> selector) => PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector); #pragma warning restore 0109 @@ -95,7 +95,7 @@ namespace Umbraco.Web.PublishedModels // properties - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] [ImplementPropertyType(""prop1"")] public string Prop1 => this.Value(""prop1""); } @@ -169,7 +169,7 @@ namespace Umbraco.Web.PublishedModels // // This code was generated by a tool. // -// Umbraco.ModelsBuilder v" + version + @" +// Umbraco.ModelsBuilder.Embedded v" + version + @" // // Changes to this file will be lost if the code is regenerated. // @@ -191,14 +191,14 @@ namespace Umbraco.Web.PublishedModels { // helpers #pragma warning disable 0109 // new is redundant - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const string ModelTypeAlias = ""type1""; - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const PublishedItemType ModelItemType = PublishedItemType.Content; - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new static IPublishedContentType GetModelContentType() => PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias); - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public static IPublishedPropertyType GetModelPropertyType(Expression> selector) => PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector); #pragma warning restore 0109 @@ -210,7 +210,7 @@ namespace Umbraco.Web.PublishedModels // properties - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder"", """ + version + @""")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] [ImplementPropertyType(""foo"")] public global::System.Collections.Generic.IEnumerable Foo => this.Value>(""foo""); } diff --git a/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs b/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs index 4a9e8704ec..5ed96365fd 100644 --- a/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs +++ b/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs @@ -1,8 +1,9 @@ using System.Configuration; using NUnit.Framework; using Umbraco.Configuration; +using Umbraco.Configuration.Legacy; using Umbraco.Core; -using Umbraco.Tests.TestHelpers; +using Umbraco.Core.Configuration; namespace Umbraco.Tests.ModelsBuilder { @@ -12,21 +13,21 @@ namespace Umbraco.Tests.ModelsBuilder [Test] public void Test1() { - var config = new ModelsBuilderConfig(TestHelper.IOHelper, modelsNamespace: "test1"); + var config = new ModelsBuilderConfig(modelsNamespace: "test1"); Assert.AreEqual("test1", config.ModelsNamespace); } [Test] public void Test2() { - var config = new ModelsBuilderConfig(TestHelper.IOHelper, modelsNamespace: "test2"); + var config = new ModelsBuilderConfig(modelsNamespace: "test2"); Assert.AreEqual("test2", config.ModelsNamespace); } [Test] public void DefaultModelsNamespace() { - var config = new ModelsBuilderConfig(TestHelper.IOHelper); + var config = new ModelsBuilderConfig(); Assert.AreEqual(Constants.ModelsBuilder.DefaultModelsNamespace, config.ModelsNamespace); } @@ -35,7 +36,7 @@ namespace Umbraco.Tests.ModelsBuilder [TestCase("c:/path/to/root", "c:/another/path/to/elsewhere", true, "c:\\another\\path\\to\\elsewhere")] public void GetModelsDirectoryTests(string root, string config, bool acceptUnsafe, string expected) { - Assert.AreEqual(expected, ModelsBuilderConfig.GetModelsDirectory(root, config, acceptUnsafe)); + Assert.AreEqual(expected, ModelsBuilderConfigExtensions.GetModelsDirectory(root, config, acceptUnsafe)); } [TestCase("c:/path/to/root", "~/../../dir/models", false)] @@ -44,7 +45,7 @@ namespace Umbraco.Tests.ModelsBuilder { Assert.Throws(() => { - var modelsDirectory = ModelsBuilderConfig.GetModelsDirectory(root, config, acceptUnsafe); + var modelsDirectory = ModelsBuilderConfigExtensions.GetModelsDirectory(root, config, acceptUnsafe); }); } } diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs index 531f08a72d..52f2365cbc 100644 --- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs +++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs @@ -37,7 +37,9 @@ namespace Umbraco.Tests.Persistence _sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider }; _logger = Mock.Of(); _umbracoVersion = TestHelper.GetUmbracoVersion(); - _databaseFactory = new UmbracoDatabaseFactory(_logger, new Lazy(() => Mock.Of()), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator); + var globalSettings = TestHelper.GetConfigs().Global(); + var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + _databaseFactory = new UmbracoDatabaseFactory(_logger, globalSettings, connectionStrings, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); } [TearDown] diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index 30bf5be17b..fe59e431ec 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -83,9 +83,9 @@ namespace Umbraco.Tests.Persistence.Repositories public void CacheActiveForIntsAndGuids() { var realCache = new AppCaches( - new ObjectCacheAppCache(TypeFinder), + new ObjectCacheAppCache(), new DictionaryAppCache(), - new IsolatedCaches(t => new ObjectCacheAppCache(TypeFinder))); + new IsolatedCaches(t => new ObjectCacheAppCache())); var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index efabddb2cd..83572180af 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -56,9 +56,9 @@ namespace Umbraco.Tests.Persistence.Repositories MediaTypeRepository mediaTypeRepository; var realCache = new AppCaches( - new ObjectCacheAppCache(TypeFinder), + new ObjectCacheAppCache(), new DictionaryAppCache(), - new IsolatedCaches(t => new ObjectCacheAppCache(TypeFinder))); + new IsolatedCaches(t => new ObjectCacheAppCache())); var provider = TestObjects.GetScopeProvider(Logger); using (var scope = provider.CreateScope()) diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs index 281e5a9365..919386f491 100644 --- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs +++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs @@ -85,10 +85,8 @@ namespace Umbraco.Tests.PropertyEditors var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, shortStringHelper); - var umbracoSettingsSection = Mock.Of(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of(), umbracoSettingsSection)) { Id = 1 }); + new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs index a24b4cbafd..6301be051d 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.PropertyEditors var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); register.Register(_ - => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()))); + => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()))); Current.Factory = composition.CreateFactory(); } diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs index d3e6dae26b..b928e5af06 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs @@ -127,9 +127,8 @@ namespace Umbraco.Tests.Published var setType1 = publishedContentTypeFactory.CreateContentType(1000, "set1", CreatePropertyTypes); - var typeFinder = new TypeFinder(Mock.Of()); - var elementsCache = new FastDictionaryAppCache(typeFinder); - var snapshotCache = new FastDictionaryAppCache(typeFinder); + var elementsCache = new FastDictionaryAppCache(); + var snapshotCache = new FastDictionaryAppCache(); var publishedSnapshot = new Mock(); publishedSnapshot.Setup(x => x.SnapshotCache).Returns(snapshotCache); diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index de12fcf7aa..e9b3c49e10 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Legacy; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.Install; @@ -20,10 +21,10 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; +using Umbraco.Tests.Common; using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache; @@ -61,9 +62,9 @@ namespace Umbraco.Tests.PublishedContent var configs = TestHelper.GetConfigs(); Mock.Get(factory).Setup(x => x.GetInstance(typeof(Configs))).Returns(configs); - var globalSettings = new GlobalSettings(TestHelper.IOHelper); + var globalSettings = new GlobalSettings(); var hostingEnvironment = Mock.Of(); - configs.Add(SettingsForTests.GenerateMockUmbracoSettings); + configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); configs.Add(() => globalSettings); Mock.Get(factory).Setup(x => x.GetInstance(typeof(IPublishedModelFactory))).Returns(PublishedModelFactory); @@ -143,7 +144,7 @@ namespace Umbraco.Tests.PublishedContent // create a data source for NuCache _source = new TestDataSource(kits); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var settings = Mock.Of(); @@ -167,7 +168,6 @@ namespace Umbraco.Tests.PublishedContent Mock.Of(), PublishedModelFactory, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), - typeFinder, hostingEnvironment, new MockShortStringHelper(), TestHelper.IOHelper, diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 08da25ba9a..8003bdf236 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Legacy; using Umbraco.Core.Events; using Umbraco.Core.Install; using Umbraco.Core.Logging; @@ -18,10 +19,10 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; +using Umbraco.Tests.Common; using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache; @@ -54,8 +55,8 @@ namespace Umbraco.Tests.PublishedContent var configs = TestHelper.GetConfigs(); Mock.Get(factory).Setup(x => x.GetInstance(typeof(Configs))).Returns(configs); - var globalSettings = new GlobalSettings(TestHelper.IOHelper); - configs.Add(SettingsForTests.GenerateMockUmbracoSettings); + var globalSettings = new GlobalSettings(); + configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); configs.Add(() => globalSettings); var publishedModelFactory = new NoopPublishedModelFactory(); @@ -184,7 +185,7 @@ namespace Umbraco.Tests.PublishedContent // create a variation accessor _variationAccesor = new TestVariationContextAccessor(); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var settings = Mock.Of(); // at last, create the complete NuCache snapshot service! @@ -207,7 +208,6 @@ namespace Umbraco.Tests.PublishedContent Mock.Of(), publishedModelFactory, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), - typeFinder, TestHelper.GetHostingEnvironment(), new MockShortStringHelper(), TestHelper.IOHelper, diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 1806493cdd..06a53db4ff 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -21,6 +21,7 @@ using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects.Accessors; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.Common; namespace Umbraco.Tests.PublishedContent { diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 89b8de8085..1aa049e25e 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -23,7 +23,7 @@ using Umbraco.Core.Models.Membership; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.Testing.Objects.Accessors; +using Umbraco.Tests.Common; namespace Umbraco.Tests.PublishedContent { diff --git a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs index 227a7c26e3..ee1e056aff 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs @@ -18,7 +18,7 @@ namespace Umbraco.Tests.Routing var umbracoContext = GetUmbracoContext(urlAsString); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); - var lookup = new ContentFinderByIdPath(Factory.GetInstance().WebRouting, Logger, Factory.GetInstance()); + var lookup = new ContentFinderByIdPath(SettingsForTests.GenerateMockWebRoutingSettings(), Logger, Factory.GetInstance()); var result = lookup.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs index 208ec20517..e8b8bab22b 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs @@ -38,7 +38,7 @@ namespace Umbraco.Tests.Routing var umbracoContext = GetUmbracoContext(urlAsString, template1.Id, globalSettings:globalSettings.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); - var lookup = new ContentFinderByUrlAndTemplate(Logger, ServiceContext.FileService, TestObjects.GetUmbracoSettings(), ServiceContext.ContentTypeService); + var lookup = new ContentFinderByUrlAndTemplate(Logger, ServiceContext.FileService, ServiceContext.ContentTypeService, SettingsForTests.GenerateMockWebRoutingSettings()); var result = lookup.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs b/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs index b9d669902d..4f11802b43 100644 --- a/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs +++ b/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs @@ -11,9 +11,10 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Routing; +using Umbraco.Tests.Common; +using SettingsForTests = Umbraco.Tests.TestHelpers.SettingsForTests; namespace Umbraco.Tests.Routing { @@ -77,15 +78,15 @@ namespace Umbraco.Tests.Routing content.Path = "-1,1046"; content.Published = true; - var umbracoSettings = Current.Configs.Settings(); + var umbracoSettings = SettingsForTests.GenerateMockRequestHandlerSettings(); var umbContext = GetUmbracoContext("http://localhost:8000"); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), + var urlProvider = new DefaultUrlProvider(umbracoSettings, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new []{urlProvider}), new MediaUrlProviderCollection(Enumerable.Empty()), Mock.Of() @@ -122,15 +123,15 @@ namespace Umbraco.Tests.Routing child.Path = "-1,1046,1173"; child.Published = true; - var umbracoSettings = Current.Configs.Settings(); + var umbracoSettings = SettingsForTests.GenerateMockRequestHandlerSettings(); var umbContext = GetUmbracoContext("http://localhost:8000"); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); + var urlProvider = new DefaultUrlProvider(umbracoSettings, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new []{urlProvider}), new MediaUrlProviderCollection(Enumerable.Empty()), Mock.Of() diff --git a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs index fb61fcffe8..5cff94d6bc 100644 --- a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs @@ -12,10 +12,10 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.PropertyEditors; using Umbraco.Web.Routing; @@ -34,14 +34,12 @@ namespace Umbraco.Tests.Routing var logger = Mock.Of(); var mediaFileSystemMock = Mock.Of(); - var contentSection = Mock.Of(); + var contentSection = Mock.Of(); var dataTypeService = Mock.Of(); - var umbracoSettingsSection = TestObjects.GetUmbracoSettings(); - var propertyEditors = new MediaUrlGeneratorCollection(new IMediaUrlGenerator[] { - new FileUploadPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, umbracoSettingsSection), - new ImageCropperPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, umbracoSettingsSection), + new FileUploadPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), + new ImageCropperPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService), }); _mediaUrlProvider = new DefaultMediaUrlProvider(propertyEditors, UriUtility); } @@ -153,7 +151,7 @@ namespace Umbraco.Tests.Routing { return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(Enumerable.Empty()), new MediaUrlProviderCollection(new []{_mediaUrlProvider}), Mock.Of() diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 48436d6690..bc58282795 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -23,10 +23,10 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Runtime; using Current = Umbraco.Web.Composing.Current; using ILogger = Umbraco.Core.Logging.ILogger; +using Umbraco.Tests.Common; namespace Umbraco.Tests.Routing { @@ -50,7 +50,7 @@ namespace Umbraco.Tests.Routing public class TestRuntime : WebRuntime { public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - : base(configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom) + : base(configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), TestHelper.GetRequestCache(), new AspNetUmbracoBootPermissionChecker()) { } @@ -69,7 +69,7 @@ namespace Umbraco.Tests.Routing var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(Composition.TypeLoader.GetUmbracoApiControllers()); Composition.RegisterUnique(umbracoApiControllerTypes); - Composition.RegisterUnique(_ => new DefaultShortStringHelper(SettingsForTests.GetDefaultUmbracoSettings())); + Composition.RegisterUnique(_ => new DefaultShortStringHelper(TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings())); } public override void TearDown() diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index de7e6d52b6..f9de3579c2 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -32,19 +32,18 @@ namespace Umbraco.Tests.Routing //create the module var logger = Mock.Of(); var globalSettings = TestObjects.GetGlobalSettings(); - var runtime = new RuntimeState(logger, Mock.Of(), globalSettings, - new Lazy(), new Lazy(), UmbracoVersion, HostingEnvironment, BackOfficeInfo); + var runtime = new RuntimeState(logger, globalSettings, UmbracoVersion, BackOfficeInfo); _module = new UmbracoInjectedModule ( - globalSettings, runtime, logger, null, // FIXME: PublishedRouter complexities... Mock.Of(), new RoutableDocumentFilter(globalSettings, IOHelper), UriUtility, - AppCaches.RequestCache + AppCaches.RequestCache, + IOHelper ); runtime.Level = RuntimeLevel.Run; diff --git a/src/Umbraco.Tests/Routing/UrlProviderTests.cs b/src/Umbraco.Tests/Routing/UrlProviderTests.cs index 481d03bce5..ee53e2ac52 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderTests.cs @@ -13,10 +13,10 @@ using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using Umbraco.Tests.Common; namespace Umbraco.Tests.Routing { @@ -34,8 +34,8 @@ namespace Umbraco.Tests.Routing protected override void ComposeSettings() { - Composition.Configs.Add(SettingsForTests.GenerateMockUmbracoSettings); - Composition.Configs.Add(SettingsForTests.GenerateMockGlobalSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockGlobalSettings); } /// @@ -48,15 +48,15 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - var requestHandlerMock = Mock.Get(umbracoSettings.RequestHandler); + var requestHandlerMock = Mock.Get(requestHandlerSettings); requestHandlerMock.Setup(x => x.AddTrailingSlash).Returns(false);// (cached routes have none) var samples = new Dictionary { @@ -102,7 +102,7 @@ namespace Umbraco.Tests.Routing { return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new []{urlProvider}), new MediaUrlProviderCollection(Enumerable.Empty()), Mock.Of() @@ -123,12 +123,12 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -152,12 +152,10 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); - var umbracoSettings = Current.Configs.Settings(); - - + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -173,7 +171,7 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); @@ -200,7 +198,7 @@ namespace Umbraco.Tests.Routing globalSettings: globalSettings.Object, snapshotService: snapshotService.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -221,7 +219,7 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; @@ -256,7 +254,7 @@ namespace Umbraco.Tests.Routing globalSettings: globalSettings.Object, snapshotService: snapshotService.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -277,7 +275,7 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; @@ -311,7 +309,7 @@ namespace Umbraco.Tests.Routing globalSettings: globalSettings.Object, snapshotService: snapshotService.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); @@ -328,12 +326,12 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -349,9 +347,9 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoSettings = Current.Configs.Settings(); + var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - var urlProvider = new DefaultUrlProvider(umbracoSettings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, new SiteDomainHelper(), UmbracoContextAccessor, UriUtility); var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: globalSettings.Object); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); diff --git a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs index ab2883ac37..d8e373b428 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -8,9 +8,9 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Routing; @@ -178,14 +178,14 @@ namespace Umbraco.Tests.Routing [TestCase(10011, "https://domain1.com", false, "/1001-1/")] public void Get_Url_SimpleDomain(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -212,14 +212,14 @@ namespace Umbraco.Tests.Routing [TestCase(10011, "https://domain1.com", false, "http://domain1.com/foo/1001-1/")] public void Get_Url_SimpleWithSchemeAndPath(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -238,14 +238,14 @@ namespace Umbraco.Tests.Routing [TestCase(1002, "http://domain1.com", false, "/1002/")] public void Get_Url_DeepDomain(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -270,14 +270,14 @@ namespace Umbraco.Tests.Routing [TestCase(100321, "http://domain3.com", false, "/fr/1003-2-1/")] public void Get_Url_NestedDomains(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -292,14 +292,14 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_DomainsAndCache() { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -356,14 +356,14 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Relative_Or_Absolute() { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -381,14 +381,14 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Alternate() { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -410,7 +410,7 @@ namespace Umbraco.Tests.Routing { return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new []{urlProvider}), new MediaUrlProviderCollection(Enumerable.Empty()), Mock.Of() diff --git a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs index ad6e7b5408..13ee5afa3e 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -10,8 +10,8 @@ using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using Umbraco.Core.Services; using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; +using Umbraco.Tests.Common; namespace Umbraco.Tests.Routing { @@ -36,7 +36,7 @@ namespace Umbraco.Tests.Routing var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var settings = SettingsForTests.GenerateMockUmbracoSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); SetDomains1(); @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Routing // get the nice url for 100111 var umbracoContext = GetUmbracoContext(url, 9999, globalSettings:globalSettings.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -99,7 +99,7 @@ namespace Umbraco.Tests.Routing { return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new []{urlProvider}), new MediaUrlProviderCollection(Enumerable.Empty()), Mock.Of() diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs index 729184eb1d..6ccb2c3b35 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -82,7 +82,7 @@ namespace Umbraco.Tests.Runtimes // test application public class TestUmbracoApplication : UmbracoApplicationBase { - public TestUmbracoApplication() : base(_logger, _configs, _ioHelper, _profiler, new AspNetHostingEnvironment(_hostingSettings), new AspNetBackOfficeInfo(_globalSettings, _ioHelper, _settings, _logger)) + public TestUmbracoApplication() : base(_logger, _configs, _ioHelper, _profiler, new AspNetHostingEnvironment(_hostingSettings), new AspNetBackOfficeInfo(_globalSettings, _ioHelper, _logger, _settings)) { } @@ -90,24 +90,20 @@ namespace Umbraco.Tests.Runtimes private static readonly IIOHelper _ioHelper = TestHelper.IOHelper; private static readonly IProfiler _profiler = new TestProfiler(); private static readonly Configs _configs = GetConfigs(); - private static readonly IGlobalSettings _globalSettings = _configs.Global(); - private static readonly IHostingSettings _hostingSettings = _configs.Hosting(); - private static readonly IUmbracoSettingsSection _settings = _configs.Settings(); + private static readonly IGlobalSettings _globalSettings = SettingsForTests.GetDefaultGlobalSettings(); + private static readonly IHostingSettings _hostingSettings = SettingsForTests.GetDefaultHostingSettings(); + private static readonly IContentSettings _contentSettings = SettingsForTests.GenerateMockContentSettings(); + private static readonly IWebRoutingSettings _settings = _configs.WebRouting(); private static Configs GetConfigs() { - var configs = new ConfigsFactory().Create(_ioHelper); - configs.Add(SettingsForTests.GetDefaultGlobalSettings); - configs.Add(SettingsForTests.GetDefaultUmbracoSettings); - configs.Add(SettingsForTests.GetDefaultHostingSettings); + var configs = new ConfigsFactory().Create(); + configs.Add(() => _globalSettings); + configs.Add(() => _contentSettings); + configs.Add(() => _hostingSettings); return configs; } - private static IProfiler GetProfiler() - { - return new TestProfiler(); - } - public IRuntime Runtime { get; private set; } protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) @@ -120,7 +116,7 @@ namespace Umbraco.Tests.Runtimes public class TestRuntime : CoreRuntime { public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - :base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom) + :base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder()) { } @@ -135,51 +131,14 @@ namespace Umbraco.Tests.Runtimes return mock.Object; } - // FIXME: so how the f* should we do it now? - /* - // pretend we have the proper migration - // else BootFailedException because our mock IUmbracoDatabaseFactory does not provide databases - protected override bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory) + public override IFactory Configure(IRegister container) { - return true; - } - */ + container.Register(Lifetime.Singleton); - // because we don't even have the core runtime component, - // there are a few required stuff that we need to compose - public override void Compose(Composition composition) - { - base.Compose(composition); - - var scopeProvider = Mock.Of(); - Mock.Get(scopeProvider) - .Setup(x => x.CreateScope( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(Mock.Of()); - - composition.RegisterUnique(scopeProvider); - } - - private IMainDom _mainDom; - - public override IFactory Boot(IRegister container) - { - var factory = base.Boot(container); - _mainDom = factory.GetInstance(); + var factory = base.Configure(container); return factory; } - public override void Terminate() - { - ((IRegisteredObject) _mainDom).Stop(false); - base.Terminate(); - } - // runs with only one single component // UmbracoCoreComponent will be force-added too // and that's it @@ -208,7 +167,7 @@ namespace Umbraco.Tests.Runtimes public void Compose(Composition composition) { - composition.Register(factory => SettingsForTests.GetDefaultUmbracoSettings()); + composition.Register(factory => SettingsForTests.GenerateMockContentSettings()); composition.RegisterUnique(); composition.Components().Append(); diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs index 6811f9f8de..f167aafb89 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -25,9 +25,7 @@ using Umbraco.Core.Runtime; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Sync; -using Umbraco.Tests.Composing; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Cache; using Umbraco.Web.Macros; @@ -36,6 +34,8 @@ using Umbraco.Web.Routing; using Umbraco.Web.Runtime; using File = System.IO.File; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Composing; namespace Umbraco.Tests.Runtimes { @@ -62,25 +62,28 @@ namespace Umbraco.Tests.Runtimes var profiler = new LogProfiler(logger); var profilingLogger = new ProfilingLogger(logger, profiler); var appCaches = AppCaches.Disabled; - var databaseFactory = new UmbracoDatabaseFactory(logger, new Lazy(() => factory.GetInstance()), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator); - var typeFinder = new TypeFinder(logger); + var globalSettings = TestHelper.GetConfigs().Global(); + var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + var typeFinder = TestHelper.GetTypeFinder(); + var databaseFactory = new UmbracoDatabaseFactory(logger,globalSettings, connectionStrings, new Lazy(() => factory.GetInstance()), TestHelper.DbProviderFactoryCreator); var ioHelper = TestHelper.IOHelper; var hostingEnvironment = Mock.Of(); var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger); var mainDom = new SimpleMainDom(); var umbracoVersion = TestHelper.GetUmbracoVersion(); var backOfficeInfo = TestHelper.GetBackOfficeInfo(); - var runtimeState = new RuntimeState(logger, null, null, new Lazy(() => mainDom), new Lazy(() => factory.GetInstance()), umbracoVersion, hostingEnvironment, backOfficeInfo); + var runtimeState = new RuntimeState(logger, null, umbracoVersion, backOfficeInfo); var configs = TestHelper.GetConfigs(); var variationContextAccessor = TestHelper.VariationContextAccessor; + // create the register and the composition var register = TestHelper.GetRegister(); var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, configs, ioHelper, appCaches); - composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator); + composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo); // create the core runtime and have it compose itself - var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom);coreRuntime.Compose(composition); + var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder); // determine actual runtime level runtimeState.DetermineRuntimeLevel(databaseFactory, logger); @@ -120,8 +123,8 @@ namespace Umbraco.Tests.Runtimes .Append(); // configure - composition.Configs.Add(SettingsForTests.GetDefaultGlobalSettings); - composition.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings); + composition.Configs.Add(TestHelpers.SettingsForTests.GetDefaultGlobalSettings); + composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); // create and register the factory Current.Factory = factory = composition.CreateFactory(); @@ -159,7 +162,7 @@ namespace Umbraco.Tests.Runtimes var scopeProvider = factory.GetInstance(); using (var scope = scopeProvider.CreateScope()) { - var creator = new DatabaseSchemaCreator(scope.Database, logger, umbracoVersion, SettingsForTests.GetDefaultGlobalSettings()); + var creator = new DatabaseSchemaCreator(scope.Database, logger, umbracoVersion, TestHelpers.SettingsForTests.GetDefaultGlobalSettings()); creator.InitializeDatabaseSchema(); scope.Complete(); } @@ -256,7 +259,7 @@ namespace Umbraco.Tests.Runtimes var profilingLogger = new ProfilingLogger(logger, profiler); var appCaches = AppCaches.Disabled; var databaseFactory = Mock.Of(); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger); var runtimeState = Mock.Of(); @@ -271,11 +274,10 @@ namespace Umbraco.Tests.Runtimes var register = TestHelper.GetRegister(); var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, configs, ioHelper, appCaches); var umbracoVersion = TestHelper.GetUmbracoVersion(); - composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator); + composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo); // create the core runtime and have it compose itself - var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom); - coreRuntime.Compose(composition); + var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder); // get the components // all of them? @@ -313,107 +315,14 @@ namespace Umbraco.Tests.Runtimes foreach (var result in resultGroup) { Console.WriteLine(); - Console.Write(ToText(result)); + Console.Write(result.ToText()); } Assert.AreEqual(0, results.Count); } - private static string ToText(ValidationResult result) - { - var text = new StringBuilder(); + - text.AppendLine($"{result.Severity}: {WordWrap(result.Message, 120)}"); - var target = result.ValidationTarget; - text.Append("\tsvce: "); - text.Append(target.ServiceName); - text.Append(target.DeclaringService.ServiceType); - if (!target.DeclaringService.ServiceName.IsNullOrWhiteSpace()) - { - text.Append(" '"); - text.Append(target.DeclaringService.ServiceName); - text.Append("'"); - } - - text.Append(" ("); - if (target.DeclaringService.Lifetime == null) - text.Append("Transient"); - else - text.Append(target.DeclaringService.Lifetime.ToString().TrimStart("LightInject.").TrimEnd("Lifetime")); - text.AppendLine(")"); - text.Append("\timpl: "); - text.Append(target.DeclaringService.ImplementingType); - text.AppendLine(); - text.Append("\tparm: "); - text.Append(target.Parameter); - text.AppendLine(); - - return text.ToString(); - } - - private static string WordWrap(string text, int width) - { - int pos, next; - var sb = new StringBuilder(); - var nl = Environment.NewLine; - - // Lucidity check - if (width < 1) - return text; - - // Parse each line of text - for (pos = 0; pos < text.Length; pos = next) - { - // Find end of line - var eol = text.IndexOf(nl, pos, StringComparison.Ordinal); - - if (eol == -1) - next = eol = text.Length; - else - next = eol + nl.Length; - - // Copy this line of text, breaking into smaller lines as needed - if (eol > pos) - { - do - { - var len = eol - pos; - - if (len > width) - len = BreakLine(text, pos, width); - - if (pos > 0) - sb.Append("\t\t"); - sb.Append(text, pos, len); - sb.Append(nl); - - // Trim whitespace following break - pos += len; - - while (pos < eol && char.IsWhiteSpace(text[pos])) - pos++; - - } while (eol > pos); - } - else sb.Append(nl); // Empty line - } - - return sb.ToString(); - } - - private static int BreakLine(string text, int pos, int max) - { - // Find last whitespace in line - var i = max - 1; - while (i >= 0 && !char.IsWhiteSpace(text[pos + i])) - i--; - if (i < 0) - return max; // No whitespace found; break at maximum length - // Find start of whitespace - while (i >= 0 && char.IsWhiteSpace(text[pos + i])) - i--; - // Return length of text before whitespace - return i + 1; - } + } } diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs index f10b141916..2291584f66 100644 --- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs +++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs @@ -19,13 +19,13 @@ namespace Umbraco.Tests.Scheduling public class BackgroundTaskRunnerTests { private ILogger _logger; - private IHostingEnvironment _hostingEnvironment; + private IApplicationShutdownRegistry _hostingEnvironment; [OneTimeSetUp] public void InitializeFixture() { _logger = new ConsoleLogger(new MessageTemplates()); - _hostingEnvironment = TestHelper.GetHostingEnvironment(); + _hostingEnvironment = TestHelper.GetHostingEnvironmentLifetime(); } [Test] @@ -934,7 +934,7 @@ namespace Umbraco.Tests.Scheduling [Test] public void SourceTaskTest() { - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironment()); + var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironmentLifetime()); var task = new SourceTask(); runner.Add(task); diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs index c65c7e3efb..01169abce2 100644 --- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs +++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs @@ -22,7 +22,7 @@ namespace Umbraco.Tests.Scheduling public async Task ThreadResumeIssue() { var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironment()); + var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime()); var work = new ThreadResumeIssueWorkItem(); runner.Add(work); @@ -77,7 +77,7 @@ namespace Umbraco.Tests.Scheduling public async Task DebuggerInterferenceIssue() { var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironment()); + var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime()); var taskCompleted = false; runner.TaskCompleted += (sender, args) => { diff --git a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs index 7b60a9fae2..fd37192da2 100644 --- a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs @@ -42,7 +42,7 @@ namespace Umbraco.Tests.Scoping composition.WithCollectionBuilder(); composition.Configs.Add(SettingsForTests.GetDefaultGlobalSettings); - composition.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings); + composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); Current.Reset(); Current.Factory = composition.CreateFactory(); diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 783beafb2e..8603d901c2 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -19,6 +19,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; +using Umbraco.Tests.Common; using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -85,7 +86,7 @@ namespace Umbraco.Tests.Scoping var memberRepository = Mock.Of(); var hostingEnvironment = TestHelper.GetHostingEnvironment(); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var settings = Mock.Of(); return new PublishedSnapshotService( @@ -105,14 +106,13 @@ namespace Umbraco.Tests.Scoping Factory.GetInstance(), new NoopPublishedModelFactory(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), - typeFinder, hostingEnvironment, new MockShortStringHelper(), IOHelper, settings); } - protected IUmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable urlProviders = null) + protected IUmbracoContext GetUmbracoContextNu(string url, RouteData routeData = null, bool setSingleton = false) { // ensure we have a PublishedSnapshotService var service = PublishedSnapshotService as PublishedSnapshotService; diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index d1963a1d2e..4c3bb288e4 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -43,9 +43,9 @@ namespace Umbraco.Tests.Scoping { // this is what's created core web runtime return new AppCaches( - new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)), + new DeepCloneAppCache(new ObjectCacheAppCache()), NoAppCache.Instance, - new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)))); + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); } [TearDown] diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 3e62b52689..852872fca0 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -44,7 +44,7 @@ namespace Umbraco.Tests.Scoping protected override void ComposeSettings() { - Composition.Configs.Add(SettingsForTests.GenerateMockUmbracoSettings); + Composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); Composition.Configs.Add(SettingsForTests.GenerateMockGlobalSettings); } diff --git a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs index 16b8859bed..8b84579fec 100644 --- a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs @@ -15,7 +15,7 @@ using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Security; - +using Umbraco.Tests.Common; namespace Umbraco.Tests.Security { @@ -42,7 +42,7 @@ namespace Umbraco.Tests.Security var runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); var mgr = new BackOfficeCookieManager( - Mock.Of(accessor => accessor.UmbracoContext == umbracoContext), runtime, TestObjects.GetGlobalSettings(), IOHelper, AppCaches.RequestCache); + Mock.Of(accessor => accessor.UmbracoContext == umbracoContext), runtime, IOHelper, AppCaches.RequestCache); var result = mgr.ShouldAuthenticateRequest(Mock.Of(), new Uri("http://localhost/umbraco")); @@ -65,7 +65,7 @@ namespace Umbraco.Tests.Security new AspNetCookieManager(httpContextAccessor)); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); - var mgr = new BackOfficeCookieManager(Mock.Of(accessor => accessor.UmbracoContext == umbCtx), runtime, TestObjects.GetGlobalSettings(), IOHelper, AppCaches.RequestCache); + var mgr = new BackOfficeCookieManager(Mock.Of(accessor => accessor.UmbracoContext == umbCtx), runtime, IOHelper, AppCaches.RequestCache); var request = new Mock(); request.Setup(owinRequest => owinRequest.Uri).Returns(new Uri("http://localhost/umbraco")); diff --git a/src/Umbraco.Tests/Security/PasswordSecurityTests.cs b/src/Umbraco.Tests/Security/PasswordSecurityTests.cs index 9ed130a62b..b1646edd28 100644 --- a/src/Umbraco.Tests/Security/PasswordSecurityTests.cs +++ b/src/Umbraco.Tests/Security/PasswordSecurityTests.cs @@ -14,14 +14,6 @@ namespace Umbraco.Tests.Security [TestFixture] public class PasswordSecurityTests { - [Test] - public void Get_Hash_Algorithm_Legacy() - { - var passwordSecurity = new PasswordSecurity(Mock.Of(x => x.UseLegacyEncoding == true && x.HashAlgorithmType == "HMACSHA256")); - var alg = passwordSecurity.GetHashAlgorithm("blah"); - Assert.IsTrue(alg is HMACSHA1); - } - [Test] public void Get_Hash_Algorithm_Default() { diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index fa47f085c9..79a2832822 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -1890,6 +1890,49 @@ namespace Umbraco.Tests.Services //Assert.AreNotEqual(content.Name, copy.Name); } + [Test] + public void Can_Copy_And_Modify_Content_With_Events() + { + // see https://github.com/umbraco/Umbraco-CMS/issues/5513 + + TypedEventHandler> copying = (sender, args) => + { + args.Copy.SetValue("title", "1"); + args.Original.SetValue("title", "2"); + }; + + TypedEventHandler> copied = (sender, args) => + { + var copyVal = args.Copy.GetValue("title"); + var origVal = args.Original.GetValue("title"); + + Assert.AreEqual("1", copyVal); + Assert.AreEqual("2", origVal); + }; + + try + { + var contentService = ServiceContext.ContentService; + + ContentService.Copying += copying; + ContentService.Copied += copied; + + var contentType = MockedContentTypes.CreateSimpleContentType(); + ServiceContext.ContentTypeService.Save(contentType); + var content = MockedContent.CreateSimpleContent(contentType); + content.SetValue("title", "New Value"); + contentService.Save(content); + + var copy = contentService.Copy(content, content.ParentId, false, Constants.Security.SuperUserId); + Assert.AreEqual("1", copy.GetValue("title")); + } + finally + { + ContentService.Copying -= copying; + ContentService.Copied -= copied; + } + } + [Test] public void Can_Copy_Recursive() { diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index 1b6b632a10..0d98574504 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -58,7 +58,7 @@ namespace Umbraco.Tests.Services var memberRepository = Mock.Of(); var hostingEnvironment = Mock.Of(); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var settings = Mock.Of(); return new PublishedSnapshotService( @@ -78,7 +78,6 @@ namespace Umbraco.Tests.Services Factory.GetInstance(), Mock.Of(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), - typeFinder, hostingEnvironment, new MockShortStringHelper(), IOHelper, diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs index e95d3a6f60..6138607e9d 100644 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -20,10 +20,10 @@ using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.Security.Providers; +using Umbraco.Tests.Common; namespace Umbraco.Tests.Services { diff --git a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs b/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs index ea2041cd9c..84ffa3b696 100644 --- a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs @@ -30,7 +30,7 @@ namespace Umbraco.Tests.Strings [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6 In The Village")] // issue is fixed public void CompatibleDefaultReplacement(string input, string expected) { - var helper = new DefaultShortStringHelper(SettingsForTests.GetDefaultUmbracoSettings()); + var helper = new DefaultShortStringHelper(SettingsForTests.GenerateMockRequestHandlerSettings()); var output = input.Length < 2 ? input : helper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); Assert.AreEqual(expected, output); } diff --git a/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs index 5fd5710a79..109142f51b 100644 --- a/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs +++ b/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Strings // NOTE pre-filters runs _before_ Recode takes place // so there still may be utf8 chars even though you want ascii - _helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + _helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.FileName, new DefaultShortStringHelperConfig.Config { //PreFilter = ClearFileChars, // done in IsTerm @@ -94,8 +94,8 @@ namespace Umbraco.Tests.Strings [Test] public void U4_4056() { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); - var contentMock = Mock.Get(settings.RequestHandler); + var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); + var contentMock = Mock.Get(settings); contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); @@ -119,8 +119,8 @@ namespace Umbraco.Tests.Strings [Test] public void U4_4056_TryAscii() { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); - var contentMock = Mock.Get(settings.RequestHandler); + var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); + var contentMock = Mock.Get(settings); contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); @@ -145,7 +145,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringUnderscoreInTerm() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is accepted within terms @@ -155,7 +155,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo_bar*nil", helper.CleanString("foo_bar nil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is not accepted within terms @@ -169,7 +169,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringLeadingChars() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // letters and digits are valid leading chars @@ -179,7 +179,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("0123foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // only letters are valid leading chars @@ -190,14 +190,14 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123 foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings())); + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings())); Assert.AreEqual("child2", helper.CleanStringForSafeAlias("1child2")); } [Test] public void CleanStringTermOnUpper() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -207,7 +207,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*Bar", helper.CleanString("fooBar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -221,7 +221,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringAcronymOnNonUpper() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -234,7 +234,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*BAnil", helper.CleanString("foo BAnil", CleanStringType.Alias)); Assert.AreEqual("foo*Bnil", helper.CleanString("foo Bnil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -251,7 +251,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringGreedyAcronyms() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -264,7 +264,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*BA*nil", helper.CleanString("foo BAnil", CleanStringType.Alias)); Assert.AreEqual("foo*Bnil", helper.CleanString("foo Bnil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -281,7 +281,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringWhiteSpace() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -294,7 +294,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSeparator() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -302,7 +302,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -310,14 +310,14 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged })); Assert.AreEqual("foobar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -329,7 +329,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSymbols() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -383,7 +383,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringEncoding() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -392,7 +392,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("中文测试", helper.CleanString("中文测试", CleanStringType.Alias)); Assert.AreEqual("léger*中文测试*ZÔRG", helper.CleanString("léger 中文测试 ZÔRG", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Ascii | CleanStringType.Unchanged, @@ -405,8 +405,8 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringDefaultConfig() { - var settings = SettingsForTests.GenerateMockUmbracoSettings(); - var contentMock = Mock.Get(settings.RequestHandler); + var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); + var contentMock = Mock.Get(settings); contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); @@ -431,7 +431,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringCasing() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, diff --git a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs b/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs index 43d97523d2..7135c63c43 100644 --- a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs +++ b/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs @@ -1,7 +1,6 @@ using Umbraco.Core.Logging; using Moq; using NUnit.Framework; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Templates; using Umbraco.Web; using Umbraco.Core.Models.PublishedContent; @@ -14,6 +13,7 @@ using Umbraco.Core.Models; using Umbraco.Core; using System.Diagnostics; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Common; namespace Umbraco.Tests.Templates { @@ -78,7 +78,7 @@ namespace Umbraco.Tests.Templates var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(Enumerable.Empty()), new MediaUrlProviderCollection(new []{mediaUrlProvider.Object}), Mock.Of() diff --git a/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs b/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs index f350a5d702..f24fad442f 100644 --- a/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs +++ b/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs @@ -6,9 +6,9 @@ using System.Web; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Routing; using Umbraco.Web.Templates; @@ -73,7 +73,7 @@ namespace Umbraco.Tests.Templates umbracoContextAccessor: umbracoContextAccessor); var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new []{contentUrlProvider.Object}), new MediaUrlProviderCollection(new []{mediaUrlProvider.Object}), Mock.Of() diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index 2bd36947c6..e035eaa807 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -38,7 +38,7 @@ namespace Umbraco.Tests.TestHelpers var ioHelper = TestHelper.IOHelper; var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var typeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), logger, diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index b09620103b..24dcb229c9 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Request; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Tests.Common; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing.Objects.Accessors; @@ -32,7 +33,6 @@ namespace Umbraco.Tests.TestHelpers protected override void Compose() { base.Compose(); - base.Compose(); Composition.RegisterUnique(); Composition.RegisterUnique(); @@ -90,18 +90,17 @@ namespace Umbraco.Tests.TestHelpers internal PublishedRouter CreatePublishedRouter(IFactory container = null, ContentFinderCollection contentFinders = null) { - return CreatePublishedRouter(TestObjects.GetUmbracoSettings().WebRouting, container ?? Factory, contentFinders); + return CreatePublishedRouter(SettingsForTests.GenerateMockWebRoutingSettings(), container ?? Factory, contentFinders); } - internal static PublishedRouter CreatePublishedRouter(IWebRoutingSection webRoutingSection, IFactory container = null, ContentFinderCollection contentFinders = null) + internal static PublishedRouter CreatePublishedRouter(IWebRoutingSettings webRoutingSettings, IFactory container = null, ContentFinderCollection contentFinders = null) { return new PublishedRouter( - webRoutingSection, + webRoutingSettings, contentFinders ?? new ContentFinderCollection(Enumerable.Empty()), new TestLastChanceFinder(), new TestVariationContextAccessor(), new ProfilingLogger(Mock.Of(), Mock.Of()), - container?.TryGetInstance() ?? Current.Factory.GetInstance(), Mock.Of(), Mock.Of(), container?.GetInstance() ?? Current.Factory.GetInstance(), diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 35197e13e0..a39219a570 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -25,6 +25,7 @@ using Umbraco.Core.Logging; using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Security.Providers; using Umbraco.Tests.Strings; +using Umbraco.Tests.Common; namespace Umbraco.Tests.TestHelpers.ControllerTesting { diff --git a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs index 56fdc96aa7..fc3d3f6b52 100644 --- a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs +++ b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs @@ -1,73 +1,19 @@ -using System.IO; -using System.Configuration; -using Moq; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; namespace Umbraco.Tests.TestHelpers { public class SettingsForTests { - public static IGlobalSettings GenerateMockGlobalSettings() - { - var config = Mock.Of( - settings => - settings.ConfigurationStatus == TestHelper.GetUmbracoVersion().SemanticVersion.ToSemanticString() && - settings.UseHttps == false && - settings.HideTopLevelNodeFromPath == false && - settings.Path == TestHelper.IOHelper.ResolveUrl("~/umbraco") && - settings.TimeOutInMinutes == 20 && - settings.DefaultUILanguage == "en" && - settings.ReservedPaths == (GlobalSettings.StaticReservedPaths + "~/umbraco") && - settings.ReservedUrls == GlobalSettings.StaticReservedUrls && - settings.UmbracoPath == "~/umbraco" && - settings.UmbracoMediaPath == "~/media" && - settings.UmbracoCssPath == "~/css" && - settings.UmbracoScriptsPath == "~/scripts" - ); + private static Common.SettingsForTests _settingsForTests = new Common.SettingsForTests(); - - - return config; - } + public static IGlobalSettings GenerateMockGlobalSettings() => _settingsForTests.GenerateMockGlobalSettings(TestHelper.GetUmbracoVersion()); /// /// Returns generated settings which can be stubbed to return whatever values necessary /// /// - public static IUmbracoSettingsSection GenerateMockUmbracoSettings() - { - var settings = new Mock(); - - var content = new Mock(); - var security = new Mock(); - var requestHandler = new Mock(); - var logging = new Mock(); - var routing = new Mock(); - - var userPasswordConfig = new Mock(); - var memberPasswordConfig = new Mock(); - security.Setup(x => x.UserPasswordConfiguration).Returns(userPasswordConfig.Object); - security.Setup(x => x.MemberPasswordConfiguration).Returns(memberPasswordConfig.Object); - - settings.Setup(x => x.Content).Returns(content.Object); - settings.Setup(x => x.Security).Returns(security.Object); - settings.Setup(x => x.RequestHandler).Returns(requestHandler.Object); - settings.Setup(x => x.Logging).Returns(logging.Object); - settings.Setup(x => x.WebRouting).Returns(routing.Object); - - //Now configure some defaults - the defaults in the config section classes do NOT pertain to the mocked data!! - settings.Setup(x => x.Content.ImageAutoFillProperties).Returns(ContentImagingElement.GetDefaultImageAutoFillProperties()); - settings.Setup(x => x.Content.ImageFileTypes).Returns(ContentImagingElement.GetDefaultImageFileTypes()); - settings.Setup(x => x.RequestHandler.AddTrailingSlash).Returns(true); - settings.Setup(x => x.RequestHandler.CharCollection).Returns(RequestHandlerElement.GetDefaultCharReplacements()); - settings.Setup(x => x.WebRouting.UrlProviderMode).Returns("Auto"); - - return settings.Object; - } + public static IContentSettings GenerateMockContentSettings() => _settingsForTests.GenerateMockContentSettings(); //// from appSettings @@ -97,73 +43,20 @@ namespace Umbraco.Tests.TestHelpers // //SaveSettings(); //} - public static void Reset() - { - ResetSettings(); - GlobalSettings.Reset(); + public static void Reset() => _settingsForTests.Reset(); - //foreach (var kvp in SavedAppSettings) - // ConfigurationManager.AppSettings.Set(kvp.Key, kvp.Value); + internal static IGlobalSettings GetDefaultGlobalSettings() => _settingsForTests.GetDefaultGlobalSettings(TestHelper.GetUmbracoVersion()); - //// set some defaults that are wrong in the config file?! - //// this is annoying, really - //HideTopLevelNodeFromPath = false; - } + internal static IHostingSettings GetDefaultHostingSettings() => _settingsForTests.GetDefaultHostingSettings(); - /// - /// This sets all settings back to default settings - /// - private static void ResetSettings() - { - _defaultGlobalSettings = null; - } + public static IWebRoutingSettings GenerateMockWebRoutingSettings() => _settingsForTests.GenerateMockWebRoutingSettings(); - private static IUmbracoSettingsSection _defaultUmbracoSettings; - private static IGlobalSettings _defaultGlobalSettings; - private static IHostingSettings _defaultHostingSettings; + public static IRequestHandlerSettings GenerateMockRequestHandlerSettings() => _settingsForTests.GenerateMockRequestHandlerSettings(); - internal static IGlobalSettings GetDefaultGlobalSettings() - { - if (_defaultGlobalSettings == null) - { - _defaultGlobalSettings = GenerateMockGlobalSettings(); - } - return _defaultGlobalSettings; - } + public static ISecuritySettings GenerateMockSecuritySettings() => _settingsForTests.GenerateMockSecuritySettings(); - internal static IHostingSettings GetDefaultHostingSettings() - { - if (_defaultHostingSettings == null) - { - _defaultHostingSettings = GenerateMockHostingSettings(); - } - return _defaultHostingSettings; - } + public static IUserPasswordConfiguration GenerateMockUserPasswordConfiguration() => _settingsForTests.GenerateMockUserPasswordConfiguration(); - private static IHostingSettings GenerateMockHostingSettings() - { - var config = Mock.Of( - settings => - settings.LocalTempStorageLocation == LocalTempStorage.EnvironmentTemp && - settings.DebugMode == false - ); - return config; - } - - internal static IUmbracoSettingsSection GetDefaultUmbracoSettings() - { - if (_defaultUmbracoSettings == null) - { - // TODO: Just make this mocks instead of reading from the config - - var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/UmbracoSettings/web.config")); - - var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = config.FullName }; - var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); - _defaultUmbracoSettings = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection; - } - - return _defaultUmbracoSettings; - } + public static IMemberPasswordConfiguration GenerateMockMemberPasswordConfiguration() => _settingsForTests.GenerateMockMemberPasswordConfiguration(); } } diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs index c79a0f5c47..f5d18e05ba 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs @@ -40,7 +40,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs { if (_factory != null) return _factory(requestContext); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var types = typeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() }); var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase)); diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index 41b97ac580..11393e3e6b 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -21,15 +21,13 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Net; using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Runtime; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Core.Sync; -using Umbraco.Net; -using Umbraco.Tests.Testing.Objects.Accessors; +using Umbraco.Tests.Common; using Umbraco.Web; using Umbraco.Web.Hosting; using Umbraco.Web.Routing; @@ -42,82 +40,74 @@ namespace Umbraco.Tests.TestHelpers /// public static class TestHelper { - - public static TypeLoader GetMockedTypeLoader() + private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal(); + private class TestHelperInternal : TestHelperBase { - return new TypeLoader(IOHelper, Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of()); + public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly) + { + + } + + public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = new UmbracoDbProviderFactoryCreator(Constants.DbProviderNames.SqlCe); + + public override IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = new SqlCeBulkSqlInsertProvider(); + + public override IMarchal Marchal { get; } = new FrameworkMarchal(); + + public override IBackOfficeInfo GetBackOfficeInfo() + => new AspNetBackOfficeInfo( + SettingsForTests.GenerateMockGlobalSettings(GetUmbracoVersion()), + TestHelper.IOHelper, Mock.Of(), SettingsForTests.GenerateMockWebRoutingSettings()); + + public override IHostingEnvironment GetHostingEnvironment() + => new AspNetHostingEnvironment(SettingsForTests.GetDefaultHostingSettings()); + + public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() + => new AspNetApplicationShutdownRegistry(); + + public override IIpResolver GetIpResolver() + => new AspNetIpResolver(); } - public static Configs GetConfigs() - { - return GetConfigsFactory().Create(IOHelper); - } - public static IRuntimeState GetRuntimeState() - { - return new RuntimeState( - Mock.Of(), - Mock.Of(), - Mock.Of(), - new Lazy(), - new Lazy(), - TestHelper.GetUmbracoVersion(), - TestHelper.GetHostingEnvironment(), - TestHelper.GetBackOfficeInfo() - ); - } + public static ITypeFinder GetTypeFinder() => _testHelperInternal.GetTypeFinder(); - public static IBackOfficeInfo GetBackOfficeInfo() - { - return new AspNetBackOfficeInfo(SettingsForTests.GenerateMockGlobalSettings(), TestHelper.IOHelper, SettingsForTests.GenerateMockUmbracoSettings(), Mock.Of()); - } + public static TypeLoader GetMockedTypeLoader() => _testHelperInternal.GetMockedTypeLoader(); - public static IConfigsFactory GetConfigsFactory() - { - return new ConfigsFactory(); - } + public static Configs GetConfigs() => _testHelperInternal.GetConfigs(); + + public static IRuntimeState GetRuntimeState() => _testHelperInternal.GetRuntimeState(); + + public static IBackOfficeInfo GetBackOfficeInfo() => _testHelperInternal.GetBackOfficeInfo(); + + public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory(); /// /// Gets the current assembly directory. /// /// The assembly directory. - public static string CurrentAssemblyDirectory - { - get - { - var codeBase = typeof(TestHelper).Assembly.CodeBase; - var uri = new Uri(codeBase); - var path = uri.LocalPath; - return Path.GetDirectoryName(path); - } - } + public static string CurrentAssemblyDirectory => _testHelperInternal.CurrentAssemblyDirectory; - public static IShortStringHelper ShortStringHelper { get; } = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); - public static IJsonSerializer JsonSerializer { get; } = new JsonNetSerializer(); - public static IVariationContextAccessor VariationContextAccessor { get; } = new TestVariationContextAccessor(); - public static IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = new UmbracoDbProviderFactoryCreator(Constants.DbProviderNames.SqlCe); - public static IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = new SqlCeBulkSqlInsertProvider(); - public static IMarchal Marchal { get; } = new FrameworkMarchal(); - public static ICoreDebug CoreDebug { get; } = new CoreDebug(); + public static IShortStringHelper ShortStringHelper => _testHelperInternal.ShortStringHelper; + public static IJsonSerializer JsonSerializer => _testHelperInternal.JsonSerializer; + public static IVariationContextAccessor VariationContextAccessor => _testHelperInternal.VariationContextAccessor; + public static IDbProviderFactoryCreator DbProviderFactoryCreator => _testHelperInternal.DbProviderFactoryCreator; + public static IBulkSqlInsertProvider BulkSqlInsertProvider => _testHelperInternal.BulkSqlInsertProvider; + public static IMarchal Marchal => _testHelperInternal.Marchal; + public static ICoreDebugSettings CoreDebugSettings => _testHelperInternal.CoreDebugSettings; - public static IIOHelper IOHelper { get; } = new IOHelper(GetHostingEnvironment()); - public static IMainDom MainDom { get; } = new MainDom(Mock.Of(), GetHostingEnvironment(), new MainDomSemaphoreLock(Mock.Of(), GetHostingEnvironment())); - public static UriUtility UriUtility { get; } = new UriUtility(GetHostingEnvironment()); + public static IIOHelper IOHelper => _testHelperInternal.IOHelper; + public static IMainDom MainDom => _testHelperInternal.MainDom; + public static UriUtility UriUtility => _testHelperInternal.UriUtility; - public static IWebRoutingSection WebRoutingSection => SettingsForTests.GetDefaultUmbracoSettings().WebRouting; + public static IWebRoutingSettings WebRoutingSettings => _testHelperInternal.WebRoutingSettings; /// /// Maps the given making it rooted on . must start with ~/ /// /// The relative path. /// - public static string MapPathForTest(string relativePath) - { - if (!relativePath.StartsWith("~/")) - throw new ArgumentException("relativePath must start with '~/'", "relativePath"); - - return relativePath.Replace("~/", CurrentAssemblyDirectory + "/"); - } + public static string MapPathForTest(string relativePath) => _testHelperInternal.MapPathForTest(relativePath); public static void InitializeContentDirectories() { @@ -164,6 +154,7 @@ namespace Umbraco.Tests.TestHelpers File.Delete(umbracoSettingsFile); } + // TODO: Move to Assertions or AssertHelper // FIXME: obsolete the dateTimeFormat thing and replace with dateDelta public static void AssertPropertyValuesAreEqual(object actual, object expected, string dateTimeFormat = null, Func sorter = null, string[] ignoreProperties = null) { @@ -307,6 +298,7 @@ namespace Umbraco.Tests.TestHelpers } } + // TODO: Move to MockedValueEditors.cs public static DataValueEditor CreateDataValueEditor(string name) { var valueType = (ValueTypes.IsValue(name)) ? name : ValueTypes.String; @@ -325,30 +317,17 @@ namespace Umbraco.Tests.TestHelpers } - public static IUmbracoVersion GetUmbracoVersion() - { - return new UmbracoVersion(GetConfigs().Global()); - } + public static IUmbracoVersion GetUmbracoVersion() => _testHelperInternal.GetUmbracoVersion(); - public static IRegister GetRegister() - { - return RegisterFactory.Create(GetConfigs().Global()); - } + public static IRegister GetRegister() => _testHelperInternal.GetRegister(); - public static IHostingEnvironment GetHostingEnvironment() - { - return new AspNetHostingEnvironment(SettingsForTests.GetDefaultHostingSettings()); - } + public static IHostingEnvironment GetHostingEnvironment() => _testHelperInternal.GetHostingEnvironment(); - public static IIpResolver GetIpResolver() - { - return new AspNetIpResolver(); - } + public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _testHelperInternal.GetHostingEnvironmentLifetime(); - public static IRequestCache GetRequestCache() - { - return new DictionaryAppCache(); - } + public static IIpResolver GetIpResolver() => _testHelperInternal.GetIpResolver(); + + public static IRequestCache GetRequestCache() => _testHelperInternal.GetRequestCache(); public static IHttpContextAccessor GetHttpContextAccessor(HttpContextBase httpContextBase = null) { @@ -369,11 +348,6 @@ namespace Umbraco.Tests.TestHelpers return mock.Object; } - public static IPublishedUrlProvider GetPublishedUrlProvider() - { - var mock = new Mock(); - - return mock.Object; - } + public static IPublishedUrlProvider GetPublishedUrlProvider() => _testHelperInternal.GetPublishedUrlProvider(); } } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 5dabb7ed06..a07be868a5 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -17,7 +17,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Services; -using Umbraco.Tests.Testing.Objects.Accessors; +using Umbraco.Tests.Common; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -140,18 +140,6 @@ namespace Umbraco.Tests.TestHelpers return umbracoContextFactory.EnsureUmbracoContext().UmbracoContext; } - public IUmbracoSettingsSection GetUmbracoSettings() - { - // FIXME: Why not use the SettingsForTest.GenerateMock ... ? - // FIXME: Shouldn't we use the default ones so they are the same instance for each test? - - var umbracoSettingsMock = new Mock(); - var webRoutingSectionMock = new Mock(); - webRoutingSectionMock.Setup(x => x.UrlProviderMode).Returns(UrlMode.Auto.ToString()); - umbracoSettingsMock.Setup(x => x.WebRouting).Returns(webRoutingSectionMock.Object); - return umbracoSettingsMock.Object; - } - public IGlobalSettings GetGlobalSettings() { return SettingsForTests.GetDefaultGlobalSettings(); diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index e58d58783c..ccbea01d0b 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -96,7 +96,7 @@ namespace Umbraco.Tests.TestHelpers ILogger logger, IIOHelper ioHelper, IGlobalSettings globalSettings, - IUmbracoSettingsSection umbracoSettings, + IContentSettings contentSettings, IEventMessagesFactory eventMessagesFactory, UrlSegmentProviderCollection urlSegmentProviders, TypeLoader typeLoader, @@ -162,7 +162,7 @@ namespace Umbraco.Tests.TestHelpers var dataTypeService = GetLazyService(factory, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), ioHelper, localizedTextService.Value, localizationService.Value, TestHelper.ShortStringHelper)); var propertyValidationService = new Lazy(() => new PropertyValidationService(propertyEditorCollection, dataTypeService.Value)); var contentService = GetLazyService(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), propertyValidationService)); - var notificationService = GetLazyService(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo(c), globalSettings, umbracoSettings.Content)); + var notificationService = GetLazyService(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo(c), globalSettings, contentSettings)); var serverRegistrationService = GetLazyService(factory, c => new ServerRegistrationService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), TestHelper.GetHostingEnvironment())); var memberGroupService = GetLazyService(factory, c => new MemberGroupService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var memberService = GetLazyService(factory, c => new MemberService(scopeProvider, logger, eventMessagesFactory, memberGroupService.Value, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); @@ -247,12 +247,18 @@ namespace Umbraco.Tests.TestHelpers // mappersBuilder.AddCore(); // var mappers = mappersBuilder.CreateCollection(); var mappers = Current.Factory.GetInstance(); - databaseFactory = new UmbracoDatabaseFactory(Constants.System.UmbracoConnectionName, logger, new Lazy(() => mappers), TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator); + databaseFactory = new UmbracoDatabaseFactory( + Constants.System.UmbracoConnectionName, + SettingsForTests.GetDefaultGlobalSettings(), + new ConnectionStrings(), + logger, + new Lazy(() => mappers), + TestHelper.DbProviderFactoryCreator); } - typeFinder = typeFinder ?? new TypeFinder(logger); + typeFinder = typeFinder ?? new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly)); fileSystems = fileSystems ?? new FileSystems(Current.Factory, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings()); - var coreDebug = Current.Configs.CoreDebug(); + var coreDebug = TestHelper.CoreDebugSettings; var mediaFileSystem = Mock.Of(); var scopeProvider = new ScopeProvider(databaseFactory, fileSystems, coreDebug, mediaFileSystem, logger, typeFinder, NoAppCache.Instance); return scopeProvider; diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index b02af84e09..fbfada118a 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -30,8 +30,8 @@ using Umbraco.Core.Migrations.Install; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.WebApi; +using Umbraco.Tests.Common; namespace Umbraco.Tests.TestHelpers { @@ -265,6 +265,7 @@ namespace Umbraco.Tests.TestHelpers Logger, Factory.GetInstance(), HostingEnvironment, + HostingLifetime, ShortStringHelper, new SiteDomainHelper(), Factory.GetInstance(), diff --git a/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs b/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs index 20b18fa728..d6a1606853 100644 --- a/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs +++ b/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs @@ -3,8 +3,8 @@ using NUnit.Framework.Internal; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Testing.Objects IHttpContextAccessor httpContextAccessor = null, IPublishedUrlProvider publishedUrlProvider = null) { - if (globalSettings == null) globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + if (globalSettings == null) globalSettings = TestHelpers.SettingsForTests.GenerateMockGlobalSettings(); if (umbracoContextAccessor == null) umbracoContextAccessor = new TestUmbracoContextAccessor(); if (httpContextAccessor == null) httpContextAccessor = TestHelper.GetHttpContextAccessor(); if (publishedUrlProvider == null) publishedUrlProvider = TestHelper.GetPublishedUrlProvider(); diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 439c9b17f2..72186dd081 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -16,9 +16,9 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -85,7 +85,7 @@ namespace Umbraco.Tests.Testing.TestingTests var theUrlProvider = new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSection, + TestHelper.WebRoutingSettings, new UrlProviderCollection(new [] { urlProvider }), new MediaUrlProviderCollection( Enumerable.Empty()) , umbracoContext.VariationContextAccessor); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index de0db554f3..0345aab2da 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -35,7 +35,6 @@ using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; using Umbraco.Web.Services; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Actions; using Umbraco.Web.ContentApps; using Umbraco.Web.PublishedCache; @@ -52,10 +51,10 @@ using Umbraco.Web.Templates; using Umbraco.Web.PropertyEditors; using Umbraco.Core.Dictionary; using Umbraco.Core.Models; +using Umbraco.Net; using Umbraco.Core.Request; using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Net; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web.AspNet; using Umbraco.Web.Install; @@ -63,6 +62,8 @@ using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; using Umbraco.Web.Trees; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.Common; + namespace Umbraco.Tests.Testing { /// @@ -138,7 +139,8 @@ namespace Umbraco.Tests.Testing protected virtual IProfilingLogger ProfilingLogger => Factory.GetInstance(); - protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(SettingsForTests.GetDefaultHostingSettings()); + protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(TestHelpers.SettingsForTests.GetDefaultHostingSettings()); + protected IApplicationShutdownRegistry HostingLifetime { get; } = new AspNetApplicationShutdownRegistry(); protected IIpResolver IpResolver => Factory.GetInstance(); protected IBackOfficeInfo BackOfficeInfo => Factory.GetInstance(); protected AppCaches AppCaches => Factory.GetInstance(); @@ -171,12 +173,12 @@ namespace Umbraco.Tests.Testing var proflogger = new ProfilingLogger(logger, profiler); IOHelper = TestHelper.IOHelper; - TypeFinder = new TypeFinder(logger); + TypeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly)); var appCaches = GetAppCaches(); - var globalSettings = SettingsForTests.GetDefaultGlobalSettings(); - var settings = SettingsForTests.GetDefaultUmbracoSettings(); + var globalSettings = TestHelpers.SettingsForTests.GetDefaultGlobalSettings(); + var settings = TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings(); - IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, settings, logger); + IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, logger, settings); IIpResolver ipResolver = new AspNetIpResolver(); UmbracoVersion = new UmbracoVersion(globalSettings); @@ -265,7 +267,7 @@ namespace Umbraco.Tests.Testing profiler = Mock.Of(); break; case UmbracoTestOptions.Logger.Serilog: - logger = new SerilogLogger(TestHelper.CoreDebug, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))); + logger = new SerilogLogger(TestHelper.CoreDebugSettings, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))); profiler = new LogProfiler(logger); break; case UmbracoTestOptions.Logger.Console: @@ -321,7 +323,7 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(factory => new UrlProvider( factory.GetInstance(), - TestObjects.GetUmbracoSettings().WebRouting, + TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings(), new UrlProviderCollection(Enumerable.Empty()), new MediaUrlProviderCollection(Enumerable.Empty()), factory.GetInstance() @@ -411,9 +413,15 @@ namespace Umbraco.Tests.Testing protected virtual void ComposeSettings() { - Composition.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings); - Composition.Configs.Add(SettingsForTests.GetDefaultGlobalSettings); - Composition.Configs.Add(SettingsForTests.GetDefaultHostingSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GetDefaultGlobalSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GetDefaultHostingSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockSecuritySettings); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockUserPasswordConfiguration); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockMemberPasswordConfiguration); + Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); + //Composition.Configs.Add(() => new DefaultUserPasswordConfig()); } @@ -426,10 +434,6 @@ namespace Umbraco.Tests.Testing // default Datalayer/Repositories/SQL/Database/etc... Composition.ComposeRepositories(); - // register basic stuff that might need to be there for some container resolvers to work - Composition.RegisterUnique(factory => factory.GetInstance().Content); - Composition.RegisterUnique(factory => factory.GetInstance().WebRouting); - Composition.RegisterUnique(); Composition.RegisterUnique(); @@ -454,11 +458,16 @@ namespace Umbraco.Tests.Testing .AddCoreMappers(); Composition.RegisterUnique(_ => new TransientEventMessagesFactory()); + + var globalSettings = TestHelper.GetConfigs().Global(); + var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + Composition.RegisterUnique(f => new UmbracoDatabaseFactory( Constants.System.UmbracoConnectionName, + globalSettings, + connectionStrings, Logger, new Lazy(f.GetInstance), - TestHelper.GetConfigs(), TestHelper.DbProviderFactoryCreator)); Composition.RegisterUnique(f => f.TryGetInstance().SqlContext); @@ -546,7 +555,7 @@ namespace Umbraco.Tests.Testing // reset all other static things that should not be static ;( UriUtility.ResetAppDomainAppVirtualPath(HostingEnvironment); - SettingsForTests.Reset(); // FIXME: should it be optional? + TestHelpers.SettingsForTests.Reset(); // FIXME: should it be optional? // clear static events DocumentRepository.ClearScopeEvents(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index ef7b50856b..33fd731088 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -77,14 +77,14 @@ - + 2.0.0-alpha.20200128.15 1.8.14 - + @@ -100,9 +100,9 @@ - + - + @@ -120,7 +120,6 @@ - @@ -144,6 +143,7 @@ + @@ -212,7 +212,6 @@ - @@ -224,9 +223,7 @@ - - @@ -242,10 +239,8 @@ - - @@ -288,6 +283,7 @@ + @@ -302,17 +298,13 @@ - - - - @@ -587,6 +579,10 @@ {f6de8da0-07cc-4ef2-8a59-2bc81dbb3830} Umbraco.PublishedCache.NuCache + + {a499779c-1b3b-48a8-b551-458e582e6e96} + Umbraco.Tests.Common + {651E1350-91B6-44B7-BD60-7207006D7003} Umbraco.Web diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 2266bd0104..91cb843eb1 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -17,7 +17,7 @@ namespace Umbraco.Tests.UmbracoExamine [OneTimeSetUp] public void InitializeFixture() { - var logger = new SerilogLogger(TestHelper.CoreDebug, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))); + var logger = new SerilogLogger(TestHelper.CoreDebugSettings, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))); _profilingLogger = new ProfilingLogger(logger, new LogProfiler(logger)); } @@ -33,7 +33,7 @@ namespace Umbraco.Tests.UmbracoExamine { base.Compose(); - Composition.RegisterUnique(_ => new DefaultShortStringHelper(SettingsForTests.GetDefaultUmbracoSettings())); + Composition.RegisterUnique(_ => new DefaultShortStringHelper(SettingsForTests.GenerateMockRequestHandlerSettings())); } } } diff --git a/src/Umbraco.Tests/Views/web.config b/src/Umbraco.Tests/Views/web.config deleted file mode 100644 index efd80424e5..0000000000 --- a/src/Umbraco.Tests/Views/web.config +++ /dev/null @@ -1,74 +0,0 @@ - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index 9ecedee056..0e757bbc6d 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -88,7 +88,7 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance(), + Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance() ); diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs index d914ef2c39..14bbc5f1fb 100644 --- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs @@ -89,10 +89,11 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance(), + Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance() + Factory.GetInstance(), + Factory.GetInstance() ); return usersController; @@ -161,10 +162,11 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance(), + Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance() + Factory.GetInstance(), + Factory.GetInstance() ); return usersController; } @@ -203,10 +205,11 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance(), + Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance() + Factory.GetInstance(), + Factory.GetInstance() ); return usersController; } @@ -280,10 +283,11 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance(), + Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance() + Factory.GetInstance(), + Factory.GetInstance() ); return usersController; } diff --git a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs index bdd7c6eb93..7906047520 100644 --- a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs @@ -13,9 +13,9 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Models; using Umbraco.Web.Mvc; diff --git a/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs index 901c737584..aa94272964 100644 --- a/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs @@ -7,8 +7,8 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Models; using Umbraco.Web.Mvc; using Current = Umbraco.Web.Composing.Current; diff --git a/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs new file mode 100644 index 0000000000..e728d75dc5 --- /dev/null +++ b/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs @@ -0,0 +1,54 @@ +using System.Web.Mvc; +using Moq; +using NUnit.Framework; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Web; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Tests.Web.Mvc +{ + [TestFixture] + public class RenderNoContentControllerTests + { + [Test] + public void Redirects_To_Root_When_Content_Published() + { + var mockUmbracoContext = new Mock(); + mockUmbracoContext.Setup(x => x.Content.HasContent()).Returns(true); + var mockIOHelper = new Mock(); + var mockGlobalSettings = new Mock(); + var controller = new RenderNoContentController(mockUmbracoContext.Object, mockIOHelper.Object, mockGlobalSettings.Object); + + var result = controller.Index() as RedirectResult; + + Assert.IsNotNull(result); + Assert.AreEqual("~/", result.Url); + } + + [Test] + public void Renders_View_When_No_Content_Published() + { + const string UmbracoPathSetting = "~/umbraco"; + const string UmbracoPath = "/umbraco"; + const string ViewPath = "~/config/splashes/NoNodes.cshtml"; + var mockUmbracoContext = new Mock(); + mockUmbracoContext.Setup(x => x.Content.HasContent()).Returns(false); + var mockIOHelper = new Mock(); + mockIOHelper.Setup(x => x.ResolveUrl(It.Is(y => y == UmbracoPathSetting))).Returns(UmbracoPath); + var mockGlobalSettings = new Mock(); + mockGlobalSettings.SetupGet(x => x.UmbracoPath).Returns(UmbracoPathSetting); + mockGlobalSettings.SetupGet(x => x.NoNodesViewPath).Returns(ViewPath); + var controller = new RenderNoContentController(mockUmbracoContext.Object, mockIOHelper.Object, mockGlobalSettings.Object); + + var result = controller.Index() as ViewResult; + Assert.IsNotNull(result); + Assert.AreEqual(ViewPath, result.ViewName); + + var model = result.Model as NoNodesViewModel; + Assert.IsNotNull(model); + Assert.AreEqual(UmbracoPath, model.UmbracoPath); + } + } +} diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 73d447d3b2..2a9b85aba5 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -11,9 +11,9 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; @@ -156,7 +156,7 @@ namespace Umbraco.Tests.Web.Mvc var content = Mock.Of(publishedContent => publishedContent.Id == 12345); - var publishedRouter = BaseWebTest.CreatePublishedRouter(TestObjects.GetUmbracoSettings().WebRouting); + var publishedRouter = BaseWebTest.CreatePublishedRouter(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings()); var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/test")); frequest.PublishedContent = content; diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index bc2b896b49..c5e9556d05 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -16,7 +16,7 @@ using Umbraco.Core.Strings; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; +using Umbraco.Tests.Common; using Umbraco.Web; using Umbraco.Web.Models; using Umbraco.Web.Mvc; @@ -385,13 +385,9 @@ namespace Umbraco.Tests.Web.Mvc ViewContext GetViewContext() { - var settings = SettingsForTests.GetDefaultUmbracoSettings(); - var logger = Mock.Of(); - var umbracoContext = GetUmbracoContext( - logger, settings, - "/dang", 0); + var umbracoContext = GetUmbracoContext("/dang", 0); - var publishedRouter = BaseWebTest.CreatePublishedRouter(TestObjects.GetUmbracoSettings().WebRouting); + var publishedRouter = BaseWebTest.CreatePublishedRouter(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings()); var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/dang")); frequest.Culture = CultureInfo.InvariantCulture; @@ -404,7 +400,7 @@ namespace Umbraco.Tests.Web.Mvc return context; } - protected IUmbracoContext GetUmbracoContext(ILogger logger, IUmbracoSettingsSection umbracoSettings, string url, int templateId, RouteData routeData = null, bool setSingleton = false) + protected IUmbracoContext GetUmbracoContext(string url, int templateId, RouteData routeData = null, bool setSingleton = false) { var svcCtx = GetServiceContext(); @@ -427,6 +423,7 @@ namespace Umbraco.Tests.Web.Mvc new TestDefaultCultureAccessor(), Current.Logger, TestObjects.GetGlobalSettings(), TestHelper.GetHostingEnvironment(), + TestHelper.GetHostingEnvironmentLifetime(), ShortStringHelper, new SiteDomainHelper(), Factory.GetInstance(), diff --git a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs index b479961896..62d7e941d7 100644 --- a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs +++ b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Web { // FIXME: bad in a unit test - but Udi has a static ctor that wants it?! var container = new Mock(); - var typeFinder = new TypeFinder(Mock.Of()); + var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; container .Setup(x => x.GetInstance(typeof(TypeLoader))) diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs index 08cd84744b..123c5d3f62 100644 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs @@ -7,10 +7,10 @@ using System.Web.Routing; using Moq; using NUnit.Framework; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs new file mode 100644 index 0000000000..92af822836 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Concurrent; +using System.Threading; +using Microsoft.Extensions.Hosting; +using Umbraco.Core; +using Umbraco.Core.Hosting; + +namespace Umbraco.Web.BackOffice.AspNetCore +{ + public class AspNetCoreApplicationShutdownRegistry : IApplicationShutdownRegistry + { + private readonly IHostApplicationLifetime _hostApplicationLifetime; + private readonly ConcurrentDictionary _registeredObjects = + new ConcurrentDictionary(); + + public AspNetCoreApplicationShutdownRegistry(IHostApplicationLifetime hostApplicationLifetime) + { + _hostApplicationLifetime = hostApplicationLifetime; + } + + public void RegisterObject(IRegisteredObject registeredObject) + { + var wrapped = new RegisteredObjectWrapper(registeredObject); + if (!_registeredObjects.TryAdd(registeredObject, wrapped)) + { + throw new InvalidOperationException("Could not register object"); + } + + var cancellationTokenRegistration = _hostApplicationLifetime.ApplicationStopping.Register(() => wrapped.Stop(true)); + wrapped.CancellationTokenRegistration = cancellationTokenRegistration; + } + + public void UnregisterObject(IRegisteredObject registeredObject) + { + if (_registeredObjects.TryGetValue(registeredObject, out var wrapped)) + { + wrapped.CancellationTokenRegistration.Unregister(); + } + } + + + private class RegisteredObjectWrapper + { + private readonly IRegisteredObject _inner; + + public RegisteredObjectWrapper(IRegisteredObject inner) + { + _inner = inner; + } + + public CancellationTokenRegistration CancellationTokenRegistration { get; set; } + + public void Stop(bool immediate) + { + _inner.Stop(immediate); + } + } + } +} diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreComposer.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreComposer.cs new file mode 100644 index 0000000000..fc38e429a0 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreComposer.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Http; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Hosting; +using Umbraco.Net; +using Umbraco.Core.Runtime; + +namespace Umbraco.Web.BackOffice.AspNetCore +{ + /// + /// Adds/replaces AspNetCore specific services + /// + [ComposeBefore(typeof(ICoreComposer))] + [ComposeAfter(typeof(CoreInitialComposer))] + public class AspNetCoreComposer : IComposer + { + public void Compose(Composition composition) + { + // AspNetCore specific services + composition.RegisterUnique(); + + // Our own netcore implementations + composition.RegisterUnique(); + composition.RegisterUnique(); + } + } +} diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs index 5cd2b590c8..6f1298918d 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Concurrent; +using System.Globalization; using System.IO; -using System.Threading; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Hosting; using Umbraco.Core; using Umbraco.Core.Configuration; @@ -12,30 +10,29 @@ namespace Umbraco.Web.BackOffice.AspNetCore { public class AspNetCoreHostingEnvironment : Umbraco.Core.Hosting.IHostingEnvironment { - private readonly ConcurrentDictionary _registeredObjects = - new ConcurrentDictionary(); + private readonly IHostingSettings _hostingSettings; private readonly IWebHostEnvironment _webHostEnvironment; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IHostApplicationLifetime _hostApplicationLifetime; + private string _localTempPath; - public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor, IHostApplicationLifetime hostHostApplicationLifetime) + public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor) { _hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings)); _webHostEnvironment = webHostEnvironment; _httpContextAccessor = httpContextAccessor; - _hostApplicationLifetime = hostHostApplicationLifetime; SiteName = webHostEnvironment.ApplicationName; ApplicationId = AppDomain.CurrentDomain.Id.ToString(); ApplicationPhysicalPath = webHostEnvironment.ContentRootPath; ApplicationVirtualPath = "/"; //TODO how to find this, This is a server thing, not application thing. - IISVersion = new Version(0, 0); // TODO not necessary IIS + IISVersion = new Version(0, 0); // TODO not necessary IIS IsDebugMode = _hostingSettings.DebugMode; } + public bool IsHosted { get; } = true; public string SiteName { get; } public string ApplicationId { get; } @@ -55,7 +52,10 @@ namespace Umbraco.Web.BackOffice.AspNetCore switch (_hostingSettings.LocalTempStorageLocation) { case LocalTempStorage.AspNetTemp: - return _localTempPath = System.IO.Path.Combine(Path.GetTempPath(),ApplicationId, "UmbracoData"); + + // TODO: I don't think this is correct? but also we probably can remove AspNetTemp as an option entirely + // since this is legacy and we shouldn't use it + return _localTempPath = System.IO.Path.Combine(Path.GetTempPath(), ApplicationId, "UmbracoData"); case LocalTempStorage.EnvironmentTemp: @@ -83,9 +83,13 @@ namespace Umbraco.Web.BackOffice.AspNetCore } } + public string MapPath(string path) + { + var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar); + return Path.Combine(_webHostEnvironment.WebRootPath, newPath); + } - public string MapPath(string path) => Path.Combine(_webHostEnvironment.WebRootPath, path); - + // TODO: Need to take into account 'root' here public string ToAbsolute(string virtualPath, string root) { if (Uri.TryCreate(virtualPath, UriKind.Absolute, out _)) @@ -99,43 +103,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore return applicationPath.Add(segment).Value; } - public void RegisterObject(IRegisteredObject registeredObject) - { - var wrapped = new RegisteredObjectWrapper(registeredObject); - if (!_registeredObjects.TryAdd(registeredObject, wrapped)) - { - throw new InvalidOperationException("Could not register object"); - } - - var cancellationTokenRegistration = _hostApplicationLifetime.ApplicationStopping.Register(() => wrapped.Stop(true)); - wrapped.CancellationTokenRegistration = cancellationTokenRegistration; - } - - public void UnregisterObject(IRegisteredObject registeredObject) - { - if (_registeredObjects.TryGetValue(registeredObject, out var wrapped)) - { - wrapped.CancellationTokenRegistration.Unregister(); - } - } - - - private class RegisteredObjectWrapper - { - private readonly IRegisteredObject _inner; - - public RegisteredObjectWrapper(IRegisteredObject inner) - { - _inner = inner; - } - - public CancellationTokenRegistration CancellationTokenRegistration { get; set; } - - public void Stop(bool immediate) - { - _inner.Stop(immediate); - } - } + } diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs index 8f231191f2..cee43757d8 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreIpResolver.cs @@ -3,7 +3,7 @@ using Umbraco.Net; namespace Umbraco.Web.BackOffice.AspNetCore { - internal class AspNetIpResolver : IIpResolver + public class AspNetIpResolver : IIpResolver { private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs index 98e040d338..247666090e 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreMarchal.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.InteropServices; using Umbraco.Core.Diagnostics; -namespace Umbraco.Web.BackOffice +namespace Umbraco.Web.BackOffice.AspNetCore { public class AspNetCoreMarchal : IMarchal diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreSessionIdResolver.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreSessionIdResolver.cs index 5470516cf7..cafb02d367 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreSessionIdResolver.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreSessionIdResolver.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Umbraco.Net; namespace Umbraco.Web.BackOffice.AspNetCore @@ -12,6 +13,18 @@ namespace Umbraco.Web.BackOffice.AspNetCore _httpContextAccessor = httpContextAccessor; } - public string SessionId => _httpContextAccessor?.HttpContext.Session?.Id; + + public string SessionId + { + get + { + var httpContext = _httpContextAccessor?.HttpContext; + // If session isn't enabled this will throw an exception so we check + var sessionFeature = httpContext?.Features.Get(); + return sessionFeature != null + ? httpContext?.Session?.Id + : "0"; + } + } } } diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs index 20cfef352d..0dca3edec8 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Umbraco.Net; -namespace Umbraco.Web.AspNet +namespace Umbraco.Web.BackOffice.AspNetCore { public class AspNetCoreUmbracoApplicationLifetime : IUmbracoApplicationLifetime { diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs index 1f06a818d6..770f4b883f 100644 --- a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeApplicationBuilderExtensions.cs @@ -1,5 +1,10 @@ using System; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Hosting; namespace Umbraco.Web.BackOffice.AspNetCore { @@ -7,12 +12,57 @@ namespace Umbraco.Web.BackOffice.AspNetCore { public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } + if (app == null) throw new ArgumentNullException(nameof(app)); return app; } + + /// + /// Start Umbraco + /// + /// + /// + public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app) + { + if (app == null) throw new ArgumentNullException(nameof(app)); + + // Register a listener for application shutdown in order to terminate the runtime + var hostLifetime = app.ApplicationServices.GetRequiredService(); + var runtime = app.ApplicationServices.GetRequiredService(); + var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime); + hostLifetime.RegisterObject(runtimeShutdown); + + // Start the runtime! + runtime.Start(); + + return app; + } + + /// + /// Ensures the runtime is shutdown when the application is shutting down + /// + private class CoreRuntimeShutdown : IRegisteredObject + { + public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime) + { + _runtime = runtime; + _hostLifetime = hostLifetime; + } + + private bool _completed = false; + private readonly IRuntime _runtime; + private readonly IApplicationShutdownRegistry _hostLifetime; + + public void Stop(bool immediate) + { + if (!_completed) + { + _completed = true; + _runtime.Terminate(); + _hostLifetime.UnregisterObject(this); + } + + } + } } } diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs deleted file mode 100644 index 2d12ad3093..0000000000 --- a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoBackOfficeServiceCollectionExtensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Configuration; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Umbraco.Composing; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Logging.Serilog; -using Umbraco.Core.Runtime; - -namespace Umbraco.Web.BackOffice.AspNetCore -{ - public static class UmbracoBackOfficeServiceCollectionExtensions - { - public static IServiceCollection AddUmbracoBackOffice(this IServiceCollection services) - { - - - services.AddSingleton(); - - CreateCompositionRoot(services); - - return services; - } - - - private static void CreateCompositionRoot(IServiceCollection services) - { - var serviceProvider = services.BuildServiceProvider(); - - var httpContextAccessor = serviceProvider.GetService(); - var webHostEnvironment = serviceProvider.GetService(); - var hostApplicationLifetime = serviceProvider.GetService(); - - var configFactory = new ConfigsFactory(); - - var hostingSettings = configFactory.HostingSettings; - var coreDebug = configFactory.CoreDebug; - - var hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor, hostApplicationLifetime); - var ioHelper = new IOHelper(hostingEnvironment); - var configs = configFactory.Create(ioHelper); - - var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, new AspNetCoreSessionIdResolver(httpContextAccessor), () => services.BuildServiceProvider().GetService(), coreDebug, ioHelper, new AspNetCoreMarchal()); - var backOfficeInfo = new AspNetCoreBackOfficeInfo(configs.Global()); - var profiler = new LogProfiler(logger); - - Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler); - } - } -} diff --git a/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoCoreServiceCollectionExtensions.cs new file mode 100644 index 0000000000..d747cb349a --- /dev/null +++ b/src/Umbraco.Web.BackOffice/AspNetCore/UmbracoCoreServiceCollectionExtensions.cs @@ -0,0 +1,167 @@ +using System; +using System.Data.Common; +using System.Reflection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Umbraco.Configuration; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Logging.Serilog; +using Umbraco.Core.Persistence; +using Umbraco.Core.Runtime; + +namespace Umbraco.Web.BackOffice.AspNetCore +{ + // TODO: Move to Umbraco.Web.Common + public static class UmbracoCoreServiceCollectionExtensions + { + /// + /// Adds the Umbraco Configuration requirements + /// + /// + /// + /// + public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services, IConfiguration configuration) + { + if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + + var configsFactory = new AspNetCoreConfigsFactory(configuration); + + var configs = configsFactory.Create(); + + services.AddSingleton(configs); + + return services; + } + + + /// + /// Adds the Umbraco Back Core requirements + /// + /// + /// + /// + public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment) + { + if (!UmbracoServiceProviderFactory.IsActive) + throw new InvalidOperationException("Ensure to add UseUmbraco() in your Program.cs after ConfigureWebHostDefaults to enable Umbraco's service provider factory"); + + var umbContainer = UmbracoServiceProviderFactory.UmbracoContainer; + + return services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly()); + } + + /// + /// Adds the Umbraco Back Core requirements + /// + /// + /// + /// + /// + /// + public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly) + { + if (services is null) throw new ArgumentNullException(nameof(services)); + if (umbContainer is null) throw new ArgumentNullException(nameof(umbContainer)); + if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly)); + + // Special case! The generic host adds a few default services but we need to manually add this one here NOW because + // we resolve it before the host finishes configuring in the call to CreateCompositionRoot + services.AddSingleton(); + + CreateCompositionRoot(services, webHostEnvironment, out var logger, out var configs, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler); + + var globalSettings = configs.Global(); + var umbracoVersion = new UmbracoVersion(globalSettings); + + // TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however + // this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now. + var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly)); + + var coreRuntime = GetCoreRuntime( + configs, + umbracoVersion, + ioHelper, + logger, + profiler, + hostingEnvironment, + backOfficeInfo, + typeFinder); + + var factory = coreRuntime.Configure(umbContainer); + + return services; + } + + private static IRuntime GetCoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, + IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, + ITypeFinder typeFinder) + { + var connectionStringConfig = configs.ConnectionStrings()[Constants.System.UmbracoConnectionName]; + var dbProviderFactoryCreator = new SqlServerDbProviderFactoryCreator( + connectionStringConfig?.ProviderName, + DbProviderFactories.GetFactory); + + // Determine if we should use the sql main dom or the default + var globalSettings = configs.Global(); + var connStrings = configs.ConnectionStrings(); + var appSettingMainDomLock = globalSettings.MainDomLock; + var mainDomLock = appSettingMainDomLock == "SqlMainDomLock" + ? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connStrings, dbProviderFactoryCreator) + : new MainDomSemaphoreLock(logger, hostingEnvironment); + + var mainDom = new MainDom(logger, mainDomLock); + + var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetCoreBootPermissionsChecker(), + hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder); + + return coreRuntime; + } + + private static void CreateCompositionRoot(IServiceCollection services, IWebHostEnvironment webHostEnvironment, + out ILogger logger, out Configs configs, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment, + out IBackOfficeInfo backOfficeInfo, out IProfiler profiler) + { + // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured + var serviceProvider = services.BuildServiceProvider(); + + var httpContextAccessor = serviceProvider.GetRequiredService(); + + configs = serviceProvider.GetService(); + if (configs == null) + throw new InvalidOperationException($"Could not resolve type {typeof(Configs)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}"); + + var hostingSettings = configs.Hosting(); + var coreDebug = configs.CoreDebug(); + var globalSettings = configs.Global(); + + hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor); + ioHelper = new IOHelper(hostingEnvironment, globalSettings); + logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, + new AspNetCoreSessionIdResolver(httpContextAccessor), + // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured + () => services.BuildServiceProvider().GetService(), coreDebug, ioHelper, + new AspNetCoreMarchal()); + + backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings); + profiler = new LogProfiler(logger); + } + + private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker + { + public void ThrowIfNotPermissions() + { + // nothing to check + } + } + + + } +} diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj index 36238f1a6d..bd20769d45 100644 --- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj +++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj @@ -10,6 +10,10 @@ + + + + diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 42a89c5d13..60e70ea170 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -14,7 +14,7 @@ "@babel/core": { "version": "7.6.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", + "integrity": "sha1-br2f4Akl9sPhd7tyahiLX1eAiP8=", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", @@ -739,7 +739,7 @@ "@babel/preset-env": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz", - "integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==", + "integrity": "sha1-nhvwWi4taHA20kxA5GOdxGzvInE=", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", @@ -865,7 +865,7 @@ "@gulp-sourcemaps/identity-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", - "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", + "integrity": "sha1-Hm/l2AJ7HyhdwNMXYvVmvM1z1ak=", "dev": true, "requires": { "acorn": "^5.0.3", @@ -884,7 +884,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -902,7 +902,7 @@ "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "integrity": "sha1-Olgr21OATGum0UZXnEblITDPSjs=", "dev": true, "requires": { "@nodelib/fs.stat": "2.0.3", @@ -912,13 +912,13 @@ "@nodelib/fs.stat": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "integrity": "sha1-NNxfTKu8cg9OYPdadH5+zWwXW9M=", "dev": true }, "@nodelib/fs.walk": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "integrity": "sha1-ARuSAqcKY2bkNspcBlhEUoqwSXY=", "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.3", @@ -928,7 +928,7 @@ "@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "integrity": "sha1-mgb08TfuhNffBGDB/bETX/psUP0=", "dev": true, "optional": true }, @@ -940,13 +940,13 @@ "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "integrity": "sha1-KGLz9Yqaf3w+eNefEw3U1xwlwqc=", "dev": true }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "integrity": "sha1-qlmhxuP7xCHgfM0xqUTDDrpSFXU=", "dev": true, "requires": { "@types/events": "*", @@ -957,7 +957,7 @@ "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", "dev": true }, "@types/node": { @@ -969,13 +969,13 @@ "@types/q": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", - "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "integrity": "sha1-aQoUdbhPKohP0HzXl8APXzE1bqg=", "dev": true }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", "dev": true, "requires": { "mime-types": "~2.1.24", @@ -985,7 +985,7 @@ "accord": { "version": "0.29.0", "resolved": "https://registry.npmjs.org/accord/-/accord-0.29.0.tgz", - "integrity": "sha512-3OOR92FTc2p5/EcOzPcXp+Cbo+3C15nV9RXHlOUBCBpHhcB+0frbSNR9ehED/o7sTcyGVtqGJpguToEdlXhD0w==", + "integrity": "sha1-t0HBdtAENcWSnUZt/oz2vukzseQ=", "dev": true, "requires": { "convert-source-map": "^1.5.0", @@ -1032,7 +1032,7 @@ "ace-builds": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.2.tgz", - "integrity": "sha512-M1JtZctO2Zg+1qeGUFZXtYKsyaRptqQtqpVzlj80I0NzGW9MF3um0DBuizIvQlrPYUlTdm+wcOPZpZoerkxQdA==" + "integrity": "sha1-avwuQ6e17/3ETYQHQ2EShSVo6A0=" }, "acorn": { "version": "7.1.0", @@ -1101,17 +1101,17 @@ "angular": { "version": "1.7.9", "resolved": "https://registry.npmjs.org/angular/-/angular-1.7.9.tgz", - "integrity": "sha512-5se7ZpcOtu0MBFlzGv5dsM1quQDoDeUTwZrWjGtTNA7O88cD8TEk5IEKCTDa3uECV9XnvKREVUr7du1ACiWGFQ==" + "integrity": "sha1-5SYW6HAcF3JMPCOM/k+URv1XC8Q=" }, "angular-animate": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.7.5.tgz", - "integrity": "sha512-kU/fHIGf2a4a3bH7E1tzALTHk+QfoUSCK9fEcMFisd6ZWvNDwPzXWAilItqOC3EDiAXPmGHaNc9/aXiD9xrAxQ==" + "integrity": "sha1-H/xsKpze4ieiunnMbNj3HsRNtdw=" }, "angular-aria": { "version": "1.7.9", "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.7.9.tgz", - "integrity": "sha512-luI3Jemd1AbOQW0krdzfEG3fM0IFtLY0bSSqIDEx3POE0XjKIC1MkrO8Csyq9PPgueLphyAPofzUwZ8YeZ88SA==" + "integrity": "sha1-kMYYlf+9h26VkVIisyp70AcK9+M=" }, "angular-chart.js": { "version": "1.1.1", @@ -1136,12 +1136,12 @@ "angular-cookies": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.5.tgz", - "integrity": "sha512-/8xvvSl/Z9Vwu8ChRm+OQE3vmli8Icwl8uTYkHqD7j7cknJP9kNaf7SgsENlsLVtOqLE/I7TCFYrSx3bmSeNQA==" + "integrity": "sha1-HFqzwFzcQ/F3e+lQbmRYfLNUNjQ=" }, "angular-dynamic-locale": { "version": "0.1.37", "resolved": "https://registry.npmjs.org/angular-dynamic-locale/-/angular-dynamic-locale-0.1.37.tgz", - "integrity": "sha512-m5Kyk8W8/mOZSqRxuByOwHBjv8labLBAgvl0Z3iQx2xT/tWCqb94imKUPwumudszdPDjxeopwyucQvm8Sw7ogw==", + "integrity": "sha1-fon70uxFvdaryJ82zaiJODjkk1Q=", "requires": { "@types/angular": "^1.6.25" } @@ -1149,7 +1149,7 @@ "angular-i18n": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-i18n/-/angular-i18n-1.7.5.tgz", - "integrity": "sha512-52+Jpt8HRJV2bqSbSU6fWkwOvGzj/DxbNpKXxnTuCS9heuJrlm77BS/lhrF4BA8+Uudnh7npr5/yRELobP+8Yw==" + "integrity": "sha1-Lie2Thl3qMa2sFHFHQF1xtTcglI=" }, "angular-local-storage": { "version": "0.7.1", @@ -1159,32 +1159,32 @@ "angular-messages": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-messages/-/angular-messages-1.7.5.tgz", - "integrity": "sha512-YDpJpFLyrIgZjE/sIAjgww1y6r3QqXBJbNDI0QjftD37vHXLkwvAOo3A4bxPw8BikyGLcJrFrgf6hRAzntJIWA==" + "integrity": "sha1-fC/XgTFaQ6GYOLEX2gFCqYhFThQ=" }, "angular-mocks": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.5.tgz", - "integrity": "sha512-I+Ue2Bkx6R9W5178DYrNvzjIdGh4wKKoCWsgz8dc7ysH4mA70Q3M9v5xRF0RUu7r+2CZj+nDeUecvh2paxcYvg==" + "integrity": "sha1-yLq6WgbtYLk0aXAmtJIWliavOEs=" }, "angular-route": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-route/-/angular-route-1.7.5.tgz", - "integrity": "sha512-7KfyEVVOWTI+jTY/j5rUNCIHGRyeCOx7YqZI/Ci3IbDK7GIsy6xH+hS5ai0Xi0sLjzDZ0PUDO4gBn+K0dVtlOg==" + "integrity": "sha1-NKNkjEB6FKAw0HXPSFMY4zuiPw4=" }, "angular-sanitize": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.7.5.tgz", - "integrity": "sha512-wjKCJOIwrkEvfD0keTnKGi6We13gtoCAQIHcdoqyoo3gwvcgNfYymVQIS3+iCGVcjfWz0jHuS3KgB4ysRWsTTA==" + "integrity": "sha1-ddSeFQccqccFgedtIJQPJjcuJNI=" }, "angular-touch": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-touch/-/angular-touch-1.7.5.tgz", - "integrity": "sha512-XNAZNG0RA1mtdwBJheViCF1H/7wOygp4MLIfs5y1K+rne6AeaYKZcV6EJs9fvgfLKLO6ecm1+3J8hoCkdhhxQw==" + "integrity": "sha1-7SYyKmhfApmyPLauqYNMEZQk2kY=" }, "angular-ui-sortable": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/angular-ui-sortable/-/angular-ui-sortable-0.19.0.tgz", - "integrity": "sha512-u/uc981Nzg4XN1bMU9qKleMTSt7F1XjMWnyGw6gxPLIeQeLZm8jWNy7tj8y2r2HmvzXFbQVq2z6rObznFKAekQ==", + "integrity": "sha1-SsQ5H8TU3lcRDbS10xp8GY0xT9A=", "requires": { "angular": ">=1.2.x", "jquery": ">=3.1.x", @@ -1247,7 +1247,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1389,7 +1389,7 @@ "arch": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz", - "integrity": "sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==", + "integrity": "sha1-j1wnMao1owkpIhuwZA7tZRdeyE4=", "dev": true, "optional": true }, @@ -1501,7 +1501,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", "dev": true } } @@ -1509,7 +1509,7 @@ "array-last": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "integrity": "sha1-eqdwc/7FZd2rJJP1+IGF9ASp0zY=", "dev": true, "requires": { "is-number": "^4.0.0" @@ -1518,7 +1518,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", "dev": true } } @@ -1532,7 +1532,7 @@ "array-sort": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "integrity": "sha1-5MBTVkU/VvU1EqfR1hI/LFTAqIo=", "dev": true, "requires": { "default-compare": "^1.0.0", @@ -1543,7 +1543,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", "dev": true } } @@ -1551,7 +1551,7 @@ "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "integrity": "sha1-t5hCCtvrHego2ErNii4j0+/oXo0=", "dev": true }, "array-uniq": { @@ -1582,7 +1582,7 @@ "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", "dev": true, "requires": { "safer-buffer": "~2.1.0" @@ -1603,13 +1603,13 @@ "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", "dev": true }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=", "dev": true, "requires": { "lodash": "^4.17.14" @@ -1626,7 +1626,7 @@ "async-done": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "integrity": "sha1-XhWqcplipLB0FPUoqIzfGOCykKI=", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -1638,13 +1638,13 @@ "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", "dev": true }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=", "dev": true }, "async-settle": { @@ -1665,13 +1665,13 @@ "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", "dev": true }, "autoprefixer": { "version": "9.6.5", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.5.tgz", - "integrity": "sha512-rGd50YV8LgwFQ2WQp4XzOTG69u1qQsXn0amww7tjqV5jJuNazgFKYEVItEBngyyvVITKOg20zr2V+9VsrXJQ2g==", + "integrity": "sha1-mPSv5+k8zPMjKHUV1CYBlhl3Xl4=", "dev": true, "requires": { "browserslist": "^4.7.0", @@ -1706,7 +1706,7 @@ "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "integrity": "sha1-8A9Qe9qjw+P/bn5emNkKesq5b38=", "dev": true, "requires": { "object.assign": "^4.1.0" @@ -1805,7 +1805,7 @@ "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "integrity": "sha1-WOzoy3XdB+ce0IxzarxfrE2/jfE=", "dev": true }, "base64id": { @@ -1841,7 +1841,7 @@ "bin-build": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", - "integrity": "sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA==", + "integrity": "sha1-xXgKJaip+WbYJEIX5sH1CCoUOGE=", "dev": true, "optional": true, "requires": { @@ -1855,7 +1855,7 @@ "bin-check": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", + "integrity": "sha1-/ElZcL3Ii7HVo1/BfmXEoUn8Skk=", "dev": true, "optional": true, "requires": { @@ -1866,7 +1866,7 @@ "bin-version": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz", - "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==", + "integrity": "sha1-WwnrKAdSsb0o8MnbP5by9DtsCDk=", "dev": true, "optional": true, "requires": { @@ -1877,7 +1877,7 @@ "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", "dev": true, "optional": true, "requires": { @@ -1893,7 +1893,7 @@ "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", "dev": true, "optional": true, "requires": { @@ -1903,7 +1903,7 @@ "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", "dev": true, "optional": true, "requires": { @@ -1916,7 +1916,7 @@ "bin-version-check": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz", - "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==", + "integrity": "sha1-fYGcYklpkfgNiT5uAqMDI2Fgj3E=", "dev": true, "optional": true, "requires": { @@ -1928,7 +1928,7 @@ "bin-wrapper": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz", - "integrity": "sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==", + "integrity": "sha1-mTSPLPhQMePvfvzn5TAK6q6WBgU=", "dev": true, "optional": true, "requires": { @@ -1943,7 +1943,7 @@ "download": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", - "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", + "integrity": "sha1-kFmqnXC1A+52oTKJe+beyOVYcjM=", "dev": true, "optional": true, "requires": { @@ -1973,14 +1973,14 @@ "file-type": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", - "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==", + "integrity": "sha1-JE87fvZBu+DMoZbHJ25LMyOZ9ow=", "dev": true, "optional": true }, "got": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", - "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "integrity": "sha1-HSP2Q5Dpf3dsrFLluTbl9RTS6Tc=", "dev": true, "optional": true, "requires": { @@ -2015,7 +2015,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", "dev": true, "optional": true, "requires": { @@ -2034,14 +2034,14 @@ "p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "integrity": "sha1-NfNj1n1SCByNlYXje8zrfgu8sqA=", "dev": true, "optional": true }, "p-event": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz", - "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==", + "integrity": "sha1-WWJ57xaassPgyuiMHPuwgHmZPvY=", "dev": true, "optional": true, "requires": { @@ -2051,7 +2051,7 @@ "p-timeout": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "integrity": "sha1-2N0ZeVldLcATnh/ka4tkbLPN8Dg=", "dev": true, "requires": { "p-finally": "^1.0.0" @@ -2060,7 +2060,7 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", "dev": true, "optional": true }, @@ -2086,7 +2086,7 @@ "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", "dev": true }, "bl": { @@ -2134,7 +2134,7 @@ "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "integrity": "sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM=", "dev": true }, "bluebird": { @@ -2146,7 +2146,7 @@ "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", "dev": true, "requires": { "bytes": "3.1.0", @@ -2164,7 +2164,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -2179,7 +2179,7 @@ "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", "dev": true } } @@ -2193,7 +2193,7 @@ "bootstrap": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" + "integrity": "sha1-w6NH1Bniia0R9AM+PEEyuHwIHXI=" }, "bootstrap-social": { "version": "5.1.1", @@ -2301,7 +2301,7 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", "dev": true }, "bufferstreams": { @@ -2316,7 +2316,7 @@ "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", "dev": true }, "cache-base": { @@ -2362,7 +2362,7 @@ "normalize-url": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "integrity": "sha1-g1qdoVUfom9w6SMpBpojqmV01+Y=", "dev": true, "optional": true, "requires": { @@ -2449,7 +2449,7 @@ "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -2473,7 +2473,7 @@ "caw": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", - "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "integrity": "sha1-bDygcfwZRyCIPC3F2psHS/x+npU=", "dev": true, "requires": { "get-proxy": "^2.0.0", @@ -2495,7 +2495,7 @@ "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -2506,7 +2506,7 @@ "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", "dev": true }, "chart.js": { @@ -2530,7 +2530,7 @@ "chartjs-color-string": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", - "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "integrity": "sha1-HfCWYhwOcHIKZPQTXqFx0FFAL3E=", "requires": { "color-name": "^1.0.0" } @@ -2538,7 +2538,7 @@ "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -2588,7 +2588,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", "dev": true } } @@ -2619,7 +2619,7 @@ "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", - "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "integrity": "sha1-LUEe92uFabbQyEBo2r6FsKpeXBc=", "dev": true, "requires": { "source-map": "~0.6.0" @@ -2628,7 +2628,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -2636,7 +2636,7 @@ "cli-color": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "integrity": "sha1-fRBzj0hSaCT4/n2lGFfLD1cv4B8=", "dev": true, "requires": { "ansi-regex": "^2.1.1", @@ -2665,7 +2665,7 @@ "clipboard": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", - "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "integrity": "sha1-g22v1mzw/qXXHOXVsL9ulYAJES0=", "requires": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -2714,7 +2714,7 @@ "cloneable-readable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "integrity": "sha1-EgoAywU7+2OiIucJ+Wg+ouEdjOw=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -2757,7 +2757,7 @@ "coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", "dev": true, "requires": { "@types/q": "^1.5.1", @@ -2795,7 +2795,7 @@ "color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", - "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "integrity": "sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -2827,12 +2827,12 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=" }, "color-string": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "integrity": "sha1-ybvF8BtYtUkvPWhXRZy2WQziBMw=", "dev": true, "requires": { "color-name": "^1.0.0", @@ -2854,13 +2854,13 @@ "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "integrity": "sha1-xQSRR51MG9rtLJztMs98fcI2D3g=", "dev": true }, "colorspace": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "integrity": "sha1-4BKJUNCCuGohaFgHlqCqXWxo2MU=", "dev": true, "requires": { "color": "3.0.x", @@ -2870,7 +2870,7 @@ "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "integrity": "sha1-2SC0Mo1TSjrIKV1o971LpsQnvpo=", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -2897,7 +2897,7 @@ "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", "dev": true, "requires": { "delayed-stream": "~1.0.0" @@ -2921,7 +2921,7 @@ "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", "dev": true }, "component-inherit": { @@ -2939,7 +2939,7 @@ "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -3000,7 +3000,7 @@ "config-chain": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "integrity": "sha1-D96NCRIA616AjK8l/mGMAvSOTvo=", "dev": true, "requires": { "ini": "^1.3.4", @@ -3010,7 +3010,7 @@ "connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "integrity": "sha1-XUk0iRDKpeB6AYALAw0MNfIEhPg=", "dev": true, "requires": { "debug": "2.6.9", @@ -3022,7 +3022,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -3046,7 +3046,7 @@ "consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=", "dev": true, "requires": { "bluebird": "^3.1.1" @@ -3055,7 +3055,7 @@ "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", "dev": true, "requires": { "safe-buffer": "5.1.2" @@ -3091,7 +3091,7 @@ "copy-props": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", - "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "integrity": "sha1-k7scrfr9MdpbuKnUtB9HHsOnLf4=", "dev": true, "requires": { "each-props": "^1.3.0", @@ -3151,7 +3151,7 @@ "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", "dev": true, "requires": { "import-fresh": "^2.0.0", @@ -3163,7 +3163,7 @@ "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -3176,7 +3176,7 @@ "css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "integrity": "sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk=", "dev": true, "requires": { "inherits": "^2.0.3", @@ -3188,7 +3188,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -3202,7 +3202,7 @@ "css-declaration-sorter": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", "dev": true, "requires": { "postcss": "^7.0.1", @@ -3224,7 +3224,7 @@ "css-select-base-adapter": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", "dev": true }, "css-tree": { @@ -3258,7 +3258,7 @@ "cssnano": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "integrity": "sha1-CsQfCxPRPUZUh+ERt3jULaYxuLI=", "dev": true, "requires": { "cosmiconfig": "^5.0.0", @@ -3270,7 +3270,7 @@ "cssnano-preset-default": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "integrity": "sha1-UexmLM/KD4izltzZZ5zbkxvhf3Y=", "dev": true, "requires": { "css-declaration-sorter": "^4.0.1", @@ -3320,7 +3320,7 @@ "cssnano-util-raw-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", "dev": true, "requires": { "postcss": "^7.0.0" @@ -3329,7 +3329,7 @@ "cssnano-util-same-parent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", "dev": true }, "csso": { @@ -3378,7 +3378,7 @@ "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "integrity": "sha1-hpgJU3LVjb7jRv/Qxwk/mfj561o=", "dev": true, "requires": { "es5-ext": "^0.10.50", @@ -3397,7 +3397,7 @@ "date-format": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "integrity": "sha1-MdW16iEc9f12TNOLr50DPffhJc8=", "dev": true }, "dateformat": { @@ -3409,7 +3409,7 @@ "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", "dev": true, "requires": { "ms": "^2.1.1" @@ -3418,7 +3418,7 @@ "debug-fabulous": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", + "integrity": "sha1-r4oIYyRlIk70F0qfBjCMPCoevI4=", "dev": true, "requires": { "debug": "3.X", @@ -3429,7 +3429,7 @@ "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", "dev": true, "requires": { "ms": "^2.1.1" @@ -3474,7 +3474,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", "dev": true, "requires": { "pify": "^3.0.0" @@ -3502,7 +3502,7 @@ "decompress-tar": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "integrity": "sha1-cYy9P8sWIJcW5womuE57pFkuWvE=", "dev": true, "requires": { "file-type": "^5.2.0", @@ -3521,7 +3521,7 @@ "decompress-tarbz2": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "integrity": "sha1-MIKluIDqQEOBY0nzeLVsUWvho5s=", "dev": true, "requires": { "decompress-tar": "^4.1.0", @@ -3534,7 +3534,7 @@ "file-type": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "integrity": "sha1-5QzXXTVv/tTjBtxPW89Sp5kDqRk=", "dev": true } } @@ -3542,7 +3542,7 @@ "decompress-targz": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "integrity": "sha1-wJvDXE0R894J8tLaU+neI+fOHu4=", "dev": true, "requires": { "decompress-tar": "^4.1.1", @@ -3603,7 +3603,7 @@ "default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "integrity": "sha1-y2ETGESthNhHiPto/QFoHKd4Gi8=", "dev": true, "requires": { "kind-of": "^5.0.2" @@ -3612,7 +3612,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", "dev": true } } @@ -3626,7 +3626,7 @@ "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", "dev": true, "requires": { "object-keys": "^1.0.12" @@ -3682,7 +3682,7 @@ "delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + "integrity": "sha1-tmtxwxWFIuirV0T3INjKDCr1kWY=" }, "depd": { "version": "1.1.2", @@ -3711,7 +3711,7 @@ "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "integrity": "sha1-yrasM99wydmnJ0kK5DrJladpsio=", "dev": true, "requires": { "colorspace": "1.1.x", @@ -3722,12 +3722,12 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=" }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "integrity": "sha1-Vtv3PZkqSpO6FYT0U0Bj/S5BcX8=", "dev": true, "requires": { "path-type": "^4.0.0" @@ -3736,7 +3736,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "integrity": "sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs=", "dev": true } } @@ -3744,7 +3744,7 @@ "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", "dev": true, "requires": { "esutils": "^2.0.2" @@ -3775,7 +3775,7 @@ "domelementtype": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "integrity": "sha1-H4vf6R9aeAYydOgDtL3O326U+U0=", "dev": true } } @@ -3783,13 +3783,13 @@ "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", "dev": true }, "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", "dev": true, "requires": { "domelementtype": "1" @@ -3798,7 +3798,7 @@ "domutils": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", "dev": true, "requires": { "dom-serializer": "0", @@ -3817,7 +3817,7 @@ "download": { "version": "6.2.5", "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", - "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", + "integrity": "sha1-rNalQuTNC7Qspwz8mMnkOwcDlxQ=", "dev": true, "optional": true, "requires": { @@ -3844,7 +3844,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", "dev": true, "optional": true, "requires": { @@ -3877,7 +3877,7 @@ "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -3921,7 +3921,7 @@ "each-props": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "integrity": "sha1-6kWkFNFt1c+kGbGoFyDVygaJIzM=", "dev": true, "requires": { "is-plain-object": "^2.0.1", @@ -3980,7 +3980,7 @@ "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", "dev": true, "requires": { "once": "^1.4.0" @@ -4000,7 +4000,7 @@ "engine.io": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", - "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "integrity": "sha1-tgKBw1SEpw7gNR6g6/+D7IyVIqI=", "dev": true, "requires": { "accepts": "~1.3.4", @@ -4073,7 +4073,7 @@ "engine.io-parser": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", - "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "integrity": "sha1-dXq5cPvy37Mse3SwMyFtVznveaY=", "dev": true, "requires": { "after": "0.8.2", @@ -4092,7 +4092,7 @@ "entities": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "integrity": "sha1-aNYITKsbB5dnVA2A5Wo5tCPkq/Q=", "dev": true }, "env-variable": { @@ -4114,7 +4114,7 @@ "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", "dev": true, "requires": { "is-arrayish": "^0.2.1" @@ -4174,7 +4174,7 @@ "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "integrity": "sha1-TrIVlMlyvEBVPSduUQU5FD21Pgo=", "dev": true }, "es6-symbol": { @@ -4190,7 +4190,7 @@ "es6-weak-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "integrity": "sha1-ttofFswswNm+Q+a9v8Xn383zHVM=", "dev": true, "requires": { "d": "1", @@ -4233,7 +4233,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true, "optional": true } @@ -4287,13 +4287,13 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", "dev": true }, "glob-parent": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "integrity": "sha1-X0wdHnSNMM1zrSlEs1d6gbCB6MI=", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -4321,19 +4321,19 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", "dev": true }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", "dev": true }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -4344,7 +4344,7 @@ "eslint-scope": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "integrity": "sha1-6HyIh8c+jR7ITxylkWRcNYv8j7k=", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -4354,7 +4354,7 @@ "eslint-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -4363,7 +4363,7 @@ "eslint-visitor-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "integrity": "sha1-4qgs6oT/JGrW+1f5veW0ZiFFnsI=", "dev": true }, "espree": { @@ -4380,7 +4380,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", "dev": true }, "esquery": { @@ -4422,13 +4422,13 @@ "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", "dev": true }, "event-emitter": { @@ -4444,7 +4444,7 @@ "eventemitter3": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "integrity": "sha1-1lF2FjiH7lnzhtZMgmELaWpKdOs=", "dev": true }, "exec-buffer": { @@ -4501,7 +4501,7 @@ "executable": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "integrity": "sha1-QVMr/zYdPlevTXY7cFgtsY9dEzw=", "dev": true, "optional": true, "requires": { @@ -4526,7 +4526,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -4570,7 +4570,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { "is-number": "^2.1.0", @@ -4627,7 +4627,7 @@ "ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "integrity": "sha1-C5jmTtgvWs8PKTG6v2khLvUt3Tc=", "dev": true, "requires": { "mime-db": "^1.28.0" @@ -4636,7 +4636,7 @@ "ext-name": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "integrity": "sha1-cHgZgdGD7hXROZPIgiBFxQbI8KY=", "dev": true, "requires": { "ext-list": "^2.0.0", @@ -4646,7 +4646,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", "dev": true }, "extend-shallow": { @@ -4673,7 +4673,7 @@ "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", "dev": true, "requires": { "chardet": "^0.7.0", @@ -4761,7 +4761,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -4802,7 +4802,7 @@ "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "integrity": "sha1-28GRVPVYaQFQojlToK29A1vkX8c=", "dev": true, "requires": { "ansi-gray": "^0.1.1", @@ -4833,7 +4833,7 @@ "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -4842,7 +4842,7 @@ "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -4851,7 +4851,7 @@ "glob-parent": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "integrity": "sha1-X0wdHnSNMM1zrSlEs1d6gbCB6MI=", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -4869,13 +4869,13 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", "dev": true }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "integrity": "sha1-T8sJmb+fvC/L3SEvbWKbmlbDklk=", "dev": true, "requires": { "braces": "^3.0.1", @@ -4885,7 +4885,7 @@ "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", "dev": true, "requires": { "is-number": "^7.0.0" @@ -4935,7 +4935,7 @@ "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", "dev": true, "requires": { "flat-cache": "^2.0.1" @@ -4962,7 +4962,7 @@ "filenamify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", - "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "integrity": "sha1-iPr0lfsbR6v9YSMAACoWIoxnfuk=", "dev": true, "requires": { "filename-reserved-regex": "^2.0.0", @@ -4996,7 +4996,7 @@ "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", "dev": true, "requires": { "debug": "2.6.9", @@ -5011,7 +5011,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -5070,7 +5070,7 @@ "fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "integrity": "sha1-0AvszxqitHXRbUI7Aji3E6LEo3s=", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -5124,13 +5124,13 @@ "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "integrity": "sha1-595vEnnd2cqarIpZcdYYYGs6q0E=", "dev": true }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", "dev": true, "requires": { "flatted": "^2.0.0", @@ -5141,18 +5141,18 @@ "flatpickr": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.5.2.tgz", - "integrity": "sha512-jDy4QYGpmiy7+Qk8QvKJ4spjDdxcx9cxMydmq1x427HkKWBw0qizLYeYM2F6tMcvvqGjU5VpJS55j4LnsaBblA==" + "integrity": "sha1-R8itRyoJbl+350uAmwcDU1OD8g0=" }, "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "integrity": "sha1-aeV8qo8OrLwoHS4stFjUb9tEngg=", "dev": true }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", "dev": true, "requires": { "inherits": "^2.0.3", @@ -5203,7 +5203,7 @@ "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", "dev": true, "requires": { "ms": "^2.1.1" @@ -5240,7 +5240,7 @@ "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -5347,7 +5347,7 @@ "fs-readfile-promise": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-3.0.1.tgz", - "integrity": "sha512-LsSxMeaJdYH27XrW7Dmq0Gx63mioULCRel63B5VeELYLavi1wF5s0XfsIdKDFdCL9hsfQ2qBvXJszQtQJ9h17A==", + "integrity": "sha1-0NMHt/au38kgwx+m5XEu+qKXyVg=", "dev": true, "requires": { "graceful-fs": "^4.1.11" @@ -5903,13 +5903,13 @@ "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=", "dev": true }, "get-proxy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", - "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "integrity": "sha1-NJ8rTZHUTE1NTpy6KtkBQ/rF75M=", "dev": true, "requires": { "npm-conf": "^1.1.0" @@ -5945,7 +5945,7 @@ "gifsicle": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-4.0.1.tgz", - "integrity": "sha512-A/kiCLfDdV+ERV/UB+2O41mifd+RxH8jlRG8DMxZO84Bma/Fw0htqZ+hY2iaalLRNyUu7tYZQslqUBJxBggxbg==", + "integrity": "sha1-MOHmHj7kiE73AmQbLpihXCEnsuI=", "dev": true, "optional": true, "requires": { @@ -5958,7 +5958,7 @@ "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", "dev": true, "optional": true, "requires": { @@ -5974,7 +5974,7 @@ "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", "dev": true, "optional": true, "requires": { @@ -5984,7 +5984,7 @@ "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", "dev": true, "optional": true, "requires": { @@ -6107,7 +6107,7 @@ "glob-watcher": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "integrity": "sha1-iKir8cTRMeuTkomUvEpZPC5d1iY=", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -6157,7 +6157,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", "dev": true }, "globby": { @@ -6179,7 +6179,7 @@ "ignore": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "integrity": "sha1-hLez2+ZFUrbvDsqZ9nQ9vsbZet8=", "dev": true }, "slash": { @@ -6193,7 +6193,7 @@ "glogg": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "integrity": "sha1-LX3XAr7aIus7/634gGltpthGMT8=", "dev": true, "requires": { "sparkles": "^1.0.0" @@ -6210,7 +6210,7 @@ "got": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "integrity": "sha1-BUUP2ECU5rvqVvRRpDqcKJFmOFo=", "dev": true, "optional": true, "requires": { @@ -6251,7 +6251,7 @@ "gulp": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "integrity": "sha1-VDZRBw/Q9qsKBlDGo+b/WnywnKo=", "dev": true, "requires": { "glob-watcher": "^5.0.3", @@ -6284,7 +6284,7 @@ "gulp-babel": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz", - "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==", + "integrity": "sha1-4NqW9PLsSojdOjAw9HbjirISbYc=", "dev": true, "requires": { "plugin-error": "^1.0.1", @@ -6304,7 +6304,7 @@ "gulp-clean-css": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz", - "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==", + "integrity": "sha1-kV7CWNxtPmpQBD9hAGbVwurE9U4=", "dev": true, "requires": { "clean-css": "4.2.1", @@ -6342,7 +6342,7 @@ "through2": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "integrity": "sha1-OSducTwzAu3544jdnIEt07glvVo=", "dev": true, "requires": { "readable-stream": "2 || 3" @@ -6353,7 +6353,7 @@ "gulp-cli": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", - "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", + "integrity": "sha1-VTMSbut/5BWn4+hKKX0zTVz3Drw=", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -6472,7 +6472,7 @@ "gulp-eslint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", - "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", + "integrity": "sha1-fUArtF+KZ2UrhoJ3ARgSBXNwqDI=", "dev": true, "requires": { "eslint": "^6.0.0", @@ -6483,7 +6483,7 @@ "gulp-imagemin": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/gulp-imagemin/-/gulp-imagemin-6.1.1.tgz", - "integrity": "sha512-fqaSR8bMc5lhqa6HzRPuJaDY6lY7rcCipe6WtqQ5+hNYTCSPYjXic+1gvFG1+8X879gjVJmIxwmqIbfjuMqTpQ==", + "integrity": "sha1-jm/ezQKZMPLObhKbJmAf0sJhPW4=", "dev": true, "requires": { "chalk": "^2.4.1", @@ -6502,7 +6502,7 @@ "gulp-less": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-4.0.1.tgz", - "integrity": "sha512-hmM2k0FfQp7Ptm3ZaqO2CkMX3hqpiIOn4OHtuSsCeFym63F7oWlEua5v6u1cIjVUKYsVIs9zPg9vbqTEb/udpA==", + "integrity": "sha1-NIwzpd3nogfFdxsdgmHRrBAhzu0=", "dev": true, "requires": { "accord": "^0.29.0", @@ -6581,7 +6581,7 @@ "gulp-notify": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz", - "integrity": "sha512-qEocs1UVoDKKUjfsxJNMNwkRla0PbsyJwsqNNXpzYWsLQ29LhxRMY3wnTGZcc4hMHtalnvah/Dwlwb4NijH/0A==", + "integrity": "sha1-KugiUAnfiB7vWb5d1aLxM3OHdk4=", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -6633,7 +6633,7 @@ "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "integrity": "sha1-+XYZXPPzR9DV9SSDVp/oAxzM6Ks=", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", @@ -6643,7 +6643,7 @@ "lodash.templatesettings": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "integrity": "sha1-5IExDwSdPPbUfpEq0JMTsVTw+zM=", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0" @@ -6667,7 +6667,7 @@ "gulp-postcss": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-8.0.0.tgz", - "integrity": "sha512-Wtl6vH7a+8IS/fU5W9IbOpcaLqKxd5L1DUOzaPmlnCbX1CrG0aWdwVnC3Spn8th0m8D59YbysV5zPUe1n/GJYg==", + "integrity": "sha1-jTdyzU0nvKVeyMtMjlduO95NxVA=", "dev": true, "requires": { "fancy-log": "^1.3.2", @@ -6680,7 +6680,7 @@ "gulp-rename": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", - "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", + "integrity": "sha1-3hxxjnxAla6GH3KW708ySGSCQL0=", "dev": true }, "gulp-sort": { @@ -6695,7 +6695,7 @@ "gulp-sourcemaps": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", + "integrity": "sha1-o/AC2HNG0sDzrsNq9+uHPyPeiuY=", "dev": true, "requires": { "@gulp-sourcemaps/identity-map": "1.X", @@ -6720,7 +6720,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -6781,7 +6781,7 @@ "gulp-watch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", - "integrity": "sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog==", + "integrity": "sha1-g9N4dS9b+0baAj5zwX7R2nBmIV0=", "dev": true, "requires": { "ansi-colors": "1.1.0", @@ -6882,7 +6882,7 @@ "gulp-wrap": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/gulp-wrap/-/gulp-wrap-0.15.0.tgz", - "integrity": "sha512-f17zkGObA+hE/FThlg55gfA0nsXbdmHK1WqzjjB2Ytq1TuhLR7JiCBJ3K4AlMzCyoFaCjfowos+VkToUNE0WTQ==", + "integrity": "sha1-6QFMm7hkOrMQ6TjURpuFaFUaVS8=", "dev": true, "requires": { "consolidate": "^0.15.1", @@ -6926,7 +6926,7 @@ "through2": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "integrity": "sha1-OSducTwzAu3544jdnIEt07glvVo=", "dev": true, "requires": { "readable-stream": "2 || 3" @@ -6992,7 +6992,7 @@ "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", "dev": true, "requires": { "ajv": "^6.5.5", @@ -7002,7 +7002,7 @@ "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", "dev": true, "requires": { "function-bind": "^1.1.1" @@ -7058,7 +7058,7 @@ "has-symbol-support-x": { "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==", + "integrity": "sha1-FAn5i8ACR9pF2mfO4KNvKC/yZFU=", "dev": true }, "has-symbols": { @@ -7070,7 +7070,7 @@ "has-to-string-tag-x": { "version": "1.4.1", "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==", + "integrity": "sha1-oEWrOD17SyASoAFIqwql8pAETU0=", "dev": true, "requires": { "has-symbol-support-x": "^1.4.1" @@ -7121,13 +7121,13 @@ "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", "dev": true }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "integrity": "sha1-dDKYzvTlrz4ZQWH7rcwhUdOgWOg=", "dev": true, "requires": { "parse-passwd": "^1.0.0" @@ -7154,7 +7154,7 @@ "html-comment-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", - "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "integrity": "sha1-l9RoiutcgYhqNk+qDK0d2hTUM6c=", "dev": true }, "htmlparser2": { @@ -7174,7 +7174,7 @@ "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=", "dev": true }, "isarray": { @@ -7212,14 +7212,14 @@ "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "integrity": "sha1-ObDhat2bYFvwqe89nar0hDtMrNI=", "dev": true, "optional": true }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", "dev": true, "requires": { "depd": "~1.1.2", @@ -7240,7 +7240,7 @@ "http-proxy": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "integrity": "sha1-2+VfY+daNH2389mZdPJpKjFKajo=", "dev": true, "requires": { "eventemitter3": "^4.0.0", @@ -7262,7 +7262,7 @@ "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -7271,13 +7271,13 @@ "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "integrity": "sha1-7BaFWOlaoYH9h9N/VcMrvLZwi4Q=", "dev": true }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", "dev": true }, "image-size": { @@ -7312,7 +7312,7 @@ "imagemin-gifsicle": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-6.0.1.tgz", - "integrity": "sha512-kuu47c6iKDQ6R9J10xCwL0lgs0+sMz3LRHqRcJ2CRBWdcNmo3T5hUaM8hSZfksptZXJLGKk8heSAvwtSdB1Fng==", + "integrity": "sha1-arrU6VVm1S5aEEq6HCS087SFgbM=", "dev": true, "optional": true, "requires": { @@ -7324,7 +7324,7 @@ "imagemin-jpegtran": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/imagemin-jpegtran/-/imagemin-jpegtran-6.0.0.tgz", - "integrity": "sha512-Ih+NgThzqYfEWv9t58EItncaaXIHR0u9RuhKa8CtVBlMBvY0dCIxgQJQCfwImA4AV1PMfmUKlkyIHJjb7V4z1g==", + "integrity": "sha1-yNO8+27JxWHCCphxQoVL5w2QsE8=", "dev": true, "optional": true, "requires": { @@ -7336,7 +7336,7 @@ "imagemin-optipng": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-7.1.0.tgz", - "integrity": "sha512-JNORTZ6j6untH7e5gF4aWdhDCxe3ODsSLKs/f7Grewy3ebZpl1ZsU+VUTPY4rzeHgaFA8GSWOoA8V2M3OixWZQ==", + "integrity": "sha1-IiXILDXlwpt/qY1Pns7hFhpo6Ig=", "dev": true, "optional": true, "requires": { @@ -7387,7 +7387,7 @@ "import-lazy": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz", - "integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==", + "integrity": "sha1-iRJ5ICyKIoD9vWZ029jaGh38Z8w=", "dev": true, "optional": true }, @@ -7437,7 +7437,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", "dev": true }, "ini": { @@ -7522,7 +7522,7 @@ "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "integrity": "sha1-1QYaYiS+WOgIOYX1AU2EQ1lXYpY=", "dev": true }, "into-stream": { @@ -7539,7 +7539,7 @@ "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "dev": true, "requires": { "loose-envify": "^1.0.0" @@ -7554,13 +7554,13 @@ "irregular-plurals": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", - "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", + "integrity": "sha1-OdQPBbAPZW0Lf6RxIw3TtxSvKHI=", "dev": true }, "is": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", + "integrity": "sha1-Yc/23TxBk9uUo9YlggcrROVkXXk=", "dev": true }, "is-absolute": { @@ -7739,7 +7739,7 @@ "is-gif": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz", - "integrity": "sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw==", + "integrity": "sha1-xL5gsmowHWlbuDOyDZtdZsbPg7E=", "dev": true, "optional": true, "requires": { @@ -7749,7 +7749,7 @@ "file-type": { "version": "10.11.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", - "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==", + "integrity": "sha1-KWHQnkZ1ufuaPua2npzSP0P9GJA=", "dev": true, "optional": true } @@ -7833,7 +7833,7 @@ "is-png": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-png/-/is-png-2.0.0.tgz", - "integrity": "sha512-4KPGizaVGj2LK7xwJIz8o5B2ubu1D/vcQsgOGFEDlpcvgZHto4gBnyd0ig7Ws+67ixmwKoNmu0hYnpo6AaKb5g==", + "integrity": "sha1-7oy8npsFBCXO3utKb7dKZJsKSo0=", "dev": true, "optional": true }, @@ -7882,7 +7882,7 @@ "is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "integrity": "sha1-13hIi9CkZmo76KFIK58rqv7eqLQ=", "dev": true }, "is-stream": { @@ -7894,7 +7894,7 @@ "is-svg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", - "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "integrity": "sha1-kyHb0pwhLlypnE+peUxxS8r6L3U=", "dev": true, "requires": { "html-comment-regex": "^1.1.0" @@ -7957,7 +7957,7 @@ "isbinaryfile": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "integrity": "sha1-XW3vPt6/boyoyunDAYOoBLX4voA=", "dev": true, "requires": { "buffer-alloc": "^1.2.0" @@ -7984,7 +7984,7 @@ "isurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=", "dev": true, "requires": { "has-to-string-tag-x": "^1.2.0", @@ -7994,13 +7994,13 @@ "jasmine-core": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", - "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", + "integrity": "sha1-Eywj5kWvlthci8oTyHWLGEKfweQ=", "dev": true }, "jpegtran-bin": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jpegtran-bin/-/jpegtran-bin-4.0.0.tgz", - "integrity": "sha512-2cRl1ism+wJUoYAYFt6O/rLBfpXNWG2dUWbgcEkTt5WGMnqI46eEro8T4C5zGROxKRqyKpCBSdHPvt5UYCtxaQ==", + "integrity": "sha1-0ArtgJ+6eqbzCBflnu5N3xmPjxA=", "dev": true, "optional": true, "requires": { @@ -8012,7 +8012,7 @@ "jquery": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", - "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" + "integrity": "sha1-cU8fjZ3eS9+lV2S6N+8hRjDYDvI=" }, "jquery-ui-dist": { "version": "1.12.1", @@ -8027,19 +8027,19 @@ "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "integrity": "sha1-xs7ljrNVA3LfjeuF+tXOZs4B1Z0=", "dev": true }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", "dev": true }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", "dev": true, "requires": { "argparse": "^1.0.7", @@ -8055,7 +8055,7 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", "dev": true }, "json-buffer": { @@ -8068,7 +8068,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", "dev": true }, "json-schema": { @@ -8098,7 +8098,7 @@ "json5": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "integrity": "sha1-gbbLBOm6SW8ccAXQe0NoomOPkLY=", "dev": true, "requires": { "minimist": "^1.2.0" @@ -8137,7 +8137,7 @@ "junk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", + "integrity": "sha1-MUmQmNkCt+mMXZucgPQ0V6iKv6E=", "dev": true }, "just-debounce": { @@ -8149,7 +8149,7 @@ "karma": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz", - "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==", + "integrity": "sha1-bZqqsDejETbcB0ACYg7hHowuMqs=", "dev": true, "requires": { "bluebird": "^3.3.0", @@ -8183,7 +8183,7 @@ "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -8193,13 +8193,13 @@ "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "integrity": "sha1-I8DfFPaogHf1+YbA0WfsA8PVU3w=", "dev": true }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -8224,7 +8224,7 @@ "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -8240,7 +8240,7 @@ "glob-parent": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "integrity": "sha1-X0wdHnSNMM1zrSlEs1d6gbCB6MI=", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -8249,7 +8249,7 @@ "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", "dev": true, "requires": { "binary-extensions": "^2.0.0" @@ -8267,19 +8267,19 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", "dev": true }, "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "integrity": "sha1-vXuRE1/GsBzePpuuM9ZZtj2IV+U=", "dev": true }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", "dev": true }, "readdirp": { @@ -8294,13 +8294,13 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", "dev": true, "requires": { "is-number": "^7.0.0" @@ -8311,7 +8311,7 @@ "karma-jasmine": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", - "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", + "integrity": "sha1-JuPjHy+vJy3YDrsOGJiRTMOhl2M=", "dev": true, "requires": { "jasmine-core": "^3.3" @@ -8320,7 +8320,7 @@ "karma-junit-reporter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz", - "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==", + "integrity": "sha1-007vfwsv0GTgiWlU6IUakM8UyPM=", "dev": true, "requires": { "path-is-absolute": "^1.0.0", @@ -8355,7 +8355,7 @@ "keyv": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "integrity": "sha1-RJI7o55osSp87H32wyaMAx8u83M=", "dev": true, "optional": true, "requires": { @@ -8389,7 +8389,7 @@ "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "integrity": "sha1-73x4TzbJ+24W3TFQ0VJneysCKKY=", "dev": true, "requires": { "colornames": "^1.1.1" @@ -8478,7 +8478,7 @@ "less": { "version": "3.10.3", "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", - "integrity": "sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==", + "integrity": "sha1-QXoJddXu7MUs/0vPo8CdNXgeZ5I=", "dev": true, "requires": { "clone": "^2.1.2", @@ -8501,7 +8501,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true, "optional": true } @@ -8559,7 +8559,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "integrity": "sha1-tEf2ZwoEVbv+7dETku/zMOoJdUg=", "dev": true }, "lodash._basecopy": { @@ -8675,7 +8675,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=", "dev": true }, "lodash.partialright": { @@ -8732,7 +8732,7 @@ "log4js": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", - "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "integrity": "sha1-5UNiXpfZ5vPm58n8GW3WqyyuMLU=", "dev": true, "requires": { "date-format": "^2.0.0", @@ -8782,7 +8782,7 @@ "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -8821,7 +8821,7 @@ "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -8849,7 +8849,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", "dev": true } } @@ -8887,7 +8887,7 @@ "marked": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", + "integrity": "sha1-tkIB8FHScbHtwQoE0a6bdLuOXA4=", "dev": true }, "matchdep": { @@ -8905,13 +8905,13 @@ "math-random": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "integrity": "sha1-XdaUPJOFSCZwFtTjTwV1gwgMUUw=", "dev": true }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=", "dev": true }, "media-typer": { @@ -8923,7 +8923,7 @@ "memoizee": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "integrity": "sha1-B6APIEaZ+alcLZ53IYJxx81hDVc=", "dev": true, "requires": { "d": "1", @@ -8967,13 +8967,13 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", "dev": true }, "merge2": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "integrity": "sha1-WzZu6DsvFYLEj4fkfPGpNSEDyoE=", "dev": true }, "micromatch": { @@ -9000,7 +9000,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", "dev": true, "optional": true }, @@ -9028,13 +9028,13 @@ "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "integrity": "sha1-SSNTiHju9CBjy4o+OweYeBSHqxs=", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -9049,7 +9049,7 @@ "minimize": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz", - "integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==", + "integrity": "sha1-ixZ28wBR2FmNdDZGvRJpCwdNpMM=", "dev": true, "requires": { "argh": "^0.1.4", @@ -9064,7 +9064,7 @@ "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", "dev": true, "requires": { "for-in": "^1.0.2", @@ -9074,7 +9074,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -9107,7 +9107,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", "dev": true }, "multipipe": { @@ -9122,7 +9122,7 @@ "mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "integrity": "sha1-rLAwDrTeI6fd7sAU4+lgRLNHIzE=", "dev": true }, "mute-stream": { @@ -9141,7 +9141,7 @@ "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -9166,7 +9166,7 @@ "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", "dev": true }, "next-tick": { @@ -9183,13 +9183,13 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", "dev": true }, "node-notifier": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "integrity": "sha1-y3La+UyTkECY4oucWQ/YZuRkvVA=", "dev": true, "requires": { "growly": "^1.3.0", @@ -9211,7 +9211,7 @@ "node.extend": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", - "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", + "integrity": "sha1-tEBFJUlKzJl0DzcDxJa31Rgsxsw=", "dev": true, "requires": { "has": "^1.0.3", @@ -9221,7 +9221,7 @@ "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -9248,18 +9248,18 @@ "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", "dev": true }, "nouislider": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.1.1.tgz", - "integrity": "sha512-3/+Z/pTBoWoJf2YXSEWRmS27LW2XxOBmGEzkPyRzB/J6QvL+0mS3QwcQp0SmWhgO5CMzbSxPmb1lDDD4HP12bg==" + "integrity": "sha1-3vgSsqqqLM+eekHdAUSiXatWc+U=" }, "now-and-later": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "integrity": "sha1-jlechoV2SnzALLaAOA6U9DzLH3w=", "dev": true, "requires": { "once": "^1.3.2" @@ -9268,7 +9268,7 @@ "npm": { "version": "6.13.6", "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.6.tgz", - "integrity": "sha512-NomC08kv7HIl1FOyLOe9Hp89kYsOsvx52huVIJ7i8hFW8Xp65lDwe/8wTIrh9q9SaQhA8hTrfXPh3BEL3TmMpw==", + "integrity": "sha1-ht+DBaTYJp0JNOyQeSDnqwec9dk=", "requires": { "JSONStream": "^1.3.5", "abbrev": "~1.1.1", @@ -12329,7 +12329,7 @@ "npm-conf": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "integrity": "sha1-JWzEe9DiGMJZxOlVC/QTvCGSr/k=", "dev": true, "requires": { "config-chain": "^1.1.11", @@ -12356,7 +12356,7 @@ "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", "dev": true, "requires": { "boolbase": "~1.0.0" @@ -12377,7 +12377,7 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", "dev": true }, "object-assign": { @@ -12432,7 +12432,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", "dev": true }, "object-visit": { @@ -12447,7 +12447,7 @@ "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -12608,7 +12608,7 @@ "optipng-bin": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-6.0.0.tgz", - "integrity": "sha512-95bB4y8IaTsa/8x6QH4bLUuyvyOoGBCLDA7wOgDL8UFqJpSUh1Hob8JRJhit+wC1ZLN3tQ7mFt7KuBj0x8F2Wg==", + "integrity": "sha1-N2Eg+nnV5x7uL1JBdu/dOl6r0xY=", "dev": true, "optional": true, "requires": { @@ -12661,7 +12661,7 @@ "os-filter-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", + "integrity": "sha1-HAti1fOiRCdJotE55t3e5ugdjRY=", "dev": true, "optional": true, "requires": { @@ -12686,7 +12686,7 @@ "p-cancelable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "integrity": "sha1-ueEjgAvOu3rBOkeb4ZW1B7mNMPo=", "dev": true, "optional": true }, @@ -12726,7 +12726,7 @@ "p-pipe": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.0.0.tgz", - "integrity": "sha512-gwwdRFmaxsT3IU+Tl3vYKVRdjfhg8Bbdjw7B+E0y6F7Yz6l+eaQLn0BRmGMXIhcPDONPtOkMoNwx1etZh4zPJA==", + "integrity": "sha1-qx+4fAuN15s7sDqKI2gPydBU4TI=", "dev": true }, "p-reduce": { @@ -12748,7 +12748,7 @@ "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", "dev": true, "requires": { "callsites": "^3.0.0" @@ -12757,7 +12757,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", "dev": true } } @@ -12815,7 +12815,7 @@ "parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "integrity": "sha1-4rXb7eAOf6m8NjYH9TMn6LBzGJs=", "dev": true }, "parse-passwd": { @@ -12845,7 +12845,7 @@ "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", "dev": true }, "pascalcase": { @@ -12884,7 +12884,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", "dev": true }, "path-root": { @@ -12994,7 +12994,7 @@ "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "integrity": "sha1-dwFr2JGdCsN3/c3QMiMolTyleBw=", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -13006,7 +13006,7 @@ "plur": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", - "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", + "integrity": "sha1-YCZ5Z4ZqjYEVBP5Y8vqrojdUals=", "dev": true, "requires": { "irregular-plurals": "^2.0.0" @@ -13032,13 +13032,13 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -13061,7 +13061,7 @@ "postcss-colormin": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13074,7 +13074,7 @@ "postcss-convert-values": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13084,7 +13084,7 @@ "postcss-discard-comments": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13093,7 +13093,7 @@ "postcss-discard-duplicates": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13102,7 +13102,7 @@ "postcss-discard-empty": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13111,7 +13111,7 @@ "postcss-discard-overridden": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13120,7 +13120,7 @@ "postcss-load-config": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", - "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "integrity": "sha1-yE1pK3u3tB3c7ZTuYuirMbQXsAM=", "dev": true, "requires": { "cosmiconfig": "^5.0.0", @@ -13130,7 +13130,7 @@ "postcss-merge-longhand": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", "dev": true, "requires": { "css-color-names": "0.0.4", @@ -13142,7 +13142,7 @@ "postcss-merge-rules": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13169,7 +13169,7 @@ "postcss-minify-font-values": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13179,7 +13179,7 @@ "postcss-minify-gradients": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13191,7 +13191,7 @@ "postcss-minify-params": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13205,7 +13205,7 @@ "postcss-minify-selectors": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13230,7 +13230,7 @@ "postcss-normalize-charset": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13239,7 +13239,7 @@ "postcss-normalize-display-values": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13250,7 +13250,7 @@ "postcss-normalize-positions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13262,7 +13262,7 @@ "postcss-normalize-repeat-style": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13274,7 +13274,7 @@ "postcss-normalize-string": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", "dev": true, "requires": { "has": "^1.0.0", @@ -13285,7 +13285,7 @@ "postcss-normalize-timing-functions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13296,7 +13296,7 @@ "postcss-normalize-unicode": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13307,7 +13307,7 @@ "postcss-normalize-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", "dev": true, "requires": { "is-absolute-url": "^2.0.0", @@ -13319,7 +13319,7 @@ "postcss-normalize-whitespace": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13329,7 +13329,7 @@ "postcss-ordered-values": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13340,7 +13340,7 @@ "postcss-reduce-initial": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13352,7 +13352,7 @@ "postcss-reduce-transforms": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13375,7 +13375,7 @@ "postcss-svgo": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", - "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "integrity": "sha1-F7mXvHEbMzurFDqu07jT1uPTglg=", "dev": true, "requires": { "is-svg": "^3.0.0", @@ -13387,7 +13387,7 @@ "postcss-unique-selectors": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13423,7 +13423,7 @@ "pretty-bytes": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz", - "integrity": "sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==", + "integrity": "sha1-8oSeJ9t5+01s/iR2T8QTTxZZifI=", "dev": true }, "pretty-hrtime": { @@ -13435,19 +13435,19 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", "dev": true }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", "dev": true }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", "dev": true }, "promise": { @@ -13488,7 +13488,7 @@ "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -13498,7 +13498,7 @@ "pumpify": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", "dev": true, "requires": { "duplexify": "^3.6.0", @@ -13509,7 +13509,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", "dev": true }, "q": { @@ -13527,13 +13527,13 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", "dev": true }, "query-string": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "integrity": "sha1-p4wBK3HBfgXy4/ojGd0zBoLvs8s=", "dev": true, "optional": true, "requires": { @@ -13554,7 +13554,7 @@ "randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "integrity": "sha1-t3bvxZN1mE42xTey9RofCv8Noe0=", "dev": true, "requires": { "is-number": "^4.0.0", @@ -13565,7 +13565,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", "dev": true } } @@ -13573,13 +13573,13 @@ "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", "dev": true }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", "dev": true, "requires": { "bytes": "3.1.0", @@ -13624,7 +13624,7 @@ "readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -13693,7 +13693,7 @@ "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "integrity": "sha1-SoVuxLVuQHfFV1icroXnpMiGmhE=", "dev": true }, "regenerate-unicode-properties": { @@ -13736,7 +13736,7 @@ "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", "dev": true }, "regexpu-core": { @@ -13756,7 +13756,7 @@ "regjsgen": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "integrity": "sha1-SPC/Gl6iBRlpKcDZeYtC0e2YRDw=", "dev": true }, "regjsparser": { @@ -13779,7 +13779,7 @@ "remove-bom-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "integrity": "sha1-wr8eN3Ug0yT2I4kuM8EMrCwlK1M=", "dev": true, "requires": { "is-buffer": "^1.1.5", @@ -13806,7 +13806,7 @@ "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", "dev": true }, "repeat-string": { @@ -13976,13 +13976,13 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "integrity": "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY=", "dev": true }, "rfdc": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "integrity": "sha1-unLME2egzNnPgahws7WL060H+MI=", "dev": true }, "rgb-regex": { @@ -14009,7 +14009,7 @@ "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", "dev": true, "requires": { "glob": "^7.1.3" @@ -14027,7 +14027,7 @@ "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "integrity": "sha1-yd06fPn0ssS2JE4XOm7YZuYd1nk=", "dev": true }, "run-sequence": { @@ -14171,7 +14171,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", "dev": true }, "semver-greatest-satisfied-range": { @@ -14186,7 +14186,7 @@ "semver-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "integrity": "sha1-qTwsWERTmncCMzeRB7OMe0rJ0zg=", "dev": true, "optional": true }, @@ -14209,7 +14209,7 @@ "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -14232,7 +14232,7 @@ "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", "dev": true }, "shebang-command": { @@ -14253,7 +14253,7 @@ "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=", "dev": true }, "signal-exit": { @@ -14265,7 +14265,7 @@ "signalr": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/signalr/-/signalr-2.4.0.tgz", - "integrity": "sha512-GPJHb3pcNk3IUui5/WG8lMuarEn+Vpc8wEvJ60w0KQ43W9FHnJcuNcF8dkZePr81eBslzicsRdyEunKNF7KjZQ==", + "integrity": "sha1-kq8AjmtSetSzbpT7s0DhNQh6YNI=", "requires": { "jquery": ">=1.6.4" } @@ -14282,7 +14282,7 @@ "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", "dev": true } } @@ -14296,7 +14296,7 @@ "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", "dev": true, "requires": { "ansi-styles": "^3.2.0", @@ -14331,7 +14331,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -14437,7 +14437,7 @@ "socket.io": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", - "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "integrity": "sha1-oGnF/qvuPmshSnW0DOBlLhz7mYA=", "dev": true, "requires": { "debug": "~3.1.0", @@ -14451,7 +14451,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -14474,7 +14474,7 @@ "socket.io-client": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", - "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "integrity": "sha1-3LOBA0NqtFeN2wJmOK4vIbYjZx8=", "dev": true, "requires": { "backo2": "1.0.2", @@ -14502,7 +14502,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -14602,13 +14602,13 @@ "sparkles": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "integrity": "sha1-AI22XtzmxQ7sDF4ijhlFBh3QQ3w=", "dev": true }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "integrity": "sha1-+4PlBERSaPFUsHTiGMh8ADzTHfQ=", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -14618,7 +14618,7 @@ "spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "integrity": "sha1-LqRQrudPKom/uUUZwH/Nb0EyKXc=", "dev": true }, "spdx-expression-parse": { @@ -14634,7 +14634,7 @@ "spdx-license-ids": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "integrity": "sha1-NpS1gEVnpFjTyARYQqY1hjL2JlQ=", "dev": true }, "spectrum-colorpicker": { @@ -14702,7 +14702,7 @@ "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", "dev": true, "requires": { "asn1": "~0.2.3", @@ -14758,7 +14758,7 @@ "stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "integrity": "sha1-rNrI2lnvK8HheiwMz2wyDRIOVV0=", "dev": true }, "stream-shift": { @@ -14770,7 +14770,7 @@ "streamroller": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", - "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "integrity": "sha1-gWfYSW7Z8Z8F7ksVjZYRMhuMrNk=", "dev": true, "requires": { "async": "^2.6.2", @@ -14783,7 +14783,7 @@ "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", "dev": true, "requires": { "ms": "^2.1.1" @@ -14892,7 +14892,7 @@ "strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "integrity": "sha1-SYdzYmT8NEzyD2w0rKnRPR1O1sU=", "dev": true, "requires": { "is-natural-number": "^4.0.1" @@ -14917,7 +14917,7 @@ "strip-json-comments": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "integrity": "sha1-hXE5dakfuHvxswXMp3OV5A0qZKc=", "dev": true }, "strip-outer": { @@ -14932,7 +14932,7 @@ "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -14956,7 +14956,7 @@ "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -14996,7 +14996,7 @@ "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", "dev": true, "requires": { "ajv": "^6.10.2", @@ -15008,7 +15008,7 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", "dev": true }, "is-fullwidth-code-point": { @@ -15020,7 +15020,7 @@ "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", "dev": true, "requires": { "emoji-regex": "^7.0.1", @@ -15031,7 +15031,7 @@ "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -15042,7 +15042,7 @@ "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "integrity": "sha1-jqVdqzeXIlPZqa+Q/c1VmuQ1xVU=", "dev": true, "requires": { "bl": "^1.0.0", @@ -15105,7 +15105,7 @@ "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "integrity": "sha1-adycGxdEbueakr9biEu0uRJ1BvU=", "dev": true }, "text-table": { @@ -15129,7 +15129,7 @@ "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", "dev": true, "requires": { "readable-stream": "~2.3.6", @@ -15171,7 +15171,7 @@ "through2-concurrent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/through2-concurrent/-/through2-concurrent-2.0.0.tgz", - "integrity": "sha512-R5/jLkfMvdmDD+seLwN7vB+mhbqzWop5fAjx5IX8/yQq7VhBhzDmhXgaHAOnhnWkCpRMM7gToYHycB0CS/pd+A==", + "integrity": "sha1-yd0sFGUE7Jli28hqUWi2PWYmafo=", "dev": true, "requires": { "through2": "^2.0.0" @@ -15180,7 +15180,7 @@ "through2-filter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "integrity": "sha1-cA54bfI2fCyIzYqlvkz5weeDElQ=", "dev": true, "requires": { "through2": "~2.0.0", @@ -15202,7 +15202,7 @@ "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "integrity": "sha1-b1ethXjgej+5+R2Th9ZWR1VeJcY=", "dev": true, "requires": { "es5-ext": "~0.10.46", @@ -15218,12 +15218,12 @@ "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + "integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM=" }, "tinymce": { "version": "4.9.7", "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.7.tgz", - "integrity": "sha512-cj0HvUuniTuIjOAJdRt5BUfeQqM5yHjbA2NOub9HUHXlCrT9OwD9WBPU6tGlaPC2l2I4eGoOnT8llosZRdQU5Q==" + "integrity": "sha1-dM5U8Hz8AmilrF409hAERljJL0c=" }, "tmp": { "version": "0.0.33", @@ -15316,7 +15316,7 @@ "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", "dev": true }, "tough-cookie": { @@ -15383,7 +15383,7 @@ "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "integrity": "sha1-hI3XaY2vo+VKbEeedZxLw/GIR6A=", "dev": true }, "type-check": { @@ -15398,7 +15398,7 @@ "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", "dev": true, "requires": { "media-typer": "0.3.0", @@ -15483,7 +15483,7 @@ "unbzip2-stream": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "integrity": "sha1-0VbSBeZw2NjDk+HALr1QZCKHP2o=", "dev": true, "requires": { "buffer": "^5.2.1", @@ -15499,12 +15499,12 @@ "underscore": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + "integrity": "sha1-BtzjSg5op7q8KbNluOdLiSUgOWE=" }, "undertaker": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "integrity": "sha1-cBZi/4zjWHFTJN/UkqTwNgVd/ks=", "dev": true, "requires": { "arr-flatten": "^1.0.1", @@ -15527,13 +15527,13 @@ "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", "dev": true }, "unicode-match-property-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^1.0.4", @@ -15555,7 +15555,7 @@ "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -15579,7 +15579,7 @@ "unique-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "integrity": "sha1-xl0RDppK35psWUiygFPZqNBMvqw=", "dev": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", @@ -15589,7 +15589,7 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", "dev": true }, "unpipe": { @@ -15653,7 +15653,7 @@ "upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "integrity": "sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ=", "dev": true }, "uri-js": { @@ -15690,13 +15690,13 @@ "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", "dev": true }, "useragent": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "integrity": "sha1-IX+UOtVAyyEoZYqyP8lg9qiMmXI=", "dev": true, "requires": { "lru-cache": "4.1.x", @@ -15734,13 +15734,13 @@ "v8-compile-cache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "integrity": "sha1-4U3jezGm0ZT1aQ1n78Tn9vxqsw4=", "dev": true }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -15820,7 +15820,7 @@ "vinyl-fs": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "integrity": "sha1-yFhJQF9nQo/qu71cXb3WT0fTG8c=", "dev": true, "requires": { "fs-mkdirp-stream": "^1.0.0", @@ -15979,7 +15979,7 @@ "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", "dev": true, "requires": { "isexe": "^2.0.0" @@ -16022,7 +16022,7 @@ "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -16042,7 +16042,7 @@ "xmlbuilder": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz", - "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==", + "integrity": "sha1-4u1nXgaDSgid37hNuW4sKwP3jBo=", "dev": true }, "xmlhttprequest-ssl": { @@ -16054,7 +16054,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=", "dev": true }, "y18n": { diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js index 3874ff9bf6..ea7f3a6d4c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js @@ -84,7 +84,7 @@ angular.module('umbraco.mocks'). "buttons_save": "Save", "buttons_saveAndPublish": "Save and publish", "buttons_saveToPublish": "Save and send for approval", - "buttons_showPage": "Preview", + "buttons_saveAndPreview": "Save and preview", "buttons_showPageDisabled": "Preview is disabled because there's no template assigned", "buttons_styleChoose": "Choose style", "buttons_styleShow": "Show styles", diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index 5bfe66b25f..9c935086a0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -588,7 +588,7 @@ When building a custom infinite editor view you can use the same components as a */ function mediaPicker(editor) { editor.view = "views/common/infiniteeditors/mediapicker/mediapicker.html"; - if (!editor.size) editor.size = "small"; + if (!editor.size) editor.size = "medium"; editor.updatedMediaNodes = []; open(editor); } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less index d06c15cd30..839e61c5f9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less @@ -256,7 +256,7 @@ body.touch .umb-tree { } &.current > .umb-tree-item__inner > .umb-tree-item__annotation { - background-color: @pinkLight; + background-color: @ui-active; } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less index 6a6a8f9f5b..2cca776614 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less @@ -115,7 +115,7 @@ li { &.is-active a { - border-left-color: @ui-active; + border-left-color: @ui-active-border; } a { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less index 1c5c275642..a52f81b92a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less @@ -1,5 +1,8 @@ -@checkboxWidth: 16px; -@checkboxHeight: 16px; +@checkboxWidth: 18px; +@checkboxHeight: 18px; +label.umb-form-check--checkbox{ + margin:3px 0; +} .umb-form-check { display: flex; @@ -10,11 +13,11 @@ cursor: pointer !important; .umb-form-check__symbol { - margin-top: 1px; + margin-top: 4px; margin-right: 10px; } .umb-form-check__info { - + margin-left:20px; } @@ -95,6 +98,10 @@ &__state { display: flex; height: 18px; + position: absolute; + margin-top: 2px; + top: 0; + left: -1px; } &__check { diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 0600c9aab6..ffc0626981 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -297,7 +297,6 @@ select[size] { } // Focus for select, file, radio, and checkbox -select, input[type="file"], input[type="radio"], input[type="checkbox"] { diff --git a/src/Umbraco.Web.UI.Client/src/less/gridview.less b/src/Umbraco.Web.UI.Client/src/less/gridview.less index 238feead90..11ba7b2795 100644 --- a/src/Umbraco.Web.UI.Client/src/less/gridview.less +++ b/src/Umbraco.Web.UI.Client/src/less/gridview.less @@ -101,6 +101,9 @@ position:relative; } + .usky-grid .grid-layout { + max-width: 600px; +} // ROW // ------------------------- @@ -517,6 +520,25 @@ position:relative; } + .usky-grid .uSky-templates .layout { + margin-top: 5px; + margin-bottom: 20px; + float: left; +} + + +.usky-grid .uSky-templates .columns { + margin-top: 5px; + margin-bottom: 25px; + float: left; +} + + +.usky-grid .uSky-templates .columns .preview-cell p { + font-size: 6px; + line-height: 8px; + text-align: center; +} /**************************************************************************************************/ diff --git a/src/Umbraco.Web.UI.Client/src/less/modals.less b/src/Umbraco.Web.UI.Client/src/less/modals.less index 925f845c4c..4ce907d06f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/modals.less +++ b/src/Umbraco.Web.UI.Client/src/less/modals.less @@ -88,9 +88,13 @@ background: @white; } -.umb-dialog .umb-btn-toolbar .umb-control-group{ - border: none; - padding: none; +.umb-dialog .abstract{ + margin-bottom:20px; +} + +.umb-dialog .umb-btn-toolbar .umb-control-group { + border: none; + padding: none; } .umb-dialog-body{ diff --git a/src/Umbraco.Web.UI.Client/src/less/sections.less b/src/Umbraco.Web.UI.Client/src/less/sections.less index 1f19786b3c..d4b5cfc998 100644 --- a/src/Umbraco.Web.UI.Client/src/less/sections.less +++ b/src/Umbraco.Web.UI.Client/src/less/sections.less @@ -31,7 +31,7 @@ ul.sections { height: 4px; bottom: 0; transform: translateY(4px); - background-color: @ui-active; + background-color: @pinkLight; position: absolute; border-radius: 3px 3px 0 0; opacity: 0; @@ -56,7 +56,7 @@ ul.sections { } &.current > a { - color: @ui-active; + color: @pinkLight; &::after { opacity: 1; @@ -79,7 +79,7 @@ ul.sections { &.current { i { opacity: 1; - background: @ui-active; + background: @pinkLight; } } @@ -111,7 +111,7 @@ ul.sections-tray { li { &.current a { - color: @ui-active; + color: @ui-active-border; opacity: 1; &::after { @@ -131,7 +131,7 @@ ul.sections-tray { content: ""; width: 4px; height: 100%; - background-color: @ui-active; + background-color: @ui-active-border; position: absolute; border-radius: 0 3px 3px 0; opacity: 0; diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index 5c0e6f7729..accd09fdd9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -75,6 +75,8 @@ @gray-9: #E9E9EB; @gray-10: #F3F3F5; @gray-11: #F6F6F7; +@gray-12: #F9F9FA; +@gray-13: #FBFBFD; @sand-1: #DED4CF;// added 2019 @sand-2: #EBDED6;// added 2019 @@ -108,7 +110,7 @@ //@blueLight: #4f89de; @blue: #2E8AEA; @blueMid: #2152A3;// updated 2019 -@blueMidLight: rgb(99, 174, 236); +@blueMidLight: #6ab4f0; @blueDark: #3544b1;// updated 2019 @blueExtraDark: #1b264f;// added 2019 @blueLight: #ADD8E6; @@ -116,6 +118,7 @@ //@orange: #f79c37;// updated 2019 @pink: #D93F4C;// #C3325F;// update 2019 @pinkLight: #f5c1bc;// added 2019 +@pinkExtraLight: #fee4e1;// added 2020 @pinkRedLight: #ff8a89;// added 2019 @brown: #9d8057;// added 2019 @brownLight: #e4e0dd;// added 2019 @@ -134,17 +137,18 @@ @ui-option-type: @blueExtraDark; @ui-option-type-hover: @blueMid; @ui-option: @white; -@ui-option-hover: @sand-7; +@ui-option-hover: @gray-12; @ui-option-disabled-type: @gray-6; @ui-option-disabled-type-hover: @gray-5; -@ui-option-disabled-hover: @sand-7; +@ui-option-disabled-hover: @gray-12; @ui-disabled-type: @gray-6; @ui-disabled-border: @gray-6; //@ui-active: #346ab3; -@ui-active: @pinkLight; +@ui-active: @pinkExtraLight; +@ui-active-border: @pinkLight; @ui-active-blur: @brownLight; @ui-active-type: @blueExtraDark; @ui-active-type-hover: @blueMid; @@ -161,19 +165,19 @@ @ui-light-type-hover: @blueMid; @ui-light-active-border: @pinkLight; -@ui-light-active-type: @blueExtraDark; -@ui-light-active-type-hover: @blueMid; +@ui-light-active-type: @blueMid; +@ui-light-active-type-hover: @blueMidLight; @ui-action: @white; -@ui-action-hover: @sand-7; +@ui-action-hover: @gray-12; @ui-action-type: @blueExtraDark; @ui-action-type-hover: @blueMid; @ui-action-border: @blueExtraDark; @ui-action-border-hover: @blueMid; @ui-action-discreet: @white; -@ui-action-discreet-hover: @sand-7; +@ui-action-discreet-hover: @gray-12; @ui-action-discreet-type: @blueExtraDark; @ui-action-discreet-type-hover: @blueMid; @ui-action-discreet-border: @gray-7; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js index c189131646..6728486a0d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js @@ -1,7 +1,7 @@ //used for the media picker dialog angular.module("umbraco") .controller("Umbraco.Editors.MediaPickerController", - function ($scope, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService, umbSessionStorage) { + function ($scope, $timeout, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService, umbSessionStorage) { var vm = this; @@ -306,9 +306,7 @@ angular.module("umbraco") }); } else { var image = $scope.images[$scope.images.length - 1]; - $scope.target = image; - $scope.target.url = mediaHelper.resolveFile(image); - selectMedia(image); + clickHandler(image); } }); }); @@ -324,7 +322,7 @@ angular.module("umbraco") // also make sure the node is not trashed if (nodePath.indexOf($scope.startNodeId.toString()) !== -1 && node.trashed === false) { - gotoFolder({ id: $scope.lastOpenedNode, name: "Media", icon: "icon-folder", path: node.path }); + gotoFolder({ id: $scope.lastOpenedNode || $scope.startNodeId, name: "Media", icon: "icon-folder", path: node.path }); return true; } else { gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" }); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js index 3ec6a3f3cb..11d80d562d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js @@ -78,18 +78,20 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController", */ function onInit () { - // load languages - languageResource.getAll().then(function (languages) { - vm.languages = languages; + if (vm.showLanguageSelector) { + // load languages + languageResource.getAll().then(function (languages) { + vm.languages = languages; - // set the default language - vm.languages.forEach(function (language) { - if (language.isDefault) { - vm.selectedLanguage = language; - vm.languageSelectorIsOpen = false; - } + // set the default language + vm.languages.forEach(function (language) { + if (language.isDefault) { + vm.selectedLanguage = language; + vm.languageSelectorIsOpen = false; + } + }); }); - }); + } if (vm.treeAlias === "content") { vm.entityType = "Document"; @@ -214,7 +216,7 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController", if (vm.dataTypeKey) { queryParams["dataTypeKey"] = vm.dataTypeKey; } - + var queryString = $.param(queryParams); //create the query string from the params object if (!queryString) { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html index 8dd78883c2..e1eb5e454a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html @@ -45,9 +45,9 @@ alias="preview" ng-if="!page.isNew && content.allowPreview && page.showPreviewButton" type="button" - button-style="info" + button-style="link" action="preview(content)" - label-key="buttons_showPage"> + label-key="buttons_saveAndPreview"> - +
- @@ -79,7 +79,7 @@
- {{ item.comment }} - +
@@ -126,7 +126,7 @@
- + diff --git a/src/Umbraco.Web.UI.Client/src/views/contentblueprints/create.html b/src/Umbraco.Web.UI.Client/src/views/contentblueprints/create.html index 6146c007b1..a8f9630d0e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/contentblueprints/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/contentblueprints/create.html @@ -1,18 +1,20 @@
-
+
-

-

+

+ Row Configurations +

+

+ Rows are predefined cells arranged horizontally +

    + class="preview-rows columns">
    -

    {{area.maxItems}}

    +

    {{area.maxItems}}

    @@ -74,17 +84,18 @@
    {{layout.label || layout.name}}
    - - - - +
-
@@ -93,7 +104,7 @@
-
+
@@ -108,22 +119,21 @@ ng-model="model.value.config">
  • - + - - +
    • -
    • - - - - - +
    • +
    @@ -137,22 +147,22 @@ ng-model="model.value.styles">
  • - + - - +
    • -
    • - - - - +
    • +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js index cde99d7b9e..340e6865ef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js @@ -49,12 +49,10 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl // when there is no match for a selected id. This will ensure that the values being set on save, are the same as before. medias = ids.map(id => { - var found = medias.find(m => - // We could use coercion (two ='s) here .. but not sure if this works equally well in all browsers and - // it's prone to someone "fixing" it at some point without knowing the effects. Rather use toString() - // compares and be completely sure it works. - m.udi.toString() === id.toString() || m.id.toString() === id.toString()); - + // We could use coercion (two ='s) here .. but not sure if this works equally well in all browsers and + // it's prone to someone "fixing" it at some point without knowing the effects. Rather use toString() + // compares and be completely sure it works. + var found = medias.find(m => m.udi.toString() === id.toString() || m.id.toString() === id.toString()); if (found) { return found; } else { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js index f2538c66c1..a25d5e798e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js @@ -591,8 +591,8 @@ } function updatePropertyActionStates() { - copyAllEntriesAction.isDisabled = !model.value || model.value.length === 0; - removeAllEntriesAction.isDisabled = !model.value || model.value.length === 0; + copyAllEntriesAction.isDisabled = !model.value || !model.value.length; + removeAllEntriesAction.isDisabled = copyAllEntriesAction.isDisabled; } diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html index bb53413060..a0098d411c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html @@ -119,7 +119,7 @@ - + diff --git a/src/Umbraco.Web.UI.NetCore/Program.cs b/src/Umbraco.Web.UI.NetCore/Program.cs index 21eb1b6585..1151f16be8 100644 --- a/src/Umbraco.Web.UI.NetCore/Program.cs +++ b/src/Umbraco.Web.UI.NetCore/Program.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; +using Umbraco.Core.Composing; namespace Umbraco.Web.UI.BackOffice { @@ -20,6 +15,7 @@ namespace Umbraco.Web.UI.BackOffice public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) + .UseUmbraco(); } } diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 8e4da28917..2753676452 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Umbraco.Web.BackOffice.AspNetCore; @@ -15,12 +16,30 @@ namespace Umbraco.Web.UI.BackOffice { public class Startup { + private readonly IWebHostEnvironment _webHostEnvironment; + private readonly IConfiguration _config; + + /// + /// Constructor + /// + /// + /// + /// + /// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337 + /// + public Startup(IWebHostEnvironment webHostEnvironment, IConfiguration config) + { + _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment)); + _config = config ?? throw new ArgumentNullException(nameof(config)); + } + // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { + services.AddUmbracoConfiguration(_config); + services.AddUmbracoCore(_webHostEnvironment); services.AddUmbracoWebsite(); - services.AddUmbracoBackOffice(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj index 69d223bcc6..ca7c3e26fa 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -14,4 +14,9 @@ + + <_ContentIncludedByDefault Remove="wwwroot\~\App_Data\TEMP\TypesCache\umbraco-types.DESKTOP-2016.hash" /> + <_ContentIncludedByDefault Remove="wwwroot\~\App_Data\TEMP\TypesCache\umbraco-types.DESKTOP-2016.list" /> + + diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.Development.json b/src/Umbraco.Web.UI.NetCore/appsettings.Development.json index 8983e0fc1c..834ea5f51f 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.Development.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.Development.json @@ -1,4 +1,7 @@ { + "ConnectionStrings": { + "umbracoDbDSN": "" + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.json b/src/Umbraco.Web.UI.NetCore/appsettings.json index d9d9a9bff6..1c89647efa 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.json @@ -1,4 +1,7 @@ { + "ConnectionStrings": { + "umbracoDbDSN": "" + }, "Logging": { "LogLevel": { "Default": "Information", @@ -6,5 +9,81 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "Umbraco": { + "CMS": { + "Imaging": { + "Resize": { + "MaxWidth": 5000, + "MaxHeight": 5000 + }, + "Cache": { + "Folder": "../App_Data/Cache", + "MaxBrowserCacheDays": 7, + "MaxCacheDays": 365, + "CachedNameLength": 8 + } + }, + "HealthChecks": { + "DisabledChecks": [ + { + "id": "1B5D221B-CE99-4193-97CB-5F3261EC73DF", + "disabledBy": 1, + "disabledOn": "2020-03-15 19:19:10" + } + ], + "NotificationSettings": { + "Enabled": true, + "FirstRunTime": "", + "PeriodInHours": 24, + "NotificationMethods": { + "Email": { + "Enabled": true, + "Verbosity": "Summary", + "Settings": { + "RecipientEmail": "" + } + } + }, + "DisabledChecks": [ + { + "id": "1B5D221B-CE99-4193-97CB-5F3261EC73DF", + "disabledBy": 1, + "disabledOn": "2020-03-15 19:19:10" + } + ] + } + }, + "Tours": { + "EnableTours": true + }, + "Core": { + "Debug": {} + }, + "Content": { + "Errors": { + "Error404": { + "default": "1047", + "en-US": "$site/error [@name = 'error']", + "en-UK": "8560867F-B88F-4C74-A9A4-679D8E5B3BFC" + } + } + }, + "RequestHandler": { + "AddTrailingSlash": true, + "CharCollection": [ + {"Char": " ", "Replacement": "-"}, + {"Char": "\"", "Replacement": ""}, + {"Char": "'", "Replacement": ""}, + {"Char": "%", "Replacement": ""}, + {"Char": ".", "Replacement": ""}, + {"Char": ";", "Replacement": ""}, + {"Char": "/", "Replacement": ""}, + {"Char": "\\", "Replacement": ""}, + {"Char": ":", "Replacement": ""}, + + ] + } + } + } } diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 7b5c221a41..fe11a8d9aa 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -84,7 +84,7 @@ - + @@ -137,13 +137,6 @@ Properties\SolutionInfo.cs - - noNodes.aspx - ASPXCodeBehind - - - noNodes.aspx - True @@ -169,11 +162,10 @@ - + - ClientDependency.config diff --git a/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml index e41185d74b..14ef376a2c 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml @@ -17,7 +17,7 @@ - + @@ -48,7 +48,7 @@ redirectUrl = Url.Action("AuthorizeUpgrade", "BackOffice") }); } - @Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection, Model.IOHelper, Model.TreeCollection, Model.HttpContextAccessor, Model.HostingEnvironment, Model.RuntimeSettings) + @Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.ContentSettings, Model.IOHelper, Model.TreeCollection, Model.HttpContextAccessor, Model.HostingEnvironment, Model.RuntimeSettings, Model.SecuritySettings) - - - diff --git a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs b/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs index 5fb2825269..6d2ce5e7e4 100644 --- a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs @@ -1,5 +1,17 @@ +using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Web; +using SixLabors.ImageSharp.Web.Caching; +using SixLabors.ImageSharp.Web.Commands; using SixLabors.ImageSharp.Web.DependencyInjection; +using SixLabors.ImageSharp.Web.Middleware; +using SixLabors.ImageSharp.Web.Processors; +using SixLabors.ImageSharp.Web.Providers; +using SixLabors.Memory; +using Umbraco.Core; +using Umbraco.Core.Configuration; namespace Umbraco.Web.Website.AspNetCore { @@ -7,11 +19,64 @@ namespace Umbraco.Web.Website.AspNetCore { public static IServiceCollection AddUmbracoWebsite(this IServiceCollection services) { - services.AddImageSharp(); - + // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured + var serviceProvider = services.BuildServiceProvider(); + var configs = serviceProvider.GetService(); + var imagingSettings = configs.Imaging(); + services.AddUmbracoImageSharp(imagingSettings); return services; } + public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, IImagingSettings imagingSettings) + { + + + services.AddImageSharpCore( + options => + { + options.Configuration = SixLabors.ImageSharp.Configuration.Default; + options.MaxBrowserCacheDays = imagingSettings.MaxBrowserCacheDays; + options.MaxCacheDays = imagingSettings.MaxCacheDays; + options.CachedNameLength = imagingSettings.CachedNameLength; + options.OnParseCommands = context => + { + RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Width, imagingSettings.MaxResizeWidth); + RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Height, imagingSettings.MaxResizeHeight); + }; + options.OnBeforeSave = _ => { }; + options.OnProcessed = _ => { }; + options.OnPrepareResponse = _ => { }; + }) + .SetRequestParser() + .SetMemoryAllocator(provider => ArrayPoolMemoryAllocator.CreateWithMinimalPooling()) + .Configure(options => + { + options.CacheFolder = imagingSettings.CacheFolder; + }) + .SetCache() + .SetCacheHash() + .AddProvider() + .AddProcessor() + .AddProcessor() + .AddProcessor(); + + return services; + } + + private static void RemoveIntParamenterIfValueGreatherThen(IDictionary commands, string parameter, int maxValue) + { + if (commands.TryGetValue(parameter, out var command)) + { + if (int.TryParse(command, out var i)) + { + if (i > maxValue) + { + commands.Remove(parameter); + } + } + } + } } + } diff --git a/src/Umbraco.Web/AppBuilderExtensions.cs b/src/Umbraco.Web/AppBuilderExtensions.cs index 870cba86f3..e9833e4379 100644 --- a/src/Umbraco.Web/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/AppBuilderExtensions.cs @@ -43,11 +43,10 @@ namespace Umbraco.Web /// Configures SignalR. ///
    /// The app builder. - /// /// - public static IAppBuilder UseSignalR(this IAppBuilder app, IGlobalSettings globalSettings, IIOHelper ioHelper) + public static IAppBuilder UseSignalR(this IAppBuilder app, IIOHelper ioHelper) { - var umbracoPath = globalSettings.GetUmbracoMvcArea(ioHelper); + var umbracoPath = ioHelper.GetUmbracoMvcArea(); var signalrPath = HttpRuntime.AppDomainAppVirtualPath + umbracoPath + "/BackOffice/signalr"; return app.MapSignalR(signalrPath, new HubConfiguration { EnableDetailedErrors = true }); } diff --git a/src/Umbraco.Web/AspNet/AspNetApplicationShutdownRegistry.cs b/src/Umbraco.Web/AspNet/AspNetApplicationShutdownRegistry.cs new file mode 100644 index 0000000000..dbd6e9e834 --- /dev/null +++ b/src/Umbraco.Web/AspNet/AspNetApplicationShutdownRegistry.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Concurrent; +using System.Web.Hosting; +using Umbraco.Core.Hosting; +using IRegisteredObject = Umbraco.Core.IRegisteredObject; + +namespace Umbraco.Web.Hosting +{ + public class AspNetApplicationShutdownRegistry : IApplicationShutdownRegistry + { + private readonly ConcurrentDictionary _registeredObjects = + new ConcurrentDictionary(); + + public void RegisterObject(IRegisteredObject registeredObject) + { + var wrapped = new RegisteredObjectWrapper(registeredObject); + if (!_registeredObjects.TryAdd(registeredObject, wrapped)) + { + throw new InvalidOperationException("Could not register object"); + } + HostingEnvironment.RegisterObject(wrapped); + } + + public void UnregisterObject(IRegisteredObject registeredObject) + { + if (_registeredObjects.TryGetValue(registeredObject, out var wrapped)) + { + HostingEnvironment.UnregisterObject(wrapped); + } + } + + private class RegisteredObjectWrapper : System.Web.Hosting.IRegisteredObject + { + private readonly IRegisteredObject _inner; + + public RegisteredObjectWrapper(IRegisteredObject inner) + { + _inner = inner; + } + + public void Stop(bool immediate) + { + _inner.Stop(immediate); + } + } + } +} diff --git a/src/Umbraco.Web/AspNet/AspNetBackOfficeInfo.cs b/src/Umbraco.Web/AspNet/AspNetBackOfficeInfo.cs index cabe56062c..1e60fedeea 100644 --- a/src/Umbraco.Web/AspNet/AspNetBackOfficeInfo.cs +++ b/src/Umbraco.Web/AspNet/AspNetBackOfficeInfo.cs @@ -11,15 +11,15 @@ namespace Umbraco.Web { private readonly IGlobalSettings _globalSettings; private readonly IIOHelper _ioHelper; - private readonly IUmbracoSettingsSection _settings; private readonly ILogger _logger; + private readonly IWebRoutingSettings _webRoutingSettings; - public AspNetBackOfficeInfo(IGlobalSettings globalSettings, IIOHelper ioHelper, IUmbracoSettingsSection settings, ILogger logger) + public AspNetBackOfficeInfo(IGlobalSettings globalSettings, IIOHelper ioHelper, ILogger logger, IWebRoutingSettings webRoutingSettings) { _globalSettings = globalSettings; _ioHelper = ioHelper; - _settings = settings; _logger = logger; + _webRoutingSettings = webRoutingSettings; } /// @@ -27,7 +27,7 @@ namespace Umbraco.Web private string GetAbsoluteUrlFromConfig() { - var url = _settings.WebRouting.UmbracoApplicationUrl; + var url = _webRoutingSettings.UmbracoApplicationUrl; if (url.IsNullOrWhiteSpace() == false) { var umbracoApplicationUrl = url.TrimEnd('/'); diff --git a/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs b/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs index aa07894aa9..a61ad356d5 100644 --- a/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs +++ b/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs @@ -1,21 +1,15 @@ using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; using System.Web; using System.Web.Hosting; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using IRegisteredObject = Umbraco.Core.IRegisteredObject; namespace Umbraco.Web.Hosting { public class AspNetHostingEnvironment : IHostingEnvironment { - private readonly ConcurrentDictionary _registeredObjects = - new ConcurrentDictionary(); + private readonly IHostingSettings _hostingSettings; private string _localTempPath; @@ -46,23 +40,7 @@ namespace Umbraco.Web.Hosting } public string ToAbsolute(string virtualPath, string root) => VirtualPathUtility.ToAbsolute(virtualPath, root); - public void RegisterObject(IRegisteredObject registeredObject) - { - var wrapped = new RegisteredObjectWrapper(registeredObject); - if (!_registeredObjects.TryAdd(registeredObject, wrapped)) - { - throw new InvalidOperationException("Could not register object"); - } - HostingEnvironment.RegisterObject(wrapped); - } - - public void UnregisterObject(IRegisteredObject registeredObject) - { - if (_registeredObjects.TryGetValue(registeredObject, out var wrapped)) - { - HostingEnvironment.UnregisterObject(wrapped); - } - } + public string LocalTempPath { @@ -101,20 +79,7 @@ namespace Umbraco.Web.Hosting } } } - private class RegisteredObjectWrapper : System.Web.Hosting.IRegisteredObject - { - private readonly IRegisteredObject _inner; - - public RegisteredObjectWrapper(IRegisteredObject inner) - { - _inner = inner; - } - - public void Stop(bool immediate) - { - _inner.Stop(immediate); - } - } + } diff --git a/src/Umbraco.Web/AspNet/AspNetSessionManager.cs b/src/Umbraco.Web/AspNet/AspNetSessionManager.cs index bf7b1c05c3..f81daadb0a 100644 --- a/src/Umbraco.Web/AspNet/AspNetSessionManager.cs +++ b/src/Umbraco.Web/AspNet/AspNetSessionManager.cs @@ -1,6 +1,6 @@ using System.Web; -using Umbraco.Core.Session; using Umbraco.Net; +using Umbraco.Core.Session; namespace Umbraco.Web.AspNet { diff --git a/src/Umbraco.Web/Compose/AuditEventsComponent.cs b/src/Umbraco.Web/Compose/AuditEventsComponent.cs index fba6e754c8..bd2520aa90 100644 --- a/src/Umbraco.Web/Compose/AuditEventsComponent.cs +++ b/src/Umbraco.Web/Compose/AuditEventsComponent.cs @@ -7,10 +7,10 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Net; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Net; using Umbraco.Web.Security; namespace Umbraco.Core.Compose diff --git a/src/Umbraco.Web/Composing/BuildManagerTypeFinder.cs b/src/Umbraco.Web/Composing/BuildManagerTypeFinder.cs deleted file mode 100644 index 994e8c26c4..0000000000 --- a/src/Umbraco.Web/Composing/BuildManagerTypeFinder.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Security; -using System.Web.Compilation; -using Umbraco.Core.Configuration; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; - -namespace Umbraco.Web.Composing -{ - /// - /// An implementation of TypeFinder that uses the BuildManager to resolve references for aspnet framework hosted websites - /// - /// - /// This finder will also try to resolve dynamic assemblies created from App_Code - /// - internal class BuildManagerTypeFinder : TypeFinder, ITypeFinder - { - - public BuildManagerTypeFinder( - IIOHelper ioHelper, - IHostingEnvironment hostingEnvironment, - ILogger logger, - ITypeFinderConfig typeFinderConfig = null) : base(logger, typeFinderConfig) - { - if (ioHelper == null) throw new ArgumentNullException(nameof(ioHelper)); - if (hostingEnvironment == null) throw new ArgumentNullException(nameof(hostingEnvironment)); - if (logger == null) throw new ArgumentNullException(nameof(logger)); - - _allAssemblies = new Lazy>(() => - { - var isHosted = hostingEnvironment.IsHosted; - try - { - if (isHosted) - { - var assemblies = new HashSet(BuildManager.GetReferencedAssemblies().Cast()); - - //here we are trying to get the App_Code assembly - var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported - var appCodeFolder = new DirectoryInfo(ioHelper.MapPath(ioHelper.ResolveUrl("~/App_code"))); - //check if the folder exists and if there are any files in it with the supported file extensions - if (appCodeFolder.Exists && fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())) - { - try - { - var appCodeAssembly = Assembly.Load("App_Code"); - if (assemblies.Contains(appCodeAssembly) == false) // BuildManager will find App_Code already - assemblies.Add(appCodeAssembly); - } - catch (FileNotFoundException ex) - { - //this will occur if it cannot load the assembly - logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code"); - } - } - } - } - catch (InvalidOperationException e) - { - if (e.InnerException is SecurityException == false) - throw; - } - - // Not hosted, just use the default implementation - return new HashSet(base.AssembliesToScan); - }); - } - - private readonly Lazy> _allAssemblies; - - /// - /// Explicitly implement and return result from BuildManager - /// - /// - /// - Type ITypeFinder.GetTypeByName (string name) => BuildManager.GetType(name, false); - - /// - /// Explicitly implement and return result from BuildManager - /// - IEnumerable ITypeFinder.AssembliesToScan => _allAssemblies.Value; - - /// - /// TypeFinder config via appSettings - /// - internal class TypeFinderConfig : ITypeFinderConfig - { - private readonly ITypeFinderSettings _settings; - private IEnumerable _assembliesAcceptingLoadExceptions; - - public TypeFinderConfig(ITypeFinderSettings settings) - { - _settings = settings; - } - - public IEnumerable AssembliesAcceptingLoadExceptions - { - get - { - if (_assembliesAcceptingLoadExceptions != null) - return _assembliesAcceptingLoadExceptions; - - var s = _settings.AssembliesAcceptingLoadExceptions; - return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s) - ? Array.Empty() - : s.Split(',').Select(x => x.Trim()).ToArray(); - } - } - } - } -} diff --git a/src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs b/src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs index 9a3e8d98f8..64f91939a7 100644 --- a/src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs +++ b/src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs @@ -14,7 +14,6 @@ namespace Umbraco.Web.Composing.CompositionExtensions composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); - composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index a431be4998..70083d47dd 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.Mapping; +using Umbraco.Net; using Umbraco.Core.PackageActions; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; @@ -18,7 +19,6 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Sync; -using Umbraco.Net; using Umbraco.Web.Actions; using Umbraco.Web.Cache; using Umbraco.Web.Editors; @@ -115,10 +115,10 @@ namespace Umbraco.Web.Composing public static UmbracoHelper UmbracoHelper => Factory.GetInstance(); - public static IUmbracoComponentRenderer UmbracoComponentRenderer => Factory.GetInstance(); - + public static ITagQuery TagQuery + => Factory.GetInstance(); public static DistributedCache DistributedCache => Factory.GetInstance(); diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 0d206f8d8d..6519cf4cf6 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -45,7 +45,7 @@ namespace Umbraco.Web.Editors private BackOfficeSignInManager _signInManager; private readonly IUserPasswordConfiguration _passwordConfiguration; private readonly IRuntimeState _runtimeState; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly ISecuritySettings _securitySettings; private readonly IIOHelper _ioHelper; public AuthenticationController( @@ -58,14 +58,14 @@ namespace Umbraco.Web.Editors IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, - IUmbracoSettingsSection umbracoSettingsSection, + ISecuritySettings securitySettings, IIOHelper ioHelper, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { _passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration)); _runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); } @@ -310,7 +310,7 @@ namespace Umbraco.Web.Editors { // If this feature is switched off in configuration the UI will be amended to not make the request to reset password available. // So this is just a server-side secondary check. - if (_umbracoSettingsSection.Security.AllowPasswordReset == false) + if (_securitySettings.AllowPasswordReset == false) { throw new HttpResponseException(HttpStatusCode.BadRequest); } @@ -534,7 +534,7 @@ namespace Umbraco.Web.Editors var action = urlHelper.Action("ValidatePasswordResetCode", "BackOffice", new { - area = GlobalSettings.GetUmbracoMvcArea(_ioHelper), + area = _ioHelper.GetUmbracoMvcArea(), u = userId, r = code }); diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 4a8d441192..e39d1658a2 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -48,12 +48,13 @@ namespace Umbraco.Web.Editors private BackOfficeSignInManager _signInManager; private readonly IUmbracoVersion _umbracoVersion; private readonly IGridConfig _gridConfig; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; private readonly TreeCollection _treeCollection; private readonly IHostingEnvironment _hostingEnvironment; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IRuntimeSettings _runtimeSettings; + private readonly ISecuritySettings _securitySettings; public BackOfficeController( IManifestParser manifestParser, @@ -66,12 +67,13 @@ namespace Umbraco.Web.Editors IRuntimeState runtimeState, IUmbracoVersion umbracoVersion, IGridConfig gridConfig, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, TreeCollection treeCollection, IHostingEnvironment hostingEnvironment, IHttpContextAccessor httpContextAccessor, - IRuntimeSettings settings) + IRuntimeSettings settings, + ISecuritySettings securitySettings) : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger) { @@ -80,12 +82,13 @@ namespace Umbraco.Web.Editors _runtimeState = runtimeState; _umbracoVersion = umbracoVersion; _gridConfig = gridConfig ?? throw new ArgumentNullException(nameof(gridConfig)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection)); _hostingEnvironment = hostingEnvironment; _httpContextAccessor = httpContextAccessor; _runtimeSettings = settings; + _securitySettings = securitySettings; } protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager()); @@ -101,8 +104,8 @@ namespace Umbraco.Web.Editors public async Task Default() { return await RenderDefaultOrProcessExternalLoginAsync( - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection,_ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings)), - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings))); + () => View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings,_ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings)), + () => View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings))); } [HttpGet] @@ -185,7 +188,7 @@ namespace Umbraco.Web.Editors { return await RenderDefaultOrProcessExternalLoginAsync( //The default view to render when there is no external login info or errors - () => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings)), + () => View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings)), //The ActionResult to perform if external login is successful () => Redirect("/")); } @@ -292,7 +295,7 @@ namespace Umbraco.Web.Editors [MinifyJavaScriptResult(Order = 1)] public JavaScriptResult ServerVariables() { - var serverVars = new BackOfficeServerVariables(Url, _runtimeState, _features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings); + var serverVars = new BackOfficeServerVariables(Url, _runtimeState, _features, GlobalSettings, _umbracoVersion, _contentSettings, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings); //cache the result if debugging is disabled var result = _hostingEnvironment.IsDebugMode @@ -386,7 +389,7 @@ namespace Umbraco.Web.Editors if (defaultResponse == null) throw new ArgumentNullException("defaultResponse"); if (externalSignInResponse == null) throw new ArgumentNullException("externalSignInResponse"); - ViewData.SetUmbracoPath(GlobalSettings.GetUmbracoMvcArea(_ioHelper)); + ViewData.SetUmbracoPath(_ioHelper.GetUmbracoMvcArea()); //check if there is the TempData with the any token name specified, if so, assign to view bag and render the view if (ViewData.FromTempData(TempData, ViewDataExtensions.TokenExternalSignInError) || diff --git a/src/Umbraco.Web/Editors/BackOfficeModel.cs b/src/Umbraco.Web/Editors/BackOfficeModel.cs index f229f908d0..3aefd58e8f 100644 --- a/src/Umbraco.Web/Editors/BackOfficeModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficeModel.cs @@ -10,27 +10,32 @@ namespace Umbraco.Web.Editors public class BackOfficeModel { - public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, IRuntimeSettings runtimeSettings) + public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, + IContentSettings contentSettings, IIOHelper ioHelper, TreeCollection treeCollection, + IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, + IRuntimeSettings runtimeSettings, ISecuritySettings securitySettings) { Features = features; GlobalSettings = globalSettings; UmbracoVersion = umbracoVersion; - UmbracoSettingsSection = umbracoSettingsSection; + ContentSettings = contentSettings; IOHelper = ioHelper; TreeCollection = treeCollection; HttpContextAccessor = httpContextAccessor; HostingEnvironment = hostingEnvironment; RuntimeSettings = runtimeSettings; + SecuritySettings = securitySettings; } public UmbracoFeatures Features { get; } public IGlobalSettings GlobalSettings { get; } public IUmbracoVersion UmbracoVersion { get; } - public IUmbracoSettingsSection UmbracoSettingsSection { get; } + public IContentSettings ContentSettings { get; } public IIOHelper IOHelper { get; } public TreeCollection TreeCollection { get; } public IHttpContextAccessor HttpContextAccessor { get; } public IHostingEnvironment HostingEnvironment { get; } public IRuntimeSettings RuntimeSettings { get; set; } + public ISecuritySettings SecuritySettings { get; set; } } } diff --git a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs index e2ea9c3234..394a0366af 100644 --- a/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs +++ b/src/Umbraco.Web/Editors/BackOfficePreviewModel.cs @@ -14,8 +14,8 @@ namespace Umbraco.Web.Editors private readonly UmbracoFeatures _features; public IEnumerable Languages { get; } - public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IEnumerable languages, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, IRuntimeSettings runtimeSettings) - : base(features, globalSettings, umbracoVersion, umbracoSettingsSection, ioHelper, treeCollection, httpContextAccessor, hostingEnvironment, runtimeSettings) + public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IEnumerable languages, IContentSettings contentSettings, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, IRuntimeSettings runtimeSettings, ISecuritySettings securitySettings) + : base(features, globalSettings, umbracoVersion, contentSettings, ioHelper, treeCollection, httpContextAccessor, hostingEnvironment, runtimeSettings, securitySettings) { _features = features; Languages = languages; diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 73264c6448..14f067a0fc 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -33,12 +33,13 @@ namespace Umbraco.Web.Editors private readonly UmbracoFeatures _features; private readonly IGlobalSettings _globalSettings; private readonly IUmbracoVersion _umbracoVersion; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; private readonly TreeCollection _treeCollection; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostingEnvironment _hostingEnvironment; private readonly IRuntimeSettings _settings; + private readonly ISecuritySettings _securitySettings; internal BackOfficeServerVariables( UrlHelper urlHelper, @@ -46,24 +47,26 @@ namespace Umbraco.Web.Editors UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, - IRuntimeSettings settings) + IRuntimeSettings settings, + ISecuritySettings securitySettings) { _urlHelper = urlHelper; _runtimeState = runtimeState; _features = features; _globalSettings = globalSettings; _umbracoVersion = umbracoVersion; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection)); _httpContextAccessor = httpContextAccessor; _hostingEnvironment = hostingEnvironment; _settings = settings; + _securitySettings = securitySettings; } /// @@ -341,30 +344,30 @@ namespace Umbraco.Web.Editors { "umbracoSettings", new Dictionary { - {"umbracoPath", _globalSettings.Path}, + {"umbracoPath", _ioHelper.BackOfficePath}, {"mediaPath", _ioHelper.ResolveUrl(globalSettings.UmbracoMediaPath).TrimEnd('/')}, {"appPluginsPath", _ioHelper.ResolveUrl(Constants.SystemDirectories.AppPlugins).TrimEnd('/')}, { "imageFileTypes", - string.Join(",", _umbracoSettingsSection.Content.ImageFileTypes) + string.Join(",", _contentSettings.ImageFileTypes) }, { "disallowedUploadFiles", - string.Join(",", _umbracoSettingsSection.Content.DisallowedUploadFiles) + string.Join(",", _contentSettings.DisallowedUploadFiles) }, { "allowedUploadFiles", - string.Join(",", _umbracoSettingsSection.Content.AllowedUploadFiles) + string.Join(",", _contentSettings.AllowedUploadFiles) }, { "maxFileSize", GetMaxRequestLength() }, - {"keepUserLoggedIn", _umbracoSettingsSection.Security.KeepUserLoggedIn}, - {"usernameIsEmail", _umbracoSettingsSection.Security.UsernameIsEmail}, + {"keepUserLoggedIn", _securitySettings.KeepUserLoggedIn}, + {"usernameIsEmail", _securitySettings.UsernameIsEmail}, {"cssPath", _ioHelper.ResolveUrl(globalSettings.UmbracoCssPath).TrimEnd('/')}, - {"allowPasswordReset", _umbracoSettingsSection.Security.AllowPasswordReset}, - {"loginBackgroundImage", _umbracoSettingsSection.Content.LoginBackgroundImage}, + {"allowPasswordReset", _securitySettings.AllowPasswordReset}, + {"loginBackgroundImage", _contentSettings.LoginBackgroundImage}, {"showUserInvite", EmailSender.CanSendRequiredEmail(globalSettings)}, {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail(globalSettings)}, } diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs index 85a4f97fb6..384270743c 100644 --- a/src/Umbraco.Web/Editors/CurrentUserController.cs +++ b/src/Umbraco.Web/Editors/CurrentUserController.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.Editors public class CurrentUserController : UmbracoAuthorizedJsonController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; private readonly IImageUrlGenerator _imageUrlGenerator; @@ -49,14 +49,14 @@ namespace Umbraco.Web.Editors IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, UmbracoMapper umbracoMapper, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, IImageUrlGenerator imageUrlGenerator, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider) { _mediaFileSystem = mediaFileSystem; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _imageUrlGenerator = imageUrlGenerator; } @@ -192,7 +192,7 @@ namespace Umbraco.Web.Editors public async Task PostSetAvatar() { //borrow the logic from the user controller - return await UsersController.PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _umbracoSettingsSection, _ioHelper, _imageUrlGenerator, Security.GetUserId().ResultOr(0)); + return await UsersController.PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _contentSettings, _ioHelper, _imageUrlGenerator, Security.GetUserId().ResultOr(0)); } /// diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs index 0ab54d9f98..19ad546b2d 100644 --- a/src/Umbraco.Web/Editors/DataTypeController.cs +++ b/src/Umbraco.Web/Editors/DataTypeController.cs @@ -43,7 +43,7 @@ namespace Umbraco.Web.Editors public class DataTypeController : BackOfficeNotificationsController { private readonly PropertyEditorCollection _propertyEditors; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; public DataTypeController( PropertyEditorCollection propertyEditors, @@ -56,12 +56,12 @@ namespace Umbraco.Web.Editors IRuntimeState runtimeState, IShortStringHelper shortStringHelper, UmbracoMapper umbracoMapper, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider) { _propertyEditors = propertyEditors; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } /// @@ -468,7 +468,7 @@ namespace Umbraco.Web.Editors public IDictionary> GetGroupedPropertyEditors() { var datatypes = new List(); - var showDeprecatedPropertyEditors = _umbracoSettingsSection.Content.ShowDeprecatedPropertyEditors; + var showDeprecatedPropertyEditors = _contentSettings.ShowDeprecatedPropertyEditors; var propertyEditors = Current.PropertyEditors .Where(x=>x.IsDeprecated == false || showDeprecatedPropertyEditors); diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 5324bf12ad..483834868f 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -787,7 +787,8 @@ namespace Umbraco.Web.Editors /// private IEnumerable ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null, bool ignoreUserStartNodes = false) { - return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, searchFrom, ignoreUserStartNodes); + var culture = ClientCulture(); + return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, culture, searchFrom, ignoreUserStartNodes); } private IEnumerable GetResultForChildren(int id, UmbracoEntityTypes entityType) diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index d9a28c70c4..39fe619b9d 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -17,13 +17,13 @@ namespace Umbraco.Web.Editors public class ImagesController : UmbracoAuthorizedApiController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSection _contentSection; + private readonly IContentSettings _contentSettings; private readonly IImageUrlGenerator _imageUrlGenerator; - public ImagesController(IMediaFileSystem mediaFileSystem, IContentSection contentSection, IImageUrlGenerator imageUrlGenerator) + public ImagesController(IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IImageUrlGenerator imageUrlGenerator) { _mediaFileSystem = mediaFileSystem; - _contentSection = contentSection; + _contentSettings = contentSettings; _imageUrlGenerator = imageUrlGenerator; } @@ -56,7 +56,7 @@ namespace Umbraco.Web.Editors var ext = Path.GetExtension(imagePath); // we need to check if it is an image by extension - if (_contentSection.IsImageFile(ext) == false) + if (_contentSettings.IsImageFile(ext) == false) return Request.CreateResponse(HttpStatusCode.NotFound); //redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 8351f5a029..40f00d54e5 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -50,7 +50,7 @@ namespace Umbraco.Web.Editors [MediaControllerControllerConfiguration] public class MediaController : ContentControllerBase { - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; public MediaController( @@ -66,14 +66,14 @@ namespace Umbraco.Web.Editors IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, UmbracoMapper umbracoMapper, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, IPublishedUrlProvider publishedUrlProvider) : base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); _mediaFileSystem = mediaFileSystem; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); } @@ -722,13 +722,13 @@ namespace Umbraco.Web.Editors var safeFileName = fileName.ToSafeFileName(ShortStringHelper); var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower(); - if (_umbracoSettingsSection.Content.IsFileAllowedForUpload(ext)) + if (_contentSettings.IsFileAllowedForUpload(ext)) { var mediaType = Constants.Conventions.MediaTypes.File; if (result.FormData["contentTypeAlias"] == Constants.Conventions.MediaTypes.AutoSelect) { - if (_umbracoSettingsSection.Content.ImageFileTypes.Contains(ext)) + if (_contentSettings.ImageFileTypes.Contains(ext)) { mediaType = Constants.Conventions.MediaTypes.Image; } diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 672b47f1eb..fe552650ea 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -14,11 +14,11 @@ using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Packaging; +using Umbraco.Net; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Net; using Umbraco.Web.JavaScript; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; diff --git a/src/Umbraco.Web/Editors/PreviewController.cs b/src/Umbraco.Web/Editors/PreviewController.cs index 0ed31e3972..3539047112 100644 --- a/src/Umbraco.Web/Editors/PreviewController.cs +++ b/src/Umbraco.Web/Editors/PreviewController.cs @@ -30,13 +30,14 @@ namespace Umbraco.Web.Editors private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ILocalizationService _localizationService; private readonly IUmbracoVersion _umbracoVersion; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; private readonly TreeCollection _treeCollection; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostingEnvironment _hostingEnvironment; private readonly ICookieManager _cookieManager; private IRuntimeSettings _runtimeSettings; + private readonly ISecuritySettings _securitySettings; public PreviewController( UmbracoFeatures features, @@ -45,13 +46,14 @@ namespace Umbraco.Web.Editors IUmbracoContextAccessor umbracoContextAccessor, ILocalizationService localizationService, IUmbracoVersion umbracoVersion, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, ICookieManager cookieManager, - IRuntimeSettings settings) + IRuntimeSettings settings, + ISecuritySettings securitySettings) { _features = features; _globalSettings = globalSettings; @@ -59,13 +61,14 @@ namespace Umbraco.Web.Editors _umbracoContextAccessor = umbracoContextAccessor; _localizationService = localizationService; _umbracoVersion = umbracoVersion; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _treeCollection = treeCollection; _httpContextAccessor = httpContextAccessor; _hostingEnvironment = hostingEnvironment; _cookieManager = cookieManager; _runtimeSettings = settings; + _securitySettings = securitySettings; } [UmbracoAuthorize(redirectToUmbracoLogin: true)] @@ -74,7 +77,7 @@ namespace Umbraco.Web.Editors { var availableLanguages = _localizationService.GetAllLanguages(); - var model = new BackOfficePreviewModel(_features, _globalSettings, _umbracoVersion, availableLanguages, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings); + var model = new BackOfficePreviewModel(_features, _globalSettings, _umbracoVersion, availableLanguages, _contentSettings, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment, _runtimeSettings, _securitySettings); if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false) { @@ -85,7 +88,7 @@ namespace Umbraco.Web.Editors } } - return View(_globalSettings.Path.EnsureEndsWith('/') + "Views/Preview/" + "Index.cshtml", model); + return View(_ioHelper.BackOfficePath.EnsureEndsWith('/') + "Views/Preview/" + "Index.cshtml", model); } /// diff --git a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs index e6a4f82a77..d1bb3f873c 100644 --- a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs @@ -19,12 +19,12 @@ namespace Umbraco.Web.Editors public class RedirectUrlManagementController : UmbracoAuthorizedApiController { private readonly ILogger _logger; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IWebRoutingSettings _webRoutingSettings; - public RedirectUrlManagementController(ILogger logger, IUmbracoSettingsSection umbracoSettingsSection) + public RedirectUrlManagementController(ILogger logger, IWebRoutingSettings webRoutingSettings) { _logger = logger; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _webRoutingSettings = webRoutingSettings; } /// @@ -34,7 +34,7 @@ namespace Umbraco.Web.Editors [HttpGet] public IHttpActionResult GetEnableState() { - var enabled = _umbracoSettingsSection.WebRouting.DisableRedirectUrlTracking == false; + var enabled = _webRoutingSettings.DisableRedirectUrlTracking == false; var userIsAdmin = UmbracoContext.Security.CurrentUser.IsAdmin(); return Ok(new { enabled, userIsAdmin }); } diff --git a/src/Umbraco.Web/Editors/TinyMceController.cs b/src/Umbraco.Web/Editors/TinyMceController.cs index e83a6676fe..ff7fdd980e 100644 --- a/src/Umbraco.Web/Editors/TinyMceController.cs +++ b/src/Umbraco.Web/Editors/TinyMceController.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.Editors { private readonly IIOHelper _ioHelper; private readonly IShortStringHelper _shortStringHelper; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; public TinyMceController( IGlobalSettings globalSettings, @@ -44,13 +44,13 @@ namespace Umbraco.Web.Editors IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IShortStringHelper shortStringHelper, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); } @@ -97,7 +97,7 @@ namespace Umbraco.Web.Editors var safeFileName = fileName.ToSafeFileName(_shortStringHelper); var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower(); - if (_umbracoSettingsSection.Content.IsFileAllowedForUpload(ext) == false || _umbracoSettingsSection.Content.ImageFileTypes.Contains(ext) == false) + if (_contentSettings.IsFileAllowedForUpload(ext) == false || _contentSettings.ImageFileTypes.Contains(ext) == false) { // Throw some error - to say can't upload this IMG type return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "This is not an image filetype extension that is approved"); diff --git a/src/Umbraco.Web/Editors/TourController.cs b/src/Umbraco.Web/Editors/TourController.cs index 6b586ed162..93ec4252df 100644 --- a/src/Umbraco.Web/Editors/TourController.cs +++ b/src/Umbraco.Web/Editors/TourController.cs @@ -25,8 +25,8 @@ namespace Umbraco.Web.Editors public class TourController : UmbracoAuthorizedJsonController { private readonly TourFilterCollection _filters; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; private readonly IIOHelper _ioHelper; + private readonly ITourSettings _tourSettings; public TourController( IGlobalSettings globalSettings, @@ -39,21 +39,21 @@ namespace Umbraco.Web.Editors IShortStringHelper shortStringHelper, UmbracoMapper umbracoMapper, TourFilterCollection filters, - IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, - IPublishedUrlProvider publishedUrlProvider) + IPublishedUrlProvider publishedUrlProvider, + ITourSettings tourSettings) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider) { _filters = filters; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); _ioHelper = ioHelper; + _tourSettings = tourSettings; } public IEnumerable GetTours() { var result = new List(); - if (_umbracoSettingsSection.BackOffice.Tours.EnableTours == false) + if (_tourSettings.EnableTours == false) return result; var user = UmbracoContext.Security.CurrentUser; diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 0aa63a1e16..9554906b0d 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -46,10 +46,11 @@ namespace Umbraco.Web.Editors public class UsersController : UmbracoAuthorizedJsonController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IUmbracoSettingsSection _umbracoSettingsSection; + private readonly IContentSettings _contentSettings; private readonly IIOHelper _ioHelper; private readonly ISqlContext _sqlContext; private readonly IImageUrlGenerator _imageUrlGenerator; + private readonly ISecuritySettings _securitySettings; public UsersController( IGlobalSettings globalSettings, @@ -62,17 +63,19 @@ namespace Umbraco.Web.Editors IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, UmbracoMapper umbracoMapper, - IUmbracoSettingsSection umbracoSettingsSection, + IContentSettings contentSettings, IIOHelper ioHelper, IImageUrlGenerator imageUrlGenerator, - IPublishedUrlProvider publishedUrlProvider) + IPublishedUrlProvider publishedUrlProvider, + ISecuritySettings securitySettings) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider) { _mediaFileSystem = mediaFileSystem; - _umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection)); + _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); _ioHelper = ioHelper; _sqlContext = sqlContext; _imageUrlGenerator = imageUrlGenerator; + _securitySettings = securitySettings; } /// @@ -93,10 +96,10 @@ namespace Umbraco.Web.Editors [AdminUsersAuthorize] public async Task PostSetAvatar(int id) { - return await PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _umbracoSettingsSection, _ioHelper, _imageUrlGenerator, id); + return await PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _contentSettings, _ioHelper, _imageUrlGenerator, id); } - internal static async Task PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, IImageUrlGenerator imageUrlGenerator, int id) + internal static async Task PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IContentSettings contentSettings, IIOHelper ioHelper, IImageUrlGenerator imageUrlGenerator, int id) { if (request.Content.IsMimeMultipartContent() == false) { @@ -131,7 +134,7 @@ namespace Umbraco.Web.Editors var safeFileName = fileName.ToSafeFileName(shortStringHelper); var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower(); - if (umbracoSettingsSection.Content.DisallowedUploadFiles.Contains(ext) == false) + if (contentSettings.DisallowedUploadFiles.Contains(ext) == false) { //generate a path of known data, we don't want this path to be guessable user.Avatar = "UserAvatars/" + (user.Id + safeFileName).GenerateHash() + "." + ext; @@ -230,7 +233,7 @@ namespace Umbraco.Web.Editors // so to do that here, we'll need to check if this current user is an admin and if not we should exclude all user who are // also admins - var hideDisabledUsers = _umbracoSettingsSection.Security.HideDisabledUsersInBackoffice; + var hideDisabledUsers = _securitySettings.HideDisabledUsersInBackoffice; var excludeUserGroups = new string[0]; var isAdmin = Security.CurrentUser.IsAdmin(); if (isAdmin == false) @@ -288,7 +291,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); } - if (_umbracoSettingsSection.Security.UsernameIsEmail) + if (_securitySettings.UsernameIsEmail) { //ensure they are the same if we're using it userSave.Username = userSave.Email; @@ -380,7 +383,7 @@ namespace Umbraco.Web.Editors } IUser user; - if (_umbracoSettingsSection.Security.UsernameIsEmail) + if (_securitySettings.UsernameIsEmail) { //ensure it's the same userSave.Username = userSave.Email; @@ -454,7 +457,7 @@ namespace Umbraco.Web.Editors if (user != null && (extraCheck == null || extraCheck(user))) { ModelState.AddModelError( - _umbracoSettingsSection.Security.UsernameIsEmail ? "Email" : "Username", + _securitySettings.UsernameIsEmail ? "Email" : "Username", "A user with the username already exists"); throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); } @@ -484,7 +487,7 @@ namespace Umbraco.Web.Editors var action = urlHelper.Action("VerifyInvite", "BackOffice", new { - area = GlobalSettings.GetUmbracoMvcArea(_ioHelper), + area = _ioHelper.GetUmbracoMvcArea(), invite = inviteToken }); @@ -574,7 +577,7 @@ namespace Umbraco.Web.Editors // if the found user has their email for username, we want to keep this synced when changing the email. // we have already cross-checked above that the email isn't colliding with anything, so we can safely assign it here. - if (_umbracoSettingsSection.Security.UsernameIsEmail && found.Username == found.Email && userSave.Username != userSave.Email) + if (_securitySettings.UsernameIsEmail && found.Username == found.Email && userSave.Username != userSave.Email) { userSave.Username = userSave.Email; } diff --git a/src/Umbraco.Web/HealthCheck/HealthCheckController.cs b/src/Umbraco.Web/HealthCheck/HealthCheckController.cs index 251c5c0ae4..bfd33399d2 100644 --- a/src/Umbraco.Web/HealthCheck/HealthCheckController.cs +++ b/src/Umbraco.Web/HealthCheck/HealthCheckController.cs @@ -20,12 +20,12 @@ namespace Umbraco.Web.HealthCheck private readonly IList _disabledCheckIds; private readonly ILogger _logger; - public HealthCheckController(HealthCheckCollection checks, ILogger logger, IHealthChecks healthChecks) + public HealthCheckController(HealthCheckCollection checks, ILogger logger, IHealthChecksSettings healthChecksSettings) { _checks = checks ?? throw new ArgumentNullException(nameof(checks)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - var healthCheckConfig = healthChecks ?? throw new ArgumentNullException(nameof(healthChecks)); + var healthCheckConfig = healthChecksSettings ?? throw new ArgumentNullException(nameof(healthChecksSettings)); _disabledCheckIds = healthCheckConfig.DisabledChecks .Select(x => x.Id) .ToList(); diff --git a/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs b/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs index 14cc205fef..ee3ab51d47 100644 --- a/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs @@ -40,9 +40,9 @@ namespace Umbraco.Web /// These are the bare minimal server variables that are required for the application to start without being authenticated, /// we will load the rest of the server vars after the user is authenticated. /// - public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, string externalLoginsUrl, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, IRuntimeSettings settings) + public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, string externalLoginsUrl, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IContentSettings contentSettings, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment, IRuntimeSettings settings, ISecuritySettings securitySettings) { - var serverVars = new BackOfficeServerVariables(uri, Current.RuntimeState, features, globalSettings, umbracoVersion, umbracoSettingsSection, ioHelper, treeCollection, httpContextAccessor, hostingEnvironment, settings); + var serverVars = new BackOfficeServerVariables(uri, Current.RuntimeState, features, globalSettings, umbracoVersion, contentSettings, ioHelper, treeCollection, httpContextAccessor, hostingEnvironment, settings, securitySettings); var minVars = serverVars.BareMinimumServerVariables(); var str = @"